From 938c3e5a587ce950a94964ea509b9e7f8834dfae Mon Sep 17 00:00:00 2001
From: wwf <yearningwang@iqtogether.com>
Date: 星期二, 20 五月 2025 10:09:00 +0800
Subject: [PATCH] 初始化
---
app/components/workflow/nodes/loop/utils.ts | 179
app/components/base/auto-height-textarea/style.module.scss | 0
app/components/header/assets/anthropic.svg | 11
app/components/base/icons/src/vender/line/images/index.ts | 1
app/components/base/list-empty/index.tsx | 38
app/components/workflow/operator/control.tsx | 103
app/components/base/icons/assets/vender/solid/users/user-01.svg | 8
app/components/base/block-input/index.tsx | 146
app/components/workflow/block-selector/tabs.tsx | 85
i18n/th-TH/app-log.ts | 98
app/components/datasets/create/website/firecrawl/header.tsx | 43
utils/tool-call.ts | 6
app/components/app/configuration/base/var-highlight/index.tsx | 37
app/components/base/prompt-editor/plugins/component-picker-block/menu.tsx | 31
app/components/datasets/common/retrieval-param-config/index.tsx | 295
app/components/workflow/nodes/start/components/var-list.tsx | 70
public/pdf.worker.min.mjs | 21
app/components/plugins/marketplace/search-box/index.tsx | 70
app/components/base/icons/assets/public/knowledge/chunk.svg | 13
app/components/datasets/documents/detail/completed/common/action-buttons.tsx | 86
app/components/workflow/nodes/if-else/components/condition-value.tsx | 108
app/components/workflow/nodes/_base/components/file-upload-setting.tsx | 199
app/components/plugins/marketplace/description/index.tsx | 71
app/components/base/icons/assets/vender/line/mediaAndDevices/stop.svg | 10
app/components/workflow/block-selector/market-place-plugin/action.tsx | 89
app/(commonLayout)/apps/assets/add.svg | 3
app/components/app/create-app-dialog/app-list/sidebar.tsx | 60
app/components/base/radio/component/group/index.tsx | 24
app/components/workflow/run/node.tsx | 258
app/components/base/checkbox/index.tsx | 51
app/components/base/icons/assets/vender/line/development/git-branch-01.svg | 5
app/components/base/logo/dify-logo.tsx | 45
app/components/plugins/utils.ts | 26
app/components/base/icons/assets/vender/line/files/file-plus-01.svg | 5
app/components/plugins/marketplace/context.tsx | 348
i18n/ja-JP/dataset-settings.ts | 43
app/components/base/pagination/type.ts | 58
app/components/base/icons/src/public/files/Pdf.tsx | 20
app/components/app/configuration/ctrl-btn-group/index.tsx | 24
i18n/fa-IR/dataset-documents.ts | 394
app/account/delete-account/index.tsx | 44
app/components/base/icons/assets/public/billing/google-cloud.svg | 8
app/components/base/icons/assets/vender/line/files/file-upload.svg | 6
service/use-base.ts | 26
app/components/datasets/create/assets/zap-fast.svg | 6
app/components/app/overview/assets/refresh-hover.svg | 3
app/components/base/icons/src/vender/line/files/FileUpload.json | 52
app/components/base/icons/src/vender/line/mediaAndDevices/Speaker.json | 112
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/index.tsx | 277
i18n/vi-VN/register.ts | 4
app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.tsx | 64
public/vs/basic-languages/flow9/flow9.js | 10
app/components/header/account-setting/model-provider-page/provider-added-card/priority-use-tip.tsx | 19
app/components/share/text-generation/run-batch/csv-download/index.tsx | 70
app/components/workflow/nodes/variable-assigner/node.tsx | 61
app/components/header/account-setting/model-provider-page/model-name/index.tsx | 84
app/components/base/chat/utils.ts | 193
app/components/base/icons/src/public/other/Icon3Dots.tsx | 20
app/components/workflow-app/hooks/use-workflow-refresh-draft.ts | 36
i18n/hi-IN/dataset-settings.ts | 48
i18n/ja-JP/app-overview.ts | 173
app/components/datasets/create/assets/md.svg | 18
app/components/workflow/panel/version-history-panel/filter/index.tsx | 81
app/components/base/icons/assets/vender/workflow/question-classifier.svg | 5
utils/semver.ts | 9
app/components/workflow/panel/version-history-panel/context-menu/index.tsx | 84
app/components/plugins/card/base/corner-mark.tsx | 12
context/external-api-panel-context.tsx | 28
app/components/workflow/limit-tips.tsx | 39
app/components/base/prompt-editor/plugins/on-blur-or-focus-block.tsx | 69
app/components/base/icons/src/vender/line/users/User01.json | 39
app/components/plugins/plugin-detail-panel/tool-selector/hooks.ts | 14
app/components/workflow/types.ts | 435
app/components/base/icons/assets/vender/solid/alertsAndFeedback/alert-triangle.svg | 5
app/components/datasets/external-knowledge-base/create/index.tsx | 128
app/components/app/create-from-dsl-modal/index.tsx | 320
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/api/page.tsx | 9
app/components/workflow/nodes/knowledge-retrieval/hooks.ts | 14
i18n/uk-UA/layout.ts | 4
app/components/workflow/nodes/assigner/components/var-list/use-var-list.ts | 39
app/components/plugins/install-plugin/base/check-task-status.ts | 63
app/components/workflow/nodes/parameter-extractor/components/extract-parameter/list.tsx | 85
app/components/base/icons/src/vender/solid/development/Container.json | 44
app/components/base/icons/assets/vender/solid/mediaAndDevices/speaker.svg | 15
app/components/base/icons/src/image/llm/Wxyy.tsx | 20
app/components/base/icons/assets/vender/line/mediaAndDevices/speaker.svg | 15
app/components/base/markdown-blocks/form.tsx | 238
i18n/it-IT/dataset-creation.ts | 241
i18n/ro-RO/run-log.ts | 31
i18n/ru-RU/dataset-creation.ts | 218
app/components/base/icons/src/vender/solid/development/Variable02.tsx | 20
app/components/base/icons/src/vender/line/editor/LetterSpacing01.json | 39
app/components/workflow/panel/chat-variable-panel/components/variable-type-select.tsx | 66
app/components/app/configuration/config-vision/index.tsx | 112
app/components/app/configuration/base/group-name/index.tsx | 24
app/components/workflow/nodes/http/types.ts | 84
app/components/base/icons/src/public/llm/OpenaiGreen.tsx | 20
app/components/base/features/new-feature-panel/feature-card.tsx | 61
app/components/base/icons/assets/public/tracing/tracing-icon.svg | 6
app/components/base/icons/assets/vender/line/editor/letter-spacing-01.svg | 5
app/components/base/icons/assets/vender/solid/editor/paragraph.svg | 5
app/components/base/icons/src/vender/workflow/TemplatingTransform.tsx | 20
app/components/plugins/plugin-page/install-plugin-dropdown.tsx | 140
app/components/base/form/components/field/number-input.tsx | 49
app/components/workflow/nodes/_base/panel.tsx | 209
app/components/base/icons/src/vender/line/files/Folder.tsx | 20
app/components/base/icons/src/vender/line/general/Target04.json | 65
public/vs/basic-languages/scheme/scheme.js | 10
app/components/base/icons/src/public/billing/Asterisk.tsx | 20
app/components/base/chat/chat-with-history/chat-wrapper.tsx | 270
app/components/workflow/nodes/_base/components/error-handle/fail-branch-card.tsx | 32
app/account/header.tsx | 39
app/components/base/icons/assets/public/llm/chatglm-text.svg | 16
app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button.tsx | 79
app/components/base/icons/src/vender/line/development/PromptEngineering.json | 65
app/components/base/icons/src/vender/line/others/LongArrowLeft.tsx | 20
app/components/app-sidebar/basic.tsx | 99
app/components/base/icons/src/public/files/Doc.json | 169
package.json | 229
app/components/header/account-setting/members-page/invited-modal/index.module.css | 21
app/components/workflow/nodes/list-operator/components/filter-condition.tsx | 113
app/components/base/icons/src/vender/features/VirtualAssistant.tsx | 20
app/components/base/icons/src/vender/line/editor/Collapse.tsx | 20
app/components/workflow/nodes/end/default.ts | 27
i18n/ru-RU/app-annotation.ts | 87
app/components/workflow/block-selector/all-tools.tsx | 168
app/components/workflow/panel/workflow-preview.tsx | 213
i18n/fr-FR/dataset-settings.ts | 43
app/components/workflow/panel/chat-variable-panel/components/variable-item.tsx | 49
service/knowledge/use-hit-testing.ts | 0
app/components/workflow/nodes/loop/components/loop-variables/empty.tsx | 13
app/components/app/configuration/config/agent/agent-setting/item-panel.tsx | 41
app/components/base/icons/assets/public/plugins/verified-light.svg | 58
app/components/base/icons/src/public/llm/Openllm.tsx | 20
app/components/base/icons/src/vender/solid/general/AnswerTriangle.json | 27
app/components/datasets/create/website/base/crawling.tsx | 37
app/components/tools/edit-custom-collection-modal/examples.ts | 181
app/components/base/icons/src/public/tracing/WeaveIcon.tsx | 16
i18n/it-IT/app.ts | 225
app/components/app/configuration/prompt-value-panel/utils.ts | 13
i18n/check-i18n.js | 85
public/screenshots/light/Workflow@2x.png | 0
app/forgot-password/page.tsx | 26
app/components/base/badge/index.css | 28
app/components/base/icons/src/vender/solid/communication/index.ts | 12
app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx | 301
app/components/workflow/hooks/use-workflow-run-event/index.ts | 15
app/components/workflow/run/utils/format-log/graph-to-log-struct.ts | 356
app/components/base/icons/src/vender/line/financeAndECommerce/Balance.json | 29
i18n/ja-JP/dataset-hit-testing.ts | 34
hooks/use-metadata.ts | 395
app/components/base/icons/assets/vender/solid/general/check-done-01.svg | 4
app/components/header/account-setting/model-provider-page/hooks.ts | 353
public/vs/base/common/worker/simpleWorker.nls.fr.js | 8
app/components/datasets/external-knowledge-base/create/ExternalApiSelection.tsx | 96
app/components/base/icons/src/vender/line/general/DotsGrid.json | 134
i18n/it-IT/app-debug.ts | 471
app/components/base/icons/src/vender/line/files/ClipboardCheck.json | 29
app/components/app/configuration/debug/debug-with-multiple-model/model-parameter-trigger.tsx | 126
app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-icon.tsx | 39
app/components/base/icons/assets/vender/features/love-message.svg | 3
app/components/base/icons/assets/vender/solid/development/container.svg | 5
app/components/base/icons/src/public/llm/Gpt3.json | 51
i18n/pl-PL/dataset-documents.ts | 396
app/components/workflow/nodes/_base/components/support-var-input/index.tsx | 52
app/components/workflow/nodes/loop/use-config.ts | 379
app/components/custom/style.module.css | 6
app/components/workflow/nodes/_base/components/field.tsx | 65
public/vs/basic-languages/elixir/elixir.js | 10
app/components/base/icons/src/vender/solid/editor/Citations.tsx | 20
app/components/base/icons/src/vender/workflow/End.tsx | 20
app/signin/components/social-auth.tsx | 62
app/components/header/account-setting/members-page/invited-modal/assets/copy-hover.svg | 3
app/components/workflow/panel/env-panel/variable-modal.tsx | 167
app/components/base/icons/assets/public/knowledge/selection-mod.svg | 13
i18n/uk-UA/app-annotation.ts | 87
app/components/base/icons/assets/vender/solid/communication/message-fast.svg | 3
app/components/workflow/run/utils/format-log/retry/index.ts | 43
i18n/sl-SI/app-overview.ts | 173
app/components/base/icons/assets/vender/line/others/icon-3-dots.svg | 5
app/components/base/notion-page-selector/base.tsx | 136
models/debug.ts | 256
app/components/base/chat/chat/chat-input-area/hooks.ts | 46
app/components/base/icons/assets/public/billing/ar-cube-1.svg | 3
app/components/base/icons/src/public/llm/OpenllmText.tsx | 20
app/components/datasets/hit-testing/utils/extension-to-file-type.ts | 31
app/components/base/icons/src/public/common/Lock.tsx | 20
app/components/base/icons/src/vender/line/communication/ChatBotSlim.json | 68
app/components/workflow/nodes/_base/components/error-handle/error-handle-type-selector.tsx | 97
public/vs/basic-languages/shell/shell.js | 10
app/components/base/icons/src/vender/solid/arrows/ChevronDown.json | 39
app/components/workflow/nodes/loop/components/loop-variables/input-mode-selec.tsx | 37
app/components/base/icons/src/vender/line/general/index.ts | 27
app/components/workflow/nodes/document-extractor/default.ts | 36
app/components/develop/md.tsx | 151
i18n/sl-SI/custom.ts | 32
app/components/plugins/plugin-page/filter-management/index.tsx | 45
app/components/base/icons/src/vender/solid/communication/MessageDotsCircle.tsx | 20
service/workflow.ts | 72
app/components/base/icons/src/image/llm/index.ts | 9
app/components/workflow/nodes/assigner/types.ts | 32
app/components/base/icons/assets/vender/solid/layout/grid-01.svg | 10
app/components/base/icons/src/vender/other/Generator.tsx | 20
app/components/workflow/nodes/_base/hooks/use-available-var-list.ts | 53
app/components/workflow/run/assets/bg-line-success.svg | 3
app/components/workflow/panel/version-history-panel/delete-confirm-modal.tsx | 42
i18n/fa-IR/time.ts | 37
app/components/base/icons/assets/vender/line/arrows/arrow-narrow-left.svg | 3
app/components/datasets/create/file-uploader/index.tsx | 381
i18n/hi-IN/custom.ts | 32
app/components/plugins/install-plugin/base/loading.tsx | 23
app/components/app/configuration/base/warning-mask/index.tsx | 43
app/components/base/icons/assets/vender/workflow/home.svg | 5
app/components/workflow/hooks/use-workflow-run-event/use-workflow-agent-log.ts | 50
app/components/datasets/create/assets/pattern-recognition-mod.svg | 12
README.md | 118
app/components/header/account-setting/menu-dialog.tsx | 60
app/components/workflow/update-dsl-modal.tsx | 302
app/components/base/icons/src/vender/line/files/FileUpload.tsx | 20
app/components/workflow/nodes/end/utils.ts | 5
app/components/develop/secret-key/assets/qrcode.svg | 4
app/components/base/icons/src/public/billing/SparklesSoft.json | 36
app/components/plugins/card/base/download-count.tsx | 19
app/components/base/icons/src/vender/other/Group.json | 66
app/(shareLayout)/chatbot/[token]/page.tsx | 11
public/vs/base/common/worker/simpleWorker.nls.zh-tw.js | 8
app/components/base/icons/assets/public/common/lock.svg | 5
app/education-apply/role-selector.tsx | 53
app/components/workflow/nodes/variable-assigner/components/var-list/use-var-list.ts | 34
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/panel.tsx | 238
app/components/base/icons/src/vender/solid/files/FileSearch02.tsx | 20
app/components/workflow/utils/node.ts | 145
app/components/datasets/create/website/jina-reader/base/field.tsx | 54
app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx | 109
app/components/app/configuration/debug/chat-user-input.tsx | 108
public/vs/basic-languages/sophia/sophia.js | 10
i18n/fr-FR/app-annotation.ts | 87
app/components/base/icons/src/vender/features/FolderUpload.json | 26
app/components/base/copy-feedback/index.tsx | 91
public/vs/basic-languages/azcli/azcli.js | 10
app/components/base/icons/src/vender/line/arrows/ChevronSelectorVertical.json | 29
i18n/vi-VN/plugin.ts | 215
app/components/share/text-generation/result/index.tsx | 466
app/components/base/icons/assets/image/llm/tongyi-text.png | 0
app/(commonLayout)/datasets/layout.tsx | 14
app/components/header/assets/bitbucket.svg | 10
app/components/app/annotation/view-annotation-modal/hit-history-no-data.tsx | 19
app/components/base/icons/src/vender/other/ReplayLine.tsx | 20
app/components/base/badge/index.tsx | 81
app/components/plugins/plugin-page/filter-management/constant.ts | 11
app/components/base/icons/assets/vender/line/editor/type-square.svg | 5
app/components/datasets/create/stepper/index.tsx | 27
app/components/base/icons/src/public/llm/AnthropicLight.json | 1046
app/components/base/date-and-time-picker/year-and-month-picker/options.tsx | 55
app/components/base/features/new-feature-panel/file-upload/index.tsx | 105
app/components/base/icons/src/vender/plugin/LeftCorner.tsx | 20
app/components/base/icons/src/vender/solid/development/FileHeart02.tsx | 20
app/components/base/icons/src/public/common/Dify.tsx | 20
app/components/base/icons/src/vender/line/development/BracketsX.tsx | 20
app/components/workflow/hooks/use-workflow-run.ts | 17
app/components/base/icons/src/vender/solid/mediaAndDevices/MagicEyes.json | 38
app/components/base/audio-btn/audio.player.manager.ts | 50
app/components/base/icons/src/public/plugins/index.ts | 7
app/components/base/icons/assets/public/common/d.svg | 16
app/components/datasets/create/assets/star.svg | 11
app/components/base/icons/src/vender/line/files/FilePlus01.tsx | 20
app/components/datasets/create/assets/close.svg | 3
app/account/account-page/index.tsx | 320
app/components/base/icons/assets/public/llm/azureai-text.svg | 30
app/components/header/assets/twitter.svg | 3
app/components/datasets/create/assets/notion.svg | 12
app/components/datasets/metadata/hooks/use-check-metadata-name.ts | 28
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx.tsx | 91
app/components/base/icons/src/public/knowledge/SelectionMod.json | 116
app/signin/assets/google.svg | 13
app/components/base/icons/src/image/llm/WxyyText.module.css | 5
app/components/base/icons/assets/vender/line/general/plus-02.svg | 5
i18n/en-US/run-log.ts | 31
i18n/ko-KR/education.ts | 47
service/knowledge/use-document.ts | 132
app/components/datasets/documents/detail/completed/segment-card/index.tsx | 254
app/components/base/icons/assets/vender/line/mapsAndTravel/route.svg | 10
app/components/base/icons/assets/vender/workflow/knowledge-retrieval.svg | 5
app/components/base/icons/src/vender/solid/editor/Colors.json | 62
app/(commonLayout)/datasets/Container.tsx | 141
app/components/datasets/documents/assets/briefcase.svg | 3
public/vs/basic-languages/qsharp/qsharp.js | 10
typography.js | 357
app/components/workflow/nodes/tool/panel.tsx | 202
app/components/base/features/hooks.ts | 16
app/components/base/icons/assets/public/thought/search.svg | 10
app/components/workflow/header/undo-redo.tsx | 66
public/logo/logo.svg | 12
i18n/language.ts | 114
app/components/workflow/hooks/use-format-time-from-now.ts | 12
i18n/zh-Hant/login.ts | 110
app/components/base/notion-page-selector/assets/notion-empty-page.svg | 3
app/components/workflow/nodes/variable-assigner/components/add-variable/index.tsx | 89
app/components/base/video-gallery/VideoPlayer.tsx | 278
app/components/base/date-and-time-picker/types.ts | 105
app/components/base/file-uploader/file-uploader-in-chat-input/index.tsx | 41
public/screenshots/light/Chatbot@2x.png | 0
i18n/ko-KR/register.ts | 3
app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/style.module.css | 20
app/components/base/icons/src/public/common/DiagonalDividingLine.json | 28
app/components/base/icons/assets/public/llm/jina.svg | 4
app/components/base/icons/src/vender/line/mediaAndDevices/Stop.json | 66
app/components/plugins/plugin-page/index.tsx | 299
app/components/base/icons/assets/public/avatar/robot.svg | 11
app/components/workflow/nodes/code/utils.ts | 3
public/vs/basic-languages/abap/abap.js | 10
app/components/base/chat/chat-with-history/hooks.tsx | 495
app/components/datasets/common/document-file-icon.tsx | 40
app/components/app/text-generate/item/index.tsx | 383
app/components/base/tag/index.tsx | 42
app/components/workflow/nodes/question-classifier/panel.tsx | 204
app/components/base/features/new-feature-panel/moderation/index.tsx | 176
app/components/base/icons/src/vender/line/development/PromptEngineering.tsx | 20
i18n/th-TH/app-debug.ts | 4
app/components/base/icons/assets/vender/line/arrows/arrow-up-right.svg | 5
app/components/workflow/nodes/code/panel.tsx | 159
app/components/base/date-and-time-picker/date-picker/index.tsx | 309
app/components/base/icons/assets/vender/line/general/upload-03.svg | 10
app/components/base/icons/src/public/llm/Cohere.tsx | 20
app/components/base/icons/src/vender/line/development/TerminalSquare.json | 39
app/components/develop/template/template_chat.zh.mdx | 1394
i18n/it-IT/workflow.ts | 946
app/components/base/icons/assets/vender/solid/mediaAndDevices/sliders-02.svg | 8
app/components/base/icons/src/public/llm/AzureOpenaiService.tsx | 20
public/vs/basic-languages/redis/redis.js | 10
app/components/workflow/panel/env-panel/index.tsx | 195
app/components/plugins/plugin-page/debug-info.tsx | 67
app/components/workflow/nodes/_base/hooks/use-node-info.ts | 22
i18n/de-DE/custom.ts | 32
app/components/base/icons/src/vender/workflow/index.ts | 21
i18n/ru-RU/app-overview.ts | 173
app/components/base/icons/src/vender/line/arrows/index.ts | 8
app/components/base/icons/src/image/llm/BaichuanTextCn.module.css | 5
app/components/base/icons/src/vender/line/education/index.ts | 1
app/components/explore/create-app-modal/index.tsx | 195
app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx | 104
app/components/base/icons/src/image/llm/Minimax.tsx | 20
app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/index.tsx | 183
.gitignore | 56
app/components/workflow/hooks/use-workflow-run-event/use-workflow-finished.ts | 35
i18n/es-ES/dataset-hit-testing.ts | 35
app/components/app/configuration/dataset-config/type-icon/index.tsx | 33
i18n/hi-IN/explore.ts | 45
app/components/base/icons/src/public/tracing/TracingIcon.tsx | 20
app/components/base/features/new-feature-panel/moderation/form-generation.tsx | 80
app/components/base/icons/src/vender/line/arrows/RefreshCw05.json | 29
app/components/base/corner-label/index.tsx | 21
app/components/billing/utils/index.ts | 29
app/components/base/icons/src/vender/solid/development/PuzzlePiece01.tsx | 20
app/components/workflow/note-node/note-editor/toolbar/divider.tsx | 7
app/components/base/chat/embedded-chatbot/header/index.tsx | 179
app/components/base/icons/src/vender/line/arrows/ChevronSelectorVertical.tsx | 20
app/components/workflow/block-selector/tool/tool-list-tree-view/item.tsx | 47
app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-loop-finished.ts | 57
app/components/base/icons/src/vender/line/shapes/CubeOutline.json | 98
app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx | 447
i18n/de-DE/app-overview.ts | 173
i18n/ko-KR/share-app.ts | 78
app/components/base/icons/src/public/tracing/LangsmithIcon.tsx | 20
app/components/develop/secret-key/assets/trash-gray.svg | 3
i18n/tr-TR/workflow.ts | 922
app/components/plugins/plugin-detail-panel/index.tsx | 62
app/components/workflow/panel/index.tsx | 50
app/components/base/prompt-editor/plugins/history-block/node.tsx | 90
public/vs/basic-languages/yaml/yaml.js | 10
app/components/base/icons/src/public/files/Yaml.tsx | 20
app/components/develop/doc.tsx | 178
app/components/base/icons/src/vender/solid/editor/Brush01.tsx | 20
app/components/app/configuration/dataset-config/params-config/weighted-score.tsx | 62
app/components/base/icons/src/public/common/Github.json | 36
context/explore-context.ts | 21
app/components/app/configuration/dataset-config/select-dataset/index.tsx | 176
app/components/base/prompt-log-modal/card.tsx | 42
i18n/pl-PL/explore.ts | 45
app/components/plugins/plugin-detail-panel/app-selector/app-trigger.tsx | 48
app/components/base/icons/assets/public/llm/openllm.svg | 12
jest.config.ts | 210
public/vs/basic-languages/less/less.js | 11
app/components/base/icons/src/vender/solid/education/Unblur.json | 152
app/components/base/notion-page-selector/workspace-selector/index.tsx | 80
app/components/base/custom-icon/index.tsx | 16
app/components/base/icons/src/image/llm/TongyiTextCn.module.css | 5
app/components/base/icons/src/vender/line/weather/index.ts | 1
app/components/workflow/nodes/document-extractor/panel.tsx | 124
app/components/base/icons/src/vender/solid/general/ZapNarrow.json | 38
app/components/workflow/nodes/if-else/node.tsx | 103
app/components/app/configuration/config/code-generator/get-code-generator-res.tsx | 230
i18n/en-US/time.ts | 37
app/components/base/icons/src/vender/line/financeAndECommerce/Tag03.tsx | 20
app/components/base/icons/src/vender/solid/arrows/ChevronDown.tsx | 20
app/components/base/icons/src/vender/line/editor/Colors.tsx | 20
app/components/workflow/nodes/knowledge-retrieval/components/dataset-item.tsx | 125
i18n/zh-Hant/workflow.ts | 921
app/components/base/icons/assets/public/llm/openai-blue.svg | 4
app/components/app/overview/apikey-info-panel/index.tsx | 73
themes/manual-light.css | 65
app/components/datasets/common/economical-retrieval-method-config/index.tsx | 42
app/components/app/overview/appCard.tsx | 273
i18n/zh-Hans/dataset-settings.ts | 43
app/components/billing/plan/index.tsx | 137
app/components/datasets/create/assets/pdf.svg | 22
i18n/en-US/dataset-settings.ts | 43
i18n/th-TH/tools.ts | 158
app/components/base/icons/assets/public/files/doc.svg | 22
app/components/workflow-app/hooks/use-workflow-run.ts | 357
app/components/workflow/nodes/if-else/components/condition-number-input.tsx | 168
app/components/workflow-app/hooks/use-workflow-start-run.tsx | 96
app/components/base/icons/src/vender/line/files/ClipboardCheck.tsx | 20
app/components/develop/secret-key/assets/qrcode-hover.svg | 4
app/components/base/date-and-time-picker/calendar/days-of-week.tsx | 21
app/components/base/icons/src/vender/workflow/TemplatingTransform.json | 154
app/components/base/grid-mask/Grid.svg | 2146
app/components/base/icons/src/vender/line/files/FileCheck02.tsx | 20
app/components/base/icons/src/vender/other/Group.tsx | 20
app/components/base/icons/src/vender/solid/communication/CuteRobot.json | 38
app/components/plugins/plugin-detail-panel/app-selector/app-picker.tsx | 123
app/components/workflow/nodes/_base/components/list-no-data-placeholder.tsx | 18
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config.ts | 8
app/components/base/icons/assets/vender/solid/mediaAndDevices/document-support-icon.svg | 3
app/components/plugins/marketplace/search-box/tags-filter.tsx | 138
i18n/pt-BR/custom.ts | 32
i18n/en-US/app-overview.ts | 173
app/components/datasets/metadata/utils/get-icon.ts | 10
app/components/workflow/nodes/tool/types.ts | 25
app/components/base/chat/chat-with-history/sidebar/item.tsx | 58
app/components/datasets/hit-testing/modify-retrieval-modal.tsx | 118
app/components/workflow/block-selector/index.tsx | 171
app/components/base/icons/src/vender/line/financeAndECommerce/GoldCoin.json | 120
app/components/datasets/metadata/hooks/use-metadata-document.ts | 159
app/components/base/icons/src/vender/line/others/Colors.json | 66
app/components/workflow/block-selector/market-place-plugin/item.tsx | 77
app/components/base/icons/src/vender/line/shapes/CubeOutline.tsx | 20
app/components/base/prompt-editor/plugins/context-block/node.tsx | 100
app/components/workflow/block-selector/hooks.ts | 55
app/components/base/icons/assets/public/plugins/verified-dark.svg | 58
app/components/base/icons/assets/public/knowledge/collapse.svg | 9
public/vs/basic-languages/powershell/powershell.js | 10
app/components/base/icons/assets/public/common/dify.svg | 8
app/components/base/icons/src/vender/solid/mediaAndDevices/Play.tsx | 20
app/components/base/icons/src/vender/workflow/Agent.json | 53
app/components/base/icons/assets/public/llm/xorbits-inference-text.svg | 42
app/components/base/chat/__tests__/multiRootNodesMessages.json | 52
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-config-modal.tsx | 390
app/components/workflow/nodes/_base/components/error-handle/hooks.ts | 123
service/demo/index.tsx | 100
app/components/header/assets/gpt.svg | 4
app/components/workflow/utils/common.ts | 35
app/components/app/configuration/config/index.tsx | 99
app/components/app/configuration/config-var/select-type-item/index.tsx | 41
app/components/base/icons/src/vender/line/general/Check.tsx | 20
i18n/th-TH/dataset-settings.ts | 43
app/components/app/log/model-info.tsx | 107
app/components/base/features/context.tsx | 27
i18n/hi-IN/tools.ts | 163
app/components/base/icons/src/vender/solid/files/Folder.json | 38
app/components/workflow/nodes/question-classifier/use-config.ts | 258
app/components/workflow/nodes/_base/components/prompt/editor.tsx | 306
app/components/app/configuration/dataset-config/params-config/weighted-score.css | 7
app/components/base/icons/assets/vender/solid/general/message-clock-circle.svg | 5
app/components/workflow/nodes/_base/components/readonly-input-with-select-var.tsx | 90
service/knowledge/use-create-dataset.ts | 223
app/(commonLayout)/apps/page.tsx | 37
app/components/app/duplicate-modal/index.tsx | 124
app/components/base/date-and-time-picker/calendar/item.tsx | 30
app/components/base/prompt-editor/plugins/placeholder.tsx | 27
app/components/workflow/nodes/variable-assigner/panel.tsx | 127
app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.json | 59
app/components/base/icons/assets/public/files/txt.svg | 23
app/components/app/configuration/config-var/config-select/index.spec.tsx | 82
app/components/base/icons/assets/image/llm/wxyy-text-cn.png | 0
i18n/th-TH/app-api.ts | 85
app/components/base/icons/assets/public/plugins/partner-dark.svg | 58
app/components/workflow/datasets-detail-store/store.ts | 38
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/type-selector.tsx | 69
app/components/base/chat/chat/answer/__mocks__/markdownContent.ts | 61
app/components/workflow/nodes/_base/components/split.tsx | 18
context/datasets-context.tsx | 21
app/components/base/icons/src/vender/features/Microphone01.tsx | 20
app/components/tools/add-tool-modal/category.tsx | 69
app/components/base/icons/src/vender/solid/FinanceAndECommerce/Scales02.tsx | 20
app/components/base/icons/src/vender/solid/layout/Grid01.tsx | 20
app/components/header/account-setting/model-provider-page/model-selector/popup.tsx | 121
app/components/base/icons/src/public/files/Docx.json | 178
app/components/base/icons/assets/vender/line/others/colors.svg | 10
app/account/layout.tsx | 40
app/components/plugins/card/base/org-info.tsx | 30
app/components/base/file-uploader/dynamic-pdf-preview.tsx | 17
app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx | 82
app/components/workflow/nodes/assigner/hooks.ts | 70
i18n/pt-BR/app-overview.ts | 173
i18n/ro-RO/billing.ts | 200
i18n/ru-RU/time.ts | 37
i18n/de-DE/app-annotation.ts | 87
app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-up.svg | 10
app/components/base/icons/assets/public/thought/web-reader.svg | 10
app/components/base/icons/assets/public/other/message-3-fill.svg | 23
app/components/base/icons/src/public/llm/index.ts | 42
app/components/workflow/utils/variable.ts | 18
app/components/workflow/nodes/_base/components/error-handle/types.ts | 13
i18n/de-DE/dataset-settings.ts | 43
app/components/base/chat/chat-with-history/header-in-mobile.tsx | 152
app/components/base/icons/src/vender/line/files/File02.json | 39
app/components/base/icons/src/vender/solid/FinanceAndECommerce/GoldCoin.tsx | 20
app/components/workflow/simple-node/index.tsx | 148
app/(commonLayout)/datasets/template/template.zh.mdx | 2394
i18n/index.ts | 29
app/components/base/chat/chat-with-history/inputs-form/index.tsx | 79
app/components/datasets/documents/assets/target.svg | 10
app/components/workflow/nodes/_base/components/input-var-type-icon.tsx | 32
app/components/workflow/run/loop-log/loop-result-panel.tsx | 148
app/components/base/icons/src/vender/line/general/InfoCircle.json | 66
app/components/base/confirm/index.tsx | 108
app/components/base/features/new-feature-panel/annotation-reply/type.ts | 4
app/components/base/icons/assets/public/llm/azure-openai-service.svg | 7
app/components/base/icons/src/public/llm/IflytekSparkTextCn.json | 98
app/components/base/radio/ui.tsx | 18
app/components/header/account-setting/data-source-page/data-source-notion/index.tsx | 85
app/signin/page.module.css | 7
app/components/base/chat/embedded-chatbot/index.tsx | 241
app/components/workflow/nodes/http/panel.tsx | 213
app/components/workflow/nodes/question-classifier/utils.ts | 3
app/components/base/icons/src/public/plugins/Wikipedia.json | 26
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/advanced-actions.tsx | 59
public/vs/editor/editor.main.nls.ru.js | 15
app/components/base/icons/assets/vender/line/editor/left-indent-02.svg | 3
app/components/base/icons/src/public/tracing/index.ts | 9
app/components/base/icons/src/vender/solid/FinanceAndECommerce/index.ts | 2
app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx | 62
docker/pm2.json | 11
app/components/datasets/documents/detail/completed/child-segment-list.tsx | 195
i18n/de-DE/register.ts | 4
app/components/base/chat/__tests__/mixedTestMessages.json | 42
app/components/base/chat/chat/answer/index.tsx | 239
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx | 144
app/components/datasets/documents/style.module.css | 118
app/components/workflow/nodes/tool/node.tsx | 53
app/account/account-page/AvatarWithEdit.tsx | 122
app/components/base/icons/src/vender/line/general/X.tsx | 20
app/components/base/icons/src/public/common/MultiPathRetrieval.tsx | 20
i18n/vi-VN/layout.ts | 4
app/components/app/annotation/batch-add-annotation-modal/index.tsx | 124
app/components/datasets/rename-modal/index.tsx | 110
app/components/workflow/nodes/assigner/components/var-list/index.tsx | 225
app/components/app/configuration/config-prompt/style.module.css | 28
app/components/base/icons/src/vender/line/alertsAndFeedback/index.ts | 3
app/components/base/icons/src/vender/solid/security/Lock01.json | 38
public/vs/basic-languages/bat/bat.js | 10
app/components/base/icons/src/public/llm/Gpt3.tsx | 20
app/components/base/icons/src/vender/features/Vision.json | 28
app/components/base/icons/assets/public/llm/chatglm.svg | 9
app/components/base/icons/assets/vender/solid/development/database-02.svg | 5
app/components/plugins/permission-setting-modal/style.module.css | 7
app/components/base/file-uploader/pdf-preview.tsx | 103
app/components/base/icons/assets/public/llm/cohere.svg | 16
app/components/base/icons/assets/vender/solid/mediaAndDevices/play.svg | 5
app/components/base/icons/src/public/llm/Replicate.json | 39
context/i18n.ts | 38
app/components/plugins/plugin-detail-panel/detail-header.tsx | 312
app/components/datasets/create/assets/research-mod.svg | 6
app/components/base/file-uploader/store.tsx | 67
app/(shareLayout)/layout.tsx | 19
app/components/workflow/blocks.tsx | 5
app/components/workflow/panel/version-history-panel/filter/use-filter.ts | 17
app/components/base/icons/assets/vender/workflow/loop.svg | 5
app/components/base/icons/src/public/llm/JinaText.json | 82
app/components/workflow/run/agent-log/index.tsx | 2
app/components/base/icons/src/public/llm/OpenaiViolet.tsx | 20
app/components/datasets/create/website/base/mock-crawl-result.ts | 24
i18n/zh-Hans/login.ts | 110
app/components/app/configuration/debug/index.tsx | 561
app/components/datasets/documents/detail/completed/common/add-another.tsx | 32
i18n/ro-RO/custom.ts | 32
app/components/base/icons/src/image/llm/Tongyi.module.css | 5
app/components/base/icons/assets/vender/solid/communication/message-dots-circle.svg | 5
i18n/hi-IN/app.ts | 214
public/education/bg.png | 0
app/components/header/account-setting/model-provider-page/model-modal/index.tsx | 401
i18n/README.md | 175
i18n/tr-TR/app-annotation.ts | 87
app/components/base/prompt-editor/plugins/component-picker-block/variable-option.tsx | 60
app/components/workflow/help-line/types.ts | 11
app/components/tools/utils/index.ts | 27
app/components/base/icons/src/public/files/Html.tsx | 20
app/components/workflow/operator/export-image.tsx | 131
app/components/plugins/plugin-detail-panel/action-list.tsx | 112
app/components/workflow/header/header-in-normal.tsx | 69
app/components/datasets/create/assets/web.svg | 4
app/components/datasets/external-api/external-knowledge-api-card/index.tsx | 151
i18n/ja-JP/workflow.ts | 920
app/components/base/icons/src/public/llm/ChatglmText.tsx | 20
app/components/base/icons/src/public/llm/Replicate.tsx | 20
app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown.tsx | 52
i18n/ru-RU/tools.ts | 158
app/components/datasets/documents/detail/completed/segment-detail.tsx | 185
app/components/base/icons/src/vender/solid/mediaAndDevices/Play.json | 38
app/components/share/text-generation/run-batch/res-download/index.tsx | 50
app/components/base/icons/assets/vender/solid/general/tool-03.svg | 9
app/components/workflow/run/loop-result-panel.tsx | 124
app/components/workflow/run/retry-log/retry-log-trigger.tsx | 41
app/reset-password/check-code/page.tsx | 96
app/components/billing/annotation-full/style.module.css | 7
app/components/header/account-setting/model-provider-page/model-badge/index.tsx | 22
app/components/base/prompt-editor/utils.ts | 328
app/education-apply/hooks.ts | 67
i18n/zh-Hant/app-annotation.ts | 90
app/components/explore/item-operation/index.tsx | 90
app/components/workflow/nodes/start/default.ts | 23
public/vs/basic-languages/sql/sql.js | 10
app/components/base/icons/assets/vender/line/time/clock-play-slim.svg | 5
app/components/workflow/nodes/_base/components/title-description-input.tsx | 87
public/vs/base/common/worker/simpleWorker.nls.ja.js | 8
app/components/base/date-and-time-picker/date-picker/header.tsx | 41
public/vs/basic-languages/vb/vb.js | 10
app/components/base/icons/assets/vender/line/others/file-code.svg | 3
app/components/workflow/header/run-and-history.tsx | 111
i18n/ja-JP/app-annotation.ts | 90
app/components/app/configuration/config-prompt/confirm-add-var/index.tsx | 69
app/components/base/icons/assets/vender/line/time/clock-refresh.svg | 9
app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal.tsx | 348
app/components/header/account-setting/data-source-page/panel/config-item.tsx | 83
app/components/share/text-generation/run-batch/index.tsx | 59
app/components/app/configuration/tools/external-data-tool-modal.tsx | 304
app/components/base/icons/src/vender/line/layout/Grid01.json | 83
public/vs/editor/editor.main.nls.ko.js | 13
app/(commonLayout)/apps/NewAppCard.tsx | 118
app/components/base/icons/assets/vender/line/others/long-arrow-right.svg | 3
app/components/base/icons/assets/vender/solid/development/pattern-recognition.svg | 11
themes/dark.css | 739
app/components/plugins/install-plugin/base/use-get-icon.ts | 16
app/components/base/icons/assets/public/llm/replicate-text.svg | 13
app/components/base/icons/src/vender/line/general/Menu01.json | 39
app/components/base/icons/src/vender/workflow/Iteration.json | 36
app/components/base/icons/src/vender/solid/general/AnswerTriangle.tsx | 20
app/components/workflow/panel/chat-record/user-input.tsx | 56
app/reset-password/page.tsx | 102
i18n/es-ES/plugin-tags.ts | 25
app/components/base/markdown-blocks/music.tsx | 37
app/components/app/configuration/config/automatic/style.module.css | 7
app/components/workflow/nodes/answer/utils.ts | 5
app/components/app/configuration/config-prompt/index.tsx | 170
i18n/th-TH/dataset.ts | 220
app/components/workflow/nodes/question-classifier/types.ts | 18
app/components/base/icons/assets/public/common/n-to-1-retrieval.svg | 18
app/components/base/icons/src/vender/workflow/LoopEnd.json | 38
app/components/base/icons/src/vender/solid/development/Database03.json | 28
app/components/base/icons/src/vender/solid/general/Eye.tsx | 20
app/components/app/configuration/debug/debug-with-single-model/index.tsx | 185
i18n/ro-RO/dataset.ts | 221
app/components/base/icons/src/public/billing/AwsMarketplace.tsx | 20
app/components/base/icons/src/public/llm/Localai.tsx | 20
app/components/workflow/note-node/note-editor/toolbar/font-size-selector.tsx | 84
app/components/datasets/create/step-two/escape.ts | 18
public/screenshots/light/TextGenerator@2x.png | 0
app/components/base/icons/src/public/thought/index.ts | 5
i18n/ko-KR/app-annotation.ts | 87
app/components/plugins/marketplace/constants.ts | 4
app/components/workflow/nodes/llm/use-config.ts | 448
app/components/base/icons/src/vender/solid/general/ArrowDownRoundFill.tsx | 20
app/components/base/icons/src/public/files/Docx.tsx | 20
app/components/base/icons/src/vender/solid/general/index.ts | 18
public/vs/basic-languages/xml/xml.js | 10
app/components/tools/types.ts | 170
app/components/base/icons/assets/vender/solid/general/edit-04.svg | 4
public/screenshots/light/Agent@2x.png | 0
app/forgot-password/ForgotPasswordForm.tsx | 123
i18n/tr-TR/time.ts | 37
app/components/workflow/nodes/_base/components/help-link.tsx | 36
app/components/base/icons/assets/vender/solid/general/arrow-down-round-fill.svg | 5
app/components/base/icons/assets/vender/line/mapsAndTravel/globe-01.svg | 10
app/components/base/icons/src/vender/line/development/PuzzlePiece01.json | 66
i18n/pt-BR/login.ts | 110
app/components/datasets/create/stop-embedding-modal/index.tsx | 45
app/components/datasets/hit-testing/components/result-item-footer.tsx | 42
app/components/base/icons/src/public/knowledge/ParentChildType.json | 56
app/components/app/configuration/debug/debug-with-multiple-model/context.tsx | 43
app/components/datasets/documents/detail/completed/common/keywords.tsx | 47
i18n/fa-IR/dataset-hit-testing.ts | 35
app/components/base/chat/embedded-chatbot/theme/utils.ts | 29
app/components/base/segmented-control/index.tsx | 68
app/components/datasets/create/step-two/language-select/index.tsx | 62
app/components/base/icons/src/public/files/Xlsx.tsx | 20
app/components/base/icons/src/vender/solid/general/Github.json | 36
app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/picker/field.tsx | 77
public/screenshots/dark/TextGenerator@3x.png | 0
app/components/base/button/index.tsx | 62
i18n/zh-Hant/app-overview.ts | 173
i18n/ro-RO/app-api.ts | 85
i18n/fa-IR/app-overview.ts | 173
app/components/base/chat/chat-with-history/context.tsx | 94
app/components/share/utils.ts | 75
app/components/base/chat/__tests__/branchedTestMessages.json | 42
app/components/app/configuration/dataset-config/context-var/index.tsx | 37
app/components/base/icons/assets/vender/line/general/edit-04.svg | 3
app/components/base/icons/src/public/llm/Jina.json | 35
app/components/base/prompt-editor/types.ts | 77
app/components/workflow/panel/env-panel/variable-trigger.tsx | 67
app/components/base/chat/chat/log/index.tsx | 42
app/components/base/icons/assets/vender/line/general/settings-01.svg | 13
app/components/base/select/index.tsx | 382
app/components/datasets/documents/detail/batch-modal/index.tsx | 66
public/vs/editor/editor.main.nls.es.js | 15
app/components/workflow/nodes/loop/insert-block.tsx | 61
app/components/workflow/nodes/loop/components/condition-value.tsx | 98
app/components/base/icons/assets/vender/solid/communication/list-sparkle.svg | 6
app/components/base/file-uploader/index.ts | 7
app/components/base/button/index.css | 186
app/components/datasets/create/assets/watercrawl.svg | 20
app/components/app-sidebar/style.module.css | 11
app/components/workflow/nodes/llm/components/prompt-generator-btn.tsx | 51
app/components/base/icons/src/public/llm/Baichuan.json | 76
app/components/workflow/nodes/knowledge-retrieval/types.ts | 133
app/components/header/assets/hugging-face.svg | 21
app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-retry.ts | 39
i18n/th-TH/billing.ts | 200
i18n/tr-TR/plugin-tags.ts | 25
i18n/de-DE/app.ts | 221
app/components/base/icons/assets/public/llm/replicate.svg | 4
app/components/base/icons/src/vender/line/time/ClockPlaySlim.tsx | 20
app/components/base/icons/assets/vender/workflow/http.svg | 10
app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx | 57
app/components/header/account-setting/members-page/invited-modal/index.tsx | 99
app/components/billing/annotation-full/usage.tsx | 32
app/components/workflow/nodes/_base/components/variable/var-type-picker.tsx | 71
app/components/base/ga/index.tsx | 60
app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-eyes.svg | 5
app/components/share/text-generation/icons/star.svg | 5
utils/context.ts | 45
app/components/tools/add-tool-modal/empty.png | 0
app/(commonLayout)/apps/assets/github.svg | 17
app/components/workflow/hooks/use-workflow.ts | 559
app/components/base/icons/assets/vender/line/financeAndECommerce/tag-03.svg | 5
app/components/base/icons/src/vender/solid/development/Database02.tsx | 20
app/components/workflow/header/editing-title.tsx | 42
app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx | 301
app/components/workflow/nodes/if-else/default.ts | 80
i18n/tr-TR/login.ts | 110
app/components/base/chat/chat/loading-anim/style.module.css | 82
app/components/base/icons/assets/vender/line/general/link-external-02.svg | 5
app/components/workflow/header/index.tsx | 51
app/components/base/param-item/score-threshold-item.tsx | 54
i18n/fa-IR/explore.ts | 44
app/components/header/app-back/index.tsx | 36
app/components/base/icons/assets/vender/line/others/bubble-x.svg | 8
app/components/datasets/external-knowledge-base/create/RetrievalSettings.tsx | 67
app/components/base/icons/assets/public/llm/gpt-4.svg | 5
app/components/plugins/plugin-item/action.tsx | 165
app/components/datasets/create/assets/family-mod.svg | 6
app/components/datasets/create/step-two/index.module.css | 413
app/components/datasets/create/website/jina-reader/base/options-wrap.tsx | 55
app/components/plugins/base/badges/verified.tsx | 29
app/components/header/account-setting/model-provider-page/provider-added-card/priority-selector.tsx | 76
app/components/tools/add-tool-modal/index.tsx | 257
app/components/workflow/nodes/llm/components/structure-output.tsx | 75
app/components/workflow/store/workflow/help-line-slice.ts | 19
app/components/base/icons/assets/vender/workflow/parameter-extractor.svg | 28
app/components/workflow/nodes/_base/components/editor/code-editor/style.css | 16
app/components/base/icons/src/public/billing/ArCube1.json | 29
app/components/base/icons/src/vender/line/users/index.ts | 2
app/components/workflow/nodes/llm/panel.tsx | 363
app/components/base/features/index.tsx | 1
app/components/base/portal-to-follow-elem/index.tsx | 187
app/components/plugins/marketplace/utils.ts | 147
app/components/base/date-and-time-picker/calendar/index.tsx | 27
app/components/datasets/create/index.tsx | 177
app/components/base/icons/src/public/billing/Buildings.json | 39
app/components/base/icons/assets/vender/line/general/hash-02.svg | 5
app/components/base/new-audio-button/index.tsx | 99
app/components/workflow/header/view-history.tsx | 221
app/components/datasets/create/website/base/checkbox-with-label.tsx | 40
app/components/plugins/plugin-detail-panel/strategy-detail.tsx | 164
app/components/base/icons/assets/public/llm/anthropic.svg | 4
i18n/hi-IN/app-debug.ts | 469
app/components/plugins/card/index.tsx | 97
i18n/uk-UA/dataset-documents.ts | 395
app/components/base/icons/assets/vender/line/development/bar-chart-square-02.svg | 5
app/(commonLayout)/plugins/page.tsx | 16
app/components/workflow/hooks/use-workflow-refresh-draft.ts | 9
app/components/base/icons/src/vender/line/communication/CuteRobot.tsx | 20
hooks/use-pay.tsx | 119
app/components/base/chat/chat-with-history/sidebar/operation.tsx | 101
app/components/datasets/documents/assets/graduationHat.svg | 3
app/components/base/icons/assets/vender/solid/files/file-05.svg | 8
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/actions.tsx | 56
i18n/uk-UA/app-debug.ts | 418
app/(commonLayout)/tools/page.tsx | 28
public/vs/basic-languages/m3/m3.js | 10
app/components/app/annotation/list.tsx | 91
app/components/workflow/panel/version-history-panel/empty.tsx | 30
app/components/workflow/custom-edge-linear-gradient-render.tsx | 53
app/components/datasets/create/assets/jina.png | 0
app/components/plugins/marketplace/list/card-wrapper.tsx | 103
app/components/workflow/nodes/answer/types.ts | 6
app/components/base/auto-height-textarea/index.tsx | 96
app/components/header/account-setting/model-provider-page/provider-added-card/cooldown-timer.tsx | 64
hooks/use-theme.ts | 13
app/components/base/button/index.spec.tsx | 110
app/components/base/input/index.spec.tsx | 124
public/vs/basic-languages/cypher/cypher.js | 10
app/components/base/icons/assets/vender/line/development/webhooks.svg | 12
app/components/plugins/install-plugin/install-bundle/steps/installed.tsx | 65
app/components/base/icons/assets/vender/solid/general/search-md.svg | 5
app/components/custom/custom-web-app-brand/index.tsx | 319
app/components/datasets/create/assets/option-card-effect-blue.svg | 12
app/(commonLayout)/app/(appDetailLayout)/[appId]/logs/page.tsx | 11
app/components/workflow/nodes/variable-assigner/hooks.ts | 165
app/components/base/icons/src/vender/solid/communication/MessageDotsCircle.json | 38
app/components/datasets/create/website/jina-reader/base/url-input.tsx | 48
app/components/base/icons/src/vender/solid/mediaAndDevices/AudioSupportIcon.tsx | 20
app/components/datasets/documents/detail/completed/common/chunk-content.tsx | 203
app/components/base/icons/assets/vender/line/alertsAndFeedback/alert-triangle.svg | 5
app/components/header/dataset-nav/index.tsx | 65
service/sso.ts | 16
.vscode/extensions.json | 7
i18n/de-DE/app-debug.ts | 392
app/components/base/notion-page-selector/assets/search.svg | 5
app/components/base/icons/src/vender/solid/mapsAndTravel/Globe06.tsx | 20
app/components/workflow/nodes/loop/use-is-var-file-attribute.ts | 35
app/components/base/premium-badge/index.tsx | 74
app/components/base/icons/src/vender/other/Openai.tsx | 20
app/components/base/premium-badge/index.css | 56
app/components/header/assets/trash.svg | 3
app/components/base/icons/src/public/llm/AnthropicText.json | 539
app/components/base/icons/src/public/common/MultiPathRetrieval.json | 153
i18n/it-IT/share-app.ts | 84
app/components/base/icons/src/vender/line/financeAndECommerce/Balance.tsx | 20
app/components/datasets/create/file-uploader/index.module.css | 131
app/components/base/icons/src/vender/line/images/ImagePlus.json | 39
app/components/workflow/nodes/_base/components/remove-button.tsx | 21
i18n/ko-KR/explore.ts | 44
i18n/pt-BR/dataset-creation.ts | 218
app/components/base/icons/src/public/llm/Azureai.tsx | 20
app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/assets/schema-generator-light.tsx | 15
app/components/base/radio/component/radio/index.tsx | 63
app/components/base/icons/src/public/llm/XorbitsInferenceText.json | 329
i18n/zh-Hans/workflow.ts | 918
app/components/base/icons/src/vender/solid/mapsAndTravel/Route.tsx | 20
app/components/workflow/panel/version-history-panel/filter/filter-switch.tsx | 33
app/components/datasets/common/document-picker/index.tsx | 118
app/components/workflow/nodes/knowledge-retrieval/node.tsx | 50
app/components/explore/app-card/index.tsx | 70
app/components/base/icons/src/public/other/DefaultToolIcon.json | 81
app/components/workflow/nodes/_base/components/next-step/container.tsx | 65
app/components/base/agent-log-modal/index.tsx | 61
app/components/base/tab-slider-plain/index.tsx | 78
app/components/plugins/install-plugin/hooks/use-check-installed.tsx | 33
app/components/base/icons/assets/vender/line/general/pin-01.svg | 5
app/activate/page.tsx | 20
app/components/app/overview/settings/index.tsx | 474
app/components/header/account-setting/data-source-page/index.module.css | 0
i18n/ko-KR/plugin-tags.ts | 25
app/education-apply/user-info.tsx | 61
public/vs/basic-languages/fsharp/fsharp.js | 10
app/components/app/configuration/config-var/var-item.tsx | 72
app/components/workflow/note-node/note-editor/toolbar/color-picker.tsx | 111
app/components/base/icons/src/public/common/D.tsx | 20
app/components/datasets/documents/detail/completed/common/batch-action.tsx | 114
app/components/workflow/run/utils/format-log/parallel/index.ts | 175
app/components/workflow/nodes/_base/hooks/use-one-step-run.ts | 543
i18n/en-US/common.ts | 671
models/share.ts | 48
app/components/app/type-selector/index.tsx | 168
i18n/uk-UA/app.ts | 214
app/dev-preview/page.tsx | 11
i18n/tr-TR/layout.ts | 3
service/_tools_util.ts | 5
i18n/ru-RU/custom.ts | 32
app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.tsx | 20
i18n/zh-Hans/layout.ts | 4
app/components/base/icons/assets/public/llm/xorbits-inference.svg | 24
i18n/ja-JP/login.ts | 110
app/components/workflow/note-node/hooks.ts | 32
app/components/develop/template/template_advanced_chat.ja.mdx | 1365
app/components/base/icons/assets/vender/line/layout/align-right-01.svg | 5
app/components/base/icons/src/public/common/Highlight.tsx | 20
app/components/base/icons/src/public/plugins/WebReader.json | 39
i18n/fr-FR/time.ts | 37
i18n/zh-Hant/custom.ts | 32
app/components/base/icons/assets/vender/solid/development/prompt-engineering.svg | 8
app/components/base/date-and-time-picker/time-picker/header.tsx | 16
app/components/app/configuration/base/icons/citation.tsx | 0
app/components/base/icons/src/vender/line/layout/LayoutGrid02.tsx | 20
app/components/base/grid-mask/style.module.css | 5
app/components/datasets/create/assets/alert-triangle.svg | 3
app/components/datasets/create/step-two/index.tsx | 1175
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-button.tsx | 71
app/components/workflow/nodes/loop-end/default.ts | 23
app/components/datasets/create/step-two/option-card.tsx | 106
app/components/workflow/run/hooks.ts | 115
app/components/base/file-icon/index.tsx | 55
app/components/base/float-popover-container/index.tsx | 37
app/components/base/icons/assets/vender/workflow/end.svg | 5
app/components/base/features/new-feature-panel/index.tsx | 126
app/components/base/icons/src/public/billing/Group2.tsx | 20
app/components/datasets/formatted-text/flavours/type.ts | 5
app/components/base/icons/src/vender/line/development/BarChartSquare02.tsx | 20
app/components/base/icons/src/vender/solid/development/BarChartSquare02.tsx | 20
i18n/hi-IN/register.ts | 3
i18n/pl-PL/common.ts | 690
app/components/workflow/nodes/code/code-parser.ts | 86
app/components/base/icons/assets/public/llm/openai-transparent.svg | 3
public/vs/basic-languages/graphql/graphql.js | 10
app/components/base/icons/src/public/billing/Sparkles.tsx | 20
i18n/es-ES/workflow.ts | 919
app/components/datasets/formatted-text/flavours/edit-slice.tsx | 115
app/components/base/icons/src/public/llm/HuggingfaceTextHub.tsx | 20
app/components/datasets/create/assets/Loading.svg | 16
app/components/workflow/nodes/http/components/key-value/bulk-edit/index.tsx | 62
app/components/base/icons/src/vender/line/layout/index.ts | 4
app/components/base/icons/src/public/llm/Zhipuai.json | 53
app/components/datasets/create/assets/gold.svg | 4
Dockerfile | 76
app/components/base/icons/src/public/education/Triangle.tsx | 20
app/components/datasets/create/assets/book-open-01.svg | 4
app/components/base/icons/src/vender/line/general/InfoCircle.tsx | 20
app/components/base/slider/index.tsx | 41
app/components/base/textarea/index.tsx | 54
i18n/fr-FR/layout.ts | 4
app/components/base/icons/assets/vender/line/general/link-03.svg | 8
app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg | 8
config/index.ts | 332
app/components/base/icons/src/vender/line/files/FileDownload02.json | 29
app/components/base/icons/src/public/plugins/Wikipedia.tsx | 20
app/components/base/icons/src/vender/workflow/Answer.json | 38
app/components/workflow/hooks/use-nodes-sync-draft.ts | 39
app/components/workflow/run/utils/format-log/agent/index.ts | 99
i18n/pl-PL/plugin.ts | 215
app/components/base/icons/assets/vender/line/financeAndECommerce/balance.svg | 3
app/components/base/file-uploader/file-image-render.tsx | 32
app/components/base/icons/assets/public/files/pdf.svg | 22
app/components/workflow/candidate-node.tsx | 111
app/components/base/icons/src/vender/line/general/Hash02.json | 38
app/components/workflow/block-selector/tool/tool-list-flat-view/list.tsx | 64
i18n/zh-Hant/app.ts | 213
app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsDown.json | 66
app/components/workflow/nodes/template-transform/utils.ts | 5
app/components/workflow/store/workflow/chat-variable-slice.ts | 34
app/components/workflow/block-selector/types.ts | 44
i18n/ro-RO/tools.ts | 158
app/components/base/icons/assets/vender/solid/mediaAndDevices/microphone-01.svg | 8
app/components/base/icons/assets/public/billing/keyframe.svg | 3
app/repos/[owner]/[repo]/releases/route.ts | 36
app/components/develop/template/template.ja.mdx | 706
app/components/workflow/nodes/_base/components/next-step/add.tsx | 108
public/vs/basic-languages/clojure/clojure.js | 10
app/components/app/configuration/base/icons/remove-icon/style.module.css | 0
public/vs/language/css/cssWorker.js | 78
app/components/header/account-setting/api-based-extension-page/index.tsx | 57
app/components/plugins/plugin-detail-panel/model-selector/index.tsx | 251
app/components/plugins/plugin-detail-panel/model-list.tsx | 46
app/components/base/features/new-feature-panel/conversation-opener/modal.tsx | 223
app/components/base/icons/src/public/billing/Keyframe.tsx | 20
app/components/base/icons/assets/public/files/yaml.svg | 1
app/components/base/chat/chat/hooks.ts | 710
app/components/base/icons/src/public/common/Line3.tsx | 20
i18n/uk-UA/dataset.ts | 222
app/components/workflow/hooks/use-nodes-interactions.ts | 1552
app/components/base/icons/src/vender/solid/communication/MessageSmileSquare.tsx | 20
app/components/base/icons/src/vender/solid/mediaAndDevices/MagicEyes.tsx | 20
app/components/datasets/documents/assets/bookOpen.svg | 3
app/components/base/icons/src/public/plugins/VerifiedLight.tsx | 20
i18n/fr-FR/dataset-hit-testing.ts | 35
app/components/base/icons/src/public/thought/ThoughtList.json | 83
public/vs/basic-languages/razor/razor.js | 10
app/components/base/icons/assets/public/llm/iflytek-spark-text-cn.svg | 11
app/components/base/icons/src/vender/solid/education/Beaker02.tsx | 20
app/components/workflow/nodes/knowledge-retrieval/components/retrieval-config.tsx | 156
app/components/base/icons/src/vender/line/arrows/ArrowUpRight.tsx | 20
app/components/base/form/components/label.spec.tsx | 53
app/components/base/icons/src/vender/line/general/LogOut04.tsx | 20
app/components/datasets/create/assets/Icon-3-dots.svg | 3
app/components/base/icons/src/vender/line/mediaAndDevices/SlidersH.tsx | 20
i18n/sl-SI/dataset-creation.ts | 218
app/components/workflow/nodes/_base/components/add-button.tsx | 33
app/components/base/icons/src/public/billing/Asterisk.json | 38
app/components/base/icons/src/vender/line/communication/AiText.json | 39
app/components/base/icons/assets/vender/workflow/code.svg | 5
i18n/it-IT/education.ts | 47
app/components/base/icons/src/public/thought/DataSet.tsx | 20
app/components/plugins/plugin-page/filter-management/search-box.tsx | 30
app/components/plugins/plugin-page/use-uploader.ts | 86
i18n/uk-UA/billing.ts | 200
i18n/en-US/plugin.ts | 215
app/components/workflow/datasets-detail-store/provider.tsx | 53
app/components/base/icons/assets/vender/workflow/if-else.svg | 5
i18n/sl-SI/tools.ts | 158
i18n/en-US/workflow.ts | 917
app/components/base/radio-card/simple/index.tsx | 45
app/components/base/icons/src/vender/line/others/Tools.tsx | 20
app/components/plugins/marketplace/index.tsx | 72
app/components/tools/marketplace/index.tsx | 118
app/components/base/form/components/field/text.tsx | 48
app/components/base/icons/src/vender/solid/mediaAndDevices/Sliders02.tsx | 20
i18n/DEV.md | 49
app/components/datasets/metadata/edit-metadata-batch/modal.tsx | 189
app/components/plugins/install-plugin/install-bundle/index.tsx | 75
app/components/datasets/external-knowledge-base/create/ExternalApiSelect.tsx | 110
app/components/workflow/nodes/_base/components/input-number-with-slider.tsx | 65
i18n/pt-BR/time.ts | 37
app/components/workflow/block-selector/tool/tool.tsx | 134
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/page.tsx | 28
app/components/base/grid-mask/index.tsx | 26
.storybook/preview.tsx | 37
app/components/datasets/hit-testing/index.tsx | 216
app/components/base/icons/assets/vender/solid/development/semantic.svg | 6
app/components/plugins/marketplace/intersection-line/hooks.ts | 30
public/vs/basic-languages/tcl/tcl.js | 10
app/components/base/features/new-feature-panel/text-to-speech/index.tsx | 102
public/vs/basic-languages/sparql/sparql.js | 10
app/components/base/icons/src/public/common/DiagonalDividingLine.tsx | 20
app/components/app/annotation/view-annotation-modal/index.tsx | 215
app/components/base/chat/embedded-chatbot/chat-wrapper.tsx | 264
app/components/workflow/nodes/http/components/authorization/index.tsx | 183
app/components/base/icons/src/vender/solid/development/BarChartSquare02.json | 38
app/components/base/icons/assets/vender/workflow/answer.svg | 5
app/components/base/icons/src/public/llm/CohereText.json | 90
app/components/base/icons/src/vender/line/files/FileText.tsx | 20
postcss.config.js | 6
app/components/workflow/panel/debug-and-preview/empty.tsx | 19
app/components/base/icons/src/vender/line/mapsAndTravel/Globe01.json | 66
app/components/base/image-uploader/image-list.tsx | 143
app/components/base/icons/assets/vender/line/files/file-02.svg | 5
app/components/base/icons/src/vender/line/mediaAndDevices/Stop.tsx | 20
app/components/base/icons/assets/public/llm/Anthropic-dark.svg | 186
app/components/base/form/components/form/submit-button.tsx | 25
public/vs/language/html/htmlWorker.js | 452
app/components/base/with-input-validation/index.tsx | 24
app/components/datasets/create/assets/setting-gear-mod.svg | 4
app/components/app/annotation/header-opts/index.tsx | 175
app/components/base/icons/src/vender/line/general/Pin01.json | 39
i18n/sl-SI/app-annotation.ts | 87
app/components/base/icons/src/public/other/RowStruct.json | 56
app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-finished.ts | 72
app/components/workflow/note-node/note-editor/plugins/format-detector-plugin/hooks.ts | 78
app/components/base/icons/src/image/llm/MinimaxText.tsx | 20
app/components/app/overview/assets/chromeplugin-install.svg | 6
app/components/base/icons/assets/vender/line/general/target-04.svg | 10
app/components/base/icons/assets/vender/solid/general/check-circle.svg | 5
i18n/pt-BR/explore.ts | 44
app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx | 189
i18n/uk-UA/plugin-tags.ts | 25
app/components/explore/item-operation/style.module.css | 33
app/components/workflow/nodes/loop/components/condition-list/index.tsx | 126
app/components/workflow/nodes/_base/hooks/use-toggle-expend.ts | 41
utils/format.spec.ts | 104
app/components/app/configuration/debug/types.ts | 18
app/components/base/icons/assets/vender/solid/editor/brush-01.svg | 4
app/components/base/icons/assets/public/llm/iflytek-spark-text.svg | 24
app/components/base/icons/src/vender/line/others/Icon3Dots.json | 39
app/components/workflow/nodes/loop/types.ts | 94
i18n/es-ES/layout.ts | 4
i18n/hi-IN/app-annotation.ts | 87
app/components/base/icons/assets/vender/solid/files/file-search-02.svg | 8
app/components/datasets/common/document-status-with-action/auto-disabled-document.tsx | 38
context/app-context.tsx | 159
app/components/workflow/nodes/http/components/timeout/index.tsx | 93
app/components/base/chat/__tests__/realWorldMessages.json | 441
app/components/base/icons/src/vender/line/arrows/ChevronRight.json | 39
app/components/workflow/nodes/http/hooks/use-key-value-list.ts | 58
app/components/datasets/preview/index.tsx | 0
app/components/base/chat/chat/chat-input-area/operation.tsx | 78
app/components/base/notion-page-selector/search-input/index.tsx | 42
i18n/fa-IR/common.ts | 672
hooks/use-breakpoints.spec.ts | 93
app/components/plugins/install-plugin/base/version.tsx | 34
app/components/base/icons/src/vender/line/general/UploadCloud01.json | 42
app/components/base/icons/src/vender/line/weather/Stars02.json | 29
app/components/base/icons/src/vender/line/general/Plus02.tsx | 20
app/components/base/icons/src/public/llm/OpenaiBlue.json | 37
public/vs/basic-languages/rust/rust.js | 10
app/components/base/loading/style.css | 41
app/components/workflow/nodes/http/use-config.ts | 235
app/components/workflow/nodes/if-else/components/condition-list/index.tsx | 136
app/components/base/icons/assets/vender/line/arrows/chevron-right.svg | 5
app/components/workflow/nodes/assigner/panel.tsx | 68
app/components/base/icons/assets/vender/solid/development/bar-chart-square-02.svg | 5
i18n/hi-IN/dataset-documents.ts | 396
app/components/base/icons/src/vender/solid/editor/TypeSquare.tsx | 20
i18n/fa-IR/login.ts | 110
app/components/base/icons/assets/vender/line/others/drag-handle.svg | 5
public/vs/basic-languages/javascript/javascript.js | 10
i18n/sl-SI/dataset-hit-testing.ts | 35
app/components/base/icons/assets/image/llm/tongyi-text-cn.png | 0
i18n/ko-KR/dataset-creation.ts | 219
app/components/workflow/store/workflow/workflow-slice.ts | 63
app/components/workflow/nodes/llm/utils.ts | 336
i18n/zh-Hans/app-annotation.ts | 90
app/components/app/store.ts | 54
i18n/zh-Hans/time.ts | 38
app/components/tools/labels/constant.ts | 4
app/(commonLayout)/datasets/page.tsx | 7
app/components/base/modal-like-wrap/index.tsx | 58
app/account/delete-account/components/verify-email.tsx | 55
app/components/datasets/documents/assets/cardLoading.svg | 15
app/components/workflow/hooks/use-selection-interactions.ts | 140
i18n/hi-IN/education.ts | 47
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/tracing-icon.tsx | 28
app/components/billing/pricing/index.tsx | 146
app/components/base/icons/src/vender/line/general/Upload03.tsx | 20
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/hooks.ts | 441
app/components/base/icons/src/vender/line/general/Edit05.tsx | 20
i18n/pl-PL/app-log.ts | 102
app/components/base/icons/src/public/files/Json.json | 178
service/fetch.ts | 208
app/components/datasets/api/index.tsx | 9
app/components/billing/pricing/select-plan-range.tsx | 54
app/components/base/prompt-editor/plugins/query-block/component.tsx | 33
app/components/app/configuration/base/warning-mask/has-not-set-api.tsx | 38
app/components/app/configuration/config-var/modal-foot.tsx | 24
app/components/base/icons/src/vender/solid/shapes/Star04.json | 36
i18n/zh-Hans/plugin-tags.ts | 25
app/components/base/chat/chat/citation/progress-tooltip.tsx | 46
app/components/workflow/nodes/knowledge-retrieval/panel.tsx | 221
app/components/workflow/nodes/answer/default.ts | 36
app/components/base/icons/src/vender/solid/communication/Logic.json | 53
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/field.tsx | 41
app/components/datasets/create/assets/file.svg | 4
app/components/header/account-setting/model-provider-page/provider-added-card/model-list.tsx | 102
app/components/base/icons/src/vender/solid/communication/MessageHeartCircle.tsx | 20
public/vs/base/common/worker/simpleWorker.nls.de.js | 8
app/components/base/icons/assets/public/tracing/weave-icon.svg | 33
app/components/base/icons/assets/vender/line/time/clock-fast-forward.svg | 3
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx | 199
i18n/ko-KR/dataset.ts | 220
public/favicon.ico | 0
app/components/base/icons/assets/public/llm/zhipuai-text-cn.svg | 8
app/components/base/icons/src/vender/solid/security/index.ts | 1
app/components/datasets/create/website/base/crawled-result.tsx | 89
app/components/base/icons/assets/vender/line/financeAndECommerce/gold-coin.svg | 16
app/components/base/icons/src/vender/line/development/TerminalSquare.tsx | 20
app/components/workflow/header/chat-variable-button.tsx | 24
app/components/base/icons/src/public/llm/Localai.json | 107
app/components/base/icons/src/vender/solid/shapes/Corner.json | 27
app/components/base/icons/src/public/llm/ZhipuaiText.tsx | 20
app/components/plugins/install-plugin/install-from-local-package/index.tsx | 133
app/components/app/configuration/debug/hooks.tsx | 158
app/components/base/icons/src/vender/line/financeAndECommerce/index.ts | 6
public/screenshots/dark/Workflow.png | 0
app/components/app/overview/assets/iframe-option.svg | 102
app/components/base/icons/src/public/plugins/VerifiedDark.tsx | 20
app/components/workflow/nodes/if-else/panel.tsx | 87
app/components/base/icons/src/public/llm/AzureaiText.tsx | 20
app/components/base/icons/src/public/llm/ChatglmText.json | 135
app/components/base/icons/assets/vender/solid/security/lock-01.svg | 5
app/components/workflow/run/agent-log/agent-result-panel.tsx | 60
app/components/base/icons/assets/public/tracing/langsmith-icon-big.svg | 24
app/components/workflow/nodes/http/utils.ts | 21
i18n/de-DE/plugin.ts | 215
i18n/it-IT/custom.ts | 33
i18n/pl-PL/register.ts | 4
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/store.ts | 34
app/components/base/icons/src/vender/solid/education/Beaker02.json | 38
app/components/base/icons/assets/public/knowledge/general-type.svg | 5
app/components/workflow/nodes/template-transform/default.ts | 38
app/components/base/param-item/index.tsx | 79
app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx | 101
app/components/base/icons/src/vender/line/general/Upload03.json | 66
app/components/base/chat/types.ts | 86
app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx | 274
hooks/use-i18n.ts | 9
i18n/zh-Hans/app-api.ts | 85
app/components/base/icons/assets/public/billing/buildings.svg | 5
app/styles/preflight.css | 379
app/components/base/icons/src/vender/solid/layout/index.ts | 1
i18n/ro-RO/app-log.ts | 98
public/vs/basic-languages/lexon/lexon.js | 10
i18n/zh-Hans/run-log.ts | 31
app/components/base/icons/src/vender/solid/editor/Citations.json | 36
public/vs/language/html/htmlMode.js | 13
app/components/base/icons/src/vender/line/editor/index.ts | 8
app/components/workflow/nodes/http/components/curl-panel.tsx | 160
app/components/app/overview/assets/refresh.svg | 3
app/components/base/icons/src/vender/solid/mediaAndDevices/MagicWand.tsx | 20
app/components/plugins/plugin-detail-panel/endpoint-modal.tsx | 96
app/components/base/icons/src/vender/solid/communication/AiText.json | 53
app/components/base/icons/assets/vender/line/users/users-01.svg | 5
app/components/base/icons/src/public/llm/ZhipuaiText.json | 44
i18n/th-TH/plugin-tags.ts | 25
app/components/base/copy-feedback/style.module.css | 15
app/components/base/icons/src/public/knowledge/Chunk.json | 116
app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-wand.svg | 10
app/components/base/icons/src/vender/line/general/Settings01.tsx | 20
app/components/base/markdown-blocks/think-block.tsx | 99
app/components/base/icons/assets/public/common/highlight.svg | 9
app/components/workflow-app/hooks/index.ts | 7
app/components/base/icons/src/vender/line/files/index.ts | 11
app/components/workflow/header/header-in-restoring.tsx | 93
public/vs/language/json/jsonWorker.js | 36
app/components/workflow/panel-contextmenu.tsx | 130
app/components/base/icons/src/vender/line/general/Edit05.json | 66
app/components/datasets/metadata/hooks/use-batch-edit-document-metadata.ts | 143
app/components/develop/secret-key/secret-key-generate.tsx | 41
app/components/base/icons/assets/vender/line/files/clipboard.svg | 3
app/components/workflow/help-line/index.tsx | 72
app/components/base/icons/src/vender/solid/development/ApiConnection.json | 53
app/components/base/chat/chat/content-switch.tsx | 39
public/vs/basic-languages/scss/scss.js | 12
app/components/base/icons/src/image/llm/Wxyy.module.css | 5
utils/permission.ts | 18
app/components/base/icons/assets/vender/solid/shapes/star-04.svg | 5
app/components/workflow/nodes/_base/components/collapse/index.tsx | 69
utils/classnames.ts | 8
app/components/base/icons/assets/public/billing/azure.svg | 25
app/components/base/icons/src/vender/line/time/ClockRefresh.tsx | 20
app/components/datasets/metadata/metadata-document/no-data.tsx | 27
app/components/workflow/nodes/_base/components/variable-tag.tsx | 94
app/components/base/icons/assets/vender/workflow/variable-x.svg | 5
app/components/base/voice-input/index.tsx | 216
i18n/uk-UA/login.ts | 110
app/components/workflow/header/checklist.tsx | 166
public/screenshots/dark/Workflow@3x.png | 0
app/components/datasets/formatted-text/formatted.tsx | 12
app/components/base/icons/src/public/llm/AnthropicDark.tsx | 20
app/components/base/icons/src/vender/line/general/CheckDone01.json | 39
app/components/workflow/nodes/assigner/utils.ts | 83
app/components/workflow/panel/global-variable-panel/index.tsx | 54
app/components/base/icons/src/public/billing/AwsMarketplace.json | 179
app/components/header/account-dropdown/index.tsx | 223
service/billing.ts | 14
app/components/app/configuration/config-vision/param-config.tsx | 42
app/components/explore/sidebar/index.tsx | 153
public/vs/basic-languages/ruby/ruby.js | 10
app/components/base/chat/chat/utils.ts | 52
public/vs/basic-languages/restructuredtext/restructuredtext.js | 10
app/components/workflow/nodes/loop/components/condition-list/condition-var-selector.tsx | 58
app/components/base/icons/src/public/files/Doc.tsx | 20
public/vs/basic-languages/scala/scala.js | 10
app/components/plugins/install-plugin/hooks/use-fold-anim-into.ts | 57
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts | 32
app/components/base/tooltip/content.tsx | 22
app/components/base/icons/src/vender/line/others/GlobalVariable.json | 28
app/components/datasets/common/check-rerank-model.ts | 70
app/components/base/icons/src/vender/line/general/LogOut01.json | 39
app/components/base/icons/assets/vender/line/files/file-arrow-01.svg | 5
app/components/billing/billing-page/index.tsx | 40
i18n/th-TH/share-app.ts | 78
app/components/datasets/metadata/edit-metadata-batch/input-combined.tsx | 61
app/components/base/icons/src/public/llm/OpenaiText.tsx | 20
app/components/develop/template/template.zh.mdx | 967
app/components/workflow/block-selector/tool-picker.tsx | 176
app/components/base/prompt-editor/plugins/component-picker-block/prompt-option.tsx | 45
app/components/base/icons/assets/vender/line/others/long-arrow-left.svg | 3
app/components/workflow/run/utils/format-log/loop/index.ts | 56
app/components/workflow/block-selector/index-bar.tsx | 97
i18n/fr-FR/run-log.ts | 31
service/apps.ts | 179
app/components/workflow/style.css | 24
public/vs/basic-languages/dart/dart.js | 10
app/components/base/avatar/index.tsx | 54
app/components/header/index.module.css | 15
app/components/workflow/nodes/_base/components/agent-strategy.tsx | 239
app/components/base/svg/index.tsx | 22
i18n/hi-IN/share-app.ts | 85
app/components/base/chat/chat/context.tsx | 66
app/components/header/account-setting/members-page/invite-modal/index.tsx | 123
app/components/app/switch-app-modal/index.tsx | 174
app/reset-password/layout.tsx | 27
i18n/pt-BR/share-app.ts | 82
app/components/base/mermaid/index.tsx | 590
app/components/workflow/nodes/iteration/types.ts | 20
app/components/base/features/new-feature-panel/image-upload/index.tsx | 114
app/components/base/icons/src/vender/workflow/QuestionClassifier.tsx | 20
app/components/base/icons/src/vender/features/TextToAudio.json | 77
app/components/base/icons/src/vender/solid/development/PromptEngineering.json | 53
app/components/workflow/header/global-variable-button.tsx | 20
app/components/workflow-app/hooks/use-workflow-template.ts | 74
app/components/base/icons/src/vender/workflow/End.json | 38
app/components/workflow/panel/chat-variable-panel/components/object-value-item.tsx | 135
app/components/workflow/nodes/_base/components/retry/retry-on-node.tsx | 91
app/components/header/account-dropdown/compliance.tsx | 185
i18n/ru-RU/education.ts | 47
app/components/workflow/nodes/_base/components/install-plugin-button.tsx | 45
i18n/de-DE/layout.ts | 4
app/components/plugins/plugin-page/plugin-tasks/hooks.ts | 100
app/components/base/icons/src/vender/line/files/FilePlus02.tsx | 20
app/components/base/tag-management/selector.tsx | 278
app/components/base/icons/src/public/common/Soc2.tsx | 20
app/components/base/video-gallery/VideoPlayer.module.css | 188
app/components/workflow/nodes/_base/components/panel-operator/change-block.tsx | 71
app/components/workflow/constants.ts | 597
app/components/workflow-app/components/workflow-header/chat-variable-trigger.tsx | 17
app/components/datasets/create/website/jina-reader/base/input.tsx | 58
app/components/base/icons/src/public/llm/OpenaiViolet.json | 37
app/components/datasets/chunk.tsx | 56
app/components/base/icons/src/vender/solid/general/ZapFast.tsx | 20
app/components/workflow/block-selector/tool/action-item.tsx | 90
app/components/workflow/hooks/use-config-vision.ts | 88
i18n/fa-IR/custom.ts | 32
app/components/plugins/marketplace/plugin-type-switch.tsx | 120
app/components/base/file-uploader/utils.ts | 196
app/components/header/account-setting/model-provider-page/model-selector/model-trigger.tsx | 78
app/components/workflow/nodes/_base/components/next-step/line.tsx | 73
app/components/base/icons/assets/vender/line/files/file-download-02.svg | 3
app/components/app/overview/embedded/index.tsx | 193
i18n/hi-IN/app-api.ts | 85
app/components/base/icons/src/public/tracing/OpikIconBig.tsx | 20
app/components/datasets/documents/detail/completed/display-toggle.tsx | 40
app/components/workflow/nodes/variable-assigner/components/node-variable-item.tsx | 111
app/components/workflow/panel/debug-and-preview/hooks.ts | 506
i18n/hi-IN/app-log.ts | 106
app/components/base/icons/src/vender/solid/mediaAndDevices/Sliders02.json | 77
app/components/workflow/nodes/_base/components/add-variable-popup-with-position.tsx | 130
i18n/fr-FR/dataset-documents.ts | 395
i18n/pl-PL/app-api.ts | 104
app/components/header/nav/nav-selector/index.tsx | 189
app/components/datasets/create/website/preview.tsx | 41
app/components/base/icons/src/vender/line/layout/AlignLeft01.json | 39
utils/get-icon.ts | 5
app/components/base/icons/IconBase.spec.tsx | 67
app/components/workflow/nodes/_base/hooks/use-resize-panel.ts | 121
app/(commonLayout)/datasets/connect/page.tsx | 8
app/components/base/icons/assets/public/llm/azureai.svg | 23
app/(commonLayout)/datasets/Datasets.tsx | 98
app/components/base/drawer/index.tsx | 94
app/components/base/icons/src/public/files/Json.tsx | 20
app/components/app/text-generate/saved-items/no-data/index.tsx | 42
app/components/base/chat/chat/thought/index.tsx | 58
app/components/datasets/common/document-status-with-action/status-with-action.tsx | 70
app/components/app/configuration/base/warning-mask/formatting-changed.tsx | 41
app/components/workflow/nodes/tool/components/input-var-list.tsx | 247
app/components/datasets/preview/header.tsx | 23
app/components/datasets/create/website/index.tsx | 161
app/components/app/configuration/debug/debug-with-multiple-model/index.tsx | 171
app/components/base/chat/chat/citation/tooltip.tsx | 46
app/components/base/icons/assets/vender/workflow/docs-extractor.svg | 9
i18n/vi-VN/explore.ts | 44
app/components/base/icons/src/vender/line/arrows/ReverseLeft.tsx | 20
app/components/share/text-generation/result/header.tsx | 113
public/screenshots/dark/Chatflow.png | 0
app/components/workflow/nodes/parameter-extractor/default.ts | 69
app/components/workflow/nodes/parameter-extractor/use-config.ts | 307
app/components/base/icons/src/public/llm/IflytekSparkTextCn.tsx | 20
app/components/base/app-icon-picker/index.tsx | 150
app/components/base/icons/src/vender/features/Document.tsx | 20
i18n/th-TH/education.ts | 47
app/components/datasets/settings/index-method-radio/assets/high-quality.svg | 12
app/components/workflow/hooks/index.ts | 19
app/components/workflow/nodes/http/node.tsx | 30
public/vs/basic-languages/cpp/cpp.js | 10
app/components/datasets/settings/index-method-radio/assets/economy.svg | 5
app/components/base/icons/src/vender/plugin/BoxSparkleFill.json | 66
app/components/header/account-setting/Integrations-page/index.tsx | 74
app/components/base/icons/src/vender/line/development/Database01.tsx | 20
assets/docx.svg | 23
app/components/workflow/nodes/loop/components/loop-variables/variable-type-select.tsx | 51
app/components/base/icons/assets/public/tracing/langfuse-icon.svg | 32
app/components/header/tools-nav/index.tsx | 39
i18n/fa-IR/layout.ts | 4
app/components/base/icons/src/vender/solid/communication/AiText.tsx | 20
app/components/workflow/block-selector/view-type-select.tsx | 58
app/components/workflow/hooks/use-workflow-interactions.ts | 403
app/components/workflow/note-node/note-editor/store.ts | 72
app/components/base/icons/src/vender/line/editor/Colors.json | 39
app/components/workflow/nodes/question-classifier/components/class-item.tsx | 60
app/(shareLayout)/completion/[token]/page.tsx | 10
app/components/tools/add-tool-modal/tools.tsx | 150
app/components/plugins/plugin-page/plugin-tasks/index.tsx | 194
public/screenshots/dark/Chatbot.png | 0
app/components/workflow/header/restoring-title.tsx | 49
app/components/workflow/panel/global-variable-panel/item.tsx | 30
app/components/workflow/nodes/_base/components/error-handle/default-value.tsx | 89
app/components/base/icons/src/vender/line/general/LinkExternal02.tsx | 20
app/components/workflow/nodes/variable-assigner/components/node-group-item.tsx | 151
app/components/workflow/utils/workflow-init.spec.ts | 69
app/components/base/loading/index.tsx | 29
app/components/workflow/nodes/_base/components/retry/style.module.css | 5
public/vs/basic-languages/twig/twig.js | 10
app/components/base/icons/src/vender/solid/alertsAndFeedback/index.ts | 1
app/components/workflow/nodes/_base/components/node-control.tsx | 94
app/components/base/icons/src/vender/line/arrows/ArrowUpRight.json | 39
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-number.tsx | 88
app/components/workflow/nodes/loop/components/condition-list/condition-item.tsx | 330
app/components/workflow/store/workflow/form-slice.ts | 18
app/components/workflow/note-node/note-editor/context.tsx | 65
app/components/workflow/nodes/template-transform/node.tsx | 13
i18n/vi-VN/app-debug.ts | 418
app/components/base/icons/src/vender/line/development/Variable.tsx | 20
app/components/workflow/nodes/llm/components/config-prompt.tsx | 247
app/components/datasets/metadata/edit-metadata-batch/label.tsx | 27
app/components/base/icons/src/vender/solid/editor/TypeSquare.json | 28
app/components/base/icons/src/vender/line/communication/ChatBotSlim.tsx | 20
app/components/base/icons/src/public/common/Dify.json | 62
app/components/base/icons/src/vender/line/general/Link03.tsx | 20
app/components/base/float-right-container/index.tsx | 23
app/components/workflow/hooks/use-workflow-run-event/use-workflow-run-event.ts | 53
public/screenshots/light/Workflow@3x.png | 0
app/components/plugins/plugin-detail-panel/app-selector/app-inputs-panel.tsx | 180
app/components/base/icons/src/vender/solid/users/Users01.tsx | 20
app/components/base/icons/assets/public/llm/huggingface.svg | 19
app/components/datasets/metadata/metadata-dataset/dataset-metadata-drawer.tsx | 248
models/app.ts | 115
i18n/hi-IN/layout.ts | 4
app/components/datasets/hit-testing/style.module.css | 43
i18n/uk-UA/register.ts | 4
app/components/datasets/external-api/external-api-modal/Form.tsx | 92
app/components/workflow/panel/version-history-panel/restore-confirm-modal.tsx | 42
app/components/base/icons/assets/vender/line/development/database-01.svg | 3
app/components/workflow/panel/chat-variable-panel/components/array-value-list.tsx | 72
i18n/zh-Hans/app-log.ts | 98
app/components/base/icons/src/public/llm/Jina.tsx | 20
app/components/plugins/plugin-page/filter-management/category-filter.tsx | 127
app/components/develop/secret-key/secret-key-modal.tsx | 147
app/components/datasets/create/website/jina-reader/header.tsx | 43
app/components/plugins/plugin-detail-panel/endpoint-card.tsx | 219
hooks/use-mitt.ts | 74
app/components/base/prompt-editor/plugins/tree-view.tsx | 19
app/components/datasets/hit-testing/components/child-chunks-item.tsx | 30
app/components/base/chat/chat/question.tsx | 178
utils/var-basePath.js | 6
i18n/fr-FR/app-overview.ts | 173
app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-trigger.tsx | 69
app/components/workflow/nodes/_base/node.tsx | 323
app/components/base/icons/src/vender/line/general/ChecklistSquare.json | 36
app/components/base/icons/src/public/llm/AzureaiText.json | 243
app/components/base/icons/assets/vender/solid/communication/bubble-text-mod.svg | 3
app/components/base/icons/src/public/llm/AnthropicText.tsx | 20
i18n/ru-RU/run-log.ts | 31
app/components/base/icons/src/vender/line/financeAndECommerce/Tag03.json | 39
i18n/pt-BR/layout.ts | 4
app/components/base/install-button/index.tsx | 27
public/vs/editor/editor.main.nls.it.js | 13
app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-iteration-next.ts | 35
app/components/base/features/types.ts | 79
app/components/base/chat/chat/try-to-ask.tsx | 47
app/components/base/icons/assets/public/files/docx.svg | 23
app/components/workflow/hooks/use-edges-interactions-without-sync.ts | 27
app/components/base/icons/src/public/llm/OpenaiGreen.json | 37
app/components/base/content-dialog/index.tsx | 51
app/components/workflow/panel/debug-and-preview/index.tsx | 144
i18n/es-ES/share-app.ts | 82
app/components/develop/index.tsx | 35
i18n/fr-FR/custom.ts | 32
i18n/es-ES/billing.ts | 200
app/components/base/icons/src/vender/plugin/BoxSparkleFill.tsx | 20
app/components/billing/apps-full-in-dialog/index.tsx | 84
app/components/datasets/documents/detail/metadata/index.tsx | 377
i18n/ja-JP/dataset-documents.ts | 394
app/components/base/icons/src/image/llm/WxyyTextCn.tsx | 20
app/components/base/icons/src/vender/workflow/Loop.json | 38
app/components/workflow/run/agent-log/agent-log-nav.tsx | 78
app/components/workflow-app/hooks/use-nodes-sync-draft.ts | 148
app/components/base/icons/src/vender/solid/general/QuestionTriangle.tsx | 20
app/components/base/chat/chat/index.tsx | 348
app/components/develop/tag.tsx | 65
public/screenshots/light/TextGenerator@3x.png | 0
app/components/base/radio-card/index.tsx | 68
app/components/base/linked-apps-panel/index.tsx | 62
app/components/workflow/nodes/knowledge-retrieval/components/add-dataset.tsx | 41
app/components/base/icons/src/vender/line/weather/Stars02.tsx | 20
app/components/base/app-icon-picker/utils.ts | 166
public/embed.js | 441
app/components/base/icons/assets/vender/line/development/brackets-x.svg | 3
app/components/base/pagination/index.tsx | 167
app/components/base/icons/src/vender/line/general/Refresh.json | 23
app/components/base/prompt-log-modal/index.tsx | 72
app/components/header/account-setting/model-provider-page/model-selector/index.tsx | 122
i18n/de-DE/dataset.ts | 221
app/components/base/icons/assets/vender/solid/development/database-03.svg | 3
app/components/base/icons/assets/vender/line/general/settings-04.svg | 5
app/components/plugins/base/badges/partner.tsx | 29
app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx | 195
assets/pdf.svg | 22
app/components/base/icons/src/public/llm/Cohere.json | 112
app/components/workflow/simple-node/constants.ts | 1
app/components/base/icons/assets/vender/workflow/list-filter.svg | 5
app/components/base/icons/assets/image/llm/minimax.png | 0
app/components/base/features/new-feature-panel/annotation-reply/config-param.tsx | 24
i18n/zh-Hant/billing.ts | 200
app/components/base/icons/assets/vender/line/files/file-text.svg | 5
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/index.tsx | 28
i18n/es-ES/plugin.ts | 215
app/components/base/icons/src/vender/solid/general/SearchMd.tsx | 20
types/feature.ts | 54
app/components/app/configuration/config/agent/prompt-editor.tsx | 149
app/components/workflow/run/iteration-log/iteration-log-trigger.tsx | 103
.vscode/settings.example.json | 26
app/components/workflow/nodes/http/default.ts | 65
i18n/en-US/dataset-creation.ts | 216
app/components/base/chat/chat/answer/tool-detail.tsx | 71
app/components/base/icons/src/vender/solid/communication/Send03.json | 36
i18n/fa-IR/dataset.ts | 221
app/components/workflow/nodes/tool/utils.ts | 5
app/components/app/configuration/config-var/select-var-type.tsx | 79
app/components/datasets/documents/detail/completed/index.tsx | 735
app/(commonLayout)/apps/assets/chat.svg | 3
app/components/base/image-uploader/audio-preview.tsx | 37
app/components/app/configuration/style.module.css | 14
app/components/base/icons/src/vender/line/others/Exchange02.json | 26
i18n/th-TH/dataset-documents.ts | 394
i18n/vi-VN/workflow.ts | 921
app/components/base/icons/src/vender/solid/communication/Logic.tsx | 20
app/components/header/account-setting/api-based-extension-page/empty.tsx | 28
app/components/workflow/panel/inputs-panel.tsx | 130
app/components/base/icons/src/vender/workflow/ListFilter.json | 38
i18n/zh-Hans/app-debug.ts | 529
app/components/workflow/panel/chat-variable-panel/components/object-value-list.tsx | 36
i18n/ru-RU/share-app.ts | 82
app/components/base/icons/assets/public/thought/thought-list.svg | 8
app/components/base/icons/src/vender/solid/education/index.ts | 4
app/components/base/icons/src/vender/solid/files/File05.tsx | 20
app/components/datasets/create/empty-dataset-creation-modal/index.tsx | 71
app/components/workflow-app/store/workflow/workflow-slice.ts | 18
app/components/base/icons/src/vender/solid/general/QuestionTriangle.json | 45
i18n/ja-JP/app.ts | 214
app/components/app/configuration/config/automatic/get-automatic-res.tsx | 330
i18n/fa-IR/register.ts | 4
app/components/header/assets/file.svg | 3
i18n/es-ES/common.ts | 671
i18n/zh-Hans/dataset-hit-testing.ts | 34
app/components/base/switch/index.tsx | 87
app/components/workflow/header/running-title.tsx | 24
app/components/base/prompt-editor/hooks.ts | 185
app/components/base/icons/src/vender/solid/development/ApiConnectionMod.json | 38
app/components/base/icons/src/vender/features/Citations.tsx | 20
app/components/datasets/documents/assets/normal.svg | 4
i18n/fr-FR/common.ts | 672
app/components/base/icons/src/vender/line/education/BookOpen01.tsx | 20
app/components/workflow/nodes/end/use-config.ts | 27
app/components/base/icons/assets/public/billing/aws-marketplace.svg | 23
app/components/base/icons/src/vender/solid/general/CheckDone01.tsx | 20
app/components/header/account-setting/language-page/index.module.css | 24
app/components/base/icons/assets/vender/solid/editor/colors.svg | 9
app/components/base/icons/src/public/plugins/PartnerLight.tsx | 20
app/components/plugins/plugin-detail-panel/operation-dropdown.tsx | 101
app/components/workflow/run/utils/format-log/index.ts | 98
app/components/base/icons/assets/vender/plugin/left-corner.svg | 3
app/components/base/icons/src/public/common/Highlight.json | 67
app/components/app-sidebar/dataset-info.tsx | 45
i18n/th-TH/explore.ts | 44
app/components/base/icons/src/vender/line/arrows/ArrowNarrowLeft.json | 29
app/components/header/account-setting/model-provider-page/model-modal/Form.tsx | 424
app/components/base/icons/src/public/education/Triangle.json | 27
app/components/base/icons/src/vender/line/general/AtSign.json | 66
app/components/workflow/nodes/list-operator/components/limit-config.tsx | 80
app/components/base/icons/assets/public/common/line-3.svg | 3
app/components/base/spinner/index.tsx | 24
app/components/datasets/settings/form/index.tsx | 354
i18n/pt-BR/dataset-hit-testing.ts | 35
app/components/develop/secret-key/assets/trash-red.svg | 3
app/components/workflow/nodes/iteration/add-block.tsx | 79
app/components/base/icons/src/vender/line/financeAndECommerce/ReceiptList.json | 29
app/components/base/icons/assets/vender/solid/general/target-04.svg | 5
app/components/base/icons/src/vender/solid/mediaAndDevices/MagicBox.json | 64
app/components/tools/workflow-tool/confirm-modal/index.tsx | 46
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/settings/page.tsx | 20
next.config.js | 69
app/components/workflow/nodes/iteration-start/default.ts | 21
public/logo/logo-embedded-chat-header@2x.png | 0
i18n/fr-FR/plugin.ts | 215
app/components/plugins/plugin-page/plugins-panel.tsx | 84
app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/assets/index.tsx | 7
app/components/base/prompt-editor/plugins/variable-value-block/utils.ts | 5
app/components/base/icons/assets/vender/solid/files/folder.svg | 5
app/components/billing/upgrade-btn/style.module.css | 9
app/components/base/icons/src/vender/solid/general/PlusCircle.json | 38
app/components/base/icons/assets/public/llm/cohere-text.svg | 11
app/components/base/icons/src/public/common/Line3.json | 28
app/components/base/icons/src/public/llm/AzureOpenaiServiceText.tsx | 20
app/components/base/icons/src/public/llm/XorbitsInferenceText.tsx | 20
app/components/base/icons/assets/vender/line/general/upload-cloud-01.svg | 4
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-string.tsx | 84
app/education-apply/types.ts | 11
app/components/base/icons/src/public/billing/Keyframe.json | 28
i18n/sl-SI/billing.ts | 200
app/components/base/radio/index.tsx | 15
app/components/base/file-uploader/file-input.tsx | 49
app/components/billing/type.ts | 107
app/dev-only/layout.tsx | 9
app/components/datasets/preview/container.tsx | 29
app/components/base/chat/__tests__/multiRootNodesWithLegacyTestMessages.json | 52
app/components/workflow-app/components/workflow-children.tsx | 69
app/components/workflow/store/workflow/panel-slice.ts | 32
i18n/pt-BR/education.ts | 47
app/components/workflow/nodes/parameter-extractor/types.ts | 37
app/components/base/icons/assets/vender/features/vision.svg | 3
app/components/datasets/common/retrieval-method-info/index.tsx | 64
app/components/datasets/documents/assets/layoutRightClose.svg | 4
app/components/workflow/nodes/variable-assigner/components/var-list/index.tsx | 86
app/components/base/icons/assets/vender/solid/general/x-circle.svg | 3
app/components/base/list-empty/horizontal-line.tsx | 21
i18n/zh-Hant/plugin-tags.ts | 25
app/components/base/icons/src/public/thought/Loading.json | 64
app/components/plugins/install-plugin/install-from-github/steps/selectPackage.tsx | 125
app/components/base/popover/index.tsx | 120
app/components/base/icons/assets/public/other/Icon-3-dots.svg | 3
app/components/base/icons/src/public/model/index.ts | 1
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-item.tsx | 196
app/components/base/icons/assets/public/billing/diamond.svg | 5
public/vs/basic-languages/mips/mips.js | 10
i18n/zh-Hant/share-app.ts | 78
app/components/workflow/nodes/tool/default.ts | 68
app/components/base/icons/src/vender/line/general/Refresh.tsx | 20
i18n/de-DE/dataset-hit-testing.ts | 35
app/components/base/icons/src/public/other/Message3Fill.tsx | 20
app/components/header/app-nav/index.tsx | 150
i18n/de-DE/billing.ts | 200
app/components/header/account-setting/key-validator/ValidateStatus.tsx | 32
app/components/workflow/nodes/assigner/use-config.ts | 133
i18n/fa-IR/tools.ts | 158
i18n/hi-IN/workflow.ts | 941
app/components/datasets/metadata/edit-metadata-batch/edited-beacon.tsx | 36
app/components/workflow/nodes/parameter-extractor/components/extract-parameter/import-from-tool.tsx | 93
app/components/base/features/new-feature-panel/more-like-this.tsx | 57
app/components/base/icons/assets/vender/line/layout/layout-grid-02.svg | 3
public/embed.min.js | 42
i18n/uk-UA/time.ts | 37
app/components/datasets/common/chunking-mode-label.tsx | 29
app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx | 114
app/components/workflow/nodes/if-else/components/condition-list/condition-operator.tsx | 94
app/components/workflow/nodes/_base/components/add-variable-popup.tsx | 36
app/components/base/icons/src/vender/line/general/Bookmark.tsx | 20
i18n/es-ES/dataset-documents.ts | 395
app/components/base/radio/context/index.tsx | 6
app/components/base/icons/src/image/llm/Tongyi.tsx | 20
app/components/base/icons/src/public/thought/ThoughtList.tsx | 20
app/components/header/account-setting/members-page/invite-modal/index.module.css | 12
pnpm-lock.yaml | 18718 ++
app/components/base/icons/assets/public/plugins/web-reader.svg | 4
app/components/base/icons/src/image/llm/BaichuanTextCn.tsx | 20
public/vs/basic-languages/hcl/hcl.js | 10
app/components/workflow/nodes/if-else/utils.ts | 174
i18n/zh-Hant/education.ts | 47
app/components/base/icons/src/vender/line/others/BubbleX.json | 57
app/components/workflow/nodes/list-operator/components/extract-input.tsx | 51
app/components/base/icons/src/vender/workflow/Jinja.tsx | 20
app/components/workflow/nodes/question-classifier/components/class-list.tsx | 87
app/components/datasets/documents/detail/embedding/style.module.css | 59
app/components/base/icons/src/vender/line/arrows/ReverseLeft.json | 39
app/components/workflow/note-node/constants.ts | 42
i18n/ru-RU/app.ts | 214
app/components/base/icons/assets/vender/line/time/clock-play.svg | 10
public/vs/editor/editor.main.nls.zh-cn.js | 15
app/(commonLayout)/app/(appDetailLayout)/[appId]/develop/page.tsx | 19
app/components/base/tooltip/index.spec.tsx | 116
app/activate/activateForm.tsx | 67
app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsDown.tsx | 20
i18n/pl-PL/dataset-hit-testing.ts | 35
service/explore.ts | 41
app/signin/invite-settings/page.tsx | 154
app/components/app/create-app-modal/index.tsx | 364
i18n/es-ES/custom.ts | 32
app/(commonLayout)/explore/layout.tsx | 16
app/components/header/account-setting/model-provider-page/provider-added-card/index.tsx | 186
app/components/billing/vector-space-full/style.module.css | 7
app/components/base/icons/src/vender/solid/shapes/Star06.tsx | 20
service/knowledge/use-metadata.ts | 146
public/logo/logo-embedded-chat-avatar.png | 0
app/components/base/icons/assets/public/files/unknown.svg | 23
app/components/base/icons/assets/vender/line/general/log-out-01.svg | 5
app/components/datasets/create/stop-embedding-modal/index.module.css | 37
app/components/base/icons/src/public/knowledge/SelectionMod.tsx | 20
app/components/workflow/nodes/_base/components/editor/wrap.tsx | 48
app/components/base/icons/src/vender/solid/mediaAndDevices/VideoSupportIcon.json | 26
i18n/es-ES/time.ts | 37
app/components/base/icons/src/vender/workflow/IterationStart.tsx | 20
app/(shareLayout)/chat/[token]/page.tsx | 11
app/components/base/icons/src/vender/line/general/Edit04.json | 29
app/components/datasets/create/website/watercrawl/header.tsx | 43
i18n/es-ES/education.ts | 47
app/components/base/icons/assets/public/tracing/weave-icon-big.svg | 33
app/components/base/icons/src/vender/line/images/ImagePlus.tsx | 20
app/components/base/loading/index.spec.tsx | 29
app/components/workflow/custom-connection-line.tsx | 40
app/components/base/icons/src/vender/solid/mediaAndDevices/Robot.tsx | 20
app/components/base/icons/script.mjs | 174
app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx | 180
i18n/pl-PL/app.ts | 221
i18n/ro-RO/login.ts | 110
app/components/datasets/documents/detail/completed/common/empty.tsx | 78
app/components/workflow/note-node/note-editor/theme/index.ts | 18
app/components/workflow/run/utils/format-log/iteration/index.spec.ts | 23
app/components/workflow/block-selector/constants.tsx | 111
app/components/workflow/note-node/note-editor/toolbar/hooks.ts | 147
app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx | 66
app/components/base/svg/style.module.css | 11
app/components/base/icons/src/vender/solid/general/MessageClockCircle.json | 36
app/components/base/icons/assets/vender/line/mediaAndDevices/sliders-h.svg | 3
app/components/app/text-generate/item/result-tab.tsx | 56
app/components/base/icons/src/public/llm/BaichuanText.json | 156
app/components/base/prompt-editor/plugins/update-block.tsx | 42
app/components/tools/provider/tool-item.tsx | 54
app/components/base/date-and-time-picker/date-picker/footer.tsx | 59
app/components/workflow/hooks/use-workflow-run-event/use-workflow-failed.ts | 26
app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx | 66
app/components/plugins/plugin-detail-panel/strategy-item.tsx | 50
app/components/base/audio-btn/style.module.css | 10
app/components/workflow/panel/version-history-panel/context-menu/use-context-menu.ts | 42
service/log.ts | 80
app/components/base/chat/__tests__/partialMessages.json | 122
app/components/workflow/nodes/assigner/node.tsx | 86
app/components/workflow/nodes/_base/components/option-card.tsx | 74
app/components/base/copy-icon/index.tsx | 53
app/components/base/icons/utils.spec.ts | 70
app/components/app/configuration/dataset-config/settings-modal/index.tsx | 390
app/components/base/form/components/field/checkbox.tsx | 43
app/components/base/icons/src/vender/solid/general/Github.tsx | 20
app/signin/_header.tsx | 42
app/components/share/text-generation/menu-dropdown.tsx | 100
app/components/base/icons/src/vender/line/general/CheckDone01.tsx | 20
app/components/workflow/hooks/use-helpline.ts | 127
app/components/header/header-wrapper.tsx | 27
i18n/zh-Hant/dataset-settings.ts | 43
app/components/base/icons/assets/public/other/row-struct.svg | 5
app/components/base/icons/src/vender/solid/editor/Paragraph.json | 44
app/components/custom/custom-web-app-brand/style.module.css | 3
app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/component.tsx | 149
app/components/workflow/run/utils/format-log/agent/data.ts | 179
app/components/base/icons/src/vender/line/editor/ImageIndentLeft.json | 39
app/components/base/icons/assets/image/llm/tongyi.png | 0
app/components/datasets/documents/detail/completed/common/dot.tsx | 11
i18n/tr-TR/app-overview.ts | 173
app/components/base/icons/src/public/llm/BaichuanText.tsx | 20
app/components/tools/labels/filter.tsx | 136
app/components/workflow/nodes/tool/use-config.ts | 325
app/components/app/configuration/config-vision/param-config-content.tsx | 142
app/components/base/icons/assets/vender/solid/development/terminal-square.svg | 5
app/components/with-i18n.tsx | 20
app/components/datasets/create/assets/normal.svg | 4
app/components/base/icons/src/vender/line/files/FileText.json | 39
i18n/zh-Hans/plugin.ts | 215
app/components/base/icons/src/vender/line/general/Pin02.json | 29
app/components/header/plugins-nav/downloading-icon.module.css | 44
app/components/base/file-uploader/utils.spec.ts | 614
app/components/datasets/create/assets/option-card-effect-purple.svg | 12
i18n/pl-PL/dataset-settings.ts | 48
app/components/base/icons/src/vender/solid/users/User01.json | 57
app/components/workflow/nodes/agent/components/tool-icon.tsx | 83
app/components/app-sidebar/completion.png | 0
app/components/workflow/block-selector/tools.tsx | 127
app/components/datasets/create/assets/file-list-3-fill.svg | 5
context/event-emitter.tsx | 28
app/components/base/icons/assets/vender/line/general/edit-05.svg | 10
app/components/base/icons/src/vender/line/others/DragHandle.json | 38
app/components/base/icons/assets/public/files/md.svg | 18
app/components/workflow/header/header-in-view-history.tsx | 50
i18n/it-IT/tools.ts | 168
app/components/develop/code.tsx | 305
public/screenshots/light/TextGenerator.png | 0
i18n/en-US/dataset-documents.ts | 394
app/components/base/icons/assets/public/llm/jina-text.svg | 12
app/components/develop/template/template_workflow.ja.mdx | 796
app/components/base/icons/src/vender/solid/development/TerminalSquare.tsx | 20
.env.example | 60
app/components/base/icons/assets/vender/solid/education/unblur.svg | 19
app/components/base/toast/index.spec.tsx | 193
app/components/base/toast/style.module.css | 44
app/components/datasets/documents/detail/embedding/skeleton/index.tsx | 66
app/components/datasets/documents/detail/completed/skeleton/full-doc-list-skeleton.tsx | 25
app/components/workflow/utils/tool.ts | 43
app/components/base/prompt-editor/plugins/variable-value-block/node.tsx | 64
app/components/workflow/nodes/document-extractor/types.ts | 6
app/components/app-sidebar/index.tsx | 126
app/components/base/dialog/index.tsx | 81
app/components/base/icons/assets/vender/line/education/book-open-01.svg | 6
app/components/base/icons/src/public/common/Github.tsx | 20
app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx | 128
app/components/app/log/filter.tsx | 101
app/components/explore/category.tsx | 60
app/components/datasets/create/file-preview/index.tsx | 70
app/components/workflow/nodes/loop-start/types.ts | 3
app/components/header/account-setting/key-validator/Operate.tsx | 87
app/components/app/configuration/config-prompt/advanced-prompt-input.tsx | 275
app/components/base/form/index.tsx | 25
app/components/datasets/create/assets/unknown.svg | 23
app/components/workflow/nodes/agent/node.tsx | 115
public/vs/basic-languages/liquid/liquid.js | 10
app/components/workflow/nodes/llm/components/config-prompt-item.tsx | 151
app/components/workflow/nodes/_base/components/before-run-form/index.tsx | 205
app/(commonLayout)/explore/installed/[appId]/page.tsx | 16
app/signin/components/mail-and-password-auth.tsx | 174
app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.tsx | 161
app/components/base/chat/chat-with-history/header/index.tsx | 164
app/components/base/icons/assets/vender/line/development/artificial-brain.svg | 3
i18n/en-US/billing.ts | 190
app/components/base/icons/src/vender/line/alertsAndFeedback/AlertTriangle.tsx | 20
app/components/base/features/new-feature-panel/conversation-opener/index.tsx | 119
app/components/app/annotation/batch-add-annotation-modal/csv-downloader.tsx | 73
app/components/datasets/documents/detail/completed/common/tag.tsx | 15
app/components/header/account-setting/model-provider-page/model-parameter-modal/status-indicators.tsx | 99
app/components/workflow/nodes/iteration/use-config.ts | 245
i18n/ru-RU/app-log.ts | 98
app/components/datasets/create/index.module.css | 0
app/components/app/create-app-dialog/index.tsx | 36
app/components/base/icons/assets/public/avatar/user.svg | 12
app/components/base/icons/src/public/llm/AzureOpenaiService.json | 74
app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.tsx | 20
i18n/de-DE/time.ts | 37
app/components/base/progress-bar/progress-circle.tsx | 64
i18n/fr-FR/app-debug.ts | 410
context/workspace-context.tsx | 36
app/components/workflow/dsl-export-confirm-modal.tsx | 86
i18n/hi-IN/dataset-hit-testing.ts | 35
app/components/datasets/documents/detail/settings/index.tsx | 96
app/components/workflow/nodes/llm/node.tsx | 36
app/components/app/configuration/base/icons/more-like-this-icon.tsx | 14
public/screenshots/dark/TextGenerator@2x.png | 0
app/components/base/chat/chat/check-input-forms-hooks.ts | 54
app/components/base/icons/src/public/other/Message3Fill.json | 173
service/refresh-token.ts | 92
i18n/ro-RO/dataset-creation.ts | 218
app/components/base/icons/src/vender/line/arrows/RefreshCcw01.json | 29
app/components/base/icons/src/vender/solid/communication/BubbleTextMod.tsx | 20
app/components/develop/secret-key/assets/pause.svg | 10
app/(commonLayout)/app/(appDetailLayout)/[appId]/workflow/page.tsx | 12
app/components/base/icons/src/vender/solid/development/Database03.tsx | 20
app/components/datasets/metadata/base/date-picker.tsx | 76
app/components/app/log/index.tsx | 129
app/components/base/icons/src/vender/solid/development/ApiConnectionMod.tsx | 20
app/components/explore/sidebar/app-nav-item/index.tsx | 75
public/vs/basic-languages/java/java.js | 10
public/screenshots/dark/Workflow@2x.png | 0
app/components/base/theme-selector.tsx | 97
i18n/hi-IN/time.ts | 37
app/components/base/icons/assets/public/llm/openai-green.svg | 4
i18n/pl-PL/run-log.ts | 31
i18n/ja-JP/register.ts | 4
app/components/datasets/common/document-status-with-action/index-failed.tsx | 70
app/components/workflow/nodes/constants.ts | 104
i18n/uk-UA/tools.ts | 158
app/components/base/icons/src/public/files/Pdf.json | 169
app/components/base/icons/src/public/llm/OpenaiTransparent.tsx | 20
app/components/base/tag-management/index.tsx | 92
app/components/base/icons/src/vender/line/layout/Grid01.tsx | 20
i18n/hi-IN/run-log.ts | 31
app/components/base/file-uploader/file-type-icon.tsx | 91
app/components/workflow/nodes/if-else/use-is-var-file-attribute.ts | 48
app/components/app/overview/appChart.tsx | 450
app/components/base/icons/src/vender/workflow/LoopEnd.tsx | 20
app/components/base/date-and-time-picker/utils/dayjs.ts | 80
app/components/billing/usage-info/vector-space-info.tsx | 36
i18n/ko-KR/billing.ts | 200
app/components/workflow/nodes/iteration/panel.tsx | 176
app/components/app/app-publisher/suggested-action.tsx | 29
i18n/zh-Hans/custom.ts | 32
app/components/base/date-and-time-picker/year-and-month-picker/footer.tsx | 25
public/vs/basic-languages/lua/lua.js | 10
app/components/base/icons/src/public/tracing/OpikIcon.json | 163
app/components/app/annotation/empty-element.tsx | 26
app/components/header/account-setting/plugin-page/SerpapiPlugin.tsx | 80
app/components/base/icons/src/vender/other/index.ts | 5
i18n/zh-Hant/tools.ts | 158
app/components/base/icons/src/public/tracing/TracingIcon.json | 47
app/components/base/icons/src/vender/other/AnthropicText.json | 539
i18n/ru-RU/login.ts | 110
i18n/fa-IR/dataset-settings.ts | 43
app/components/base/chat/embedded-chatbot/hooks.tsx | 405
app/components/base/prompt-editor/plugins/query-block/index.tsx | 68
app/components/workflow/nodes/variable-assigner/types.ts | 15
app/components/datasets/create/top-bar/index.tsx | 47
app/components/tools/utils/to-form-schema.ts | 96
i18n/ru-RU/layout.ts | 4
app/components/workflow/nodes/if-else/components/condition-files-list-value.tsx | 115
app/(commonLayout)/app/(appDetailLayout)/[appId]/configuration/page.tsx | 10
app/components/base/icons/src/vender/solid/FinanceAndECommerce/GoldCoin.json | 26
app/components/base/icons/src/vender/workflow/IfElse.json | 38
app/components/base/icons/assets/vender/workflow/loop-end.svg | 5
app/components/base/icons/src/vender/solid/users/UsersPlus.json | 77
app/components/app/configuration/config/feature/use-feature.tsx | 96
app/components/base/icons/src/vender/line/others/BubbleX.tsx | 20
app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx | 221
app/components/base/voice-input/index.module.css | 10
app/components/workflow/nodes/iteration-start/constants.ts | 1
i18n/ja-JP/explore.ts | 44
i18n/th-TH/app-overview.ts | 173
app/components/datasets/documents/detail/completed/skeleton/parent-chunk-card-skeleton.tsx | 45
app/components/base/icons/src/vender/solid/communication/ChatBot.json | 58
app/components/base/features/new-feature-panel/citation.tsx | 56
app/components/base/icons/assets/public/billing/group-2.svg | 3
app/components/base/prompt-editor/plugins/variable-value-block/index.tsx | 52
app/components/base/icons/src/vender/line/general/Pin01.tsx | 20
app/components/header/account-dropdown/workplace-selector/index.module.css | 5
public/vs/base/worker/workerMain.js | 27
app/components/base/file-uploader/audio-preview.tsx | 46
app/components/workflow/hooks/use-checklist.ts | 260
app/components/develop/secret-key/assets/copy-hover.svg | 3
app/components/plugins/install-plugin/install-bundle/item/marketplace-item.tsx | 36
i18n/fa-IR/billing.ts | 200
app/components/base/icons/assets/vender/line/editor/image-indent-left.svg | 5
i18n/sl-SI/education.ts | 47
app/account/avatar.tsx | 109
app/components/base/icons/src/vender/solid/development/Database02.json | 46
app/components/base/icons/src/vender/plugin/LeftCorner.json | 27
app/components/base/input-number/index.spec.tsx | 97
app/components/base/icons/src/vender/line/general/Edit02.tsx | 20
i18n/ru-RU/dataset-documents.ts | 395
app/components/explore/installed-app/index.tsx | 42
i18n/ru-RU/app-api.ts | 85
app/components/base/icons/src/public/files/Html.json | 178
app/components/base/divider/index.spec.tsx | 55
app/components/base/icons/src/public/common/NTo1Retrieval.tsx | 20
app/components/workflow/nodes/list-operator/use-config.ts | 188
app/components/tools/provider/detail.tsx | 430
app/components/workflow/nodes/list-operator/components/sub-variable-picker.tsx | 73
i18n/zh-Hant/dataset.ts | 221
app/components/base/icons/assets/vender/line/development/container.svg | 3
app/components/workflow/hooks/use-workflow-run-event/use-workflow-started.ts | 58
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-operator.tsx | 98
models/common.ts | 304
i18n/en-US/dataset.ts | 221
service/use-tools.ts | 121
app/components/datasets/hit-testing/components/score.tsx | 28
app/components/datasets/documents/detail/segment-add/index.tsx | 135
app/components/swr-initor.tsx | 89
app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config.ts | 89
app/components/base/icons/assets/vender/solid/files/file-zip.svg | 6
app/components/base/icons/src/vender/other/Generator.json | 37
i18n/sl-SI/share-app.ts | 79
utils/var.ts | 110
app/components/workflow/nodes/loop/components/loop-variables/form-item.tsx | 144
app/components/workflow/nodes/agent/components/model-bar.tsx | 75
app/components/base/drawer-plus/index.tsx | 105
app/components/base/icons/assets/public/common/iso.svg | 1
app/components/base/icons/assets/public/thought/loading.svg | 10
app/components/plugins/plugin-detail-panel/model-selector/llm-params-panel.tsx | 126
app/components/datasets/create/website/watercrawl/options.tsx | 85
app/components/plugins/install-plugin/base/installed.tsx | 60
i18n/zh-Hant/layout.ts | 4
app/components/app/workflow-log/filter.tsx | 74
app/components/base/radio/style.module.css | 13
app/components/base/icons/assets/image/llm/wxyy-text.png | 0
app/components/base/icons/src/vender/line/mediaAndDevices/PlayCircle.json | 86
app/components/base/icons/src/public/thought/WebReader.tsx | 20
app/components/plugins/install-plugin/install-from-local-package/steps/uploading.tsx | 99
app/components/base/icons/src/public/tracing/LangfuseIcon.json | 236
app/components/base/icons/src/vender/workflow/IterationStart.json | 36
app/page.tsx | 18
i18n/it-IT/time.ts | 37
app/components/plugins/marketplace/list/index.tsx | 79
app/components/workflow/nodes/variable-assigner/utils.ts | 16
app/components/base/icons/src/vender/workflow/Home.json | 38
app/components/base/prompt-editor/plugins/custom-text/node.tsx | 52
app/education-apply/verify-state-modal.tsx | 122
app/components/base/icons/src/vender/solid/mapsAndTravel/Globe06.json | 57
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/auto-width-input.tsx | 81
app/components/workflow/nodes/_base/components/remove-effect-var-confirm.tsx | 31
app/components/base/file-uploader/types.ts | 33
app/components/base/icons/src/public/avatar/Robot.tsx | 20
i18n/th-TH/time.ts | 37
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/style.module.css | 9
app/components/billing/config.ts | 86
app/components/base/icons/src/public/llm/OpenaiText.json | 77
i18n/ko-KR/dataset-documents.ts | 394
app/components/base/icons/assets/vender/solid/editor/type-square.svg | 3
i18n/en-US/share-app.ts | 82
app/components/base/image-uploader/chat-image-uploader.tsx | 159
app/components/workflow/nodes/if-else/components/condition-add.tsx | 76
app/components/workflow/nodes/llm/components/resolution-picker.tsx | 44
i18n/fa-IR/workflow.ts | 921
i18n/ko-KR/app-overview.ts | 173
app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx | 154
i18n/hi-IN/common.ts | 694
app/components/workflow/nodes/loop/node.tsx | 61
app/components/datasets/documents/detail/completed/skeleton/paragraph-list-skeleton.tsx | 76
public/logo/logo-site-dark.png | 0
public/vs/language/json/jsonMode.js | 15
app/components/datasets/create/assets/trash.svg | 3
app/components/plugins/install-plugin/hooks/use-hide-logic.ts | 40
app/components/workflow/nodes/_base/components/variable/output-var-list.tsx | 109
public/vs/basic-languages/ecl/ecl.js | 10
app/components/workflow/hooks/use-nodes-interactions-without-sync.ts | 27
app/components/datasets/create/assets/rerank.svg | 13
i18n/ru-RU/billing.ts | 200
app/components/workflow/nodes/http/components/api-input.tsx | 81
app/account/delete-account/state.tsx | 39
app/components/app/configuration/prompt-mode/advanced-mode-waring.tsx | 52
app/components/base/icons/src/vender/solid/mediaAndDevices/DocumentSupportIcon.json | 26
app/components/base/logo/logo-embedded-chat-header.tsx | 24
app/components/base/icons/src/vender/solid/arrows/HighPriority.json | 53
app/components/workflow/nodes/_base/components/editor/code-editor/index.tsx | 197
app/components/base/icons/src/vender/solid/mediaAndDevices/AudioSupportIcon.json | 26
app/components/tools/setting/build-in/config-credentials.tsx | 130
app/components/base/icons/src/vender/workflow/Agent.tsx | 20
app/components/base/icons/src/vender/line/development/GitBranch01.tsx | 20
app/components/base/text-generation/types.ts | 43
app/components/workflow/panel/version-history-panel/loading/index.tsx | 19
app/components/datasets/hit-testing/assets/grid.svg | 6
app/components/base/icons/assets/vender/workflow/agent.svg | 8
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-popup.tsx | 259
app/components/app/annotation/type.ts | 39
app/components/base/badge.tsx | 37
service/plugins.ts | 108
app/components/base/chat/embedded-chatbot/utils.ts | 3
i18n/zh-Hans/explore.ts | 44
i18n/es-ES/run-log.ts | 31
app/components/datasets/create/step-three/index.module.css | 75
public/screenshots/light/Chatbot.png | 0
app/components/workflow/hooks-store/provider.tsx | 36
app/components/datasets/create/assets/sliders-02.svg | 8
app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.tsx | 38
app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-box.svg | 9
app/components/plugins/plugin-page/plugin-info.tsx | 41
app/components/plugins/plugin-detail-panel/tool-selector/index.tsx | 458
i18n/pt-BR/app-api.ts | 85
i18n/ro-RO/plugin-tags.ts | 25
app/components/base/icons/src/vender/line/general/Edit04.tsx | 20
app/components/workflow/nodes/loop/components/condition-list/condition-operator.tsx | 94
app/components/workflow/custom-edge.tsx | 170
app/components/base/icons/src/vender/line/editor/LeftIndent02.json | 29
utils/app-redirection.ts | 17
app/components/base/icons/src/vender/line/mapsAndTravel/Route.json | 66
app/components/header/utils/util.ts | 25
app/components/workflow/hooks/use-shortcuts.ts | 202
app/components/base/icons/src/public/llm/ZhipuaiTextCn.tsx | 20
app/components/header/assets/github.svg | 17
app/components/base/icons/assets/vender/other/openai.svg | 9
app/components/base/icons/src/vender/line/general/Plus02.json | 39
app/(shareLayout)/workflow/[token]/page.tsx | 11
app/components/workflow/store/workflow/version-slice.ts | 26
app/components/header/account-setting/model-provider-page/utils.ts | 195
app/components/header/assets/azure.svg | 4
app/components/plugins/plugin-page/filter-management/store.ts | 27
i18n/th-TH/dataset-creation.ts | 218
app/components/base/icons/src/vender/workflow/Llm.tsx | 20
i18n/zh-Hans/common.ts | 671
i18n/pt-BR/common.ts | 672
app/components/base/list-empty/vertical-line.tsx | 21
themes/markdown-light.css | 44
app/components/base/icons/assets/vender/line/arrows/chevron-down-double.svg | 5
service/knowledge/use-segment.ts | 172
app/(commonLayout)/datasets/store.ts | 11
app/account/delete-account/components/feed-back.tsx | 68
app/components/base/form/form-scenarios/demo/types.ts | 34
public/vs/basic-languages/freemarker2/freemarker2.js | 12
public/vs/basic-languages/protobuf/protobuf.js | 11
app/components/plugins/card/card-more-info.tsx | 36
app/components/workflow/hooks/use-workflow-history.ts | 150
app/components/base/icons/src/vender/line/files/Folder.json | 39
app/components/datasets/metadata/metadata-dataset/create-metadata-modal.tsx | 45
app/components/sentry-initor.tsx | 29
i18n/hi-IN/plugin-tags.ts | 25
app/components/base/chat/chat-with-history/inputs-form/content.tsx | 115
app/account/page.tsx | 7
i18n/ko-KR/time.ts | 37
app/components/base/chat/chat/answer/operation.tsx | 195
app/components/base/icons/assets/vender/line/general/pin-02.svg | 3
app/signin/components/sso-auth.tsx | 73
app/components/base/icons/src/public/knowledge/LayoutRight2LineMod.tsx | 20
app/components/tools/workflow-tool/method-selector.tsx | 77
app/components/header/assets/sync.svg | 3
app/signin/normalForm.tsx | 217
app/components/base/icons/assets/vender/solid/communication/cute-robot.svg | 5
app/components/base/icons/src/vender/workflow/IfElse.tsx | 20
app/components/workflow/nodes/_base/components/selector.tsx | 96
public/vs/basic-languages/mdx/mdx.js | 10
i18n/tr-TR/app-api.ts | 85
app/components/base/chat/chat/answer/basic-content.tsx | 31
app/components/workflow/nodes/knowledge-retrieval/default.ts | 57
app/components/header/plugins-nav/downloading-icon.tsx | 17
app/components/base/icons/src/public/common/D.json | 125
app/components/base/icons/assets/vender/features/virtual-assistant.svg | 4
app/components/app/configuration/config/config-document.tsx | 78
app/components/base/tag-management/filter.tsx | 147
i18n/es-ES/dataset-creation.ts | 218
app/components/base/icons/src/vender/solid/communication/MessageFast.tsx | 20
app/components/datasets/create/website/no-data.tsx | 69
i18n/fr-FR/app.ts | 213
i18n/de-DE/dataset-documents.ts | 396
app/components/datasets/create/icons.ts | 16
app/components/base/icons/src/vender/solid/general/Edit04.json | 39
i18n/ru-RU/dataset-hit-testing.ts | 35
app/components/base/icons/assets/vender/line/communication/message-fast-plus.svg | 3
app/components/header/account-setting/model-provider-page/provider-icon/index.tsx | 53
app/components/base/icons/assets/vender/line/shapes/cube-outline.svg | 13
app/components/app/configuration/config/assistant-type-picker/index.tsx | 165
app/(commonLayout)/datasets/template/template.en.mdx | 2352
app/components/base/icons/assets/vender/line/editor/bezier-curve-03.svg | 5
app/components/base/icons/src/public/llm/AnthropicDark.json | 1046
app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx | 168
i18n/sl-SI/app-api.ts | 85
app/components/workflow/nodes/_base/components/file-type-item.tsx | 78
app/components/i18n.tsx | 31
app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle.json | 38
app/components/header/account-setting/model-provider-page/model-icon/index.tsx | 50
app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-started.ts | 92
i18n/en-US/education.ts | 47
app/components/workflow/nodes/knowledge-retrieval/utils.ts | 244
app/components/workflow/block-selector/tool/tool-list-tree-view/list.tsx | 56
hooks/use-timestamp.ts | 25
app/components/base/chat/chat/answer/index.stories.tsx | 96
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/card.tsx | 46
app/components/workflow/nodes/template-transform/types.ts | 6
app/signin/layout.tsx | 21
i18n/pl-PL/education.ts | 47
app/components/base/icons/assets/public/common/message-chat-square.svg | 4
app/components/base/icons/src/vender/line/general/DotsGrid.tsx | 20
app/components/base/icons/src/vender/solid/general/Download02.json | 29
app/components/base/icons/src/vender/solid/users/UserEdit02.tsx | 20
i18n/zh-Hans/dataset-creation.ts | 216
app/components/base/icons/assets/vender/solid/general/zap-narrow.svg | 5
app/components/base/icons/src/public/billing/ArCube1.tsx | 20
app/components/workflow/nodes/_base/components/error-handle/error-handle-on-panel.tsx | 91
app/components/app/configuration/dataset-config/index.tsx | 288
app/components/base/icons/assets/public/plugins/partner-light.svg | 58
i18n/pt-BR/dataset.ts | 221
app/components/workflow/nodes/agent/default.ts | 143
app/components/workflow/nodes/start/types.ts | 5
app/components/base/icons/assets/vender/solid/mapsAndTravel/globe-06.svg | 8
i18n/pl-PL/custom.ts | 33
app/components/base/icons/src/vender/line/others/Exchange02.tsx | 20
app/components/base/icons/assets/vender/line/layout/grid-01.svg | 10
i18n/fr-FR/dataset-creation.ts | 218
app/components/base/toast/index.tsx | 161
app/components/workflow/panel/version-history-panel/index.tsx | 279
app/components/base/icons/src/vender/solid/general/PlusCircle.tsx | 20
app/components/plugins/hooks.ts | 108
app/components/base/icons/assets/public/llm/anthropic-text.svg | 78
app/components/base/icons/src/public/billing/SparklesSoft.tsx | 20
app/components/base/features/new-feature-panel/annotation-reply/index.tsx | 153
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/index.tsx | 75
app/components/base/icons/src/public/tracing/LangfuseIconBig.json | 236
app/components/header/account-setting/language-page/index.tsx | 86
app/components/datasets/metadata/edit-metadata-batch/add-row.tsx | 45
app/components/app/configuration/base/feature-panel/index.tsx | 48
i18n/ro-RO/app-annotation.ts | 87
app/components/base/form/components/label.tsx | 48
app/components/workflow/nodes/knowledge-retrieval/components/dataset-list.tsx | 82
app/components/header/nav/index.module.css | 0
service/base.ts | 584
app/components/header/account-setting/members-page/index.tsx | 178
app/components/workflow/hooks/use-workflow-variables.ts | 113
i18n/vi-VN/dataset-hit-testing.ts | 35
i18n/th-TH/custom.ts | 32
app/components/datasets/external-api/external-api-modal/index.tsx | 218
app/components/base/icons/src/vender/line/mediaAndDevices/index.ts | 6
themes/manual-dark.css | 65
app/components/header/account-dropdown/support.tsx | 94
app/components/datasets/hit-testing/textarea.tsx | 200
i18n/it-IT/run-log.ts | 31
i18n/sl-SI/run-log.ts | 31
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-value-method.tsx | 71
app/components/base/tab-slider/index.tsx | 87
app/components/workflow/hooks/use-nodes-layout.ts | 96
app/components/base/icons/src/vender/line/general/Settings04.json | 39
app/components/base/theme-switcher.tsx | 58
app/components/base/app-icon/index.tsx | 71
app/components/share/text-generation/result/content.tsx | 34
app/components/base/icons/src/vender/line/general/AtSign.tsx | 20
i18n/uk-UA/explore.ts | 44
app/(commonLayout)/apps/assets/completion-solid.svg | 4
hooks/use-app-favicon.ts | 44
app/reset-password/set-password/page.tsx | 193
app/components/base/markdown-blocks/button.tsx | 39
app/components/billing/vector-space-full/index.tsx | 29
app/components/share/text-generation/info-modal.tsx | 49
app/components/workflow/block-selector/market-place-plugin/list.tsx | 131
i18n/ja-JP/app-log.ts | 98
i18n/ko-KR/dataset-hit-testing.ts | 35
app/components/base/icons/src/vender/line/time/ClockRefresh.json | 62
i18n/en-US/custom.ts | 32
service/use-workflow.ts | 87
app/(shareLayout)/webapp-signin/page.tsx | 103
app/components/plugins/plugin-detail-panel/agent-strategy-list.tsx | 58
app/components/base/notion-page-selector/notion-page-selector-modal/index.tsx | 63
app/components/datasets/create/website/base/error-message.tsx | 30
app/components/plugins/install-plugin/install-from-marketplace/index.tsx | 125
app/components/header/assets/salesforce.svg | 12
app/components/base/icons/src/vender/line/mapsAndTravel/Globe01.tsx | 20
app/components/base/chat/chat-with-history/sidebar/list.tsx | 40
app/components/datasets/create/assets/folder-plus.svg | 3
app/components/base/icons/src/public/common/MessageChatSquare.json | 37
app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-loop-started.ts | 82
i18n/ko-KR/workflow.ts | 921
app/components/workflow/nodes/llm/types.ts | 68
i18n/tr-TR/dataset.ts | 221
app/components/base/app-icon-picker/style.module.css | 12
app/components/workflow/run/agent-log/agent-log-item.tsx | 126
app/components/workflow/utils/edge.ts | 23
app/components/explore/index.tsx | 63
app/components/workflow/run/assets/bg-line-error.svg | 3
i18n/hi-IN/dataset-creation.ts | 238
app/components/base/icons/src/vender/solid/general/ZapFast.json | 79
app/components/workflow/nodes/_base/components/input-support-select-var.tsx | 126
public/vs/basic-languages/typescript/typescript.js | 10
app/components/base/icons/src/public/files/Txt.json | 180
app/components/plugins/plugin-detail-panel/tool-selector/tool-credentials-form.tsx | 97
app/components/header/account-setting/model-provider-page/hooks.spec.ts | 87
app/components/base/icons/src/vender/solid/files/File05.json | 55
i18n/zh-Hans/tools.ts | 158
app/components/app/overview/embedded/style.module.css | 20
app/components/base/chat/chat/citation/popup.tsx | 131
app/components/workflow/nodes/_base/components/variable/assigned-var-reference-popup.tsx | 39
app/components/plugins/plugin-page/filter-management/tag-filter.tsx | 122
app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.tsx | 62
app/components/workflow/nodes/_base/components/config-vision.tsx | 91
app/components/base/icons/src/public/knowledge/ParentChildType.tsx | 20
app/components/base/icons/assets/vender/solid/general/download-02.svg | 3
app/components/workflow/run/status.tsx | 151
i18n/zh-Hant/register.ts | 4
app/components/base/icons/src/public/llm/HuggingfaceTextHub.json | 350
app/components/workflow/utils/workflow.ts | 329
app/components/base/icons/assets/public/llm/localai-text.svg | 22
app/components/datasets/hit-testing/components/result-item-external.tsx | 60
app/components/base/icons/src/public/common/index.ts | 15
app/components/base/icons/src/vender/solid/layout/Grid01.json | 79
app/components/plugins/marketplace/search-box/search-box-wrapper.tsx | 45
app/components/workflow/panel/version-history-panel/filter/filter-item.tsx | 32
app/components/app/create-app-dialog/app-card/index.tsx | 60
app/components/base/icons/src/vender/line/development/ArtificialBrain.json | 29
app/components/workflow/nodes/code/dependency-picker.tsx | 85
app/components/base/icons/src/public/llm/OpenaiBlack.tsx | 20
app/components/plugins/install-plugin/install-bundle/steps/install.tsx | 118
app/components/datasets/create/assets/arrow-narrow-left.svg | 3
app/components/datasets/documents/detail/completed/status-item.tsx | 22
app/components/header/account-setting/members-page/invited-modal/assets/copied.svg | 3
app/components/workflow/block-selector/blocks.tsx | 125
app/(commonLayout)/apps/assets/link-gray.svg | 3
i18n/pl-PL/share-app.ts | 83
app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.json | 55
app/components/datasets/documents/detail/new-segment.tsx | 205
public/vs/basic-languages/pug/pug.js | 10
public/vs/basic-languages/msdax/msdax.js | 10
app/components/base/icons/assets/vender/line/general/menu-01.svg | 5
app/components/app/configuration/config-var/config-modal/index.tsx | 249
app/components/base/icons/assets/vender/line/files/file-check-02.svg | 5
app/components/workflow/nodes/_base/components/next-step/operator.tsx | 129
app/components/workflow/run/assets/highlight.svg | 9
app/components/workflow/utils/layout.ts | 178
service/datasets.ts | 289
public/vs/basic-languages/cameligo/cameligo.js | 10
app/components/workflow/nodes/document-extractor/node.tsx | 42
app/components/base/icons/src/vender/line/general/UploadCloud01.tsx | 20
app/components/base/simple-pie-chart/index.module.css | 4
app/components/base/icons/assets/vender/workflow/iteration-start.svg | 5
app/components/base/icons/assets/vender/line/development/terminal-square.svg | 5
app/components/plugins/marketplace/sort-dropdown/index.tsx | 94
app/components/base/features/new-feature-panel/feature-bar.tsx | 145
app/components/datasets/documents/assets/layoutRightShow.svg | 4
public/screenshots/dark/Chatbot@3x.png | 0
app/components/base/icons/src/public/common/Gdpr.tsx | 20
app/components/base/prompt-editor/plugins/history-block/index.tsx | 80
app/components/base/mermaid/utils.ts | 232
app/components/base/icons/src/public/files/Md.json | 144
app/components/base/icons/src/public/llm/LocalaiText.tsx | 20
app/components/workflow/nodes/start/components/var-item.tsx | 103
themes/tailwind-theme-var-define.ts | 740
app/components/base/icons/assets/vender/solid/users/user-edit-02.svg | 14
app/components/datasets/create/website/firecrawl/index.tsx | 217
app/components/app-sidebar/app-info.tsx | 418
app/components/base/icons/src/vender/solid/editor/Colors.tsx | 20
app/components/base/icons/assets/vender/line/communication/message-check-remove.svg | 5
app/components/workflow/nodes/parameter-extractor/components/extract-parameter/item.tsx | 59
app/components/base/chat/chat/citation/index.tsx | 125
app/components/base/date-and-time-picker/time-picker/options.tsx | 71
app/components/base/icons/src/vender/line/financeAndECommerce/Tag01.tsx | 20
app/components/base/icons/src/public/thought/DataSet.json | 64
app/components/header/account-setting/data-source-page/panel/types.ts | 4
app/components/app/configuration/debug/debug-with-multiple-model/debug-item.tsx | 129
public/screenshots/light/Chatflow.png | 0
app/components/workflow/nodes/_base/hooks/use-var-list.ts | 37
app/components/workflow/run/output-panel.tsx | 111
i18n/ro-RO/register.ts | 4
app/components/workflow/hooks/use-edges-interactions.ts | 161
app/components/app/configuration/config-var/input-type-icon.tsx | 44
app/components/base/chat/chat/answer/__mocks__/workflowProcess.ts | 138
app/components/base/icons/assets/vender/solid/FinanceAndECommerce/gold-coin.svg | 3
app/components/base/icons/src/vender/line/mediaAndDevices/SlidersH.json | 29
app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx | 169
app/components/base/chat/constants.ts | 2
app/components/datasets/documents/detail/completed/skeleton/general-list-skeleton.tsx | 74
app/components/base/icons/src/public/plugins/PartnerDark.json | 447
app/components/base/icons/src/vender/solid/general/SearchMd.json | 38
app/components/base/app-icon-picker/ImageInput.tsx | 126
public/screenshots/light/Agent@3x.png | 0
app/components/base/icons/src/public/files/index.ts | 11
app/components/base/icons/assets/vender/other/generator.svg | 4
app/components/base/icons/assets/public/tracing/langfuse-icon-big.svg | 32
app/components/base/image-gallery/index.tsx | 84
i18n/tr-TR/billing.ts | 200
app/components/base/icons/src/vender/solid/development/FileHeart02.json | 50
app/components/app/create-app-dialog/app-list/index.tsx | 253
app/components/base/icons/src/vender/workflow/Http.json | 71
context/query-client.tsx | 23
i18n/es-ES/app-api.ts | 85
public/vs/language/typescript/tsWorker.js | 37249 +++++
i18n/sl-SI/app.ts | 214
app/components/workflow/nodes/_base/components/group.tsx | 25
app/components/workflow/panel/version-history-panel/version-history-item.tsx | 137
i18n/de-DE/dataset-creation.ts | 218
public/vs/basic-languages/sb/sb.js | 10
i18n/vi-VN/dataset-creation.ts | 218
i18n/ko-KR/layout.ts | 3
app/components/datasets/create/step-one/index.tsx | 325
i18n/sl-SI/dataset.ts | 221
app/components/base/icons/utils.ts | 66
app/components/datasets/create/website/jina-reader/index.tsx | 230
app/components/base/icons/src/vender/solid/development/Semantic.json | 53
i18n/tr-TR/tools.ts | 158
app/components/plugins/base/key-value-item.tsx | 66
app/components/datasets/documents/detail/metadata/style.module.css | 103
app/components/base/icons/src/vender/solid/mediaAndDevices/DocumentSupportIcon.tsx | 20
app/components/header/account-setting/key-validator/declarations.ts | 43
assets/md.svg | 18
app/components/base/icons/src/vender/solid/development/index.ts | 13
app/components/base/chat/chat/chat-input-area/index.tsx | 246
i18n/pt-BR/billing.ts | 201
app/components/header/account-setting/key-validator/index.tsx | 122
app/components/base/icons/src/public/tracing/LangsmithIcon.json | 188
app/components/base/icons/src/vender/features/MessageFast.json | 28
app/components/base/icons/src/vender/line/development/FileHeart02.tsx | 20
app/components/base/icons/src/public/files/Unknown.tsx | 20
app/components/base/icons/src/vender/solid/development/PuzzlePiece01.json | 38
app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-iteration-finished.ts | 60
app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/hooks.ts | 115
app/components/base/icons/assets/vender/line/arrows/chevron-selector-vertical.svg | 3
app/components/base/icons/src/vender/line/general/LogOut01.tsx | 20
public/vs/editor/editor.main.nls.de.js | 15
app/components/datasets/create/notion-page-preview/index.tsx | 75
app/components/base/icons/src/vender/workflow/Llm.json | 38
i18n/fa-IR/plugin.ts | 215
i18n/it-IT/plugin.ts | 215
app/components/plugins/marketplace/empty/line.tsx | 21
app/components/base/icons/src/vender/line/development/Container.tsx | 20
public/vs/base/common/worker/simpleWorker.nls.it.js | 8
app/components/base/notion-page-selector/notion-page-selector-modal/index.module.css | 28
public/vs/basic-languages/csp/csp.js | 10
app/components/workflow/nodes/_base/components/collapse/field-collapse.tsx | 36
utils/index.ts | 101
app/components/datasets/create/website/index.module.css | 13
service/use-models.ts | 17
app/components/base/icons/assets/vender/line/general/check-done-01.svg | 5
public/vs/basic-languages/powerquery/powerquery.js | 10
app/components/base/icons/src/vender/line/general/Target04.tsx | 20
app/components/workflow/store/workflow/history-slice.ts | 25
i18n/ja-JP/plugin-tags.ts | 25
app/components/base/icons/src/vender/features/Document.json | 23
app/components/plugins/plugin-detail-panel/utils.ts | 21
app/components/datasets/create/step-two/unescape.ts | 54
app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-down.svg | 10
app/components/workflow/nodes/_base/hooks/use-node-crud.ts | 19
app/components/base/icons/assets/public/thought/data-set.svg | 10
app/components/plugins/marketplace/list/list-with-collection.tsx | 86
i18n/tr-TR/dataset-hit-testing.ts | 35
app/components/datasets/create/website/firecrawl/options.tsx | 85
app/components/workflow/nodes/assigner/components/operation-selector.tsx | 128
app/components/workflow/nodes/parameter-extractor/components/reasoning-mode-picker.tsx | 49
app/components/base/icons/src/public/common/Iso.tsx | 20
public/vs/basic-languages/pascal/pascal.js | 10
app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx | 295
app/components/app/configuration/config/agent-setting-button.tsx | 47
app/components/datasets/create/empty-dataset-creation-modal/index.module.css | 35
utils/classnames.spec.ts | 56
app/components/workflow/nodes/_base/components/node-resizer.tsx | 60
app/components/base/icons/assets/public/llm/zhipuai.svg | 8
i18n/zh-Hans/app.ts | 201
i18n/ko-KR/custom.ts | 32
app/components/base/icons/src/public/llm/Huggingface.json | 158
app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.tsx | 20
i18n/vi-VN/billing.ts | 200
i18n/fa-IR/dataset-creation.ts | 218
app/components/base/chat/chat/answer/more.tsx | 46
i18n/en-US/app.ts | 200
public/vs/basic-languages/markdown/markdown.js | 10
app/components/base/icons/src/public/education/index.ts | 1
utils/index.spec.ts | 295
app/components/base/icons/assets/vender/line/arrows/refresh-cw-05.svg | 3
i18n/vi-VN/app-api.ts | 85
app/components/base/icons/assets/public/education/triangle.svg | 3
app/components/datasets/create/stepper/step.tsx | 46
app/components/workflow/run/loop-log/loop-log-trigger.tsx | 109
app/components/base/icons/src/vender/line/development/Webhooks.json | 89
app/components/app/configuration/dataset-config/card-item/item.tsx | 122
app/components/header/account-setting/api-based-extension-page/selector.tsx | 127
app/(commonLayout)/datasets/create/page.tsx | 12
app/components/plugins/card/base/placeholder.tsx | 51
app/components/workflow/run/loop-log/index.tsx | 2
app/components/base/icons/assets/public/billing/asterisk.svg | 5
app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/tree-indent-line.tsx | 24
app/components/base/icons/assets/vender/line/editor/colors.svg | 5
app/components/base/icons/src/vender/workflow/DocsExtractor.tsx | 20
app/components/base/icons/src/vender/solid/development/Container.tsx | 20
i18n/pl-PL/login.ts | 115
app/components/base/icons/src/public/billing/Sparkles.json | 95
utils/format.ts | 58
app/components/base/icons/assets/vender/line/weather/stars-02.svg | 3
app/components/header/index.tsx | 115
app/components/base/icons/assets/public/other/default-tool-icon.svg | 9
app/components/base/icons/assets/vender/solid/development/api-connection.svg | 8
app/components/header/account-setting/members-page/edit-workspace-modal/index.module.css | 0
i18n/ro-RO/dataset-hit-testing.ts | 35
app/components/workflow/run/utils/format-log/iteration/index.ts | 56
app/components/base/icons/src/public/llm/AzureOpenaiServiceText.json | 236
app/components/app/configuration/base/icons/suggested-questions-after-answer-icon.tsx | 12
i18n/es-ES/dataset.ts | 219
app/components/base/svg-gallery/index.tsx | 78
app/components/base/icons/src/vender/line/files/FileArrow01.json | 39
app/components/base/prompt-editor/plugins/component-picker-block/hooks.tsx | 288
public/vs/basic-languages/bicep/bicep.js | 11
app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsx | 160
app/components/base/icons/assets/vender/line/general/refresh.svg | 1
app/components/datasets/create/assets/star-07.svg | 11
i18n/sl-SI/common.ts | 871
app/(commonLayout)/layout.tsx | 38
app/components/base/icons/src/vender/line/general/LogIn04.tsx | 20
app/components/datasets/create/assets/piggy-bank-01.svg | 4
app/components/base/icons/assets/vender/line/mediaAndDevices/microphone-01.svg | 5
i18n/de-DE/common.ts | 672
app/components/workflow/nodes/iteration/node.tsx | 72
service/use-education.ts | 67
app/components/base/icons/src/vender/line/general/Bookmark.json | 29
app/components/workflow/nodes/_base/components/setting-item.tsx | 28
app/components/workflow/nodes/end/node.tsx | 88
app/components/base/icons/src/image/llm/MinimaxText.module.css | 5
i18n/vi-VN/dataset-documents.ts | 394
app/components/base/icons/src/public/tracing/LangsmithIconBig.tsx | 20
app/components/plugins/provider-card.tsx | 99
app/components/base/image-uploader/uploader.tsx | 58
app/components/base/icons/src/vender/solid/shapes/index.ts | 3
app/components/datasets/create/assets/html.svg | 23
app/components/base/icons/src/vender/line/general/Hash02.tsx | 20
app/components/base/icons/src/vender/line/communication/MessageFastPlus.tsx | 20
app/components/workflow/syncing-data-modal.tsx | 15
i18n/ko-KR/app.ts | 210
app/components/base/icons/assets/public/common/gdpr.svg | 53
app/components/plugins/update-plugin/from-market-place.tsx | 154
app/components/workflow/nodes/loop-start/default.ts | 21
app/components/base/icons/src/public/llm/Anthropic.tsx | 20
app/components/develop/secret-key/secret-key-button.tsx | 35
app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form.tsx | 275
app/components/base/icons/assets/vender/solid/development/variable-02.svg | 9
app/components/base/icons/src/vender/line/time/index.ts | 4
app/components/datasets/documents/assets/typeSquare.svg | 3
app/components/app/configuration/config-var/index.tsx | 271
app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle.tsx | 20
app/components/base/icons/assets/vender/line/communication/chat-bot.svg | 14
app/components/tools/edit-custom-collection-modal/modal.tsx | 360
i18n/en-US/login.ts | 109
app/components/workflow/nodes/_base/components/error-handle/utils.ts | 83
i18n/ro-RO/time.ts | 37
app/components/workflow/nodes/_base/components/variable/var-list.tsx | 109
app/components/datasets/documents/assets/messageTextCircle.svg | 3
app/components/workflow/nodes/http/components/authorization/radio-group.tsx | 62
i18n/server.ts | 56
app/components/base/icons/src/vender/workflow/ListFilter.tsx | 20
app/components/base/icons/src/image/llm/TongyiText.module.css | 5
app/components/base/icons/src/vender/line/general/LogOut04.json | 53
app/components/billing/usage-info/apps-info.tsx | 34
public/vs/basic-languages/wgsl/wgsl.js | 307
i18n/uk-UA/app-overview.ts | 173
app/components/billing/progress-bar/index.tsx | 24
app/components/base/icons/assets/vender/solid/general/question-triangle.svg | 6
service/use-plugins.ts | 529
app/components/workflow/nodes/code/node.tsx | 13
i18n/sl-SI/time.ts | 37
app/components/base/icons/assets/vender/line/others/exchange-02.svg | 3
app/components/base/icons/assets/vender/solid/general/answer-triangle.svg | 3
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/create/page.tsx | 20
app/components/base/icons/assets/vender/features/citations.svg | 3
assets/action.svg | 5
app/components/header/account-setting/plugin-page/utils.ts | 34
i18n/ja-JP/app-debug.ts | 527
app/components/base/icons/assets/vender/line/financeAndECommerce/receipt-list.svg | 3
i18n/ru-RU/plugin-tags.ts | 25
app/components/base/icons/src/public/common/SparklesSoft.tsx | 20
app/components/datasets/external-knowledge-base/create/declarations.ts | 12
app/components/datasets/create/assets/docx.svg | 23
app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx | 65
app/components/base/chat/chat-with-history/sidebar/index.tsx | 179
app/components/base/icons/src/image/llm/TongyiText.tsx | 20
app/components/header/account-setting/model-provider-page/model-parameter-modal/model-display.tsx | 25
app/components/base/icons/assets/public/files/json.svg | 23
app/components/base/icons/src/public/model/Checked.json | 29
i18n/i18next-config.ts | 65
public/logo/logo-embedded-chat-header@3x.png | 0
app/components/base/date-and-time-picker/year-and-month-picker/header.tsx | 27
i18n/ko-KR/plugin.ts | 215
app/components/base/icons/assets/vender/line/users/user-01.svg | 5
app/components/base/mermaid/utils.spec.ts | 8
i18n/vi-VN/plugin-tags.ts | 25
app/components/plugins/plugin-mutation-model/index.tsx | 79
public/logo/logo-embedded-chat-header.png | 0
app/components/app/configuration/images/prompt.svg | 19
app/components/datasets/create/step-two/preview-item/index.tsx | 78
app/components/datasets/formatted-text/flavours/preview-slice.tsx | 56
app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/index.tsx | 25
app/components/workflow/utils/index.ts | 8
app/components/workflow/nodes/_base/components/panel-operator/index.tsx | 77
app/components/workflow/nodes/iteration-start/index.tsx | 42
public/screenshots/light/Chatflow@2x.png | 0
app/components/base/icons/src/vender/solid/development/PatternRecognition.json | 98
app/components/base/prompt-editor/plugins/history-block/component.tsx | 92
app/components/base/icons/assets/public/llm/openai-violet.svg | 4
app/components/workflow/simple-node/types.ts | 3
app/components/base/image-uploader/text-generation-image-uploader.tsx | 148
app/components/workflow/operator/add-block.tsx | 111
app/components/base/icons/src/vender/solid/security/Lock01.tsx | 20
app/components/datasets/create/assets/upload-cloud-01.svg | 4
i18n/en-US/explore.ts | 44
app/components/base/icons/src/public/model/Checked.tsx | 20
app/components/base/icons/src/image/llm/Minimax.module.css | 5
i18n/tr-TR/dataset-settings.ts | 43
utils/emoji.ts | 11
app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx | 238
i18n/ja-JP/app-api.ts | 85
app/components/base/icons/assets/public/files/csv.svg | 24
app/components/base/icons/src/public/files/Txt.tsx | 20
app/components/workflow/run/utils/format-log/graph-to-log-struct.spec.ts | 138
app/components/datasets/documents/assets/file.svg | 3
app/components/workflow/nodes/start/use-config.ts | 82
app/components/workflow/nodes/question-classifier/node.tsx | 72
app/components/base/notion-page-selector/assets/clear.svg | 3
app/components/base/icons/src/vender/workflow/ParameterExtractor.json | 266
app/components/base/prompt-editor/plugins/query-block/query-block-replacement-block.tsx | 60
app/components/base/spinner/index.spec.tsx | 49
app/components/header/license-env/index.tsx | 32
app/components/base/icons/src/vender/solid/editor/Paragraph.tsx | 20
.storybook/main.ts | 19
app/components/base/with-input-validation/index.spec.tsx | 41
app/components/app/annotation/remove-annotation-confirm-modal/index.tsx | 29
app/components/workflow/nodes/iteration-start/types.ts | 3
app/components/base/icons/src/vender/line/layout/AlignRight01.json | 39
app/components/base/icons/src/public/llm/Openllm.json | 83
app/components/workflow/nodes/list-operator/types.ts | 38
app/components/workflow/run/status-container.tsx | 51
app/components/datasets/documents/rename-modal.tsx | 76
app/components/workflow/hooks-store/store.ts | 75
i18n/it-IT/dataset.ts | 227
i18n/pt-BR/app-log.ts | 105
app/init/page.tsx | 17
app/components/workflow/nodes/list-operator/node.tsx | 42
app/components/base/icons/src/vender/line/development/FileHeart02.json | 52
app/components/base/icons/assets/public/llm/huggingface-text-hub.svg | 45
app/components/base/icons/assets/public/knowledge/layout-right-2-line-mod.svg | 5
app/components/datasets/metadata/metadata-dataset/select-metadata.tsx | 82
app/(commonLayout)/datasets/DatasetCard.tsx | 240
app/components/app/configuration/base/warning-mask/cannot-query-dataset.tsx | 31
app/components/header/account-setting/data-source-page/data-source-website/index.tsx | 132
i18n/zh-Hant/time.ts | 37
app/components/base/icons/assets/vender/solid/communication/chat-bot.svg | 7
app/components/workflow/nodes/code/default.ts | 43
i18n/en-US/app-annotation.ts | 87
app/components/base/icons/src/public/llm/Huggingface.tsx | 20
app/components/datasets/create/assets/annotation-info.svg | 3
app/components/workflow/header/view-workflow-history.tsx | 273
app/components/base/icons/src/vender/line/development/CodeBrowser.tsx | 20
i18n/it-IT/app-annotation.ts | 89
app/components/base/search-input/index.tsx | 77
app/components/base/features/new-feature-panel/text-to-speech/voice-settings.tsx | 47
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/advanced-options.tsx | 77
.storybook/storybook.css | 6
app/components/base/icons/assets/vender/line/financeAndECommerce/tag-01.svg | 10
context/dataset-detail.ts | 17
app/components/header/plugins-nav/index.tsx | 66
i18n/fr-FR/app-api.ts | 85
i18n/pt-BR/register.ts | 4
app/install/installForm.tsx | 184
app/components/base/icons/assets/vender/solid/FinanceAndECommerce/scales-02.svg | 5
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/required-switch.tsx | 25
app/components/base/icons/assets/public/llm/zhipuai-text.svg | 6
app/components/develop/template/template_workflow.zh.mdx | 783
app/components/datasets/create/website/jina-reader/options.tsx | 61
app/components/header/account-setting/model-provider-page/model-selector/feature-icon.tsx | 124
app/components/base/icons/src/vender/line/users/User01.tsx | 20
service/_tools_util.spec.ts | 16
i18n/th-TH/layout.ts | 3
i18n/uk-UA/education.ts | 47
app/components/base/icons/assets/vender/line/general/x.svg | 5
app/components/workflow-app/hooks/use-is-chat-mode.ts | 7
app/components/base/icons/src/vender/line/general/Settings04.tsx | 20
app/components/plugins/plugin-page/use-permission.ts | 61
app/components/base/icons/src/vender/line/others/Colors.tsx | 20
app/components/base/icons/src/vender/solid/communication/Send03.tsx | 20
app/components/base/icons/src/public/billing/Diamond.tsx | 20
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/add-field.tsx | 33
service/strategy.ts | 10
app/components/app/text-generate/saved-items/index.tsx | 75
app/components/base/icons/src/vender/line/others/Env.tsx | 20
service/tag.ts | 47
app/components/base/icons/src/vender/workflow/Assigner.json | 68
app/components/workflow/hooks/use-workflow-run-event/use-workflow-text-replace.ts | 23
app/components/app/configuration/tools/index.tsx | 191
app/components/base/icons/src/vender/line/communication/index.ts | 6
app/components/workflow/nodes/_base/components/variable/constant-field.tsx | 65
i18n/ru-RU/workflow.ts | 921
app/components/base/icons/src/public/tracing/WeaveIcon.json | 279
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/page.tsx | 20
app/components/base/icons/src/public/other/Icon3Dots.json | 29
app/signin/page.tsx | 15
app/components/base/icons/src/vender/line/mapsAndTravel/index.ts | 2
app/components/base/action-button/index.tsx | 73
i18n/vi-VN/app-log.ts | 100
app/components/base/icons/src/vender/workflow/VariableX.tsx | 20
app/components/base/icons/assets/public/model/checked.svg | 3
i18n/pt-BR/dataset-documents.ts | 395
app/components/base/icons/src/vender/line/files/FileDownload02.tsx | 20
app/components/plugins/install-plugin/hooks/use-refresh-plugin-list.tsx | 48
app/(commonLayout)/app/(appDetailLayout)/[appId]/annotations/page.tsx | 15
i18n/ro-RO/plugin.ts | 215
app/components/base/icons/src/public/llm/Azureai.json | 180
i18n/sl-SI/login.ts | 110
i18n/ro-RO/app-overview.ts | 173
app/components/base/icons/src/vender/line/editor/AlignLeft.json | 39
app/components/base/icons/assets/vender/line/general/edit-02.svg | 10
app/components/base/icons/src/public/llm/HuggingfaceText.json | 322
app/components/base/icons/src/vender/line/editor/BezierCurve03.json | 38
app/components/base/action-button/index.css | 45
app/components/workflow/hooks/use-workflow-run-event/use-workflow-text-chunk.ts | 25
app/components/base/icons/src/public/llm/Microsoft.tsx | 20
app/components/workflow/nodes/end/panel.tsx | 49
i18n/de-DE/explore.ts | 44
public/vs/basic-languages/apex/apex.js | 10
i18n/tr-TR/register.ts | 3
app/components/workflow/nodes/list-operator/panel.tsx | 184
app/components/header/account-setting/index.tsx | 229
app/components/header/account-setting/model-provider-page/index.tsx | 161
app/components/base/icons/src/public/llm/Chatglm.json | 72
public/vs/basic-languages/perl/perl.js | 10
app/components/base/prompt-editor/plugins/query-block/node.tsx | 59
app/components/billing/pricing/self-hosted-plan-item.tsx | 176
app/components/datasets/external-api/declarations.ts | 16
i18n/tr-TR/app-log.ts | 98
app/components/datasets/create/website/jina-reader/base/checkbox-with-label.tsx | 40
app/components/header/indicator/index.tsx | 59
app/components/app/annotation/index.tsx | 287
app/components/app/create-from-dsl-modal/dsl-confirm-modal.tsx | 46
app/components/base/icons/assets/vender/line/editor/collapse.svg | 9
app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx | 380
app/components/header/app-selector/index.tsx | 112
app/components/workflow/nodes/_base/components/next-step/item.tsx | 86
app/components/base/icons/src/image/llm/WxyyText.tsx | 20
i18n/ru-RU/common.ts | 672
app/components/datasets/create/assets/txt.svg | 23
app/components/base/icons/src/public/common/MessageChatSquare.tsx | 20
app/components/base/icons/assets/vender/line/others/tools.svg | 14
app/components/base/image-uploader/image-link-input.tsx | 56
app/components/workflow/nodes/_base/components/retry/retry-on-panel.tsx | 117
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/hitTesting/page.tsx | 20
app/components/develop/secret-key/assets/copy.svg | 3
app/components/base/icons/src/vender/line/time/ClockPlaySlim.json | 39
app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/assets/schema-generator-dark.tsx | 15
app/components/workflow/nodes/start/panel.tsx | 184
app/components/browser-initor.tsx | 52
types/workflow.ts | 354
i18n/fa-IR/share-app.ts | 78
app/components/datasets/create/website/watercrawl/index.tsx | 217
app/components/base/emoji-picker/index.tsx | 65
app/components/billing/apps-full-in-dialog/style.module.css | 7
app/components/datasets/documents/detail/completed/child-segment-detail.tsx | 134
app/(commonLayout)/apps/assets/discord.svg | 3
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-date.tsx | 86
i18n/it-IT/billing.ts | 213
app/components/base/icons/src/vender/workflow/Home.tsx | 20
app/components/workflow/run/agent-log/agent-log-trigger.tsx | 49
app/components/base/icons/src/public/llm/OpenllmText.json | 143
i18n/tr-TR/dataset-documents.ts | 394
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/[documentId]/page.tsx | 21
app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/picker/index.tsx | 82
service/debug.ts | 114
app/components/datasets/metadata/metadata-dataset/field.tsx | 23
app/components/base/icons/src/vender/line/financeAndECommerce/ReceiptList.tsx | 20
app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx | 170
i18n/vi-VN/dataset.ts | 221
i18n/fa-IR/education.ts | 47
app/components/base/icons/src/vender/solid/users/UsersPlus.tsx | 20
app/components/base/icons/src/vender/line/development/Webhooks.tsx | 20
app/components/workflow/nodes/_base/components/editor/text-editor.tsx | 63
app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.tsx | 161
app/education-apply/search-input.tsx | 122
i18n/ro-RO/education.ts | 47
app/components/base/icons/assets/vender/solid/editor/citations.svg | 5
app/components/base/icons/src/vender/features/MessageFast.tsx | 20
public/screenshots/light/Workflow.png | 0
app/components/base/icons/assets/public/common/github.svg | 5
app/components/workflow/operator/hooks.ts | 41
i18n/ro-RO/share-app.ts | 82
app/components/header/env-nav/index.tsx | 46
public/vs/basic-languages/objective-c/objective-c.js | 10
app/components/base/icons/assets/public/tracing/opik-icon.svg | 88
app/components/base/icons/src/vender/line/others/LongArrowRight.json | 27
app/components/app/configuration/base/var-highlight/style.module.css | 3
app/components/workflow/store/workflow/tool-slice.ts | 26
app/components/datasets/hit-testing/components/result-item.tsx | 100
app/components/base/icons/src/public/llm/XorbitsInference.tsx | 20
app/components/base/form/form-scenarios/demo/index.tsx | 68
service/common.ts | 353
public/vs/editor/editor.main.nls.zh-tw.js | 13
app/components/header/account-setting/model-provider-page/model-selector/empty-trigger.tsx | 40
public/vs/basic-languages/systemverilog/systemverilog.js | 10
app/components/header/account-dropdown/workplace-selector/index.tsx | 94
app/components/workflow/nodes/agent/panel.tsx | 177
app/components/workflow/context.tsx | 29
app/components/datasets/formatted-text/flavours/shared.tsx | 80
app/components/base/icons/src/vender/solid/development/Semantic.tsx | 20
app/signin/check-code/page.tsx | 96
i18n/it-IT/dataset-settings.ts | 48
app/components/app/configuration/base/icons/remove-icon/index.tsx | 31
app/components/base/icons/src/vender/solid/communication/ListSparkle.json | 53
app/components/workflow/nodes/if-else/use-config.ts | 278
app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx | 154
app/components/datasets/hit-testing/components/chunk-detail-modal.tsx | 92
app/components/app/annotation/edit-annotation-modal/index.tsx | 146
app/components/workflow/nodes/_base/components/panel-operator/panel-operator-popup.tsx | 197
app/components/base/icons/src/vender/solid/communication/CuteRobot.tsx | 20
app/education-apply/education-apply-page.tsx | 189
assets/doc.svg | 22
app/components/datasets/create/assets/progress-indicator.svg | 8
i18n/en-US/plugin-tags.ts | 25
i18n/vi-VN/app.ts | 214
public/screenshots/light/Agent.png | 0
app/components/base/icons/assets/vender/solid/education/beaker-02.svg | 5
i18n/de-DE/education.ts | 47
i18n/it-IT/login.ts | 120
app/components/base/icons/src/public/plugins/VerifiedLight.json | 456
app/components/tools/add-tool-modal/empty.tsx | 21
app/components/header/account-setting/Integrations-page/index.module.css | 24
context/debug-configuration.ts | 263
app/components/develop/template/template.en.mdx | 708
i18n/th-TH/register.ts | 3
app/components/base/icons/src/public/llm/JinaText.tsx | 20
app/components/base/icons/src/vender/line/layout/AlignLeft01.tsx | 20
i18n/zh-Hant/dataset-hit-testing.ts | 35
app/components/base/icons/src/vender/line/layout/AlignRight01.tsx | 20
app/components/workflow/hooks/use-nodes-data.ts | 77
app/components/base/form/form-scenarios/demo/contact-fields.tsx | 35
app/components/base/icons/src/vender/solid/mediaAndDevices/VideoSupportIcon.tsx | 20
app/components/plugins/constants.ts | 27
app/components/app/configuration/debug/debug-with-multiple-model/text-generation-item.tsx | 144
app/components/base/icons/src/public/files/Unknown.json | 199
i18n/it-IT/app-api.ts | 106
app/components/base/icons/src/vender/solid/communication/EditList.json | 53
app/components/workflow/nodes/http/components/key-value/index.tsx | 62
app/components/base/chat/chat-with-history/header/mobile-operation-dropdown.tsx | 59
public/vs/editor/editor.main.css | 6
app/components/header/assets/google.svg | 13
app/components/base/form/components/field/select.tsx | 51
i18n/ru-RU/explore.ts | 44
app/components/base/audio-gallery/AudioPlayer.tsx | 319
app/components/base/icons/src/vender/line/files/Clipboard.json | 29
app/components/workflow/hooks-store/index.ts | 2
app/components/base/icons/src/public/knowledge/GeneralType.json | 38
i18n/pt-BR/run-log.ts | 31
app/components/base/icons/src/vender/solid/general/MessageClockCircle.tsx | 20
app/components/workflow/nodes/_base/components/retry/utils.ts | 0
i18n/zh-Hant/explore.ts | 44
app/components/base/select/locale.tsx | 61
app/components/base/icons/src/vender/line/financeAndECommerce/Tag01.json | 66
app/components/datasets/hit-testing/components/result-item-meta.tsx | 45
app/components/base/tag-management/tag-item-editor.tsx | 151
app/components/base/agent-log-modal/tracing.tsx | 25
app/components/base/icons/src/public/common/Lock.json | 38
public/screenshots/dark/TextGenerator.png | 0
app/components/base/icons/src/public/thought/Loading.tsx | 20
app/components/base/icons/src/vender/line/financeAndECommerce/GoldCoin.tsx | 20
app/components/base/icons/src/vender/features/Microphone01.json | 37
i18n/ja-JP/dataset-creation.ts | 216
app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.tsx | 140
app/components/workflow/panel/chat-variable-panel/components/variable-modal-trigger.tsx | 69
i18n/ja-JP/dataset.ts | 221
i18n/es-ES/app-overview.ts | 173
app/components/workflow-app/index.tsx | 108
app/components/workflow/nodes/start/node.tsx | 40
themes/light.css | 739
app/components/tools/marketplace/hooks.ts | 117
app/(commonLayout)/apps/assets/right-arrow.svg | 3
i18n/tr-TR/run-log.ts | 31
public/vs/basic-languages/st/st.js | 10
app/components/base/icons/src/public/plugins/Google.json | 53
app/components/workflow/nodes/assigner/default.ts | 52
i18n/fr-FR/billing.ts | 200
i18n/fr-FR/register.ts | 4
app/components/app/configuration/config/automatic/automatic-btn.tsx | 25
app/components/base/icons/src/vender/solid/arrows/index.ts | 2
app/components/base/icons/src/public/knowledge/Chunk.tsx | 20
app/components/datasets/hit-testing/modify-external-retrieval-modal.tsx | 71
app/components/base/icons/assets/vender/solid/shapes/corner.svg | 3
app/components/base/pagination/hook.ts | 95
i18n/hi-IN/login.ts | 115
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/utils.ts | 66
app/components/base/file-uploader/file-uploader-in-attachment/index.tsx | 133
app/components/base/icons/assets/vender/solid/development/file-heart-02.svg | 6
app/components/base/icons/src/vender/line/mapsAndTravel/Route.tsx | 20
app/components/base/icons/src/vender/line/arrows/ChevronDownDouble.tsx | 20
models/log.ts | 355
app/components/base/icons/src/vender/line/editor/LetterSpacing01.tsx | 20
app/components/app/app-publisher/features-wrapper.tsx | 86
app/components/plugins/plugin-detail-panel/app-selector/index.tsx | 143
app/components/base/icons/assets/vender/solid/users/users-plus.svg | 10
app/components/base/icons/src/public/tracing/WeaveIconBig.tsx | 16
app/components/datasets/create/embedding-process/index.module.css | 89
public/vs/basic-languages/dockerfile/dockerfile.js | 10
app/components/base/icons/src/vender/solid/communication/MessageSmileSquare.json | 38
app/components/base/image-uploader/utils.ts | 36
app/components/base/icons/src/vender/line/education/BookOpen01.json | 49
app/components/base/icons/src/vender/line/others/Apps02.json | 36
app/components/header/account-setting/key-validator/hooks.ts | 31
app/components/header/account-setting/plugin-page/index.tsx | 38
app/components/base/icons/src/public/common/Notion.tsx | 20
app/components/header/explore-nav/index.tsx | 38
app/components/app/configuration/features/experience-enhance-group/more-like-this/index.tsx | 51
app/components/base/icons/src/vender/line/general/Settings01.json | 86
app/components/header/maintenance-notice.tsx | 39
app/components/base/icons/src/vender/line/time/ClockPlay.tsx | 20
app/components/workflow/nodes/_base/components/info-panel.tsx | 27
app/components/app/workflow-log/detail.tsx | 26
public/vs/basic-languages/solidity/solidity.js | 10
public/vs/basic-languages/pascaligo/pascaligo.js | 10
app/components/workflow/note-node/note-editor/utils.ts | 22
app/components/base/icons/src/vender/solid/files/FileZip.json | 47
app/components/workflow/nodes/code/use-config.ts | 178
public/vs/basic-languages/python/python.js | 10
app/components/workflow/nodes/index.tsx | 52
app/components/base/icons/src/vender/line/files/FileArrow01.tsx | 20
utils/timezone.ts | 7
app/components/base/icons/assets/vender/solid/development/puzzle-piece-01.svg | 5
app/components/base/icons/src/public/llm/CohereText.tsx | 20
i18n/zh-Hant/common.ts | 672
app/components/base/icons/assets/public/tracing/opik-icon-big.svg | 87
app/components/workflow/nodes/_base/components/retry/types.ts | 5
app/components/base/icons/assets/image/llm/minimax-text.png | 0
app/components/develop/template/template_chat.ja.mdx | 1392
app/components/base/icons/src/vender/line/financeAndECommerce/CoinsStacked01.tsx | 20
app/components/header/account-setting/api-based-extension-page/modal.tsx | 150
app/components/base/image-uploader/image-preview.tsx | 269
app/components/base/app-icon-picker/hooks.tsx | 43
app/components/tools/labels/selector.tsx | 122
app/components/base/icons/src/vender/line/general/LinkExternal02.json | 38
app/components/header/assets/notion.svg | 12
app/components/base/tab-slider-new/index.tsx | 40
app/components/base/chat/embedded-chatbot/inputs-form/content.tsx | 115
i18n/pt-BR/plugin-tags.ts | 25
app/components/base/icons/src/vender/line/general/LogIn04.json | 53
app/components/base/icons/src/vender/line/editor/ImageIndentLeft.tsx | 20
app/components/base/icons/src/vender/other/AnthropicText.tsx | 20
app/components/base/icons/src/vender/line/general/Pin02.tsx | 20
app/components/develop/template/template_chat.en.mdx | 1700
public/screenshots/dark/Chatbot@2x.png | 0
app/components/base/icons/src/public/llm/Zhipuai.tsx | 20
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/context.tsx | 50
app/components/billing/priority-label/index.tsx | 65
app/components/base/image-gallery/style.module.css | 22
app/components/plugins/install-plugin/install-bundle/item/github-item.tsx | 62
app/components/base/icons/assets/vender/line/financeAndECommerce/coins-stacked-01.svg | 5
i18n/vi-VN/run-log.ts | 31
app/components/header/account-setting/model-provider-page/system-model-selector/index.tsx | 265
app/components/base/icons/src/public/billing/GoogleCloud.tsx | 20
app/components/base/icons/src/public/tracing/OpikIconBig.json | 162
app/components/datasets/metadata/hooks/use-edit-dataset-metadata.ts | 96
i18n/fr-FR/dataset.ts | 220
i18n/vi-VN/app-overview.ts | 173
app/components/base/icons/src/public/llm/IflytekSparkText.json | 187
app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter.tsx | 63
app/components/workflow/panel/debug-and-preview/conversation-variable-modal.tsx | 156
middleware.ts | 86
public/vs/editor/editor.main.js | 762
app/components/datasets/documents/assets/bezierCurve.svg | 3
app/components/base/icons/src/vender/solid/communication/MessageFast.json | 28
app/components/base/icons/src/vender/solid/education/Unblur.tsx | 20
i18n/it-IT/common.ts | 703
app/components/base/icons/src/public/knowledge/Collapse.tsx | 20
app/components/base/icons/src/vender/line/development/PuzzlePiece01.tsx | 20
i18n/fr-FR/plugin-tags.ts | 25
public/screenshots/dark/Chatflow@3x.png | 0
app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx | 90
app/components/base/icons/src/vender/line/files/Clipboard.tsx | 20
app/components/workflow/store/workflow/env-variable-slice.ts | 20
app/components/base/icons/assets/vender/solid/communication/send-03.svg | 5
app/components/base/chat/chat-with-history/header/operation.tsx | 73
app/components/workflow/nodes/utils.ts | 30
i18n/ru-RU/plugin.ts | 215
app/components/base/icons/src/vender/solid/files/FileSearch02.json | 57
app/components/base/icons/IconBase.tsx | 39
app/components/base/audio-gallery/index.tsx | 12
app/components/workflow/features.tsx | 60
app/components/workflow/nodes/loop-start/constants.ts | 1
i18n/pl-PL/workflow.ts | 921
app/components/datasets/documents/detail/completed/common/segment-index-tag.tsx | 40
public/vs/basic-languages/redshift/redshift.js | 10
app/components/base/markdown.tsx | 355
app/components/base/icons/assets/vender/solid/general/plus-circle.svg | 5
app/components/app/annotation/add-annotation-modal/index.tsx | 121
app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx | 83
app/components/base/features/new-feature-panel/file-upload/setting-modal.tsx | 53
app/account/account-page/index.module.css | 9
app/components/base/prompt-editor/index.tsx | 226
app/components/workflow/block-icon.tsx | 147
app/components/base/icons/assets/public/billing/sparkles.svg | 14
i18n/it-IT/dataset-hit-testing.ts | 36
i18n/ja-JP/billing.ts | 192
app/components/header/account-setting/model-provider-page/model-selector/deprecated-model-trigger.tsx | 54
app/components/base/file-uploader/file-from-link-or-local/index.tsx | 129
app/components/base/icons/assets/public/llm/openai-text.svg | 8
i18n/ro-RO/app.ts | 214
app/components/workflow/nodes/question-classifier/components/advanced-setting.tsx | 82
app/components/base/icons/src/vender/line/arrows/ArrowNarrowLeft.tsx | 20
app/components/workflow/run/tracing-panel.tsx | 199
app/components/base/icons/assets/vender/workflow/llm.svg | 5
app/components/workflow/run/index.tsx | 172
app/components/base/chat/embedded-chatbot/inputs-form/index.tsx | 79
app/components/datasets/hit-testing/assets/plugin.svg | 10
app/components/plugins/card/base/description.tsx | 31
app/components/base/icons/src/vender/line/files/File02.tsx | 20
app/components/app/configuration/dataset-config/context-var/var-picker.tsx | 104
public/vs/language/typescript/tsMode.js | 20
app/components/base/icons/src/vender/solid/general/Edit03.tsx | 20
app/components/plugins/marketplace/types.ts | 59
i18n/tr-TR/app-debug.ts | 460
app/components/workflow/note-node/note-editor/plugins/format-detector-plugin/index.tsx | 9
i18n/it-IT/app-log.ts | 102
i18n/uk-UA/dataset-settings.ts | 43
tailwind.config.js | 12
app/components/custom/custom-page/index.tsx | 38
service/share.ts | 270
types/app.ts | 450
app/components/base/icons/src/vender/solid/editor/index.ts | 5
app/components/plugins/update-plugin/from-github.tsx | 26
app/components/base/features/new-feature-panel/file-upload/setting-content.tsx | 89
i18n/es-ES/tools.ts | 158
app/components/datasets/create/assets/xlsx.svg | 18
app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx | 126
app/components/base/icons/src/vender/solid/general/Tool03.tsx | 20
app/components/workflow/nodes/loop/panel.tsx | 160
app/components/plugins/install-plugin/utils.ts | 60
app/components/workflow/nodes/answer/node.tsx | 26
app/components/plugins/install-plugin/install-from-local-package/steps/install.tsx | 164
app/components/base/icons/assets/image/llm/baichuan-text-cn.png | 0
i18n/zh-Hans/app-overview.ts | 173
app/components/develop/secret-key/assets/play.svg | 11
app/components/workflow/nodes/loop/components/condition-files-list-value.tsx | 115
app/components/base/audio-btn/audio.ts | 247
context/provider-context.tsx | 201
app/components/base/icons/src/vender/solid/mediaAndDevices/Speaker.tsx | 20
i18n/fr-FR/app-log.ts | 98
i18n/sl-SI/workflow.ts | 1354
app/components/base/icons/src/vender/features/index.ts | 10
app/components/base/icons/assets/vender/line/general/info-circle.svg | 10
i18n/ru-RU/dataset-settings.ts | 43
app/components/datasets/settings/permission-selector/index.tsx | 195
app/components/workflow/hooks/use-panel-interactions.ts | 37
i18n/en-US/tools.ts | 158
app/components/base/icons/assets/vender/features/document.svg | 3
app/components/plugins/update-plugin/index.tsx | 33
app/components/workflow/note-node/note-editor/toolbar/command.tsx | 83
i18n/en-US/app-debug.ts | 537
i18n/zh-Hant/dataset-creation.ts | 218
app/components/base/icons/src/public/tracing/LangsmithIconBig.json | 188
app/components/header/assets/alpha.svg | 4
service/use-apps.ts | 27
app/components/base/chat/chat/loading-anim/index.tsx | 17
app/components/datasets/documents/index.tsx | 350
app/components/base/icons/src/public/common/Iso.json | 121
app/components/base/icons/assets/public/common/sparkles-soft.svg | 6
app/components/workflow/hooks/use-node-data-update.ts | 43
utils/time.ts | 12
app/components/base/icons/src/vender/features/ContentModeration.tsx | 20
app/components/tools/workflow-tool/configure-button.tsx | 258
app/components/base/icons/src/public/other/RowStruct.tsx | 20
app/components/base/icons/src/public/other/index.ts | 4
app/components/base/icons/assets/vender/line/others/global-variable.svg | 3
app/components/base/icons/src/vender/line/others/FileCode.json | 26
app/components/datasets/documents/assets/globe.svg | 10
i18n/uk-UA/workflow.ts | 921
app/components/base/icons/src/vender/features/TextToAudio.tsx | 20
app/components/base/agent-log-modal/iteration.tsx | 51
app/components/base/icons/assets/public/tracing/langsmith-icon.svg | 24
app/components/base/icons/assets/vender/features/microphone-01.svg | 4
app/components/base/icons/src/vender/line/users/Users01.tsx | 20
app/components/workflow/shortcuts-name.tsx | 32
i18n/ja-JP/tools.ts | 158
app/components/workflow/nodes/iteration/default.ts | 63
app/components/workflow/index.tsx | 379
app/components/workflow/nodes/_base/components/toggle-expand-btn.tsx | 30
app/components/app/configuration/config-prompt/simple-prompt-input.tsx | 284
app/components/app/configuration/base/warning-mask/style.module.css | 8
app/components/workflow/nodes/answer/panel.tsx | 47
i18n/en-US/app-log.ts | 98
app/(commonLayout)/apps/hooks/useAppsQueryState.ts | 60
app/components/base/icons/src/vender/solid/general/CheckCircle.tsx | 20
public/vs/base/common/worker/simpleWorker.nls.js | 8
app/components/workflow/nodes/variable-assigner/use-config.ts | 190
app/components/plugins/marketplace/empty/index.tsx | 63
i18n/vi-VN/time.ts | 37
app/components/base/icons/assets/public/llm/baichuan.svg | 11
app/components/base/prompt-editor/plugins/context-block/component.tsx | 104
app/components/base/icons/src/vender/solid/development/PatternRecognition.tsx | 20
app/components/base/icons/assets/public/llm/openai-black.svg | 4
public/vs/basic-languages/postiats/postiats.js | 10
app/install/page.tsx | 20
app/components/workflow/nodes/_base/hooks/use-output-var-list.ts | 121
i18n/fa-IR/app-annotation.ts | 87
app/components/datasets/metadata/metadata-dataset/select-metadata-modal.tsx | 82
app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-variable-selector.tsx | 92
app/components/workflow/nodes/_base/components/error-handle/error-handle-tip.tsx | 43
app/components/header/account-setting/data-source-page/panel/style.module.css | 17
app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-iteration-started.ts | 85
app/components/header/account-setting/model-provider-page/model-parameter-modal/index.tsx | 267
i18n/de-DE/workflow.ts | 921
app/components/base/icons/src/vender/line/mediaAndDevices/Speaker.tsx | 20
app/components/datasets/create/embedding-process/index.tsx | 357
public/screenshots/dark/Agent.png | 0
i18n/th-TH/dataset-hit-testing.ts | 35
app/components/datasets/create/assets/check.svg | 3
app/components/base/icons/assets/vender/solid/arrows/high-priority.svg | 6
app/components/develop/template/template_advanced_chat.en.mdx | 1660
app/components/datasets/documents/detail/embedding/index.tsx | 314
app/dev-only/i18n-checker/page.tsx | 164
i18n/uk-UA/dataset-creation.ts | 218
app/components/workflow/nodes/_base/components/retry/hooks.ts | 41
app/components/base/icons/assets/vender/line/general/log-out-04.svg | 8
i18n/ro-RO/layout.ts | 4
app/components/base/icons/src/public/llm/IflytekSpark.tsx | 20
app/components/datasets/loading.tsx | 0
app/components/base/icons/assets/vender/workflow/assigner.svg | 9
app/components/workflow/note-node/note-editor/editor.tsx | 66
utils/timezone.json | 1274
app/components/base/icons/src/image/llm/TongyiTextCn.tsx | 20
app/components/base/icons/assets/vender/line/arrows/refresh-ccw-01.svg | 3
public/vs/basic-languages/pgsql/pgsql.js | 10
app/components/base/icons/assets/vender/line/files/file-plus-02.svg | 3
app/components/datasets/create/website/jina-reader/base/error-message.tsx | 30
app/components/app/configuration/dataset-config/params-config/config-content.tsx | 382
app/components/base/icons/src/vender/line/mediaAndDevices/PlayCircle.tsx | 20
app/components/base/icons/assets/vender/line/arrows/reverse-left.svg | 5
app/components/base/icons/src/vender/line/financeAndECommerce/CoinsStacked01.json | 39
i18n/sl-SI/plugin.ts | 215
app/styles/markdown.scss | 1044
app/components/workflow/hooks/use-workflow-mode.ts | 14
app/components/datasets/external-knowledge-base/create/InfoPanel.tsx | 33
global.d.ts | 5
app/components/workflow/nodes/loop/add-block.tsx | 80
app/components/base/portal-to-follow-elem/index.spec.tsx | 121
app/components/plugins/update-plugin/plugin-version-picker.tsx | 118
app/signin/oneMoreStep.tsx | 176
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/[documentId]/settings/page.tsx | 21
app/components/workflow/panel/debug-and-preview/user-input.tsx | 56
i18n/tr-TR/explore.ts | 44
app/components/base/param-item/top-k-item.tsx | 54
app/components/app/overview/assets/chromeplugin-option.svg | 159
app/components/develop/template/template_workflow.en.mdx | 792
app/components/base/notion-page-selector/assets/notion-page.svg | 3
app/components/base/icons/src/vender/workflow/Jinja.json | 98
app/components/share/text-generation/run-once/index.tsx | 184
public/vs/editor/editor.main.nls.ja.js | 15
app/components/workflow/note-node/note-editor/toolbar/operator.tsx | 107
app/components/base/icons/src/vender/workflow/Loop.tsx | 20
app/components/base/icons/src/public/llm/OpenaiTransparent.json | 26
app/components/plugins/plugin-detail-panel/app-selector/app-inputs-form.tsx | 125
i18n/zh-Hant/plugin.ts | 215
app/components/workflow/panel/chat-variable-panel/index.tsx | 202
i18n/pl-PL/plugin-tags.ts | 25
assets/csv.svg | 22
app/components/base/notion-page-selector/index.tsx | 2
app/components/base/voice-input/utils.ts | 47
i18n/vi-VN/custom.ts | 32
app/components/base/features/new-feature-panel/moderation/moderation-content.tsx | 72
app/components/base/icons/src/public/knowledge/GeneralType.tsx | 20
app/components/base/date-and-time-picker/hooks.ts | 49
app/components/header/plan-badge/index.tsx | 64
app/components/base/icons/src/vender/line/editor/LeftIndent02.tsx | 20
app/components/base/icons/src/vender/line/development/Database01.json | 29
app/components/base/icons/src/vender/line/communication/AiText.tsx | 20
app/components/base/features/new-feature-panel/follow-up.tsx | 56
app/components/base/icons/src/public/files/Csv.json | 181
app/components/base/tag-management/tag-remove-modal.tsx | 49
app/components/base/icons/src/vender/line/development/Database03.tsx | 20
i18n/zh-Hant/run-log.ts | 31
app/components/base/icons/src/vender/solid/users/User01.tsx | 20
i18n/it-IT/app-overview.ts | 193
app/components/tools/workflow-tool/index.tsx | 282
service/use-endpoints.ts | 149
app/components/base/icons/src/vender/line/development/Variable.json | 62
app/components/base/video-gallery/index.tsx | 12
app/components/datasets/create/step-two/inputs.tsx | 79
app/components/workflow/nodes/http/components/key-value/key-value-edit/index.tsx | 87
app/components/base/agent-log-modal/detail.tsx | 132
app/components/workflow/run/special-result-panel.tsx | 98
app/(commonLayout)/app/(appDetailLayout)/layout.tsx | 28
app/components/base/answer-icon/index.tsx | 47
app/components/base/icons/src/vender/solid/general/Target04.tsx | 20
public/screenshots/light/Chatbot@3x.png | 0
app/components/base/file-uploader/video-preview.tsx | 45
app/components/plugins/types.ts | 457
i18n/de-DE/share-app.ts | 82
app/components/workflow/nodes/parameter-extractor/components/extract-parameter/update.tsx | 189
app/components/base/prompt-editor/plugins/component-picker-block/index.tsx | 227
app/components/header/account-setting/api-based-extension-page/item.tsx | 74
app/components/base/icons/src/vender/solid/shapes/Star04.tsx | 20
hooks/use-breakpoints.ts | 29
app/components/base/icons/src/public/plugins/Google.tsx | 20
app/components/base/slider/style.css | 11
app/components/tools/edit-custom-collection-modal/config-credentials.tsx | 154
app/components/base/select/pure.tsx | 157
app/components/base/icons/assets/vender/solid/communication/ai-text.svg | 6
app/components/base/file-uploader/file-uploader-in-chat-input/file-list.tsx | 82
app/components/base/icons/src/vender/line/development/Database03.json | 29
app/components/base/tag-input/index.tsx | 121
app/components/explore/app-list/style.module.css | 29
app/components/workflow/workflow-history-store.tsx | 121
app/components/workflow/run/utils/format-log/retry/index.spec.ts | 21
app/components/datasets/documents/detail/completed/segment-card/chunk-content.tsx | 57
app/components/base/icons/src/vender/line/others/Tools.json | 119
i18n/pt-BR/workflow.ts | 921
app/components/base/icons/src/vender/line/development/ArtificialBrain.tsx | 20
public/vs/basic-languages/html/html.js | 10
app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars.tsx | 170
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chartView.tsx | 106
app/components/datasets/create/assets/option-card-effect-orange.svg | 12
i18n/de-DE/run-log.ts | 32
app/components/base/icons/assets/vender/line/files/folder.svg | 5
app/components/develop/secret-key/input-copy.tsx | 57
app/components/base/icons/assets/vender/solid/education/bubble-text.svg | 5
app/components/base/icons/src/public/billing/Azure.tsx | 20
i18n/ko-KR/tools.ts | 158
app/components/base/icons/src/vender/solid/communication/EditList.tsx | 20
assets/json.svg | 23
app/components/datasets/create/assets/doc.svg | 22
app/components/plugins/plugin-item/index.tsx | 197
app/components/base/icons/src/public/llm/Chatglm.tsx | 20
app/components/base/icons/src/vender/solid/users/UserEdit02.json | 92
app/components/workflow/run/retry-log/retry-result-panel.tsx | 46
app/components/datasets/create/assets/note-mod.svg | 5
assets/txt.svg | 23
app/components/app/app-publisher/version-info-modal.tsx | 112
app/components/header/account-setting/members-page/invited-modal/assets/copy.svg | 3
app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx | 128
app/(commonLayout)/apps/assets/link.svg | 3
app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.json | 38
i18n/ru-RU/register.ts | 4
app/components/base/icons/src/vender/line/development/GitBranch01.json | 39
app/components/base/icons/src/vender/solid/general/XCircle.json | 29
app/components/base/chat/chat/type.ts | 147
app/components/workflow/nodes/document-extractor/use-config.ts | 111
app/components/base/features/new-feature-panel/speech-to-text.tsx | 56
i18n/tr-TR/share-app.ts | 78
app/components/workflow/nodes/_base/components/output-vars.tsx | 85
app/components/datasets/documents/assets/star.svg | 11
i18n/th-TH/app.ts | 210
public/vs/base/common/worker/simpleWorker.nls.ko.js | 8
app/components/base/icons/src/vender/solid/general/ZapNarrow.tsx | 20
app/components/base/icons/src/vender/workflow/Http.tsx | 20
app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx | 110
app/components/datasets/documents/assets/atSign.svg | 10
app/components/base/icons/src/vender/line/general/Link03.json | 57
i18n/fr-FR/workflow.ts | 920
app/components/base/icons/src/vender/line/others/index.ts | 12
app/components/base/input-number/index.tsx | 114
app/components/base/dropdown/index.tsx | 106
app/components/base/icons/src/vender/line/shapes/index.ts | 1
app/components/workflow/nodes/llm/components/json-schema-config-modal/schema-editor.tsx | 23
app/(commonLayout)/app/(appDetailLayout)/[appId]/layout-main.tsx | 177
app/components/base/icons/src/vender/line/alertsAndFeedback/AlertTriangle.json | 39
app/components/workflow/note-node/note-editor/index.tsx | 3
app/(commonLayout)/apps/Apps.tsx | 219
docker/entrypoint.sh | 40
i18n/sl-SI/explore.ts | 44
app/components/base/icons/src/public/thought/Search.json | 64
__mocks__/mime.js | 0
app/components/base/icons/src/image/llm/WxyyTextCn.module.css | 5
i18n/ro-RO/dataset-settings.ts | 43
app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx | 232
i18n/ja-JP/layout.ts | 4
app/components/base/fullscreen-modal/index.tsx | 74
app/components/base/icons/src/public/billing/GoogleCloud.json | 66
app/components/base/icons/src/public/tracing/LangfuseIcon.tsx | 20
app/components/base/icons/assets/vender/solid/development/api-connection-mod.svg | 5
app/components/base/icons/src/vender/line/development/index.ts | 14
app/components/plugins/marketplace/intersection-line/index.tsx | 21
app/components/base/icons/src/vender/solid/communication/ChatBot.tsx | 20
i18n/pt-BR/app.ts | 214
app/components/base/input/index.tsx | 97
app/components/header/assets/serpapi.png | 0
app/components/base/icons/src/public/avatar/Robot.json | 92
app/components/base/icons/src/public/billing/index.ts | 11
public/screenshots/dark/Chatflow@2x.png | 0
app/components/workflow/utils/workflow-init.ts | 338
i18n/tr-TR/education.ts | 47
app/components/base/icons/assets/vender/line/general/checklist-square.svg | 5
app/components/datasets/metadata/edit-metadata-batch/input-has-set-multiple-value.tsx | 34
app/components/base/icons/assets/public/llm/microsoft.svg | 8
app/components/base/notion-icon/index.tsx | 58
app/components/workflow-app/components/workflow-header/index.tsx | 31
app/components/base/icons/src/public/tracing/WeaveIconBig.json | 279
app/components/workflow/run/agent-log/agent-log-nav-more.tsx | 61
app/components/datasets/metadata/metadata-document/info-group.tsx | 111
app/components/base/icons/src/vender/workflow/Assigner.tsx | 20
app/components/base/chat/chat-with-history/sidebar/rename-modal.tsx | 47
app/components/base/icons/src/public/common/SparklesSoft.json | 47
app/components/app/app-publisher/publish-with-multiple-model.tsx | 108
app/components/app/configuration/hooks/use-advanced-prompt-config.ts | 194
app/components/base/icons/src/vender/solid/mediaAndDevices/Speaker.json | 112
public/vs/basic-languages/pla/pla.js | 10
app/components/app/log/var-panel.tsx | 83
app/components/base/icons/assets/public/billing/sparkles-soft.svg | 4
app/components/workflow/nodes/_base/components/node-status-icon.tsx | 43
app/components/base/icons/src/public/llm/XorbitsInference.json | 176
app/components/develop/secret-key/assets/copied.svg | 3
app/components/workflow/note-node/note-editor/theme/theme.css | 32
i18n/ro-RO/workflow.ts | 921
i18n/tr-TR/app.ts | 210
app/components/base/icons/src/vender/line/others/LongArrowRight.tsx | 20
i18n/ja-JP/time.ts | 37
app/components/base/icons/src/public/llm/IflytekSparkText.tsx | 20
i18n/ro-RO/dataset-documents.ts | 395
app/components/base/chat/__tests__/legacyTestMessages.json | 42
app/components/workflow/nodes/variable-assigner/components/var-group-item.tsx | 178
i18n/th-TH/plugin.ts | 215
public/vs/base/common/worker/simpleWorker.nls.ru.js | 8
app/components/base/icons/src/public/llm/HuggingfaceText.tsx | 20
app/components/base/icons/src/vender/solid/general/ArrowDownRoundFill.json | 36
app/(commonLayout)/explore/apps/page.tsx | 8
app/components/base/emoji-picker/Inner.tsx | 173
i18n/th-TH/run-log.ts | 31
app/components/datasets/create/website/base/input.tsx | 63
app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx | 398
i18n/ja-JP/education.ts | 47
public/vs/basic-languages/php/php.js | 10
app/components/base/icons/src/vender/line/development/Container.json | 29
app/components/base/icons/src/public/llm/IflytekSpark.json | 44
app/components/base/icons/src/vender/features/ContentModeration.json | 28
app/components/workflow/nodes/_base/components/node-handle.tsx | 215
app/components/datasets/create/website/base/field.tsx | 54
app/components/base/form/form-scenarios/demo/shared-options.tsx | 14
app/components/base/icons/assets/public/common/soc2.svg | 103
app/components/base/icons/src/vender/solid/files/FileZip.tsx | 20
app/components/workflow/nodes/parameter-extractor/node.tsx | 32
app/components/base/qrcode/index.tsx | 80
app/components/app/create-from-dsl-modal/uploader.tsx | 141
app/components/base/icons/src/vender/line/communication/MessageCheckRemove.json | 39
app/components/base/features/new-feature-panel/dialog-wrapper.tsx | 55
app/components/base/icons/src/public/files/Md.tsx | 20
app/components/datasets/create/website/base/crawled-result-item.tsx | 60
i18n/ja-JP/run-log.ts | 31
app/components/base/icons/src/vender/solid/education/Heart02.tsx | 20
app/components/app/configuration/config/agent/agent-tools/index.tsx | 302
app/components/workflow/nodes/code/types.ts | 19
app/components/base/icons/src/vender/line/communication/MessageCheckRemove.tsx | 20
i18n/hi-IN/plugin.ts | 215
app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/schema-node.tsx | 194
app/components/app/overview/style.module.css | 31
app/components/base/icons/assets/vender/solid/communication/logic.svg | 8
app/components/header/account-setting/model-provider-page/model-parameter-modal/configuration-button.tsx | 32
app/components/plugins/install-plugin/install-bundle/item/package-item.tsx | 41
app/components/plugins/install-plugin/install-from-github/steps/setURL.tsx | 56
app/components/base/icons/assets/vender/solid/mediaAndDevices/audio-support-icon.svg | 3
app/components/header/account-setting/members-page/operation/index.tsx | 134
i18n/es-ES/app.ts | 213
i18n/sl-SI/plugin-tags.ts | 25
app/components/base/icons/assets/public/llm/localai.svg | 15
app/components/base/icons/src/vender/line/files/FileCheck02.json | 39
hooks/use-import-dsl.ts | 163
app/components/header/account-setting/model-provider-page/model-modal/Input.tsx | 74
i18n/pl-PL/dataset.ts | 227
app/components/base/icons/src/vender/line/files/FilePlus02.json | 29
app/components/base/icons/src/vender/solid/development/ApiConnection.tsx | 20
app/components/plugins/card/base/title.tsx | 13
app/(commonLayout)/apps/assets/completion.svg | 3
app/components/workflow/nodes/knowledge-retrieval/use-config.ts | 452
i18n/zh-Hans/dataset.ts | 221
app/components/base/icons/assets/vender/line/layout/align-left-01.svg | 5
app/components/datasets/common/retrieval-method-config/index.tsx | 157
app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.tsx | 20
app/components/datasets/create/assets/piggy-bank-mod.svg | 7
app/components/base/icons/src/vender/line/general/Edit02.json | 66
app/components/base/icons/src/vender/solid/shapes/Star06.json | 62
i18n/es-ES/app-log.ts | 98
app/components/base/icons/src/vender/solid/general/Edit03.json | 57
app/components/base/icons/src/vender/line/communication/ChatBot.json | 93
i18n/ja-JP/plugin.ts | 215
i18n/ko-KR/run-log.ts | 31
app/components/header/account-setting/members-page/invite-modal/role-selector.tsx | 95
i18n/es-ES/login.ts | 110
i18n/es-ES/explore.ts | 44
app/components/base/icons/src/vender/line/others/DragHandle.tsx | 20
app/components/app/configuration/index.tsx | 1068
i18n/it-IT/plugin-tags.ts | 25
app/components/base/icons/src/vender/line/time/ClockFastForward.tsx | 20
app/components/app/overview/assets/code-browser.svg | 3
app/components/base/icons/src/public/files/Xlsx.json | 145
app/components/workflow/nodes/start/utils.ts | 5
app/(commonLayout)/datasets/NewDatasetCard.tsx | 42
app/components/base/date-and-time-picker/time-picker/index.tsx | 170
app/(commonLayout)/datasets/Doc.tsx | 131
app/components/workflow/nodes/end/types.ts | 5
i18n/zh-Hans/education.ts | 47
app/components/base/icons/assets/vender/workflow/jinja.svg | 13
app/components/base/prompt-editor/constants.tsx | 58
app/components/workflow/store/index.ts | 1
i18n/uk-UA/share-app.ts | 78
i18n/fr-FR/share-app.ts | 82
i18n/vi-VN/login.ts | 110
app/components/develop/ApiServer.tsx | 36
i18n/tr-TR/dataset-creation.ts | 218
i18n/pt-BR/plugin.ts | 215
app/components/workflow/nodes/agent/use-config.ts | 220
i18n/pl-PL/app-annotation.ts | 89
app/components/app/configuration/config-prompt/conversation-history/history-panel.tsx | 60
i18n/ko-KR/app-debug.ts | 418
app/(commonLayout)/app/(appDetailLayout)/[appId]/style.module.css | 6
app/components/workflow/nodes/loop/components/condition-list/condition-input.tsx | 53
app/components/base/chip/index.tsx | 109
app/components/base/icons/src/vender/solid/FinanceAndECommerce/Scales02.json | 48
app/components/base/icons/assets/vender/solid/arrows/chevron-down.svg | 5
app/components/base/logo/logo-embedded-chat-avatar.tsx | 19
i18n/de-DE/tools.ts | 158
app/components/base/icons/src/vender/solid/general/Download02.tsx | 20
assets/html.svg | 23
app/components/develop/secret-key/style.module.css | 57
models/explore.ts | 37
public/vs/basic-languages/kotlin/kotlin.js | 10
app/signin/assets/github.svg | 17
public/vs/editor/editor.main.nls.fr.js | 13
app/components/app-sidebar/navLink.tsx | 63
app/components/base/icons/src/vender/line/others/GlobalVariable.tsx | 20
i18n/pl-PL/billing.ts | 212
app/components/base/chat/chat/answer/__mocks__/markdownContentSVG.ts | 27
app/components/base/icons/src/vender/line/others/LongArrowLeft.json | 27
app/components/datasets/external-knowledge-base/create/KnowledgeBaseInfo.tsx | 53
app/components/workflow/panel/record.tsx | 33
app/components/base/icons/assets/vender/solid/shapes/star-06.svg | 9
app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-filter/metadata-filter-selector.tsx | 106
i18n/sl-SI/app-log.ts | 98
app/components/base/icons/src/vender/line/editor/TypeSquare.tsx | 20
app/components/base/icons/src/public/knowledge/Collapse.json | 62
app/components/base/icons/src/public/common/Soc2.json | 938
app/components/base/chat/chat/question.stories.tsx | 33
app/(commonLayout)/education-apply/page.tsx | 29
app/components/billing/annotation-full/index.tsx | 31
public/logo/logo-monochrome-white.svg | 12
app/components/tools/add-tool-modal/type.tsx | 34
i18n/hi-IN/billing.ts | 213
app/components/plugins/plugin-detail-panel/model-selector/tts-params-panel.tsx | 67
app/components/app/configuration/config-prompt/message-type-selector.tsx | 50
app/components/base/chat/chat/thought/panel.tsx | 28
app/components/app/configuration/dataset-config/card-item/style.module.css | 22
app/components/base/icons/src/vender/solid/education/BubbleText.tsx | 20
app/components/workflow/nodes/template-transform/panel.tsx | 130
app/components/base/file-uploader/file-uploader-in-chat-input/file-item.tsx | 156
app/components/base/icons/src/public/plugins/PartnerDark.tsx | 20
app/components/share/text-generation/no-data/index.tsx | 22
public/vs/basic-languages/swift/swift.js | 13
app/components/base/icons/assets/public/knowledge/parent-child-type.svg | 7
app/components/workflow/plugin-dependency/hooks.ts | 17
app/components/share/text-generation/run-batch/csv-reader/index.tsx | 73
app/components/workflow/nodes/knowledge-retrieval/components/metadata/add-condition.tsx | 95
i18n/auto-gen-i18n.js | 109
app/components/base/icons/src/vender/solid/education/BubbleText.json | 38
app/components/base/icons/src/vender/features/LoveMessage.tsx | 20
app/components/base/icons/src/vender/line/editor/AlignLeft.tsx | 20
app/components/base/copy-btn/index.tsx | 54
context/modal-context.tsx | 380
app/components/base/file-uploader/hooks.ts | 367
app/components/base/sort/index.tsx | 92
app/components/header/account-setting/data-source-page/index.tsx | 20
app/components/base/icons/src/vender/solid/communication/MessageHeartCircle.json | 38
app/components/datasets/create/step-three/index.tsx | 75
i18n/hi-IN/dataset.ts | 228
app/components/base/icons/src/vender/workflow/Answer.tsx | 20
assets/delete.svg | 3
app/components/base/icons/assets/vender/features/message-fast.svg | 3
app/components/base/icons/assets/vender/solid/general/zap-fast.svg | 10
i18n/fr-FR/login.ts | 110
app/components/datasets/documents/detail/completed/segment-list.tsx | 119
app/components/workflow/run/assets/bg-line-warning.svg | 3
app/components/workflow/nodes/if-else/components/condition-list/condition-item.tsx | 336
app/components/workflow/panel/env-panel/env-item.tsx | 53
i18n/vi-VN/common.ts | 672
i18n/ko-KR/login.ts | 110
app/components/base/icons/assets/vender/features/content-moderation.svg | 3
app/components/base/icons/assets/vender/solid/mediaAndDevices/robot.svg | 5
app/components/app/configuration/config-var/config-modal/field.tsx | 24
app/components/workflow/nodes/loop/components/condition-number-input.tsx | 168
app/components/i18n-server.tsx | 22
app/components/header/github-star/index.tsx | 27
app/components/base/icons/assets/public/llm/huggingface-text.svg | 42
app/components/base/icons/src/public/plugins/WebReader.tsx | 20
app/components/base/icons/src/public/common/NTo1Retrieval.json | 146
i18n/pl-PL/dataset-creation.ts | 234
app/components/base/icons/assets/vender/other/anthropic-text.svg | 78
app/components/base/icons/src/vender/solid/general/XCircle.tsx | 20
app/components/header/account-setting/collapse/index.tsx | 54
app/components/workflow/nodes/answer/use-config.ts | 41
app/components/base/features/new-feature-panel/annotation-reply/config-param-modal.tsx | 139
app/components/workflow/nodes/list-operator/default.ts | 65
i18n/ro-RO/app-debug.ts | 427
app/components/base/icons/assets/vender/other/replay-line.svg | 5
app/components/base/checkbox/assets/indeterminate-icon.tsx | 11
app/components/workflow/nodes/if-else/components/condition-list/condition-var-selector.tsx | 58
app/components/base/icons/assets/vender/solid/general/eye.svg | 4
app/components/workflow/note-node/note-editor/toolbar/index.tsx | 48
app/components/workflow/run/result-text.tsx | 75
app/components/base/file-uploader/file-list-in-log.tsx | 106
app/components/base/icons/src/vender/solid/users/index.ts | 4
app/components/workflow/nodes/loop/use-interactions.ts | 149
app/components/datasets/documents/list.tsx | 687
i18n/en-US/register.ts | 4
app/components/workflow/store/workflow/workflow-draft-slice.ts | 36
app/components/base/features/new-feature-panel/annotation-reply/score-slider/index.tsx | 46
app/components/base/icons/assets/vender/solid/mediaAndDevices/video-support-icon.svg | 3
i18n/fa-IR/run-log.ts | 31
app/components/base/auto-height-textarea/common.tsx | 54
app/components/base/icons/src/vender/workflow/Iteration.tsx | 20
app/components/base/chat/embedded-chatbot/theme/theme-context.ts | 75
app/components/base/icons/src/public/billing/Buildings.tsx | 20
app/components/base/icons/assets/vender/other/group.svg | 8
app/components/base/icons/src/vender/other/ReplayLine.json | 36
i18n/fa-IR/app-debug.ts | 455
app/components/header/account-setting/key-validator/KeyInput.tsx | 77
app/components/base/icons/src/vender/solid/development/Variable02.json | 62
public/screenshots/dark/Agent@3x.png | 0
app/components/workflow/operator/tip-popup.tsx | 33
app/(commonLayout)/datasets/(datasetDetailLayout)/layout.tsx | 16
app/components/base/icons/src/vender/line/others/FileCode.tsx | 20
app/components/base/icons/src/vender/solid/general/Edit04.tsx | 20
app/components/workflow/panel/version-history-panel/context-menu/menu-item.tsx | 39
app/components/base/icons/src/public/files/Yaml.json | 181
app/components/base/divider/with-label.tsx | 23
app/components/base/icons/src/vender/solid/editor/Brush01.json | 35
app/components/plugins/card/base/card-icon.tsx | 66
i18n/pl-PL/app-overview.ts | 191
app/components/workflow/note-node/index.tsx | 130
app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx | 104
app/components/header/account-about/index.tsx | 87
hooks/use-timestamp.spec.ts | 65
public/vs/basic-languages/julia/julia.js | 10
app/components/workflow/run/utils/format-log/loop/index.spec.ts | 23
app/components/header/account-setting/data-source-page/panel/index.tsx | 145
app/components/base/date-and-time-picker/common/option-list-item.tsx | 38
app/components/workflow/run/assets/bg-line-running.svg | 3
i18n/fr-FR/education.ts | 47
app/components/signin/countdown.tsx | 41
app/education-apply/constants.ts | 2
app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-panel.tsx | 51
i18n/vi-VN/education.ts | 47
app/components/base/icons/src/public/llm/Gpt4.tsx | 20
app/components/plugins/marketplace/hooks.ts | 177
app/components/base/icons/src/public/tracing/LangfuseIconBig.tsx | 20
app/components/base/icons/assets/public/llm/baichuan-text.svg | 19
app/components/base/icons/src/vender/features/FolderUpload.tsx | 20
app/components/workflow/nodes/_base/components/switch-plugin-version.tsx | 126
app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx | 14
app/components/base/date-and-time-picker/time-picker/footer.tsx | 37
public/vs/basic-languages/r/r.js | 10
i18n/ro-RO/common.ts | 672
app/components/base/icons/assets/public/plugins/google.svg | 6
app/components/base/tooltip/index.tsx | 116
i18n/es-ES/app-debug.ts | 419
app/components/base/tag-management/store.ts | 19
app/components/datasets/common/document-picker/document-list.tsx | 42
app/components/workflow/nodes/template-transform/use-config.ts | 137
app/components/base/icons/src/public/llm/ReplicateText.tsx | 20
app/components/app/configuration/config-prompt/prompt-editor-height-resize-wrap.tsx | 96
app/components/base/chat/chat/thought/tool.tsx | 106
app/components/base/features/store.ts | 66
app/components/base/icons/assets/public/files/html.svg | 23
app/components/base/icons/assets/vender/line/general/log-in-04.svg | 8
app/components/base/icons/src/public/knowledge/index.ts | 6
app/components/base/icons/src/vender/features/Citations.json | 26
app/components/base/icons/assets/public/common/diagonal-dividing-line.svg | 3
app/components/base/icons/src/vender/workflow/KnowledgeRetrieval.tsx | 20
app/components/base/icons/src/vender/solid/development/TerminalSquare.json | 38
app/components/base/icons/assets/vender/features/folder-upload.svg | 3
app/components/base/icons/src/public/llm/Microsoft.json | 76
public/vs/base/common/worker/simpleWorker.nls.es.js | 8
app/components/base/icons/src/vender/line/arrows/RefreshCw05.tsx | 20
app/components/plugins/plugin-page/empty/index.tsx | 121
public/vs/basic-languages/mysql/mysql.js | 10
app/components/header/account-setting/model-provider-page/provider-added-card/add-model-button.tsx | 27
public/vs/basic-languages/go/go.js | 10
app/components/base/icons/src/vender/line/general/X.json | 39
app/components/datasets/create/step-one/index.module.css | 66
i18n/zh-Hant/app-debug.ts | 404
app/components/base/icons/assets/public/llm/azure-openai-service-text.svg | 25
public/vs/basic-languages/csharp/csharp.js | 10
app/components/workflow/plugin-dependency/store.ts | 11
app/components/workflow/nodes/loop/components/loop-variables/index.tsx | 28
app/routePrefixHandle.tsx | 53
i18n/de-DE/plugin-tags.ts | 25
app/components/datasets/create/website/base/url-input.tsx | 48
app/components/base/icons/assets/vender/line/development/variable.svg | 9
service/use-common.ts | 28
app/components/workflow-app/components/workflow-header/features-trigger.tsx | 152
app/components/base/icons/assets/public/plugins/wikipedia.svg | 3
app/components/base/icons/src/vender/line/arrows/ChevronDownDouble.json | 39
app/components/base/file-uploader/constants.ts | 8
app/components/base/copy-btn/style.module.css | 15
app/components/datasets/metadata/metadata-document/index.tsx | 120
app/components/base/icons/assets/vender/workflow/templating-transform.svg | 19
app/components/base/image-uploader/hooks.ts | 270
utils/model-config.ts | 164
app/components/base/icons/src/vender/workflow/DocsExtractor.json | 64
app/components/base/icons/src/vender/line/general/ChecklistSquare.tsx | 20
app/components/base/icons/src/public/common/Gdpr.json | 340
app/components/base/icons/src/vender/features/VirtualAssistant.json | 35
i18n/uk-UA/run-log.ts | 31
app/components/base/icons/src/vender/solid/mediaAndDevices/Robot.json | 38
app/components/base/icons/src/public/files/Csv.tsx | 20
app/components/explore/app-list/index.tsx | 246
i18n/fa-IR/plugin-tags.ts | 25
i18n/fa-IR/app.ts | 214
app/init/InitPasswordPopup.tsx | 83
app/components/app/configuration/features/experience-enhance-group/index.tsx | 43
app/components/tools/edit-custom-collection-modal/test-api.tsx | 134
app/components/billing/upgrade-btn/index.tsx | 67
app/components/base/icons/assets/public/common/multi-path-retrieval.svg | 19
app/components/base/icons/assets/vender/line/files/clipboard-check.svg | 3
hooks/use-moderate.ts | 49
app/components/base/icons/src/public/llm/AnthropicLight.tsx | 20
app/components/base/skeleton/index.tsx | 50
app/components/base/icons/assets/vender/line/mediaAndDevices/play-circle.svg | 13
app/components/base/notion-page-selector/assets/down-arrow.svg | 3
i18n/hi-IN/app-overview.ts | 191
i18n/en-US/app-api.ts | 85
app/components/base/icons/assets/vender/solid/communication/message-heart-circle.svg | 5
app/signin/components/mail-and-code-auth.tsx | 72
app/components/base/icons/src/vender/solid/files/Folder.tsx | 20
i18n/ru-RU/app-debug.ts | 463
app/components/base/icons/src/vender/line/communication/CuteRobot.json | 39
app/components/workflow/run/meta.tsx | 117
app/components/base/chat/chat/answer/workflow-process.tsx | 94
i18n/ja-JP/common.ts | 672
i18n/zh-Hans/share-app.ts | 78
app/components/datasets/metadata/metadata-dataset/create-content.tsx | 90
app/components/base/icons/assets/vender/solid/education/heart-02.svg | 3
app/components/plugins/plugin-page/context.tsx | 89
app/components/base/icons/assets/public/files/xlsx.svg | 18
app/components/base/icons/src/vender/line/files/FilePlus01.json | 39
app/components/base/icons/src/vender/line/communication/MessageFastPlus.json | 29
i18n/es-ES/app-annotation.ts | 87
app/(commonLayout)/datasets/DatasetFooter.tsx | 19
app/components/workflow/nodes/llm/components/json-schema-config-modal/json-importer.tsx | 136
app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/generated-result.tsx | 121
app/components/base/tag-management/constant.ts | 6
i18n/en-US/layout.ts | 4
service/tools.ts | 160
app/account/delete-account/components/check-email.tsx | 48
app/components/app/configuration/dataset-config/params-config/index.tsx | 156
app/components/workflow/nodes/llm/components/json-schema-config-modal/code-editor.tsx | 140
app/components/workflow/run/iteration-log/index.tsx | 2
app/components/workflow/header/version-history-button.tsx | 66
public/logo/logo-site.png | 0
app/components/workflow-app/components/workflow-main.tsx | 91
app/components/base/icons/src/public/llm/Anthropic.json | 37
app/components/base/icons/src/public/plugins/PartnerLight.json | 446
public/screenshots/light/Chatflow@3x.png | 0
app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.json | 39
app/components/base/icons/src/vender/solid/files/index.ts | 4
app/components/app/configuration/base/operation-btn/index.tsx | 44
app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/show/index.tsx | 39
models/datasets.ts | 694
app/components/workflow/nodes/http/components/edit-body/index.tsx | 204
public/vs/basic-languages/ini/ini.js | 10
app/components/workflow/run/utils/format-log/agent/index.spec.ts | 15
i18n/it-IT/layout.ts | 4
app/components/base/form/components/field/options.tsx | 34
i18n/uk-UA/common.ts | 673
app/components/base/icons/src/vender/line/communication/ChatBot.tsx | 20
public/vs/base/common/worker/simpleWorker.nls.zh-cn.js | 8
service/use-strategy.ts | 36
app/components/base/icons/src/public/llm/LocalaiText.json | 170
app/components/workflow/operator/index.tsx | 35
app/components/base/icons/assets/vender/solid/users/users-01.svg | 10
app/components/app/configuration/config/agent/agent-setting/index.tsx | 165
app/components/base/icons/src/public/llm/Baichuan.tsx | 20
i18n/es-ES/register.ts | 4
app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-filter/index.tsx | 105
eslint.config.mjs | 249
app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsUp.json | 66
app/components/develop/secret-key/assets/svged.svg | 1
app/(commonLayout)/apps/AppCard.tsx | 426
app/components/base/icons/src/public/common/Notion.json | 83
app/components/base/icons/src/vender/workflow/Code.tsx | 20
app/components/app-sidebar/expert.png | 0
jest.setup.ts | 6
app/components/base/icons/assets/vender/solid/general/edit-03.svg | 8
i18n/ko-KR/common.ts | 668
app/components/workflow/nodes/_base/components/before-run-form/form.tsx | 97
public/vs/basic-languages/handlebars/handlebars.js | 10
app/components/base/icons/src/vender/line/development/CodeBrowser.json | 39
app/components/base/message-log-modal/index.tsx | 71
i18n/de-DE/app-api.ts | 85
app/components/develop/secret-key/assets/svg.svg | 1
app/components/base/icons/src/vender/solid/general/CheckCircle.json | 38
app/components/workflow/nodes/_base/components/variable/var-full-path-panel.tsx | 59
app/components/workflow/nodes/variable-assigner/default.ts | 59
app/components/base/icons/src/vender/line/development/BracketsX.json | 29
app/components/base/icons/src/vender/solid/mediaAndDevices/MagicWand.json | 73
app/components/base/icons/src/public/avatar/User.json | 89
app/components/app/configuration/config-var/config-select/index.tsx | 96
app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/prompt-editor.tsx | 108
app/components/base/icons/src/vender/line/time/ClockFastForward.json | 29
i18n/it-IT/register.ts | 4
i18n/sl-SI/layout.ts | 4
app/components/plugins/marketplace/list/list-wrapper.tsx | 75
app/components/base/prompt-editor/plugins/context-block/index.tsx | 75
app/components/tools/edit-custom-collection-modal/index.tsx | 366
app/components/workflow/header/env-button.tsx | 24
app/components/workflow/nodes/if-else/types.ts | 71
i18n/it-IT/explore.ts | 45
service/annotation.ts | 65
app/components/app/annotation/filter.tsx | 48
i18n/ja-JP/custom.ts | 32
utils/clipboard.ts | 35
app/components/datasets/create/assets/selection-mod.svg | 12
app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/show/field.tsx | 74
i18n/de-DE/login.ts | 110
app/components/base/icons/src/public/knowledge/LayoutRight2LineMod.json | 36
i18n/fr-FR/explore.ts | 44
i18n/pt-BR/dataset-settings.ts | 43
i18n/ja-JP/share-app.ts | 78
app/components/base/pagination/pagination.tsx | 190
app/components/app/overview/customize/index.tsx | 119
app/components/base/icons/src/vender/line/editor/TypeSquare.json | 38
app/components/base/progress-bar/index.tsx | 20
app/components/datasets/create/assets/csv.svg | 22
app/components/workflow/nodes/loop-start/index.tsx | 42
app/(commonLayout)/apps/assets/chat-solid.svg | 4
app/components/base/icons/src/public/thought/WebReader.json | 64
app/components/workflow/nodes/http/components/key-value/key-value-edit/input-item.tsx | 109
app/components/workflow/store/workflow/index.ts | 81
app/components/datasets/documents/detail/style.module.css | 11
app/components/base/icons/src/public/llm/OpenaiBlack.json | 37
app/components/base/text-generation/hooks.ts | 61
app/components/workflow/nodes/loop/components/loop-variables/item.tsx | 78
i18n/it-IT/dataset-documents.ts | 397
app/components/workflow/nodes/if-else/components/condition-list/condition-input.tsx | 56
app/components/base/audio-btn/index.tsx | 110
app/components/base/icons/assets/image/llm/wxyy.png | 0
app/components/datasets/settings/index-method-radio/index.tsx | 106
app/components/base/icons/src/vender/line/time/ClockPlay.json | 66
app/components/base/simple-pie-chart/index.tsx | 67
app/components/workflow/nodes/iteration/use-interactions.ts | 155
i18n/vi-VN/share-app.ts | 78
app/components/workflow-app/components/workflow-panel.tsx | 109
app/components/workflow/store/workflow/node-slice.ts | 76
i18n/en-US/dataset-hit-testing.ts | 34
app/components/plugins/install-plugin/install-from-marketplace/steps/install.tsx | 172
app/components/workflow/nodes/_base/components/next-step/index.tsx | 114
app/components/base/icons/src/vender/line/layout/LayoutGrid02.json | 29
app/components/base/icons/src/vender/solid/development/PromptEngineering.tsx | 20
app/components/base/notion-page-selector/page-selector/index.tsx | 320
i18n/zh-Hans/dataset-documents.ts | 393
app/components/base/icons/src/public/plugins/VerifiedDark.json | 457
hooks/use-knowledge.ts | 32
public/vs/language/css/cssMode.js | 13
app/components/base/app-icon/style.module.css | 23
public/screenshots/dark/Agent@2x.png | 0
i18n/ko-KR/app-log.ts | 99
models/user.ts | 17
app/components/app/overview/assets/scripts-option.svg | 160
i18n/sl-SI/app-debug.ts | 242
app/components/base/icons/assets/vender/plugin/box-sparkle-fill.svg | 9
app/components/develop/template/template_advanced_chat.zh.mdx | 1684
app/components/base/icons/src/vender/solid/mediaAndDevices/MagicBox.tsx | 20
app/components/workflow/nodes/llm/components/json-schema-config-modal/index.tsx | 34
i18n/zh-Hant/dataset-documents.ts | 394
app/components/base/icons/assets/vender/line/general/bookmark.svg | 3
app/components/base/icons/src/vender/solid/users/Users01.json | 79
app/components/base/icons/src/vender/other/Openai.json | 80
app/components/datasets/documents/detail/completed/common/regeneration-modal.tsx | 132
app/components/base/chat/chat-with-history/index.tsx | 253
app/components/base/icons/assets/public/llm/iflytek-spark.svg | 5
i18n/th-TH/workflow.ts | 920
app/components/base/icons/src/vender/features/LoveMessage.json | 26
i18n/tr-TR/plugin.ts | 215
app/components/base/icons/src/vender/line/general/Check.json | 39
public/vs/base/browser/ui/codicons/codicon/codicon.ttf | 0
i18n/sl-SI/register.ts | 4
i18n/fa-IR/app-api.ts | 85
app/components/base/icons/assets/public/llm/Anthropic-light.svg | 186
i18n/uk-UA/plugin.ts | 215
i18n/es-ES/dataset-settings.ts | 43
i18n/th-TH/login.ts | 109
i18n/zh-Hans/billing.ts | 190
app/components/base/icons/src/vender/line/general/Menu01.tsx | 20
app/components/plugins/permission-setting-modal/modal.tsx | 93
app/components/base/icons/src/vender/line/editor/Collapse.json | 62
app/components/base/icons/assets/public/llm/openllm-text.svg | 19
app/components/workflow/run/result-panel.tsx | 160
i18n/pt-BR/app-debug.ts | 423
app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx | 240
app/components/workflow/nodes/_base/components/editor/base.tsx | 123
app/components/datasets/documents/detail/completed/style.module.css | 146
app/styles/globals.css | 700
app/components/plugins/install-plugin/hooks.ts | 107
app/components/base/icons/assets/vender/solid/mapsAndTravel/route.svg | 7
app/components/datasets/documents/detail/completed/common/full-screen-drawer.tsx | 36
app/components/plugins/plugin-page/list/index.tsx | 23
app/components/base/prompt-editor/plugins/variable-block/index.tsx | 45
i18n/ro-RO/explore.ts | 44
i18n/uk-UA/app-api.ts | 85
app/components/workflow/nodes/loop/components/condition-wrap.tsx | 146
app/components/base/icons/assets/vender/line/others/apps-02.svg | 5
app/(commonLayout)/list.module.css | 217
app/components/plugins/base/badges/icon-with-tooltip.tsx | 37
app/components/base/icons/src/vender/line/others/Env.json | 90
app/(commonLayout)/datasets/template/template.ja.mdx | 2005
app/components/base/icons/src/vender/workflow/KnowledgeRetrieval.json | 38
i18n/pt-BR/app-annotation.ts | 87
.husky/pre-commit | 78
app/components/workflow/panel/chat-record/index.tsx | 138
app/components/plugins/plugin-detail-panel/endpoint-list.tsx | 122
i18n/pl-PL/tools.ts | 162
app/components/base/icons/assets/vender/solid/communication/edit-list.svg | 6
app/components/base/icons/src/vender/workflow/QuestionClassifier.json | 38
app/components/base/icons/src/vender/solid/communication/BubbleTextMod.json | 28
app/components/datasets/external-api/external-api-panel/index.tsx | 90
app/components/app/configuration/config-prompt/conversation-history/edit-modal.tsx | 58
app/components/billing/annotation-full/modal.tsx | 47
app/components/app/configuration/config-var/config-string/index.tsx | 45
app/components/base/tab-header/index.tsx | 50
i18n/pl-PL/time.ts | 37
app/components/workflow/nodes/_base/components/code-generator-button.tsx | 48
app/components/base/icons/src/vender/workflow/ParameterExtractor.tsx | 20
app/components/plugins/install-plugin/install-from-github/index.tsx | 235
app/components/datasets/create/website/base/options-wrap.tsx | 55
app/components/base/icons/src/public/avatar/User.tsx | 20
app/components/workflow/nodes/_base/hooks/use-node-help-link.ts | 69
app/components/datasets/create/assets/json.svg | 23
app/components/datasets/external-knowledge-base/connector/index.tsx | 36
app/components/base/radio-card/simple/style.module.css | 25
app/components/plugins/install-plugin/base/loading-error.tsx | 45
i18n/sl-SI/dataset-settings.ts | 43
i18n/pl-PL/layout.ts | 4
i18n/languages.json | 151
app/components/base/icons/assets/vender/line/general/dots-grid.svg | 15
app/components/datasets/metadata/types.ts | 41
app/components/share/text-generation/index.tsx | 676
app/components/base/icons/assets/vender/line/development/file-heart-02.svg | 6
app/components/base/icons/src/vender/line/arrows/ChevronRight.tsx | 20
app/components/header/account-setting/model-provider-page/declarations.ts | 271
app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx | 367
app/components/workflow/run/iteration-log/iteration-result-panel.tsx | 128
app/components/workflow/nodes/loop/default.ts | 94
app/components/datasets/common/document-picker/preview-document-picker.tsx | 82
app/components/datasets/create/notion-page-preview/index.module.css | 33
app/components/base/icons/src/vender/line/editor/BezierCurve03.tsx | 20
i18n/vi-VN/app-annotation.ts | 87
app/components/base/icons/src/public/thought/Search.tsx | 20
app/components/workflow/nodes/if-else/components/condition-wrap.tsx | 226
app/components/base/icons/src/vender/features/Vision.tsx | 20
app/components/datasets/create/file-preview/index.module.css | 39
tsconfig.json | 42
app/components/datasets/documents/detail/completed/new-child-segment.tsx | 174
app/components/workflow/nodes/code/code-parser.spec.ts | 326
app/components/base/icons/src/vender/solid/communication/ListSparkle.tsx | 20
app/components/billing/header-billing-btn/index.tsx | 60
public/vs/loader.js | 11
app/components/base/divider/index.tsx | 36
app/components/base/icons/assets/vender/solid/mediaAndDevices/stop-circle.svg | 5
app/components/workflow/operator/zoom-in-out.tsx | 229
i18n/fa-IR/app-log.ts | 98
app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown.tsx | 48
app/components/base/icons/assets/vender/line/editor/align-left.svg | 5
app/components/base/icons/assets/vender/line/images/image-plus.svg | 5
app/components/base/icons/src/vender/solid/general/CheckDone01.json | 37
public/vs/editor/editor.main.nls.js | 13
app/components/app/log-annotation/index.tsx | 63
app/components/base/icons/src/public/billing/Group2.json | 29
app/components/base/icons/src/vender/workflow/Code.json | 38
app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout.tsx | 17
i18n/uk-UA/dataset-hit-testing.ts | 35
i18n/zh-Hans/register.ts | 4
i18n/zh-Hant/app-api.ts | 85
app/components/app/configuration/dataset-config/card-item/index.tsx | 58
public/vs/basic-languages/coffee/coffee.js | 10
app/components/base/agent-log-modal/result.tsx | 126
app/components/base/app-unavailable.tsx | 29
app/components/base/icons/assets/vender/features/text-to-audio.svg | 8
app/components/workflow/nodes/llm/default.ts | 91
app/components/base/icons/src/vender/solid/mapsAndTravel/index.ts | 2
context/external-knowledge-api-context.tsx | 46
app/components/plugins/install-plugin/install-bundle/item/loaded-item.tsx | 51
app/components/plugins/install-plugin/install-from-local-package/ready-to-install.tsx | 76
app/components/base/modal/index.css | 7
app/components/datasets/documents/detail/index.tsx | 300
app/components/base/icons/assets/vender/line/development/code-browser.svg | 5
app/components/base/icons/assets/vender/line/development/prompt-engineering.svg | 7
utils/zod.spec.ts | 173
app/components/workflow/nodes/question-classifier/default.ts | 76
app/components/workflow/hooks/use-workflow-run-event/use-workflow-node-loop-next.ts | 35
app/components/base/icons/src/vender/solid/general/Tool03.json | 62
i18n/de-DE/app-log.ts | 98
i18n/ko-KR/dataset-settings.ts | 43
i18n/fr-FR/tools.ts | 158
app/components/base/icons/src/vender/solid/general/Target04.json | 46
app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx | 163
app/components/base/icons/src/public/llm/ReplicateText.json | 116
app/components/tools/add-tool-modal/D.png | 0
i18n/ko-KR/app-api.ts | 87
app/components/plugins/plugin-detail-panel/tool-selector/tool-trigger.tsx | 63
app/components/base/chat/__tests__/__snapshots__/utils.spec.ts.snap | 2804
app/components/base/icons/assets/vender/workflow/iteration.svg | 5
app/components/base/icons/src/public/billing/Azure.json | 193
app/components/datasets/metadata/add-metadata-button.tsx | 31
app/components/workflow/nodes/_base/components/variable/utils.ts | 1496
app/components/base/icons/src/public/other/DefaultToolIcon.tsx | 20
i18n/pt-BR/tools.ts | 158
themes/markdown-dark.css | 44
i18n/ru-RU/dataset.ts | 221
app/components/base/icons/assets/vender/line/communication/chat-bot-slim.svg | 9
app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx | 128
app/components/tools/edit-custom-collection-modal/get-schema.tsx | 123
app/page.module.css | 266
public/vs/basic-languages/css/css.js | 12
app/components/app/workflow-log/index.tsx | 120
app/components/datasets/metadata/metadata-document/field.tsx | 26
i18n/tr-TR/custom.ts | 32
hooks/use-tab-searchparams.ts | 44
app/components/base/modal/index.tsx | 86
app/components/base/notion-page-selector/assets/setting.svg | 11
app/components/base/icons/src/vender/workflow/VariableX.json | 38
app/components/datasets/metadata/edit-metadata-batch/edit-row.tsx | 56
app/components/app/configuration/prompt-value-panel/index.tsx | 214
app/components/workflow/plugin-dependency/index.tsx | 24
service/knowledge/use-import.ts | 0
app/components/app/configuration/ctrl-btn-group/style.module.css | 6
app/components/base/icons/src/public/billing/Diamond.json | 39
i18n/tr-TR/common.ts | 672
app/components/base/icons/assets/vender/line/general/check.svg | 5
app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger.tsx | 112
app/components/workflow-app/hooks/use-workflow-init.ts | 123
app/components/workflow/note-node/types.ts | 17
app/components/header/nav/index.tsx | 95
app/components/base/chat/__tests__/utils.spec.ts | 271
app/components/workflow/block-selector/use-sticky-scroll.ts | 45
app/components/base/icons/src/vender/solid/general/Eye.json | 37
app/components/app/log/list.tsx | 764
i18n/th-TH/app-annotation.ts | 87
bin/uglify-embed.js | 9
app/components/base/image-uploader/video-preview.tsx | 37
i18n/uk-UA/custom.ts | 32
app/components/workflow/nodes/parameter-extractor/panel.tsx | 273
i18n/sl-SI/dataset-documents.ts | 395
app/components/workflow/nodes/_base/components/memory-config.tsx | 207
app/components/workflow/run/assets/highlight-dark.svg | 9
app/components/base/icons/src/vender/solid/education/Heart02.json | 26
app/components/base/icons/src/vender/solid/shapes/Corner.tsx | 20
i18n/th-TH/common.ts | 667
app/components/base/icons/src/vender/line/arrows/RefreshCcw01.tsx | 20
app/components/base/icons/src/vender/solid/mapsAndTravel/Route.json | 58
app/components/workflow/hooks/use-workflow-start-run.tsx | 13
app/components/base/chat/chat/answer/suggested-questions.tsx | 37
app/components/base/icons/src/vender/line/users/Users01.json | 39
app/components/workflow/panel/version-history-panel/loading/item.tsx | 40
app/components/base/icons/src/vender/line/development/BarChartSquare02.json | 39
app/components/base/icons/assets/vender/solid/general/github.svg | 5
app/layout.tsx | 85
app/components/base/icons/assets/vender/solid/communication/message-smile-square.svg | 5
.dockerignore | 24
app/components/base/icons/src/vender/solid/arrows/HighPriority.tsx | 20
app/components/billing/pricing/plan-item.tsx | 235
app/components/tools/provider/custom-create-card.tsx | 76
app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsUp.tsx | 20
app/components/base/icons/assets/vender/line/development/puzzle-piece-01.svg | 10
app/components/base/icons/assets/public/common/notion.svg | 12
i18n/vi-VN/tools.ts | 158
app/components/base/checkbox/index.spec.tsx | 67
app/components/base/icons/assets/vender/line/others/env.svg | 11
app/components/base/icons/src/public/llm/Gpt4.json | 51
i18n/zh-Hant/app-log.ts | 98
app/components/workflow/nodes/http/components/key-value/key-value-edit/item.tsx | 135
app/components/base/button/add-button.tsx | 22
app/components/base/icons/src/public/llm/OpenaiBlue.tsx | 20
app/components/base/icons/src/vender/line/others/Apps02.tsx | 20
app/components/billing/usage-info/index.tsx | 71
app/components/workflow/node-contextmenu.tsx | 51
app/components/base/icons/src/vender/line/others/Icon3Dots.tsx | 20
app/components/datasets/documents/assets/hitLoading.svg | 15
app/components/app/annotation/add-annotation-modal/edit-item/index.tsx | 45
app/components/datasets/hit-testing/assets/clock.svg | 3
tailwind-common-config.ts | 138
i18n/vi-VN/dataset-settings.ts | 43
assets/xlsx.svg | 18
app/components/base/agent-log-modal/tool-call.tsx | 142
app/components/base/icons/assets/vender/line/communication/ai-text.svg | 5
app/components/base/button/index.stories.tsx | 107
app/components/workflow/nodes/_base/components/error-handle/error-handle-on-node.tsx | 67
i18n/pl-PL/app-debug.ts | 466
app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts | 12
app/components/base/icons/assets/vender/line/development/database-03.svg | 3
app/components/base/icons/src/public/tracing/OpikIcon.tsx | 20
app/components/workflow/panel/chat-variable-panel/type.ts | 8
app/components/app/app-publisher/index.tsx | 304
app/components/workflow/nodes/llm/components/json-schema-config-modal/error-message.tsx | 27
app/components/base/icons/assets/vender/line/general/at-sign.svg | 10
app/components/workflow/nodes/agent/types.ts | 16
app/forgot-password/ChangePasswordForm.tsx | 176
app/components/base/icons/assets/vender/line/communication/cute-robot.svg | 5
app/components/base/icons/src/public/avatar/index.ts | 2
app/components/base/chat/embedded-chatbot/context.tsx | 81
app/components/base/icons/assets/public/llm/gpt-3.svg | 5
app/components/workflow/run/retry-log/index.tsx | 2
app/components/base/icons/src/vender/plugin/index.ts | 2
i18n/uk-UA/app-log.ts | 98
app/components/base/icons/src/public/llm/ZhipuaiTextCn.json | 62
app/components/app/workflow-log/list.tsx | 145
app/components/workflow/nodes/loop/components/condition-add.tsx | 74
app/components/base/chat/chat/answer/agent-content.tsx | 61
app/components/tools/provider-list.tsx | 165
3,891 files changed, 416,477 insertions(+), 1 deletions(-)
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..31eb66c
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,24 @@
+.env
+.env.*
+
+# Logs
+logs
+*.log*
+
+# node
+node_modules
+.husky
+.next
+
+# vscode
+.vscode
+
+# webstorm
+.idea
+*.iml
+*.iws
+*.ipr
+
+
+# Jetbrains
+.idea
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..e501df9
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,60 @@
+# For production release, change this to PRODUCTION
+NEXT_PUBLIC_DEPLOY_ENV=DEVELOPMENT
+# The deployment edition, SELF_HOSTED
+NEXT_PUBLIC_EDITION=SELF_HOSTED
+# The base URL of console application, refers to the Console base URL of WEB service if console domain is
+# different from api or web app domain.
+# example: http://cloud.dify.ai/console/api
+NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api
+NEXT_PUBLIC_WEB_PREFIX=http://localhost:3000
+# The URL for Web APP, refers to the Web App base URL of WEB service if web app domain is different from
+# console or api domain.
+# example: http://udify.app/api
+NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
+NEXT_PUBLIC_PUBLIC_WEB_PREFIX=http://localhost:3000
+# The API PREFIX for MARKETPLACE
+NEXT_PUBLIC_MARKETPLACE_API_PREFIX=https://marketplace.dify.ai/api/v1
+# The URL for MARKETPLACE
+NEXT_PUBLIC_MARKETPLACE_URL_PREFIX=https://marketplace.dify.ai
+
+# SENTRY
+NEXT_PUBLIC_SENTRY_DSN=
+
+# Disable Next.js Telemetry (https://nextjs.org/telemetry)
+NEXT_TELEMETRY_DISABLED=1
+
+# Disable Upload Image as WebApp icon default is false
+NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON=false
+
+# The timeout for the text generation in millisecond
+NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS=60000
+
+# CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
+NEXT_PUBLIC_CSP_WHITELIST=
+# Default is not allow to embed into iframe to prevent Clickjacking: https://owasp.org/www-community/attacks/Clickjacking
+NEXT_PUBLIC_ALLOW_EMBED=
+
+# Github Access Token, used for invoking Github API
+NEXT_PUBLIC_GITHUB_ACCESS_TOKEN=
+# The maximum number of top-k value for RAG.
+NEXT_PUBLIC_TOP_K_MAX_VALUE=10
+
+# The maximum number of tokens for segmentation
+NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=4000
+
+# Maximum loop count in the workflow
+NEXT_PUBLIC_LOOP_NODE_MAX_COUNT=100
+
+# Maximum number of tools in the agent/workflow
+NEXT_PUBLIC_MAX_TOOLS_NUM=10
+
+# Maximum number of Parallelism branches in the workflow
+NEXT_PUBLIC_MAX_PARALLEL_LIMIT=10
+
+# The maximum number of iterations for agent setting
+NEXT_PUBLIC_MAX_ITERATIONS_NUM=5
+
+NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER=true
+NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL=true
+NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL=true
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..048c5f6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,56 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+/.history
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# local env files
+.env*.local
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
+
+# npm
+package-lock.json
+
+# yarn
+.pnp.cjs
+.pnp.loader.mjs
+.yarn/
+
+.favorites.json
+
+# storybook
+/storybook-static
+*storybook.log
+
+# mise
+mise.toml
+
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100644
index 0000000..2ad3922
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1,78 @@
+#!/bin/sh
+# get the list of modified files
+files=$(git diff --cached --name-only)
+
+# check if api or web directory is modified
+
+api_modified=false
+web_modified=false
+
+for file in $files
+do
+ # Use POSIX compliant pattern matching
+ case "$file" in
+ api/*.py)
+ # set api_modified flag to true
+ api_modified=true
+ ;;
+ web/*)
+ # set web_modified flag to true
+ web_modified=true
+ ;;
+ esac
+done
+
+# run linters based on the modified modules
+
+if $api_modified; then
+ echo "Running Ruff linter on api module"
+
+ # run Ruff linter auto-fixing
+ uv run --project api --dev ruff check --fix ./api
+
+ # run Ruff linter checks
+ uv run --project api --dev ruff check ./api || status=$?
+
+ status=${status:-0}
+
+
+ if [ $status -ne 0 ]; then
+ echo "Ruff linter on api module error, exit code: $status"
+ echo "Please run 'dev/reformat' to fix the fixable linting errors."
+ exit 1
+ fi
+fi
+
+if $web_modified; then
+ echo "Running ESLint on web module"
+ cd ./web || exit 1
+ lint-staged
+
+ echo "Running unit tests check"
+ modified_files=$(git diff --cached --name-only -- utils | grep -v '\.spec\.ts$' || true)
+
+ if [ -n "$modified_files" ]; then
+ for file in $modified_files; do
+ test_file="${file%.*}.spec.ts"
+ echo "Checking for test file: $test_file"
+
+ # check if the test file exists
+ if [ -f "../$test_file" ]; then
+ echo "Detected changes in $file, running corresponding unit tests..."
+ pnpm run test "../$test_file"
+
+ if [ $? -ne 0 ]; then
+ echo "Unit tests failed. Please fix the errors before committing."
+ exit 1
+ fi
+ echo "Unit tests for $file passed."
+ else
+ echo "Warning: $file does not have a corresponding test file."
+ fi
+
+ done
+ echo "All unit tests for modified web/utils files have passed."
+ fi
+
+ cd ../
+fi
diff --git a/.storybook/main.ts b/.storybook/main.ts
new file mode 100644
index 0000000..fecf774
--- /dev/null
+++ b/.storybook/main.ts
@@ -0,0 +1,19 @@
+import type { StorybookConfig } from '@storybook/nextjs'
+
+const config: StorybookConfig = {
+ // stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
+ stories: ['../app/components/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
+ addons: [
+ '@storybook/addon-onboarding',
+ '@storybook/addon-links',
+ '@storybook/addon-essentials',
+ '@chromatic-com/storybook',
+ '@storybook/addon-interactions',
+ ],
+ framework: {
+ name: '@storybook/nextjs',
+ options: {},
+ },
+ staticDirs: ['../public'],
+}
+export default config
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
new file mode 100644
index 0000000..5532860
--- /dev/null
+++ b/.storybook/preview.tsx
@@ -0,0 +1,37 @@
+import React from 'react'
+import type { Preview } from '@storybook/react'
+import { withThemeByDataAttribute } from '@storybook/addon-themes'
+import I18nServer from '../app/components/i18n-server'
+
+import '../app/styles/globals.css'
+import '../app/styles/markdown.scss'
+import './storybook.css'
+
+export const decorators = [
+ withThemeByDataAttribute({
+ themes: {
+ light: 'light',
+ dark: 'dark',
+ },
+ defaultTheme: 'light',
+ attributeName: 'data-theme',
+ }),
+ (Story) => {
+ return <I18nServer>
+ <Story />
+ </I18nServer>
+ },
+]
+
+const preview: Preview = {
+ parameters: {
+ controls: {
+ matchers: {
+ color: /(background|color)$/i,
+ date: /Date$/i,
+ },
+ },
+ },
+}
+
+export default preview
diff --git a/.storybook/storybook.css b/.storybook/storybook.css
new file mode 100644
index 0000000..85df108
--- /dev/null
+++ b/.storybook/storybook.css
@@ -0,0 +1,6 @@
+html,
+body {
+ max-width: unset;
+ overflow: auto;
+ user-select: text;
+}
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..e0e72ce
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,7 @@
+{
+ "recommendations": [
+ "bradlc.vscode-tailwindcss",
+ "firsttris.vscode-jest-runner",
+ "kisstkondoros.vscode-codemetrics"
+ ]
+}
diff --git a/.vscode/settings.example.json b/.vscode/settings.example.json
new file mode 100644
index 0000000..ce5c9d6
--- /dev/null
+++ b/.vscode/settings.example.json
@@ -0,0 +1,26 @@
+{
+ "prettier.enable": false,
+ "editor.formatOnSave": true,
+ "editor.codeActionsOnSave": {
+ "source.fixAll.eslint": "explicit"
+ },
+ "eslint.format.enable": true,
+ "[python]": {
+ "editor.formatOnType": true
+ },
+ "[html]": {
+ "editor.defaultFormatter": "vscode.html-language-features"
+ },
+ "[typescriptreact]": {
+ "editor.defaultFormatter": "vscode.typescript-language-features"
+ },
+ "[javascriptreact]": {
+ "editor.defaultFormatter": "vscode.typescript-language-features"
+ },
+ "[jsonc]": {
+ "editor.defaultFormatter": "vscode.json-language-features"
+ },
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "typescript.enablePromptUseWorkspaceTsdk": true,
+ "npm.packageManager": "pnpm"
+}
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..dfc5ba8
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,76 @@
+# base image
+FROM node:22-alpine3.21 AS base
+LABEL maintainer="takatost@gmail.com"
+
+# if you located in China, you can use aliyun mirror to speed up
+# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
+
+RUN apk add --no-cache tzdata
+RUN npm install -g pnpm@10.8.0
+ENV PNPM_HOME="/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
+
+
+# install packages
+FROM base AS packages
+
+WORKDIR /app/web
+
+COPY package.json .
+COPY pnpm-lock.yaml .
+
+# if you located in China, you can use taobao registry to speed up
+# RUN pnpm install --frozen-lockfile --registry https://registry.npmmirror.com/
+
+RUN pnpm install --frozen-lockfile
+
+# build resources
+FROM base AS builder
+WORKDIR /app/web
+COPY --from=packages /app/web/ .
+COPY . .
+
+ENV NODE_OPTIONS="--max-old-space-size=4096"
+RUN pnpm build
+
+
+# production stage
+FROM base AS production
+
+ENV NODE_ENV=production
+ENV EDITION=SELF_HOSTED
+ENV DEPLOY_ENV=PRODUCTION
+ENV CONSOLE_API_URL=http://127.0.0.1:5001
+ENV APP_API_URL=http://127.0.0.1:5001
+ENV MARKETPLACE_API_URL=https://marketplace.dify.ai
+ENV MARKETPLACE_URL=https://marketplace.dify.ai
+ENV PORT=3000
+ENV NEXT_TELEMETRY_DISABLED=1
+ENV PM2_INSTANCES=2
+
+# set timezone
+ENV TZ=UTC
+RUN ln -s /usr/share/zoneinfo/${TZ} /etc/localtime \
+ && echo ${TZ} > /etc/timezone
+
+
+WORKDIR /app/web
+COPY --from=builder /app/web/public ./public
+COPY --from=builder /app/web/.next/standalone ./
+COPY --from=builder /app/web/.next/static ./.next/static
+
+COPY docker/entrypoint.sh ./entrypoint.sh
+
+
+# global runtime packages
+RUN pnpm add -g pm2 \
+ && mkdir /.pm2 \
+ && chown -R 1001:0 /.pm2 /app/web \
+ && chmod -R g=u /.pm2 /app/web
+
+ARG COMMIT_SHA
+ENV COMMIT_SHA=${COMMIT_SHA}
+
+USER 1001
+EXPOSE 3000
+ENTRYPOINT ["/bin/sh", "./entrypoint.sh"]
diff --git a/README.md b/README.md
index ed958fd..ddb1155 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,120 @@
-## app-qxueyou-dify
+# Dify Frontend
+
+This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
+
+## Getting Started
+
+### Run by source code
+
+Before starting the web frontend service, please make sure the following environment is ready.
+- [Node.js](https://nodejs.org) >= v22.11.x
+- [pnpm](https://pnpm.io) v10.x
+
+First, install the dependencies:
+
+```bash
+pnpm install
+```
+
+Then, configure the environment variables. Create a file named `.env.local` in the current directory and copy the contents from `.env.example`. Modify the values of these environment variables according to your requirements:
+
+```bash
+cp .env.example .env.local
+```
+
+```
+# For production release, change this to PRODUCTION
+NEXT_PUBLIC_DEPLOY_ENV=DEVELOPMENT
+# The deployment edition, SELF_HOSTED
+NEXT_PUBLIC_EDITION=SELF_HOSTED
+# The base URL of console application, refers to the Console base URL of WEB service if console domain is
+# different from api or web app domain.
+# example: http://cloud.dify.ai/console/api
+NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api
+NEXT_PUBLIC_WEB_PREFIX=http://localhost:3000
+# The URL for Web APP, refers to the Web App base URL of WEB service if web app domain is different from
+# console or api domain.
+# example: http://udify.app/api
+NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
+NEXT_PUBLIC_PUBLIC_WEB_PREFIX=http://localhost:3000
+
+# SENTRY
+NEXT_PUBLIC_SENTRY_DSN=
+```
+
+Finally, run the development server:
+
+```bash
+pnpm run dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the file under folder `app`. The page auto-updates as you edit the file.
+
+## Deploy
+
+### Deploy on server
+
+First, build the app for production:
+
+```bash
+pnpm run build
+```
+
+Then, start the server:
+
+```bash
+pnpm run start
+```
+
+If you want to customize the host and port:
+
+```bash
+pnpm run start --port=3001 --host=0.0.0.0
+```
+
+If you want to customize the number of instances launched by PM2, you can configure `PM2_INSTANCES` in `docker-compose.yaml` or `Dockerfile`.
+
+## Storybook
+
+This project uses [Storybook](https://storybook.js.org/) for UI component development.
+
+To start the storybook server, run:
+
+```bash
+pnpm storybook
+```
+
+Open [http://localhost:6006](http://localhost:6006) with your browser to see the result.
+
+## Lint Code
+
+If your IDE is VSCode, rename `web/.vscode/settings.example.json` to `web/.vscode/settings.json` for lint code setting.
+
+## Test
+
+We start to use [Jest](https://jestjs.io/) and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) for Unit Testing.
+
+You can create a test file with a suffix of `.spec` beside the file that to be tested. For example, if you want to test a file named `util.ts`. The test file name should be `util.spec.ts`.
+
+Run test:
+
+```bash
+pnpm run test
+```
+
+If you are not familiar with writing tests, here is some code to refer to:
+* [classnames.spec.ts](./utils/classnames.spec.ts)
+* [index.spec.tsx](./app/components/base/button/index.spec.tsx)
+
+## Documentation
+
+Visit <https://docs.dify.ai/getting-started/readme> to view the full documentation.
+
+## Community
+
+The Dify community can be found on [Discord community](https://discord.gg/5AEfbxcd9k), where you can ask questions, voice ideas, and share your projects.
diff --git a/__mocks__/mime.js b/__mocks__/mime.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/__mocks__/mime.js
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/annotations/page.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/annotations/page.tsx"
new file mode 100644
index 0000000..5fb3ff4
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/annotations/page.tsx"
@@ -0,0 +1,15 @@
+import React from 'react'
+import Main from '@/app/components/app/log-annotation'
+import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
+
+export type IProps = {
+ params: Promise<{ appId: string }>
+}
+
+const Logs = async () => {
+ return (
+ <Main pageType={PageType.annotation} />
+ )
+}
+
+export default Logs
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/configuration/page.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/configuration/page.tsx"
new file mode 100644
index 0000000..41143b9
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/configuration/page.tsx"
@@ -0,0 +1,10 @@
+import React from 'react'
+import Configuration from '@/app/components/app/configuration'
+
+const IConfiguration = async () => {
+ return (
+ <Configuration />
+ )
+}
+
+export default IConfiguration
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/develop/page.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/develop/page.tsx"
new file mode 100644
index 0000000..415d822
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/develop/page.tsx"
@@ -0,0 +1,19 @@
+import React from 'react'
+import type { Locale } from '@/i18n'
+import DevelopMain from '@/app/components/develop'
+
+export type IDevelopProps = {
+ params: Promise<{ locale: Locale; appId: string }>
+}
+
+const Develop = async (props: IDevelopProps) => {
+ const params = await props.params
+
+ const {
+ appId,
+ } = params
+
+ return <DevelopMain appId={appId} />
+}
+
+export default Develop
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/layout-main.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/layout-main.tsx"
new file mode 100644
index 0000000..1434a81
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/layout-main.tsx"
@@ -0,0 +1,177 @@
+'use client'
+import type { FC } from 'react'
+import { useUnmount } from 'ahooks'
+import React, { useCallback, useEffect, useState } from 'react'
+import { usePathname, useRouter } from 'next/navigation'
+import {
+ RiDashboard2Fill,
+ RiDashboard2Line,
+ RiFileList3Fill,
+ RiFileList3Line,
+ RiTerminalBoxFill,
+ RiTerminalBoxLine,
+ RiTerminalWindowFill,
+ RiTerminalWindowLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { useShallow } from 'zustand/react/shallow'
+import { useContextSelector } from 'use-context-selector'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import { useStore } from '@/app/components/app/store'
+import AppSideBar from '@/app/components/app-sidebar'
+import type { NavIcon } from '@/app/components/app-sidebar/navLink'
+import { fetchAppDetail, fetchAppSSO } from '@/service/apps'
+import AppContext, { useAppContext } from '@/context/app-context'
+import Loading from '@/app/components/base/loading'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import type { App } from '@/types/app'
+
+export type IAppDetailLayoutProps = {
+ children: React.ReactNode
+ appId: string
+}
+
+const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
+ const {
+ children,
+ appId, // get appId in path
+ } = props
+ const { t } = useTranslation()
+ const router = useRouter()
+ const pathname = usePathname()
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+ const { isCurrentWorkspaceEditor, isLoadingCurrentWorkspace } = useAppContext()
+ const { appDetail, setAppDetail, setAppSiderbarExpand } = useStore(useShallow(state => ({
+ appDetail: state.appDetail,
+ setAppDetail: state.setAppDetail,
+ setAppSiderbarExpand: state.setAppSiderbarExpand,
+ })))
+ const [isLoadingAppDetail, setIsLoadingAppDetail] = useState(false)
+ const [appDetailRes, setAppDetailRes] = useState<App | null>(null)
+ const [navigation, setNavigation] = useState<Array<{
+ name: string
+ href: string
+ icon: NavIcon
+ selectedIcon: NavIcon
+ }>>([])
+ const systemFeatures = useContextSelector(AppContext, state => state.systemFeatures)
+
+ const getNavigations = useCallback((appId: string, isCurrentWorkspaceEditor: boolean, mode: string) => {
+ const navs = [
+ ...(isCurrentWorkspaceEditor
+ ? [{
+ name: t('common.appMenus.promptEng'),
+ href: `/app/${appId}/${(mode === 'workflow' || mode === 'advanced-chat') ? 'workflow' : 'configuration'}`,
+ icon: RiTerminalWindowLine,
+ selectedIcon: RiTerminalWindowFill,
+ }]
+ : []
+ ),
+ {
+ name: t('common.appMenus.apiAccess'),
+ href: `/app/${appId}/develop`,
+ icon: RiTerminalBoxLine,
+ selectedIcon: RiTerminalBoxFill,
+ },
+ ...(isCurrentWorkspaceEditor
+ ? [{
+ name: mode !== 'workflow'
+ ? t('common.appMenus.logAndAnn')
+ : t('common.appMenus.logs'),
+ href: `/app/${appId}/logs`,
+ icon: RiFileList3Line,
+ selectedIcon: RiFileList3Fill,
+ }]
+ : []
+ ),
+ {
+ name: t('common.appMenus.overview'),
+ href: `/app/${appId}/overview`,
+ icon: RiDashboard2Line,
+ selectedIcon: RiDashboard2Fill,
+ },
+ ]
+ return navs
+ }, [])
+
+ useEffect(() => {
+ if (appDetail) {
+ document.title = `${(appDetail.name || 'App')} - Dify`
+ const localeMode = localStorage.getItem('app-detail-collapse-or-expand') || 'expand'
+ const mode = isMobile ? 'collapse' : 'expand'
+ setAppSiderbarExpand(isMobile ? mode : localeMode)
+ // TODO: consider screen size and mode
+ // if ((appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow') && (pathname).endsWith('workflow'))
+ // setAppSiderbarExpand('collapse')
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [appDetail, isMobile])
+
+ useEffect(() => {
+ setAppDetail()
+ setIsLoadingAppDetail(true)
+ fetchAppDetail({ url: '/apps', id: appId }).then((res) => {
+ setAppDetailRes(res)
+ }).catch((e: any) => {
+ if (e.status === 404)
+ router.replace('/apps')
+ }).finally(() => {
+ setIsLoadingAppDetail(false)
+ })
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [appId, pathname])
+
+ useEffect(() => {
+ if (!appDetailRes || isLoadingCurrentWorkspace || isLoadingAppDetail)
+ return
+ const res = appDetailRes
+ // redirection
+ const canIEditApp = isCurrentWorkspaceEditor
+ if (!canIEditApp && (pathname.endsWith('configuration') || pathname.endsWith('workflow') || pathname.endsWith('logs'))) {
+ router.replace(`/app/${appId}/overview`)
+ return
+ }
+ if ((res.mode === 'workflow' || res.mode === 'advanced-chat') && (pathname).endsWith('configuration')) {
+ router.replace(`/app/${appId}/workflow`)
+ }
+ else if ((res.mode !== 'workflow' && res.mode !== 'advanced-chat') && (pathname).endsWith('workflow')) {
+ router.replace(`/app/${appId}/configuration`)
+ }
+ else {
+ setAppDetail({ ...res, enable_sso: false })
+ setNavigation(getNavigations(appId, isCurrentWorkspaceEditor, res.mode))
+ if (systemFeatures.enable_web_sso_switch_component && canIEditApp) {
+ fetchAppSSO({ appId }).then((ssoRes) => {
+ setAppDetail({ ...res, enable_sso: ssoRes.enabled })
+ })
+ }
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [appDetailRes, isCurrentWorkspaceEditor, isLoadingAppDetail, isLoadingCurrentWorkspace, systemFeatures.enable_web_sso_switch_component])
+
+ useUnmount(() => {
+ setAppDetail()
+ })
+
+ if (!appDetail) {
+ return (
+ <div className='flex h-full items-center justify-center bg-background-body'>
+ <Loading />
+ </div>
+ )
+ }
+
+ return (
+ <div className={cn(s.app, 'relative flex', 'overflow-hidden')}>
+ {appDetail && (
+ <AppSideBar title={appDetail.name} icon={appDetail.icon} icon_background={appDetail.icon_background as string} desc={appDetail.mode} navigation={navigation} />
+ )}
+ <div className="grow overflow-hidden bg-components-panel-bg">
+ {children}
+ </div>
+ </div>
+ )
+}
+export default React.memo(AppDetailLayout)
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/layout.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/layout.tsx"
new file mode 100644
index 0000000..491a046
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/layout.tsx"
@@ -0,0 +1,14 @@
+import Main from './layout-main'
+
+const AppDetailLayout = async (props: {
+ children: React.ReactNode
+ params: Promise<{ appId: string }>
+}) => {
+ const {
+ children,
+ params,
+ } = props
+
+ return <Main appId={(await params).appId}>{children}</Main>
+}
+export default AppDetailLayout
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/logs/page.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/logs/page.tsx"
new file mode 100644
index 0000000..244a357
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/logs/page.tsx"
@@ -0,0 +1,11 @@
+import React from 'react'
+import Main from '@/app/components/app/log-annotation'
+import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
+
+const Logs = async () => {
+ return (
+ <Main pageType={PageType.log} />
+ )
+}
+
+export default Logs
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/cardView.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/cardView.tsx"
new file mode 100644
index 0000000..79b4594
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/cardView.tsx"
@@ -0,0 +1,144 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext, useContextSelector } from 'use-context-selector'
+import AppCard from '@/app/components/app/overview/appCard'
+import Loading from '@/app/components/base/loading'
+import { ToastContext } from '@/app/components/base/toast'
+import {
+ fetchAppDetail,
+ fetchAppSSO,
+ updateAppSSO,
+ updateAppSiteAccessToken,
+ updateAppSiteConfig,
+ updateAppSiteStatus,
+} from '@/service/apps'
+import type { App, AppSSO } from '@/types/app'
+import type { UpdateAppSiteCodeResponse } from '@/models/app'
+import { asyncRunSafe } from '@/utils'
+import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
+import type { IAppCardProps } from '@/app/components/app/overview/appCard'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import AppContext from '@/context/app-context'
+
+export type ICardViewProps = {
+ appId: string
+ isInPanel?: boolean
+ className?: string
+}
+
+const CardView: FC<ICardViewProps> = ({ appId, isInPanel, className }) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const appDetail = useAppStore(state => state.appDetail)
+ const setAppDetail = useAppStore(state => state.setAppDetail)
+ const systemFeatures = useContextSelector(AppContext, state => state.systemFeatures)
+
+ const updateAppDetail = async () => {
+ try {
+ const res = await fetchAppDetail({ url: '/apps', id: appId })
+ if (systemFeatures.enable_web_sso_switch_component) {
+ const ssoRes = await fetchAppSSO({ appId })
+ setAppDetail({ ...res, enable_sso: ssoRes.enabled })
+ }
+ else {
+ setAppDetail({ ...res })
+ }
+ }
+ catch (error) { console.error(error) }
+ }
+
+ const handleCallbackResult = (err: Error | null, message?: string) => {
+ const type = err ? 'error' : 'success'
+
+ message ||= (type === 'success' ? 'modifiedSuccessfully' : 'modifiedUnsuccessfully')
+
+ if (type === 'success')
+ updateAppDetail()
+
+ notify({
+ type,
+ message: t(`common.actionMsg.${message}`),
+ })
+ }
+
+ const onChangeSiteStatus = async (value: boolean) => {
+ const [err] = await asyncRunSafe<App>(
+ updateAppSiteStatus({
+ url: `/apps/${appId}/site-enable`,
+ body: { enable_site: value },
+ }) as Promise<App>,
+ )
+
+ handleCallbackResult(err)
+ }
+
+ const onChangeApiStatus = async (value: boolean) => {
+ const [err] = await asyncRunSafe<App>(
+ updateAppSiteStatus({
+ url: `/apps/${appId}/api-enable`,
+ body: { enable_api: value },
+ }) as Promise<App>,
+ )
+
+ handleCallbackResult(err)
+ }
+
+ const onSaveSiteConfig: IAppCardProps['onSaveSiteConfig'] = async (params) => {
+ const [err] = await asyncRunSafe<App>(
+ updateAppSiteConfig({
+ url: `/apps/${appId}/site`,
+ body: params,
+ }) as Promise<App>,
+ )
+ if (!err)
+ localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
+
+ if (systemFeatures.enable_web_sso_switch_component) {
+ const [sso_err] = await asyncRunSafe<AppSSO>(
+ updateAppSSO({ id: appId, enabled: Boolean(params.enable_sso) }) as Promise<AppSSO>,
+ )
+ if (sso_err) {
+ handleCallbackResult(sso_err)
+ return
+ }
+ }
+
+ handleCallbackResult(err)
+ }
+
+ const onGenerateCode = async () => {
+ const [err] = await asyncRunSafe<UpdateAppSiteCodeResponse>(
+ updateAppSiteAccessToken({
+ url: `/apps/${appId}/site/access-token-reset`,
+ }) as Promise<UpdateAppSiteCodeResponse>,
+ )
+
+ handleCallbackResult(err, err ? 'generatedUnsuccessfully' : 'generatedSuccessfully')
+ }
+
+ if (!appDetail)
+ return <Loading />
+
+ return (
+ <div className={className || 'mb-6 grid w-full grid-cols-1 gap-6 xl:grid-cols-2'}>
+ <AppCard
+ appInfo={appDetail}
+ cardType="webapp"
+ isInPanel={isInPanel}
+ onChangeStatus={onChangeSiteStatus}
+ onGenerateCode={onGenerateCode}
+ onSaveSiteConfig={onSaveSiteConfig}
+ />
+ <AppCard
+ cardType="api"
+ appInfo={appDetail}
+ isInPanel={isInPanel}
+ onChangeStatus={onChangeApiStatus}
+ />
+ </div>
+ )
+}
+
+export default CardView
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/chartView.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/chartView.tsx"
new file mode 100644
index 0000000..4afba06
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/chartView.tsx"
@@ -0,0 +1,106 @@
+'use client'
+import React, { useState } from 'react'
+import dayjs from 'dayjs'
+import quarterOfYear from 'dayjs/plugin/quarterOfYear'
+import { useTranslation } from 'react-i18next'
+import type { PeriodParams } from '@/app/components/app/overview/appChart'
+import { AvgResponseTime, AvgSessionInteractions, AvgUserInteractions, ConversationsChart, CostChart, EndUsersChart, MessagesChart, TokenPerSecond, UserSatisfactionRate, WorkflowCostChart, WorkflowDailyTerminalsChart, WorkflowMessagesChart } from '@/app/components/app/overview/appChart'
+import type { Item } from '@/app/components/base/select'
+import { SimpleSelect } from '@/app/components/base/select'
+import { TIME_PERIOD_MAPPING } from '@/app/components/app/log/filter'
+import { useStore as useAppStore } from '@/app/components/app/store'
+
+dayjs.extend(quarterOfYear)
+
+const today = dayjs()
+
+const queryDateFormat = 'YYYY-MM-DD HH:mm'
+
+export type IChartViewProps = {
+ appId: string
+}
+
+export default function ChartView({ appId }: IChartViewProps) {
+ const { t } = useTranslation()
+ const appDetail = useAppStore(state => state.appDetail)
+ const isChatApp = appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow'
+ const isWorkflow = appDetail?.mode === 'workflow'
+ const [period, setPeriod] = useState<PeriodParams>({ name: t('appLog.filter.period.last7days'), query: { start: today.subtract(7, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } })
+
+ const onSelect = (item: Item) => {
+ if (item.value === -1) {
+ setPeriod({ name: item.name, query: undefined })
+ }
+ else if (item.value === 0) {
+ const startOfToday = today.startOf('day').format(queryDateFormat)
+ const endOfToday = today.endOf('day').format(queryDateFormat)
+ setPeriod({ name: item.name, query: { start: startOfToday, end: endOfToday } })
+ }
+ else {
+ setPeriod({ name: item.name, query: { start: today.subtract(item.value as number, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } })
+ }
+ }
+
+ if (!appDetail)
+ return null
+
+ return (
+ <div>
+ <div className='system-xl-semibold mb-4 mt-8 flex flex-row items-center text-text-primary'>
+ <span className='mr-3'>{t('appOverview.analysis.title')}</span>
+ <SimpleSelect
+ items={Object.entries(TIME_PERIOD_MAPPING).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}`) }))}
+ className='mt-0 !w-40'
+ onSelect={(item) => {
+ const id = item.value
+ const value = TIME_PERIOD_MAPPING[id]?.value ?? '-1'
+ const name = item.name || t('appLog.filter.period.allTime')
+ onSelect({ value, name })
+ }}
+ defaultValue={'2'}
+ />
+ </div>
+ {!isWorkflow && (
+ <div className='mb-6 grid w-full grid-cols-1 gap-6 xl:grid-cols-2'>
+ <ConversationsChart period={period} id={appId} />
+ <EndUsersChart period={period} id={appId} />
+ </div>
+ )}
+ {!isWorkflow && (
+ <div className='mb-6 grid w-full grid-cols-1 gap-6 xl:grid-cols-2'>
+ {isChatApp
+ ? (
+ <AvgSessionInteractions period={period} id={appId} />
+ )
+ : (
+ <AvgResponseTime period={period} id={appId} />
+ )}
+ <TokenPerSecond period={period} id={appId} />
+ </div>
+ )}
+ {!isWorkflow && (
+ <div className='mb-6 grid w-full grid-cols-1 gap-6 xl:grid-cols-2'>
+ <UserSatisfactionRate period={period} id={appId} />
+ <CostChart period={period} id={appId} />
+ </div>
+ )}
+ {!isWorkflow && isChatApp && (
+ <div className='mb-6 grid w-full grid-cols-1 gap-6 xl:grid-cols-2'>
+ <MessagesChart period={period} id={appId} />
+ </div>
+ )}
+ {isWorkflow && (
+ <div className='mb-6 grid w-full grid-cols-1 gap-6 xl:grid-cols-2'>
+ <WorkflowMessagesChart period={period} id={appId} />
+ <WorkflowDailyTerminalsChart period={period} id={appId} />
+ </div>
+ )}
+ {isWorkflow && (
+ <div className='mb-6 grid w-full grid-cols-1 gap-6 xl:grid-cols-2'>
+ <WorkflowCostChart period={period} id={appId} />
+ <AvgUserInteractions period={period} id={appId} />
+ </div>
+ )}
+ </div>
+ )
+}
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/page.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/page.tsx"
new file mode 100644
index 0000000..0f1bb7e
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/page.tsx"
@@ -0,0 +1,28 @@
+import React from 'react'
+import ChartView from './chartView'
+import CardView from './cardView'
+import TracingPanel from './tracing/panel'
+import ApikeyInfoPanel from '@/app/components/app/overview/apikey-info-panel'
+
+export type IDevelopProps = {
+ params: Promise<{ appId: string }>
+}
+
+const Overview = async (props: IDevelopProps) => {
+ const params = await props.params
+
+ const {
+ appId,
+ } = params
+
+ return (
+ <div className="h-full overflow-scroll bg-chatbot-bg px-4 py-6 sm:px-12">
+ <ApikeyInfoPanel />
+ <TracingPanel />
+ <CardView appId={appId} />
+ <ChartView appId={appId} />
+ </div>
+ )
+}
+
+export default Overview
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/config-button.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/config-button.tsx"
new file mode 100644
index 0000000..3d05575
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/config-button.tsx"
@@ -0,0 +1,71 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import {
+ RiEqualizer2Line,
+} from '@remixicon/react'
+import type { PopupProps } from './config-popup'
+import ConfigPopup from './config-popup'
+import cn from '@/utils/classnames'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+
+type Props = {
+ readOnly: boolean
+ className?: string
+ hasConfigured: boolean
+ controlShowPopup?: number
+} & PopupProps
+
+const ConfigBtn: FC<Props> = ({
+ className,
+ hasConfigured,
+ controlShowPopup,
+ ...popupProps
+}) => {
+ const [open, doSetOpen] = useState(false)
+ const openRef = useRef(open)
+ const setOpen = useCallback((v: boolean) => {
+ doSetOpen(v)
+ openRef.current = v
+ }, [doSetOpen])
+
+ const handleTrigger = useCallback(() => {
+ setOpen(!openRef.current)
+ }, [setOpen])
+
+ useEffect(() => {
+ if (controlShowPopup)
+ // setOpen(!openRef.current)
+ setOpen(true)
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [controlShowPopup])
+
+ if (popupProps.readOnly && !hasConfigured)
+ return null
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 12,
+ crossAxis: hasConfigured ? 8 : 49,
+ }}
+ >
+ <PortalToFollowElemTrigger onClick={handleTrigger}>
+ <div className={cn(className, 'rounded-md p-1')}>
+ <RiEqualizer2Line className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[11]'>
+ <ConfigPopup {...popupProps} />
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(ConfigBtn)
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/config-popup.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/config-popup.tsx"
new file mode 100644
index 0000000..0efc508
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/config-popup.tsx"
@@ -0,0 +1,259 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import TracingIcon from './tracing-icon'
+import ProviderPanel from './provider-panel'
+import type { LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type'
+import { TracingProvider } from './type'
+import ProviderConfigModal from './provider-config-modal'
+import Indicator from '@/app/components/header/indicator'
+import Switch from '@/app/components/base/switch'
+import Tooltip from '@/app/components/base/tooltip'
+import Divider from '@/app/components/base/divider'
+import cn from '@/utils/classnames'
+
+const I18N_PREFIX = 'app.tracing'
+
+export type PopupProps = {
+ appId: string
+ readOnly: boolean
+ enabled: boolean
+ onStatusChange: (enabled: boolean) => void
+ chosenProvider: TracingProvider | null
+ onChooseProvider: (provider: TracingProvider) => void
+ langSmithConfig: LangSmithConfig | null
+ langFuseConfig: LangFuseConfig | null
+ opikConfig: OpikConfig | null
+ weaveConfig: WeaveConfig | null
+ onConfigUpdated: (provider: TracingProvider, payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig) => void
+ onConfigRemoved: (provider: TracingProvider) => void
+}
+
+const ConfigPopup: FC<PopupProps> = ({
+ appId,
+ readOnly,
+ enabled,
+ onStatusChange,
+ chosenProvider,
+ onChooseProvider,
+ langSmithConfig,
+ langFuseConfig,
+ opikConfig,
+ weaveConfig,
+ onConfigUpdated,
+ onConfigRemoved,
+}) => {
+ const { t } = useTranslation()
+
+ const [currentProvider, setCurrentProvider] = useState<TracingProvider | null>(TracingProvider.langfuse)
+ const [isShowConfigModal, {
+ setTrue: showConfigModal,
+ setFalse: hideConfigModal,
+ }] = useBoolean(false)
+ const handleOnConfig = useCallback((provider: TracingProvider) => {
+ return () => {
+ setCurrentProvider(provider)
+ showConfigModal()
+ }
+ }, [showConfigModal])
+
+ const handleOnChoose = useCallback((provider: TracingProvider) => {
+ return () => {
+ onChooseProvider(provider)
+ }
+ }, [onChooseProvider])
+
+ const handleConfigUpdated = useCallback((payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig) => {
+ onConfigUpdated(currentProvider!, payload)
+ hideConfigModal()
+ }, [currentProvider, hideConfigModal, onConfigUpdated])
+
+ const handleConfigRemoved = useCallback(() => {
+ onConfigRemoved(currentProvider!)
+ hideConfigModal()
+ }, [currentProvider, hideConfigModal, onConfigRemoved])
+
+ const providerAllConfigured = langSmithConfig && langFuseConfig && opikConfig && weaveConfig
+ const providerAllNotConfigured = !langSmithConfig && !langFuseConfig && !opikConfig && !weaveConfig
+
+ const switchContent = (
+ <Switch
+ className='ml-3'
+ defaultValue={enabled}
+ onChange={onStatusChange}
+ disabled={providerAllNotConfigured}
+ />
+ )
+ const langSmithPanel = (
+ <ProviderPanel
+ type={TracingProvider.langSmith}
+ readOnly={readOnly}
+ config={langSmithConfig}
+ hasConfigured={!!langSmithConfig}
+ onConfig={handleOnConfig(TracingProvider.langSmith)}
+ isChosen={chosenProvider === TracingProvider.langSmith}
+ onChoose={handleOnChoose(TracingProvider.langSmith)}
+ key="langSmith-provider-panel"
+ />
+ )
+
+ const langfusePanel = (
+ <ProviderPanel
+ type={TracingProvider.langfuse}
+ readOnly={readOnly}
+ config={langFuseConfig}
+ hasConfigured={!!langFuseConfig}
+ onConfig={handleOnConfig(TracingProvider.langfuse)}
+ isChosen={chosenProvider === TracingProvider.langfuse}
+ onChoose={handleOnChoose(TracingProvider.langfuse)}
+ key="langfuse-provider-panel"
+ />
+ )
+
+ const opikPanel = (
+ <ProviderPanel
+ type={TracingProvider.opik}
+ readOnly={readOnly}
+ config={opikConfig}
+ hasConfigured={!!opikConfig}
+ onConfig={handleOnConfig(TracingProvider.opik)}
+ isChosen={chosenProvider === TracingProvider.opik}
+ onChoose={handleOnChoose(TracingProvider.opik)}
+ key="opik-provider-panel"
+ />
+ )
+
+ const weavePanel = (
+ <ProviderPanel
+ type={TracingProvider.weave}
+ readOnly={readOnly}
+ config={weaveConfig}
+ hasConfigured={!!weaveConfig}
+ onConfig={handleOnConfig(TracingProvider.weave)}
+ isChosen={chosenProvider === TracingProvider.weave}
+ onChoose={handleOnChoose(TracingProvider.weave)}
+ key="weave-provider-panel"
+ />
+ )
+ const configuredProviderPanel = () => {
+ const configuredPanels: JSX.Element[] = []
+
+ if (langFuseConfig)
+ configuredPanels.push(langfusePanel)
+
+ if (langSmithConfig)
+ configuredPanels.push(langSmithPanel)
+
+ if (opikConfig)
+ configuredPanels.push(opikPanel)
+
+ if (weaveConfig)
+ configuredPanels.push(weavePanel)
+
+ return configuredPanels
+ }
+
+ const moreProviderPanel = () => {
+ const notConfiguredPanels: JSX.Element[] = []
+
+ if (!langFuseConfig)
+ notConfiguredPanels.push(langfusePanel)
+
+ if (!langSmithConfig)
+ notConfiguredPanels.push(langSmithPanel)
+
+ if (!opikConfig)
+ notConfiguredPanels.push(opikPanel)
+
+ if (!weaveConfig)
+ notConfiguredPanels.push(weavePanel)
+
+ return notConfiguredPanels
+ }
+
+ const configuredProviderConfig = () => {
+ if (currentProvider === TracingProvider.langSmith)
+ return langSmithConfig
+ if (currentProvider === TracingProvider.langfuse)
+ return langFuseConfig
+ if (currentProvider === TracingProvider.opik)
+ return opikConfig
+ return weaveConfig
+ }
+
+ return (
+ <div className='w-[420px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-xl'>
+ <div className='flex items-center justify-between'>
+ <div className='flex items-center'>
+ <TracingIcon size='md' className='mr-2' />
+ <div className='title-2xl-semi-bold text-text-primary'>{t(`${I18N_PREFIX}.tracing`)}</div>
+ </div>
+ <div className='flex items-center'>
+ <Indicator color={enabled ? 'green' : 'gray'} />
+ <div className={cn('system-xs-semibold-uppercase ml-1 text-text-tertiary', enabled && 'text-util-colors-green-green-600')}>
+ {t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
+ </div>
+ {!readOnly && (
+ <>
+ {providerAllNotConfigured
+ ? (
+ <Tooltip
+ popupContent={t(`${I18N_PREFIX}.disabledTip`)}
+ >
+ {switchContent}
+ </Tooltip>
+ )
+ : switchContent}
+ </>
+ )}
+ </div>
+ </div>
+
+ <div className='system-xs-regular mt-2 text-text-tertiary'>
+ {t(`${I18N_PREFIX}.tracingDescription`)}
+ </div>
+ <Divider className='my-3' />
+ <div className='relative'>
+ {(providerAllConfigured || providerAllNotConfigured)
+ ? (
+ <>
+ <div className='system-xs-medium-uppercase text-text-tertiary'>{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`)}</div>
+ <div className='mt-2 space-y-2'>
+ {langfusePanel}
+ {langSmithPanel}
+ {opikPanel}
+ {weavePanel}
+ </div>
+ </>
+ )
+ : (
+ <>
+ <div className='system-xs-medium-uppercase text-text-tertiary'>{t(`${I18N_PREFIX}.configProviderTitle.configured`)}</div>
+ <div className='mt-2 space-y-2'>
+ {configuredProviderPanel()}
+ </div>
+ <div className='system-xs-medium-uppercase mt-3 text-text-tertiary'>{t(`${I18N_PREFIX}.configProviderTitle.moreProvider`)}</div>
+ <div className='mt-2 space-y-2'>
+ {moreProviderPanel()}
+ </div>
+ </>
+ )}
+
+ </div>
+ {isShowConfigModal && (
+ <ProviderConfigModal
+ appId={appId}
+ type={currentProvider!}
+ payload={configuredProviderConfig()}
+ onCancel={hideConfigModal}
+ onSaved={handleConfigUpdated}
+ onChosen={onChooseProvider}
+ onRemoved={handleConfigRemoved}
+ />
+ )}
+ </div>
+ )
+}
+export default React.memo(ConfigPopup)
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/config.ts" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/config.ts"
new file mode 100644
index 0000000..5d3c407
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/config.ts"
@@ -0,0 +1,8 @@
+import { TracingProvider } from './type'
+
+export const docURL = {
+ [TracingProvider.langSmith]: 'https://docs.smith.langchain.com/',
+ [TracingProvider.langfuse]: 'https://docs.langfuse.com',
+ [TracingProvider.opik]: 'https://www.comet.com/docs/opik/tracing/integrations/dify#setup-instructions',
+ [TracingProvider.weave]: 'https://weave-docs.wandb.ai/',
+}
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/field.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/field.tsx"
new file mode 100644
index 0000000..eecd356
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/field.tsx"
@@ -0,0 +1,41 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import Input from '@/app/components/base/input'
+
+type Props = {
+ className?: string
+ label: string
+ labelClassName?: string
+ value: string | number
+ onChange: (value: string) => void
+ isRequired?: boolean
+ placeholder?: string
+}
+
+const Field: FC<Props> = ({
+ className,
+ label,
+ labelClassName,
+ value,
+ onChange,
+ isRequired = false,
+ placeholder = '',
+}) => {
+ return (
+ <div className={cn(className)}>
+ <div className='flex py-[7px]'>
+ <div className={cn(labelClassName, 'flex h-[18px] items-center text-[13px] font-medium text-text-primary')}>{label} </div>
+ {isRequired && <span className='ml-0.5 text-xs font-semibold text-[#D92D20]'>*</span>}
+ </div>
+ <Input
+ value={value}
+ onChange={e => onChange(e.target.value)}
+ className='h-9'
+ placeholder={placeholder}
+ />
+ </div>
+ )
+}
+export default React.memo(Field)
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/panel.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/panel.tsx"
new file mode 100644
index 0000000..8575117
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/panel.tsx"
@@ -0,0 +1,238 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import {
+ RiArrowDownDoubleLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { usePathname } from 'next/navigation'
+import { useBoolean } from 'ahooks'
+import type { LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type'
+import { TracingProvider } from './type'
+import TracingIcon from './tracing-icon'
+import ConfigButton from './config-button'
+import cn from '@/utils/classnames'
+import { LangfuseIcon, LangsmithIcon, OpikIcon, WeaveIcon } from '@/app/components/base/icons/src/public/tracing'
+import Indicator from '@/app/components/header/indicator'
+import { fetchTracingConfig as doFetchTracingConfig, fetchTracingStatus, updateTracingStatus } from '@/service/apps'
+import type { TracingStatus } from '@/models/app'
+import Toast from '@/app/components/base/toast'
+import { useAppContext } from '@/context/app-context'
+import Loading from '@/app/components/base/loading'
+import Divider from '@/app/components/base/divider'
+
+const I18N_PREFIX = 'app.tracing'
+
+const Title = ({
+ className,
+}: {
+ className?: string
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={cn('system-xl-semibold flex items-center text-text-primary', className)}>
+ {t('common.appMenus.overview')}
+ </div>
+ )
+}
+const Panel: FC = () => {
+ const { t } = useTranslation()
+ const pathname = usePathname()
+ const matched = pathname.match(/\/app\/([^/]+)/)
+ const appId = (matched?.length && matched[1]) ? matched[1] : ''
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const readOnly = !isCurrentWorkspaceEditor
+
+ const [isLoaded, {
+ setTrue: setLoaded,
+ }] = useBoolean(false)
+
+ const [tracingStatus, setTracingStatus] = useState<TracingStatus | null>(null)
+ const enabled = tracingStatus?.enabled || false
+ const handleTracingStatusChange = async (tracingStatus: TracingStatus, noToast?: boolean) => {
+ await updateTracingStatus({ appId, body: tracingStatus })
+ setTracingStatus(tracingStatus)
+ if (!noToast) {
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.success'),
+ })
+ }
+ }
+
+ const handleTracingEnabledChange = (enabled: boolean) => {
+ handleTracingStatusChange({
+ tracing_provider: tracingStatus?.tracing_provider || null,
+ enabled,
+ })
+ }
+ const handleChooseProvider = (provider: TracingProvider) => {
+ handleTracingStatusChange({
+ tracing_provider: provider,
+ enabled: true,
+ })
+ }
+ const inUseTracingProvider: TracingProvider | null = tracingStatus?.tracing_provider || null
+
+ const InUseProviderIcon
+ = inUseTracingProvider === TracingProvider.langSmith
+ ? LangsmithIcon
+ : inUseTracingProvider === TracingProvider.langfuse
+ ? LangfuseIcon
+ : inUseTracingProvider === TracingProvider.opik
+ ? OpikIcon
+ : inUseTracingProvider === TracingProvider.weave
+ ? WeaveIcon
+ : LangsmithIcon
+
+ const [langSmithConfig, setLangSmithConfig] = useState<LangSmithConfig | null>(null)
+ const [langFuseConfig, setLangFuseConfig] = useState<LangFuseConfig | null>(null)
+ const [opikConfig, setOpikConfig] = useState<OpikConfig | null>(null)
+ const [weaveConfig, setWeaveConfig] = useState<WeaveConfig | null>(null)
+ const hasConfiguredTracing = !!(langSmithConfig || langFuseConfig || opikConfig || weaveConfig)
+
+ const fetchTracingConfig = async () => {
+ const { tracing_config: langSmithConfig, has_not_configured: langSmithHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.langSmith })
+ if (!langSmithHasNotConfig)
+ setLangSmithConfig(langSmithConfig as LangSmithConfig)
+ const { tracing_config: langFuseConfig, has_not_configured: langFuseHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.langfuse })
+ if (!langFuseHasNotConfig)
+ setLangFuseConfig(langFuseConfig as LangFuseConfig)
+ const { tracing_config: opikConfig, has_not_configured: OpikHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.opik })
+ if (!OpikHasNotConfig)
+ setOpikConfig(opikConfig as OpikConfig)
+ const { tracing_config: weaveConfig, has_not_configured: weaveHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.weave })
+ if (!weaveHasNotConfig)
+ setWeaveConfig(weaveConfig as WeaveConfig)
+ }
+
+ const handleTracingConfigUpdated = async (provider: TracingProvider) => {
+ // call api to hide secret key value
+ const { tracing_config } = await doFetchTracingConfig({ appId, provider })
+ if (provider === TracingProvider.langSmith)
+ setLangSmithConfig(tracing_config as LangSmithConfig)
+ else if (provider === TracingProvider.langfuse)
+ setLangFuseConfig(tracing_config as LangFuseConfig)
+ else if (provider === TracingProvider.opik)
+ setOpikConfig(tracing_config as OpikConfig)
+ else if (provider === TracingProvider.weave)
+ setWeaveConfig(tracing_config as WeaveConfig)
+ }
+
+ const handleTracingConfigRemoved = (provider: TracingProvider) => {
+ if (provider === TracingProvider.langSmith)
+ setLangSmithConfig(null)
+ else if (provider === TracingProvider.langfuse)
+ setLangFuseConfig(null)
+ else if (provider === TracingProvider.opik)
+ setOpikConfig(null)
+ else if (provider === TracingProvider.weave)
+ setWeaveConfig(null)
+ if (provider === inUseTracingProvider) {
+ handleTracingStatusChange({
+ enabled: false,
+ tracing_provider: null,
+ }, true)
+ }
+ }
+
+ useEffect(() => {
+ (async () => {
+ const tracingStatus = await fetchTracingStatus({ appId })
+ setTracingStatus(tracingStatus)
+ await fetchTracingConfig()
+ setLoaded()
+ })()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+
+ const [controlShowPopup, setControlShowPopup] = useState<number>(0)
+ const showPopup = useCallback(() => {
+ setControlShowPopup(Date.now())
+ }, [setControlShowPopup])
+ if (!isLoaded) {
+ return (
+ <div className='mb-3 flex items-center justify-between'>
+ <Title className='h-[41px]' />
+ <div className='w-[200px]'>
+ <Loading />
+ </div>
+ </div>
+ )
+ }
+
+ return (
+ <div className={cn('mb-3 flex items-center justify-between')}>
+ <Title className='h-[41px]' />
+ <div
+ className={cn(
+ 'flex cursor-pointer items-center rounded-xl border-l-[0.5px] border-t border-effects-highlight bg-background-default-dodge p-2 shadow-xs hover:border-effects-highlight-lightmode-off hover:bg-background-default-lighter',
+ controlShowPopup && 'border-effects-highlight-lightmode-off bg-background-default-lighter',
+ )}
+ onClick={showPopup}
+ >
+ {!inUseTracingProvider && (
+ <>
+ <TracingIcon size='md' />
+ <div className='system-sm-semibold mx-2 text-text-secondary'>{t(`${I18N_PREFIX}.title`)}</div>
+ <div className='flex items-center' onClick={e => e.stopPropagation()}>
+ <ConfigButton
+ appId={appId}
+ readOnly={readOnly}
+ hasConfigured={false}
+ enabled={enabled}
+ onStatusChange={handleTracingEnabledChange}
+ chosenProvider={inUseTracingProvider}
+ onChooseProvider={handleChooseProvider}
+ langSmithConfig={langSmithConfig}
+ langFuseConfig={langFuseConfig}
+ opikConfig={opikConfig}
+ weaveConfig={weaveConfig}
+ onConfigUpdated={handleTracingConfigUpdated}
+ onConfigRemoved={handleTracingConfigRemoved}
+ controlShowPopup={controlShowPopup}
+ />
+ </div>
+ <Divider type='vertical' className='h-3.5' />
+ <div className='rounded-md p-1'>
+ <RiArrowDownDoubleLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </>
+ )}
+ {hasConfiguredTracing && (
+ <>
+ <div className='ml-4 mr-1 flex items-center'>
+ <Indicator color={enabled ? 'green' : 'gray'} />
+ <div className='system-xs-semibold-uppercase ml-1.5 text-text-tertiary'>
+ {t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
+ </div>
+ </div>
+ {InUseProviderIcon && <InUseProviderIcon className='ml-1 h-4' />}
+ <Divider type='vertical' className='h-3.5' />
+ <div className='flex items-center' onClick={e => e.stopPropagation()}>
+ <ConfigButton
+ appId={appId}
+ readOnly={readOnly}
+ hasConfigured
+ className='ml-2'
+ enabled={enabled}
+ onStatusChange={handleTracingEnabledChange}
+ chosenProvider={inUseTracingProvider}
+ onChooseProvider={handleChooseProvider}
+ langSmithConfig={langSmithConfig}
+ langFuseConfig={langFuseConfig}
+ opikConfig={opikConfig}
+ weaveConfig={weaveConfig}
+ onConfigUpdated={handleTracingConfigUpdated}
+ onConfigRemoved={handleTracingConfigRemoved}
+ controlShowPopup={controlShowPopup}
+ />
+ </div>
+ </>
+ )}
+ </div >
+ </div >
+ )
+}
+export default React.memo(Panel)
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/provider-config-modal.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/provider-config-modal.tsx"
new file mode 100644
index 0000000..c0b52a9
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/provider-config-modal.tsx"
@@ -0,0 +1,390 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import Field from './field'
+import type { LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type'
+import { TracingProvider } from './type'
+import { docURL } from './config'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+} from '@/app/components/base/portal-to-follow-elem'
+import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
+import Button from '@/app/components/base/button'
+import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
+import Confirm from '@/app/components/base/confirm'
+import { addTracingConfig, removeTracingConfig, updateTracingConfig } from '@/service/apps'
+import Toast from '@/app/components/base/toast'
+import Divider from '@/app/components/base/divider'
+
+type Props = {
+ appId: string
+ type: TracingProvider
+ payload?: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | null
+ onRemoved: () => void
+ onCancel: () => void
+ onSaved: (payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig) => void
+ onChosen: (provider: TracingProvider) => void
+}
+
+const I18N_PREFIX = 'app.tracing.configProvider'
+
+const langSmithConfigTemplate = {
+ api_key: '',
+ project: '',
+ endpoint: '',
+}
+
+const langFuseConfigTemplate = {
+ public_key: '',
+ secret_key: '',
+ host: '',
+}
+
+const opikConfigTemplate = {
+ api_key: '',
+ project: '',
+ url: '',
+ workspace: '',
+}
+
+const weaveConfigTemplate = {
+ api_key: '',
+ entity: '',
+ project: '',
+ endpoint: '',
+}
+
+const ProviderConfigModal: FC<Props> = ({
+ appId,
+ type,
+ payload,
+ onRemoved,
+ onCancel,
+ onSaved,
+ onChosen,
+}) => {
+ const { t } = useTranslation()
+ const isEdit = !!payload
+ const isAdd = !isEdit
+ const [isSaving, setIsSaving] = useState(false)
+ const [config, setConfig] = useState<LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig>((() => {
+ if (isEdit)
+ return payload
+
+ if (type === TracingProvider.langSmith)
+ return langSmithConfigTemplate
+
+ else if (type === TracingProvider.langfuse)
+ return langFuseConfigTemplate
+
+ else if (type === TracingProvider.opik)
+ return opikConfigTemplate
+
+ return weaveConfigTemplate
+ })())
+ const [isShowRemoveConfirm, {
+ setTrue: showRemoveConfirm,
+ setFalse: hideRemoveConfirm,
+ }] = useBoolean(false)
+
+ const handleRemove = useCallback(async () => {
+ await removeTracingConfig({
+ appId,
+ provider: type,
+ })
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.remove'),
+ })
+ onRemoved()
+ hideRemoveConfirm()
+ }, [hideRemoveConfirm, appId, type, t, onRemoved])
+
+ const handleConfigChange = useCallback((key: string) => {
+ return (value: string) => {
+ setConfig({
+ ...config,
+ [key]: value,
+ })
+ }
+ }, [config])
+
+ const checkValid = useCallback(() => {
+ let errorMessage = ''
+ if (type === TracingProvider.langSmith) {
+ const postData = config as LangSmithConfig
+ if (!postData.api_key)
+ errorMessage = t('common.errorMsg.fieldRequired', { field: 'API Key' })
+ if (!errorMessage && !postData.project)
+ errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.project`) })
+ }
+
+ if (type === TracingProvider.langfuse) {
+ const postData = config as LangFuseConfig
+ if (!errorMessage && !postData.secret_key)
+ errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.secretKey`) })
+ if (!errorMessage && !postData.public_key)
+ errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.publicKey`) })
+ if (!errorMessage && !postData.host)
+ errorMessage = t('common.errorMsg.fieldRequired', { field: 'Host' })
+ }
+
+ if (type === TracingProvider.opik) {
+ // todo: check field validity
+ // const postData = config as OpikConfig
+ }
+
+ if (type === TracingProvider.weave) {
+ const postData = config as WeaveConfig
+ if (!errorMessage && !postData.api_key)
+ errorMessage = t('common.errorMsg.fieldRequired', { field: 'API Key' })
+ if (!errorMessage && !postData.project)
+ errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.project`) })
+ }
+
+ return errorMessage
+ }, [config, t, type])
+ const handleSave = useCallback(async () => {
+ if (isSaving)
+ return
+ const errorMessage = checkValid()
+ if (errorMessage) {
+ Toast.notify({
+ type: 'error',
+ message: errorMessage,
+ })
+ return
+ }
+ const action = isEdit ? updateTracingConfig : addTracingConfig
+ try {
+ await action({
+ appId,
+ body: {
+ tracing_provider: type,
+ tracing_config: config,
+ },
+ })
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.success'),
+ })
+ onSaved(config)
+ if (isAdd)
+ onChosen(type)
+ }
+ finally {
+ setIsSaving(false)
+ }
+ }, [appId, checkValid, config, isAdd, isEdit, isSaving, onChosen, onSaved, t, type])
+
+ return (
+ <>
+ {!isShowRemoveConfirm
+ ? (
+ <PortalToFollowElem open>
+ <PortalToFollowElemContent className='z-[60] h-full w-full'>
+ <div className='fixed inset-0 flex items-center justify-center bg-background-overlay'>
+ <div className='mx-2 max-h-[calc(100vh-120px)] w-[640px] overflow-y-auto rounded-2xl bg-components-panel-bg shadow-xl'>
+ <div className='px-8 pt-8'>
+ <div className='mb-4 flex items-center justify-between'>
+ <div className='title-2xl-semi-bold text-text-primary'>{t(`${I18N_PREFIX}.title`)}{t(`app.tracing.${type}.title`)}</div>
+ </div>
+
+ <div className='space-y-4'>
+ {type === TracingProvider.weave && (
+ <>
+ <Field
+ label='API Key'
+ labelClassName='!text-sm'
+ isRequired
+ value={(config as WeaveConfig).api_key}
+ onChange={handleConfigChange('api_key')}
+ placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!}
+ />
+ <Field
+ label={t(`${I18N_PREFIX}.project`)!}
+ labelClassName='!text-sm'
+ isRequired
+ value={(config as WeaveConfig).project}
+ onChange={handleConfigChange('project')}
+ placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!}
+ />
+ <Field
+ label='Entity'
+ labelClassName='!text-sm'
+ value={(config as WeaveConfig).entity}
+ onChange={handleConfigChange('entity')}
+ placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'Entity' })!}
+ />
+ <Field
+ label='Endpoint'
+ labelClassName='!text-sm'
+ value={(config as WeaveConfig).endpoint}
+ onChange={handleConfigChange('endpoint')}
+ placeholder={'https://trace.wandb.ai/'}
+ />
+ </>
+ )}
+ {type === TracingProvider.langSmith && (
+ <>
+ <Field
+ label='API Key'
+ labelClassName='!text-sm'
+ isRequired
+ value={(config as LangSmithConfig).api_key}
+ onChange={handleConfigChange('api_key')}
+ placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!}
+ />
+ <Field
+ label={t(`${I18N_PREFIX}.project`)!}
+ labelClassName='!text-sm'
+ isRequired
+ value={(config as LangSmithConfig).project}
+ onChange={handleConfigChange('project')}
+ placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!}
+ />
+ <Field
+ label='Endpoint'
+ labelClassName='!text-sm'
+ value={(config as LangSmithConfig).endpoint}
+ onChange={handleConfigChange('endpoint')}
+ placeholder={'https://api.smith.langchain.com'}
+ />
+ </>
+ )}
+ {type === TracingProvider.langfuse && (
+ <>
+ <Field
+ label={t(`${I18N_PREFIX}.secretKey`)!}
+ labelClassName='!text-sm'
+ value={(config as LangFuseConfig).secret_key}
+ isRequired
+ onChange={handleConfigChange('secret_key')}
+ placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.secretKey`) })!}
+ />
+ <Field
+ label={t(`${I18N_PREFIX}.publicKey`)!}
+ labelClassName='!text-sm'
+ isRequired
+ value={(config as LangFuseConfig).public_key}
+ onChange={handleConfigChange('public_key')}
+ placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.publicKey`) })!}
+ />
+ <Field
+ label='Host'
+ labelClassName='!text-sm'
+ isRequired
+ value={(config as LangFuseConfig).host}
+ onChange={handleConfigChange('host')}
+ placeholder='https://cloud.langfuse.com'
+ />
+ </>
+ )}
+ {type === TracingProvider.opik && (
+ <>
+ <Field
+ label='API Key'
+ labelClassName='!text-sm'
+ value={(config as OpikConfig).api_key}
+ onChange={handleConfigChange('api_key')}
+ placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!}
+ />
+ <Field
+ label={t(`${I18N_PREFIX}.project`)!}
+ labelClassName='!text-sm'
+ value={(config as OpikConfig).project}
+ onChange={handleConfigChange('project')}
+ placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!}
+ />
+ <Field
+ label='Workspace'
+ labelClassName='!text-sm'
+ value={(config as OpikConfig).workspace}
+ onChange={handleConfigChange('workspace')}
+ placeholder={'default'}
+ />
+ <Field
+ label='Url'
+ labelClassName='!text-sm'
+ value={(config as OpikConfig).url}
+ onChange={handleConfigChange('url')}
+ placeholder={'https://www.comet.com/opik/api/'}
+ />
+ </>
+ )}
+ </div>
+ <div className='my-8 flex h-8 items-center justify-between'>
+ <a
+ className='flex items-center space-x-1 text-xs font-normal leading-[18px] text-[#155EEF]'
+ target='_blank'
+ href={docURL[type]}
+ >
+ <span>{t(`${I18N_PREFIX}.viewDocsLink`, { key: t(`app.tracing.${type}.title`) })}</span>
+ <LinkExternal02 className='h-3 w-3' />
+ </a>
+ <div className='flex items-center'>
+ {isEdit && (
+ <>
+ <Button
+ className='h-9 text-sm font-medium text-text-secondary'
+ onClick={showRemoveConfirm}
+ >
+ <span className='text-[#D92D20]'>{t('common.operation.remove')}</span>
+ </Button>
+ <Divider className='mx-3 h-[18px]' />
+ </>
+ )}
+ <Button
+ className='mr-2 h-9 text-sm font-medium text-text-secondary'
+ onClick={onCancel}
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ className='h-9 text-sm font-medium'
+ variant='primary'
+ onClick={handleSave}
+ loading={isSaving}
+ >
+ {t(`common.operation.${isAdd ? 'saveAndEnable' : 'save'}`)}
+ </Button>
+ </div>
+
+ </div>
+ </div>
+ <div className='border-t-[0.5px] border-divider-regular'>
+ <div className='flex items-center justify-center bg-background-section-burn py-3 text-xs text-text-tertiary'>
+ <Lock01 className='mr-1 h-3 w-3 text-text-tertiary' />
+ {t('common.modelProvider.encrypted.front')}
+ <a
+ className='mx-1 text-primary-600'
+ target='_blank' rel='noopener noreferrer'
+ href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
+ >
+ PKCS1_OAEP
+ </a>
+ {t('common.modelProvider.encrypted.back')}
+ </div>
+ </div>
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+ : (
+ <Confirm
+ isShow
+ type='warning'
+ title={t(`${I18N_PREFIX}.removeConfirmTitle`, { key: t(`app.tracing.${type}.title`) })!}
+ content={t(`${I18N_PREFIX}.removeConfirmContent`)}
+ onConfirm={handleRemove}
+ onCancel={hideRemoveConfirm}
+ />
+ )}
+ </>
+ )
+}
+export default React.memo(ProviderConfigModal)
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/provider-panel.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/provider-panel.tsx"
new file mode 100644
index 0000000..bdccc50
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/provider-panel.tsx"
@@ -0,0 +1,104 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import {
+ RiEqualizer2Line,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { TracingProvider } from './type'
+import cn from '@/utils/classnames'
+import { LangfuseIconBig, LangsmithIconBig, OpikIconBig, WeaveIconBig } from '@/app/components/base/icons/src/public/tracing'
+import { Eye as View } from '@/app/components/base/icons/src/vender/solid/general'
+
+const I18N_PREFIX = 'app.tracing'
+
+type Props = {
+ type: TracingProvider
+ readOnly: boolean
+ isChosen: boolean
+ config: any
+ onChoose: () => void
+ hasConfigured: boolean
+ onConfig: () => void
+}
+
+const getIcon = (type: TracingProvider) => {
+ return ({
+ [TracingProvider.langSmith]: LangsmithIconBig,
+ [TracingProvider.langfuse]: LangfuseIconBig,
+ [TracingProvider.opik]: OpikIconBig,
+ [TracingProvider.weave]: WeaveIconBig,
+ })[type]
+}
+
+const ProviderPanel: FC<Props> = ({
+ type,
+ readOnly,
+ isChosen,
+ config,
+ onChoose,
+ hasConfigured,
+ onConfig,
+}) => {
+ const { t } = useTranslation()
+ const Icon = getIcon(type)
+
+ const handleConfigBtnClick = useCallback((e: React.MouseEvent) => {
+ e.stopPropagation()
+ onConfig()
+ }, [onConfig])
+
+ const viewBtnClick = useCallback((e: React.MouseEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+
+ const url = config?.project_url
+ if (url)
+ window.open(url, '_blank', 'noopener,noreferrer')
+ }, [config?.project_url])
+
+ const handleChosen = useCallback((e: React.MouseEvent) => {
+ e.stopPropagation()
+ if (isChosen || !hasConfigured || readOnly)
+ return
+ onChoose()
+ }, [hasConfigured, isChosen, onChoose, readOnly])
+ return (
+ <div
+ className={cn(
+ 'rounded-xl border-[1.5px] bg-background-section-burn px-4 py-3',
+ isChosen ? 'border-components-option-card-option-selected-border bg-background-section' : 'border-transparent',
+ !isChosen && hasConfigured && !readOnly && 'cursor-pointer',
+ )}
+ onClick={handleChosen}
+ >
+ <div className={'flex items-center justify-between space-x-1'}>
+ <div className='flex items-center'>
+ <Icon className='h-6' />
+ {isChosen && <div className='system-2xs-medium-uppercase ml-1 flex h-4 items-center rounded-[4px] border border-text-accent-secondary px-1 text-text-accent-secondary'>{t(`${I18N_PREFIX}.inUse`)}</div>}
+ </div>
+ {!readOnly && (
+ <div className={'flex items-center justify-between space-x-1'}>
+ {hasConfigured && (
+ <div className='flex h-6 cursor-pointer items-center space-x-1 rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-2 text-text-secondary shadow-xs' onClick={viewBtnClick} >
+ <View className='h-3 w-3' />
+ <div className='text-xs font-medium'>{t(`${I18N_PREFIX}.view`)}</div>
+ </div>
+ )}
+ <div
+ className='flex h-6 cursor-pointer items-center space-x-1 rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-2 text-text-secondary shadow-xs'
+ onClick={handleConfigBtnClick}
+ >
+ <RiEqualizer2Line className='h-3 w-3' />
+ <div className='text-xs font-medium'>{t(`${I18N_PREFIX}.config`)}</div>
+ </div>
+ </div>
+ )}
+ </div>
+ <div className='system-xs-regular mt-2 text-text-tertiary'>
+ {t(`${I18N_PREFIX}.${type}.description`)}
+ </div>
+ </div>
+ )
+}
+export default React.memo(ProviderPanel)
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/tracing-icon.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/tracing-icon.tsx"
new file mode 100644
index 0000000..ec9117d
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/tracing-icon.tsx"
@@ -0,0 +1,28 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import { TracingIcon as Icon } from '@/app/components/base/icons/src/public/tracing'
+
+type Props = {
+ className?: string
+ size: 'lg' | 'md'
+}
+
+const sizeClassMap = {
+ lg: 'w-9 h-9 p-2 rounded-[10px]',
+ md: 'w-6 h-6 p-1 rounded-lg',
+}
+
+const TracingIcon: FC<Props> = ({
+ className,
+ size,
+}) => {
+ const sizeClass = sizeClassMap[size]
+ return (
+ <div className={cn(className, sizeClass, 'bg-primary-500 shadow-md')}>
+ <Icon className='h-full w-full' />
+ </div>
+ )
+}
+export default React.memo(TracingIcon)
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/type.ts" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/type.ts"
new file mode 100644
index 0000000..386c589
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/overview/tracing/type.ts"
@@ -0,0 +1,32 @@
+export enum TracingProvider {
+ langSmith = 'langsmith',
+ langfuse = 'langfuse',
+ opik = 'opik',
+ weave = 'weave',
+}
+
+export type LangSmithConfig = {
+ api_key: string
+ project: string
+ endpoint: string
+}
+
+export type LangFuseConfig = {
+ public_key: string
+ secret_key: string
+ host: string
+}
+
+export type OpikConfig = {
+ api_key: string
+ project: string
+ workspace: string
+ url: string
+}
+
+export type WeaveConfig = {
+ api_key: string
+ entity: string
+ project: string
+ endpoint: string
+}
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/style.module.css" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/style.module.css"
new file mode 100644
index 0000000..45c7d19
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/style.module.css"
@@ -0,0 +1,6 @@
+.app {
+ flex-grow: 1;
+ height: 0;
+ border-radius: 16px 16px 0px 0px;
+ box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.05), 0px 0px 2px -1px rgba(0, 0, 0, 0.03);
+}
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/workflow/page.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/workflow/page.tsx"
new file mode 100644
index 0000000..d5df70f
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/\133appId\135/workflow/page.tsx"
@@ -0,0 +1,12 @@
+'use client'
+
+import WorkflowApp from '@/app/components/workflow-app'
+
+const Page = () => {
+ return (
+ <div className='h-full w-full overflow-x-auto'>
+ <WorkflowApp />
+ </div>
+ )
+}
+export default Page
diff --git "a/app/\050commonLayout\051/app/\050appDetailLayout\051/layout.tsx" "b/app/\050commonLayout\051/app/\050appDetailLayout\051/layout.tsx"
new file mode 100644
index 0000000..dda198f
--- /dev/null
+++ "b/app/\050commonLayout\051/app/\050appDetailLayout\051/layout.tsx"
@@ -0,0 +1,28 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect } from 'react'
+import { useRouter } from 'next/navigation'
+import { useAppContext } from '@/context/app-context'
+
+export type IAppDetail = {
+ children: React.ReactNode
+}
+
+const AppDetail: FC<IAppDetail> = ({ children }) => {
+ const router = useRouter()
+ const { isCurrentWorkspaceDatasetOperator } = useAppContext()
+
+ useEffect(() => {
+ if (isCurrentWorkspaceDatasetOperator)
+ return router.replace('/datasets')
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isCurrentWorkspaceDatasetOperator])
+
+ return (
+ <>
+ {children}
+ </>
+ )
+}
+
+export default React.memo(AppDetail)
diff --git "a/app/\050commonLayout\051/apps/AppCard.tsx" "b/app/\050commonLayout\051/apps/AppCard.tsx"
new file mode 100644
index 0000000..c2ad1f1
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/AppCard.tsx"
@@ -0,0 +1,426 @@
+'use client'
+
+import { useContext, useContextSelector } from 'use-context-selector'
+import { useRouter } from 'next/navigation'
+import { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiMoreFill } from '@remixicon/react'
+import type { App } from '@/types/app'
+import Confirm from '@/app/components/base/confirm'
+import Toast, { ToastContext } from '@/app/components/base/toast'
+import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps'
+import DuplicateAppModal from '@/app/components/app/duplicate-modal'
+import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal'
+import AppIcon from '@/app/components/base/app-icon'
+import AppsContext, { useAppContext } from '@/context/app-context'
+import type { HtmlContentProps } from '@/app/components/base/popover'
+import CustomPopover from '@/app/components/base/popover'
+import Divider from '@/app/components/base/divider'
+import { WEB_PREFIX } from '@/config'
+import { getRedirection } from '@/utils/app-redirection'
+import { useProviderContext } from '@/context/provider-context'
+import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
+import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
+import EditAppModal from '@/app/components/explore/create-app-modal'
+import SwitchAppModal from '@/app/components/app/switch-app-modal'
+import type { Tag } from '@/app/components/base/tag-management/constant'
+import TagSelector from '@/app/components/base/tag-management/selector'
+import type { EnvironmentVariable } from '@/app/components/workflow/types'
+import DSLExportConfirmModal from '@/app/components/workflow/dsl-export-confirm-modal'
+import { fetchWorkflowDraft } from '@/service/workflow'
+import { fetchInstalledAppList } from '@/service/explore'
+import { AppTypeIcon } from '@/app/components/app/type-selector'
+import cn from '@/utils/classnames'
+
+export type AppCardProps = {
+ app: App
+ onRefresh?: () => void
+}
+
+const AppCard = ({ app, onRefresh }: AppCardProps) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const { onPlanInfoChanged } = useProviderContext()
+ const { push } = useRouter()
+
+ const mutateApps = useContextSelector(
+ AppsContext,
+ state => state.mutateApps,
+ )
+
+ const [showEditModal, setShowEditModal] = useState(false)
+ const [showDuplicateModal, setShowDuplicateModal] = useState(false)
+ const [showSwitchModal, setShowSwitchModal] = useState<boolean>(false)
+ const [showConfirmDelete, setShowConfirmDelete] = useState(false)
+ const [secretEnvList, setSecretEnvList] = useState<EnvironmentVariable[]>([])
+
+ const onConfirmDelete = useCallback(async () => {
+ try {
+ await deleteApp(app.id)
+ notify({ type: 'success', message: t('app.appDeleted') })
+ if (onRefresh)
+ onRefresh()
+ mutateApps()
+ onPlanInfoChanged()
+ }
+ catch (e: any) {
+ notify({
+ type: 'error',
+ message: `${t('app.appDeleteFailed')}${'message' in e ? `: ${e.message}` : ''}`,
+ })
+ }
+ setShowConfirmDelete(false)
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [app.id])
+
+ const onEdit: CreateAppModalProps['onConfirm'] = useCallback(async ({
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ description,
+ use_icon_as_answer_icon,
+ }) => {
+ try {
+ await updateAppInfo({
+ appID: app.id,
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ description,
+ use_icon_as_answer_icon,
+ })
+ setShowEditModal(false)
+ notify({
+ type: 'success',
+ message: t('app.editDone'),
+ })
+ if (onRefresh)
+ onRefresh()
+ mutateApps()
+ }
+ catch {
+ notify({ type: 'error', message: t('app.editFailed') })
+ }
+ }, [app.id, mutateApps, notify, onRefresh, t])
+
+ const onCopy: DuplicateAppModalProps['onConfirm'] = async ({ name, icon_type, icon, icon_background }) => {
+ try {
+ const newApp = await copyApp({
+ appID: app.id,
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ mode: app.mode,
+ })
+ setShowDuplicateModal(false)
+ notify({
+ type: 'success',
+ message: t('app.newApp.appCreated'),
+ })
+ localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
+ if (onRefresh)
+ onRefresh()
+ mutateApps()
+ onPlanInfoChanged()
+ getRedirection(isCurrentWorkspaceEditor, newApp, push)
+ }
+ catch {
+ notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
+ }
+ }
+
+ const onExport = async (include = false) => {
+ try {
+ const { data } = await exportAppConfig({
+ appID: app.id,
+ include,
+ })
+ const a = document.createElement('a')
+ const file = new Blob([data], { type: 'application/yaml' })
+ a.href = URL.createObjectURL(file)
+ a.download = `${app.name}.yml`
+ a.click()
+ }
+ catch {
+ notify({ type: 'error', message: t('app.exportFailed') })
+ }
+ }
+
+ const exportCheck = async () => {
+ if (app.mode !== 'workflow' && app.mode !== 'advanced-chat') {
+ onExport()
+ return
+ }
+ try {
+ const workflowDraft = await fetchWorkflowDraft(`/apps/${app.id}/workflows/draft`)
+ const list = (workflowDraft.environment_variables || []).filter(env => env.value_type === 'secret')
+ if (list.length === 0) {
+ onExport()
+ return
+ }
+ setSecretEnvList(list)
+ }
+ catch {
+ notify({ type: 'error', message: t('app.exportFailed') })
+ }
+ }
+
+ const onSwitch = () => {
+ if (onRefresh)
+ onRefresh()
+ mutateApps()
+ setShowSwitchModal(false)
+ }
+
+ const Operations = (props: HtmlContentProps) => {
+ const onMouseLeave = async () => {
+ props.onClose?.()
+ }
+ const onClickSettings = async (e: React.MouseEvent<HTMLButtonElement>) => {
+ e.stopPropagation()
+ props.onClick?.()
+ e.preventDefault()
+ setShowEditModal(true)
+ }
+ const onClickDuplicate = async (e: React.MouseEvent<HTMLButtonElement>) => {
+ e.stopPropagation()
+ props.onClick?.()
+ e.preventDefault()
+ setShowDuplicateModal(true)
+ }
+ const onClickExport = async (e: React.MouseEvent<HTMLButtonElement>) => {
+ e.stopPropagation()
+ props.onClick?.()
+ e.preventDefault()
+ exportCheck()
+ }
+ const onClickSwitch = async (e: React.MouseEvent<HTMLDivElement>) => {
+ e.stopPropagation()
+ props.onClick?.()
+ e.preventDefault()
+ setShowSwitchModal(true)
+ }
+ const onClickDelete = async (e: React.MouseEvent<HTMLDivElement>) => {
+ e.stopPropagation()
+ props.onClick?.()
+ e.preventDefault()
+ setShowConfirmDelete(true)
+ }
+ const onClickInstalledApp = async (e: React.MouseEvent<HTMLButtonElement>) => {
+ e.stopPropagation()
+ props.onClick?.()
+ e.preventDefault()
+ try {
+ const { installed_apps }: any = await fetchInstalledAppList(app.id) || {}
+ if (installed_apps?.length > 0)
+ window.open(`${WEB_PREFIX}/explore/installed/${installed_apps[0].id}`, '_blank')
+ else
+ throw new Error('No app found in Explore')
+ }
+ catch (e: any) {
+ Toast.notify({ type: 'error', message: `${e.message || e}` })
+ }
+ }
+ return (
+ <div className="relative w-full py-1" onMouseLeave={onMouseLeave}>
+ <button className='mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover' onClick={onClickSettings}>
+ <span className='system-sm-regular text-text-secondary'>{t('app.editApp')}</span>
+ </button>
+ <Divider className="!my-1" />
+ <button className='mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover' onClick={onClickDuplicate}>
+ <span className='system-sm-regular text-text-secondary'>{t('app.duplicate')}</span>
+ </button>
+ <button className='mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover' onClick={onClickExport}>
+ <span className='system-sm-regular text-text-secondary'>{t('app.export')}</span>
+ </button>
+ {(app.mode === 'completion' || app.mode === 'chat') && (
+ <>
+ <Divider className="!my-1" />
+ <div
+ className='mx-1 flex h-9 cursor-pointer items-center rounded-lg px-3 py-2 hover:bg-state-base-hover'
+ onClick={onClickSwitch}
+ >
+ <span className='text-sm leading-5 text-text-secondary'>{t('app.switch')}</span>
+ </div>
+ </>
+ )}
+ <Divider className="!my-1" />
+ <button className='mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover' onClick={onClickInstalledApp}>
+ <span className='system-sm-regular text-text-secondary'>{t('app.openInExplore')}</span>
+ </button>
+ <Divider className="!my-1" />
+ <div
+ className='group mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-destructive-hover'
+ onClick={onClickDelete}
+ >
+ <span className='system-sm-regular text-text-secondary group-hover:text-text-destructive'>
+ {t('common.operation.delete')}
+ </span>
+ </div>
+ </div>
+ )
+ }
+
+ const [tags, setTags] = useState<Tag[]>(app.tags)
+ useEffect(() => {
+ setTags(app.tags)
+ }, [app.tags])
+
+ return (
+ <>
+ <div
+ onClick={(e) => {
+ e.preventDefault()
+ getRedirection(isCurrentWorkspaceEditor, app, push)
+ }}
+ className='group relative col-span-1 inline-flex h-[160px] cursor-pointer flex-col rounded-xl border-[1px] border-solid border-components-card-border bg-components-card-bg shadow-sm transition-all duration-200 ease-in-out hover:shadow-lg'
+ >
+ <div className='flex h-[66px] shrink-0 grow-0 items-center gap-3 px-[14px] pb-3 pt-[14px]'>
+ <div className='relative shrink-0'>
+ <AppIcon
+ size="large"
+ iconType={app.icon_type}
+ icon={app.icon}
+ background={app.icon_background}
+ imageUrl={app.icon_url}
+ />
+ <AppTypeIcon type={app.mode} wrapperClassName='absolute -bottom-0.5 -right-0.5 w-4 h-4 shadow-sm' className='h-3 w-3' />
+ </div>
+ <div className='w-0 grow py-[1px]'>
+ <div className='flex items-center text-sm font-semibold leading-5 text-text-secondary'>
+ <div className='truncate' title={app.name}>{app.name}</div>
+ </div>
+ <div className='flex items-center text-[10px] font-medium leading-[18px] text-text-tertiary'>
+ {app.mode === 'advanced-chat' && <div className='truncate'>{t('app.types.advanced').toUpperCase()}</div>}
+ {app.mode === 'chat' && <div className='truncate'>{t('app.types.chatbot').toUpperCase()}</div>}
+ {app.mode === 'agent-chat' && <div className='truncate'>{t('app.types.agent').toUpperCase()}</div>}
+ {app.mode === 'workflow' && <div className='truncate'>{t('app.types.workflow').toUpperCase()}</div>}
+ {app.mode === 'completion' && <div className='truncate'>{t('app.types.completion').toUpperCase()}</div>}
+ </div>
+ </div>
+ </div>
+ <div className='title-wrapper h-[90px] px-[14px] text-xs leading-normal text-text-tertiary'>
+ <div
+ className={cn(tags.length ? 'line-clamp-2' : 'line-clamp-4', 'group-hover:line-clamp-2')}
+ title={app.description}
+ >
+ {app.description}
+ </div>
+ </div>
+ <div className={cn(
+ 'absolute bottom-1 left-0 right-0 h-[42px] shrink-0 items-center pb-[6px] pl-[14px] pr-[6px] pt-1',
+ tags.length ? 'flex' : '!hidden group-hover:!flex',
+ )}>
+ {isCurrentWorkspaceEditor && (
+ <>
+ <div className={cn('flex w-0 grow items-center gap-1')} onClick={(e) => {
+ e.stopPropagation()
+ e.preventDefault()
+ }}>
+ <div className={cn(
+ 'mr-[41px] w-full grow group-hover:!mr-0 group-hover:!block',
+ tags.length ? '!block' : '!hidden',
+ )}>
+ <TagSelector
+ position='bl'
+ type='app'
+ targetID={app.id}
+ value={tags.map(tag => tag.id)}
+ selectedTags={tags}
+ onCacheUpdate={setTags}
+ onChange={onRefresh}
+ />
+ </div>
+ </div>
+ <div className='mx-1 !hidden h-[14px] w-[1px] shrink-0 group-hover:!flex' />
+ <div className='!hidden shrink-0 group-hover:!flex'>
+ <CustomPopover
+ htmlContent={<Operations />}
+ position="br"
+ trigger="click"
+ btnElement={
+ <div
+ className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-md'
+ >
+ <RiMoreFill className='h-4 w-4 text-text-tertiary' />
+ </div>
+ }
+ btnClassName={open =>
+ cn(
+ open ? '!bg-black/5 !shadow-none' : '!bg-transparent',
+ 'h-8 w-8 rounded-md border-none !p-2 hover:!bg-black/5',
+ )
+ }
+ popupClassName={
+ (app.mode === 'completion' || app.mode === 'chat')
+ ? '!w-[256px] translate-x-[-224px]'
+ : '!w-[160px] translate-x-[-128px]'
+ }
+ className={'!z-20 h-fit'}
+ />
+ </div>
+ </>
+ )}
+ </div>
+ </div>
+ {showEditModal && (
+ <EditAppModal
+ isEditModal
+ appName={app.name}
+ appIconType={app.icon_type}
+ appIcon={app.icon}
+ appIconBackground={app.icon_background}
+ appIconUrl={app.icon_url}
+ appDescription={app.description}
+ appMode={app.mode}
+ appUseIconAsAnswerIcon={app.use_icon_as_answer_icon}
+ show={showEditModal}
+ onConfirm={onEdit}
+ onHide={() => setShowEditModal(false)}
+ />
+ )}
+ {showDuplicateModal && (
+ <DuplicateAppModal
+ appName={app.name}
+ icon_type={app.icon_type}
+ icon={app.icon}
+ icon_background={app.icon_background}
+ icon_url={app.icon_url}
+ show={showDuplicateModal}
+ onConfirm={onCopy}
+ onHide={() => setShowDuplicateModal(false)}
+ />
+ )}
+ {showSwitchModal && (
+ <SwitchAppModal
+ show={showSwitchModal}
+ appDetail={app}
+ onClose={() => setShowSwitchModal(false)}
+ onSuccess={onSwitch}
+ />
+ )}
+ {showConfirmDelete && (
+ <Confirm
+ title={t('app.deleteAppConfirmTitle')}
+ content={t('app.deleteAppConfirmContent')}
+ isShow={showConfirmDelete}
+ onConfirm={onConfirmDelete}
+ onCancel={() => setShowConfirmDelete(false)}
+ />
+ )}
+ {secretEnvList.length > 0 && (
+ <DSLExportConfirmModal
+ envList={secretEnvList}
+ onConfirm={onExport}
+ onClose={() => setSecretEnvList([])}
+ />
+ )}
+ </>
+ )
+}
+
+export default AppCard
diff --git "a/app/\050commonLayout\051/apps/Apps.tsx" "b/app/\050commonLayout\051/apps/Apps.tsx"
new file mode 100644
index 0000000..1375f4d
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/Apps.tsx"
@@ -0,0 +1,219 @@
+'use client'
+
+import { useCallback, useEffect, useRef, useState } from 'react'
+import {
+ useRouter,
+} from 'next/navigation'
+import useSWRInfinite from 'swr/infinite'
+import { useTranslation } from 'react-i18next'
+import { useDebounceFn } from 'ahooks'
+import {
+ RiApps2Line,
+ RiExchange2Line,
+ RiFile4Line,
+ RiMessage3Line,
+ RiRobot3Line,
+} from '@remixicon/react'
+import AppCard from './AppCard'
+import NewAppCard from './NewAppCard'
+import useAppsQueryState from './hooks/useAppsQueryState'
+import type { AppListResponse } from '@/models/app'
+import { fetchAppList } from '@/service/apps'
+import { useAppContext } from '@/context/app-context'
+import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
+import { CheckModal } from '@/hooks/use-pay'
+import TabSliderNew from '@/app/components/base/tab-slider-new'
+import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
+import Input from '@/app/components/base/input'
+import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
+import TagManagementModal from '@/app/components/base/tag-management'
+import TagFilter from '@/app/components/base/tag-management/filter'
+import CheckboxWithLabel from '@/app/components/datasets/create/website/base/checkbox-with-label'
+
+const getKey = (
+ pageIndex: number,
+ previousPageData: AppListResponse,
+ activeTab: string,
+ isCreatedByMe: boolean,
+ tags: string[],
+ keywords: string,
+) => {
+ if (!pageIndex || previousPageData.has_more) {
+ const params: any = { url: 'apps', params: { page: pageIndex + 1, limit: 30, name: keywords, is_created_by_me: isCreatedByMe } }
+
+ if (activeTab !== 'all')
+ params.params.mode = activeTab
+ else
+ delete params.params.mode
+
+ if (tags.length)
+ params.params.tag_ids = tags
+
+ return params
+ }
+ return null
+}
+
+const Apps = () => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
+ const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
+ const [activeTab, setActiveTab] = useTabSearchParams({
+ defaultTab: 'all',
+ })
+ const { query: { tagIDs = [], keywords = '', isCreatedByMe: queryIsCreatedByMe = false }, setQuery } = useAppsQueryState()
+ const [isCreatedByMe, setIsCreatedByMe] = useState(queryIsCreatedByMe)
+ const [tagFilterValue, setTagFilterValue] = useState<string[]>(tagIDs)
+ const [searchKeywords, setSearchKeywords] = useState(keywords)
+ const newAppCardRef = useRef<HTMLDivElement>(null)
+ const setKeywords = useCallback((keywords: string) => {
+ setQuery(prev => ({ ...prev, keywords }))
+ }, [setQuery])
+ const setTagIDs = useCallback((tagIDs: string[]) => {
+ setQuery(prev => ({ ...prev, tagIDs }))
+ }, [setQuery])
+
+ const { data, isLoading, error, setSize, mutate } = useSWRInfinite(
+ (pageIndex: number, previousPageData: AppListResponse) => getKey(pageIndex, previousPageData, activeTab, isCreatedByMe, tagIDs, searchKeywords),
+ fetchAppList,
+ {
+ revalidateFirstPage: true,
+ shouldRetryOnError: false,
+ dedupingInterval: 500,
+ errorRetryCount: 3,
+ },
+ )
+
+ const anchorRef = useRef<HTMLDivElement>(null)
+ const options = [
+ { value: 'all', text: t('app.types.all'), icon: <RiApps2Line className='mr-1 h-[14px] w-[14px]' /> },
+ { value: 'chat', text: t('app.types.chatbot'), icon: <RiMessage3Line className='mr-1 h-[14px] w-[14px]' /> },
+ { value: 'agent-chat', text: t('app.types.agent'), icon: <RiRobot3Line className='mr-1 h-[14px] w-[14px]' /> },
+ { value: 'completion', text: t('app.types.completion'), icon: <RiFile4Line className='mr-1 h-[14px] w-[14px]' /> },
+ { value: 'advanced-chat', text: t('app.types.advanced'), icon: <RiMessage3Line className='mr-1 h-[14px] w-[14px]' /> },
+ { value: 'workflow', text: t('app.types.workflow'), icon: <RiExchange2Line className='mr-1 h-[14px] w-[14px]' /> },
+ ]
+
+ useEffect(() => {
+ document.title = `${t('common.menus.apps')} - Dify`
+ if (localStorage.getItem(NEED_REFRESH_APP_LIST_KEY) === '1') {
+ localStorage.removeItem(NEED_REFRESH_APP_LIST_KEY)
+ mutate()
+ }
+ }, [mutate, t])
+
+ useEffect(() => {
+ if (isCurrentWorkspaceDatasetOperator)
+ return router.replace('/datasets')
+ }, [router, isCurrentWorkspaceDatasetOperator])
+
+ useEffect(() => {
+ const hasMore = data?.at(-1)?.has_more ?? true
+ let observer: IntersectionObserver | undefined
+
+ if (error) {
+ if (observer)
+ observer.disconnect()
+ return
+ }
+
+ if (anchorRef.current) {
+ observer = new IntersectionObserver((entries) => {
+ if (entries[0].isIntersecting && !isLoading && !error && hasMore)
+ setSize((size: number) => size + 1)
+ }, { rootMargin: '100px' })
+ observer.observe(anchorRef.current)
+ }
+ return () => observer?.disconnect()
+ }, [isLoading, setSize, anchorRef, mutate, data, error])
+
+ const { run: handleSearch } = useDebounceFn(() => {
+ setSearchKeywords(keywords)
+ }, { wait: 500 })
+ const handleKeywordsChange = (value: string) => {
+ setKeywords(value)
+ handleSearch()
+ }
+
+ const { run: handleTagsUpdate } = useDebounceFn(() => {
+ setTagIDs(tagFilterValue)
+ }, { wait: 500 })
+ const handleTagsChange = (value: string[]) => {
+ setTagFilterValue(value)
+ handleTagsUpdate()
+ }
+
+ const handleCreatedByMeChange = useCallback(() => {
+ const newValue = !isCreatedByMe
+ setIsCreatedByMe(newValue)
+ setQuery(prev => ({ ...prev, isCreatedByMe: newValue }))
+ }, [isCreatedByMe, setQuery])
+
+ return (
+ <>
+ <div className='sticky top-0 z-10 flex flex-wrap items-center justify-between gap-y-2 bg-background-body px-12 pb-2 pt-4 leading-[56px]'>
+ <TabSliderNew
+ value={activeTab}
+ onChange={setActiveTab}
+ options={options}
+ />
+ <div className='flex items-center gap-2'>
+ <CheckboxWithLabel
+ className='mr-2'
+ label={t('app.showMyCreatedAppsOnly')}
+ isChecked={isCreatedByMe}
+ onChange={handleCreatedByMeChange}
+ />
+ <TagFilter type='app' value={tagFilterValue} onChange={handleTagsChange} />
+ <Input
+ showLeftIcon
+ showClearIcon
+ wrapperClassName='w-[200px]'
+ value={keywords}
+ onChange={e => handleKeywordsChange(e.target.value)}
+ onClear={() => handleKeywordsChange('')}
+ />
+ </div>
+ </div>
+ {(data && data[0].total > 0)
+ ? <div className='relative grid grow grid-cols-1 content-start gap-4 px-12 pt-2 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6'>
+ {isCurrentWorkspaceEditor
+ && <NewAppCard ref={newAppCardRef} onSuccess={mutate} />}
+ {data.map(({ data: apps }) => apps.map(app => (
+ <AppCard key={app.id} app={app} onRefresh={mutate} />
+ )))}
+ </div>
+ : <div className='relative grid grow grid-cols-1 content-start gap-4 overflow-hidden px-12 pt-2 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6'>
+ {isCurrentWorkspaceEditor
+ && <NewAppCard ref={newAppCardRef} className='z-10' onSuccess={mutate} />}
+ <NoAppsFound />
+ </div>}
+ <CheckModal />
+ <div ref={anchorRef} className='h-0'> </div>
+ {showTagManagementModal && (
+ <TagManagementModal type='app' show={showTagManagementModal} />
+ )}
+ </>
+ )
+}
+
+export default Apps
+
+function NoAppsFound() {
+ const { t } = useTranslation()
+ function renderDefaultCard() {
+ const defaultCards = Array.from({ length: 36 }, (_, index) => (
+ <div key={index} className='inline-flex h-[160px] rounded-xl bg-background-default-lighter'></div>
+ ))
+ return defaultCards
+ }
+ return (
+ <>
+ {renderDefaultCard()}
+ <div className='absolute bottom-0 left-0 right-0 top-0 flex items-center justify-center bg-gradient-to-t from-background-body to-transparent'>
+ <span className='system-md-medium text-text-tertiary'>{t('app.newApp.noAppsFound')}</span>
+ </div>
+ </>
+ )
+}
diff --git "a/app/\050commonLayout\051/apps/NewAppCard.tsx" "b/app/\050commonLayout\051/apps/NewAppCard.tsx"
new file mode 100644
index 0000000..0b42577
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/NewAppCard.tsx"
@@ -0,0 +1,118 @@
+'use client'
+
+import { useMemo, useState } from 'react'
+import {
+ useRouter,
+ useSearchParams,
+} from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import CreateAppTemplateDialog from '@/app/components/app/create-app-dialog'
+import CreateAppModal from '@/app/components/app/create-app-modal'
+import CreateFromDSLModal, { CreateFromDSLModalTab } from '@/app/components/app/create-from-dsl-modal'
+import { useProviderContext } from '@/context/provider-context'
+import { FileArrow01, FilePlus01, FilePlus02 } from '@/app/components/base/icons/src/vender/line/files'
+import cn from '@/utils/classnames'
+
+export type CreateAppCardProps = {
+ className?: string
+ onSuccess?: () => void
+}
+
+const CreateAppCard = (
+ {
+ ref,
+ className,
+ onSuccess,
+ }: CreateAppCardProps & {
+ ref: React.RefObject<HTMLDivElement>;
+ },
+) => {
+ const { t } = useTranslation()
+ const { onPlanInfoChanged } = useProviderContext()
+ const searchParams = useSearchParams()
+ const { replace } = useRouter()
+ const dslUrl = searchParams.get('remoteInstallUrl') || undefined
+
+ const [showNewAppTemplateDialog, setShowNewAppTemplateDialog] = useState(false)
+ const [showNewAppModal, setShowNewAppModal] = useState(false)
+ const [showCreateFromDSLModal, setShowCreateFromDSLModal] = useState(!!dslUrl)
+
+ const activeTab = useMemo(() => {
+ if (dslUrl)
+ return CreateFromDSLModalTab.FROM_URL
+
+ return undefined
+ }, [dslUrl])
+
+ return (
+ <div
+ ref={ref}
+ className={cn('relative col-span-1 inline-flex h-[160px] flex-col justify-between rounded-xl border-[0.5px] border-components-card-border bg-components-card-bg', className)}
+ >
+ <div className='grow rounded-t-xl p-2'>
+ <div className='px-6 pb-1 pt-2 text-xs font-medium leading-[18px] text-text-tertiary'>{t('app.createApp')}</div>
+ <button className='mb-1 flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] font-medium leading-[18px] text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary' onClick={() => setShowNewAppModal(true)}>
+ <FilePlus01 className='mr-2 h-4 w-4 shrink-0' />
+ {t('app.newApp.startFromBlank')}
+ </button>
+ <button className='flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] font-medium leading-[18px] text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary' onClick={() => setShowNewAppTemplateDialog(true)}>
+ <FilePlus02 className='mr-2 h-4 w-4 shrink-0' />
+ {t('app.newApp.startFromTemplate')}
+ </button>
+ <button
+ onClick={() => setShowCreateFromDSLModal(true)}
+ className='flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] font-medium leading-[18px] text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary'>
+ <FileArrow01 className='mr-2 h-4 w-4 shrink-0' />
+ {t('app.importDSL')}
+ </button>
+ </div>
+
+ <CreateAppModal
+ show={showNewAppModal}
+ onClose={() => setShowNewAppModal(false)}
+ onSuccess={() => {
+ onPlanInfoChanged()
+ if (onSuccess)
+ onSuccess()
+ }}
+ onCreateFromTemplate={() => {
+ setShowNewAppTemplateDialog(true)
+ setShowNewAppModal(false)
+ }}
+ />
+ <CreateAppTemplateDialog
+ show={showNewAppTemplateDialog}
+ onClose={() => setShowNewAppTemplateDialog(false)}
+ onSuccess={() => {
+ onPlanInfoChanged()
+ if (onSuccess)
+ onSuccess()
+ }}
+ onCreateFromBlank={() => {
+ setShowNewAppModal(true)
+ setShowNewAppTemplateDialog(false)
+ }}
+ />
+ <CreateFromDSLModal
+ show={showCreateFromDSLModal}
+ onClose={() => {
+ setShowCreateFromDSLModal(false)
+
+ if (dslUrl)
+ replace('/')
+ }}
+ activeTab={activeTab}
+ dslUrl={dslUrl}
+ onSuccess={() => {
+ onPlanInfoChanged()
+ if (onSuccess)
+ onSuccess()
+ }}
+ />
+ </div>
+ )
+}
+
+CreateAppCard.displayName = 'CreateAppCard'
+export default CreateAppCard
+export { CreateAppCard }
diff --git "a/app/\050commonLayout\051/apps/assets/add.svg" "b/app/\050commonLayout\051/apps/assets/add.svg"
new file mode 100644
index 0000000..9958e85
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/add.svg"
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8 4V8M8 8V12M8 8H12M8 8H4" stroke="#6B7280" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/assets/chat-solid.svg" "b/app/\050commonLayout\051/apps/assets/chat-solid.svg"
new file mode 100644
index 0000000..a793e98
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/chat-solid.svg"
@@ -0,0 +1,4 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M0.631586 8.25C0.631586 6.46656 2.04586 5 3.8158 5C5.58573 5 7.00001 6.46656 7.00001 8.25C7.00001 10.0334 5.58573 11.5 3.8158 11.5C3.45197 11.5 3.10149 11.4375 2.77474 11.3222C2.72073 11.3031 2.68723 11.2913 2.66266 11.2832C2.65821 11.2817 2.65456 11.2806 2.65164 11.2796L2.64892 11.2799C2.63177 11.2818 2.60839 11.285 2.56507 11.2909L1.06766 11.4954C0.905637 11.5175 0.743029 11.459 0.632239 11.3387C0.521449 11.2185 0.476481 11.0516 0.511825 10.8919L0.817497 9.51109C0.828118 9.46311 0.833802 9.43722 0.837453 9.41817C0.83766 9.4171 0.838022 9.41517 0.838022 9.41517C0.837114 9.412 0.835963 9.40808 0.834525 9.40332C0.826292 9.37605 0.814183 9.33888 0.794499 9.27863C0.688657 8.95463 0.631586 8.60857 0.631586 8.25Z" fill="#98A2B3"/>
+<path d="M2.57377 4.1863C2.96256 4.06535 3.37698 4 3.80894 4C6.16566 4 8.00006 5.94534 8.00006 8.24999C8.00006 8.65682 7.9429 9.05245 7.8358 9.42816C8.10681 9.37948 8.36964 9.30678 8.6219 9.21229C8.65748 9.19897 8.69298 9.18534 8.72893 9.17304C8.75795 9.17641 8.78684 9.18093 8.81574 9.18517L10.4222 9.42065C10.498 9.43179 10.5841 9.44444 10.6591 9.4487C10.7422 9.45343 10.8713 9.45292 11.0081 9.39408C11.1789 9.32061 11.3164 9.18628 11.3938 9.01716C11.4558 8.88174 11.4593 8.75269 11.4564 8.66955C11.4539 8.59442 11.4433 8.5081 11.4339 8.43202L11.2309 6.78307C11.2256 6.7402 11.2229 6.71768 11.2213 6.70118C11.23 6.66505 11.2466 6.6301 11.2598 6.59546C11.4492 6.09896 11.5526 5.56093 11.5526 5C11.5526 2.51163 9.52304 0.5 7.02632 0.5C4.80843 0.5 2.95915 2.08742 2.57377 4.1863Z" fill="#98A2B3"/>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/assets/chat.svg" "b/app/\050commonLayout\051/apps/assets/chat.svg"
new file mode 100644
index 0000000..0971349
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/chat.svg"
@@ -0,0 +1,3 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.1667 6.66634H15.8333C16.2754 6.66634 16.6993 6.84194 17.0118 7.1545C17.3244 7.46706 17.5 7.89098 17.5 8.33301V13.333C17.5 13.775 17.3244 14.199 17.0118 14.5115C16.6993 14.8241 16.2754 14.9997 15.8333 14.9997H14.1667V18.333L10.8333 14.9997H7.5C7.28111 14.9999 7.06433 14.9569 6.86211 14.8731C6.6599 14.7893 6.47623 14.6663 6.32167 14.5113M6.32167 14.5113L9.16667 11.6663H12.5C12.942 11.6663 13.366 11.4907 13.6785 11.1782C13.9911 10.8656 14.1667 10.4417 14.1667 9.99967V4.99967C14.1667 4.55765 13.9911 4.13372 13.6785 3.82116C13.366 3.5086 12.942 3.33301 12.5 3.33301H4.16667C3.72464 3.33301 3.30072 3.5086 2.98816 3.82116C2.67559 4.13372 2.5 4.55765 2.5 4.99967V9.99967C2.5 10.4417 2.67559 10.8656 2.98816 11.1782C3.30072 11.4907 3.72464 11.6663 4.16667 11.6663H5.83333V14.9997L6.32167 14.5113Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/assets/completion-solid.svg" "b/app/\050commonLayout\051/apps/assets/completion-solid.svg"
new file mode 100644
index 0000000..a9dc7e3
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/completion-solid.svg"
@@ -0,0 +1,4 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.5 1.00779C6.5 0.994638 6.5 0.988062 6.49943 0.976137C6.48764 0.729248 6.27052 0.51224 6.02363 0.50056C6.01171 0.499996 6.0078 0.499998 6.00001 0.5H4.37933C3.97686 0.499995 3.64468 0.49999 3.37409 0.522098C3.09304 0.545061 2.83469 0.594343 2.59202 0.717989C2.2157 0.909735 1.90973 1.2157 1.71799 1.59202C1.59434 1.83469 1.54506 2.09304 1.5221 2.37409C1.49999 2.64468 1.49999 2.97686 1.5 3.37934V8.62066C1.49999 9.02313 1.49999 9.35532 1.5221 9.62591C1.54506 9.90696 1.59434 10.1653 1.71799 10.408C1.90973 10.7843 2.2157 11.0903 2.59202 11.282C2.83469 11.4057 3.09304 11.4549 3.37409 11.4779C3.64468 11.5 3.97686 11.5 4.37934 11.5H7.62066C8.02314 11.5 8.35532 11.5 8.62591 11.4779C8.90696 11.4549 9.16531 11.4057 9.40798 11.282C9.78431 11.0903 10.0903 10.7843 10.282 10.408C10.4057 10.1653 10.4549 9.90696 10.4779 9.62591C10.5 9.35532 10.5 9.02314 10.5 8.62066V4.99997C10.5 4.9922 10.5 4.98832 10.4994 4.97641C10.4878 4.72949 10.2707 4.51236 10.0238 4.50057C10.0119 4.50001 10.0054 4.50001 9.99225 4.50001L7.78404 4.50001C7.65786 4.50002 7.53496 4.50004 7.43089 4.49153C7.31659 4.48219 7.18172 4.46016 7.04601 4.39101C6.85785 4.29514 6.70487 4.14216 6.609 3.954C6.53985 3.81828 6.51781 3.68342 6.50848 3.56912C6.49997 3.46504 6.49999 3.34215 6.5 3.21596L6.5 1.00779ZM4 6.5C3.72386 6.5 3.5 6.72386 3.5 7C3.5 7.27614 3.72386 7.5 4 7.5H8C8.27614 7.5 8.5 7.27614 8.5 7C8.5 6.72386 8.27614 6.5 8 6.5H4ZM4 8.5C3.72386 8.5 3.5 8.72386 3.5 9C3.5 9.27614 3.72386 9.5 4 9.5H7C7.27614 9.5 7.5 9.27614 7.5 9C7.5 8.72386 7.27614 8.5 7 8.5H4Z" fill="#98A2B3"/>
+<path d="M9.45398 3.5C9.60079 3.5 9.67419 3.5 9.73432 3.46314C9.81925 3.41107 9.87002 3.28842 9.84674 3.19157C9.83025 3.12299 9.78238 3.07516 9.68665 2.97952L8.02049 1.31336C7.92484 1.21762 7.87701 1.16975 7.80843 1.15326C7.71158 1.12998 7.58893 1.18075 7.53687 1.26567C7.5 1.3258 7.5 1.39921 7.5 1.54602L7.5 3.09998C7.5 3.23999 7.5 3.30999 7.52725 3.36347C7.55122 3.41051 7.58946 3.44876 7.6365 3.47272C7.68998 3.49997 7.75998 3.49997 7.9 3.49998L9.45398 3.5Z" fill="#98A2B3"/>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/assets/completion.svg" "b/app/\050commonLayout\051/apps/assets/completion.svg"
new file mode 100644
index 0000000..34af441
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/completion.svg"
@@ -0,0 +1,3 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M16.25 11.875V9.6875C16.25 8.1342 14.9908 6.875 13.4375 6.875H12.1875C11.6697 6.875 11.25 6.45527 11.25 5.9375V4.6875C11.25 3.1342 9.9908 1.875 8.4375 1.875H6.875M6.875 12.5H13.125M6.875 15H10M8.75 1.875H4.6875C4.16973 1.875 3.75 2.29473 3.75 2.8125V17.1875C3.75 17.7053 4.16973 18.125 4.6875 18.125H15.3125C15.8303 18.125 16.25 17.7053 16.25 17.1875V9.375C16.25 5.23286 12.8921 1.875 8.75 1.875Z" stroke="#1F2A37" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/assets/discord.svg" "b/app/\050commonLayout\051/apps/assets/discord.svg"
new file mode 100644
index 0000000..9f22a1a
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/discord.svg"
@@ -0,0 +1,3 @@
+<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M22.0101 4.50191C20.3529 3.74154 18.5759 3.18133 16.7179 2.86048C16.6841 2.85428 16.6503 2.86976 16.6328 2.90071C16.4043 3.30719 16.1511 3.83748 15.9738 4.25429C13.9754 3.95511 11.9873 3.95511 10.0298 4.25429C9.85253 3.82822 9.59019 3.30719 9.36062 2.90071C9.34319 2.87079 9.30939 2.85532 9.27555 2.86048C7.41857 3.18031 5.64152 3.74051 3.98335 4.50191C3.96899 4.5081 3.95669 4.51843 3.94852 4.53183C0.577841 9.56755 -0.345529 14.4795 0.107445 19.3306C0.109495 19.3543 0.122817 19.377 0.141265 19.3914C2.36514 21.0246 4.51935 22.0161 6.63355 22.6732C6.66739 22.6836 6.70324 22.6712 6.72477 22.6433C7.22489 21.9604 7.6707 21.2402 8.05293 20.4829C8.07549 20.4386 8.05396 20.386 8.00785 20.3684C7.30073 20.1002 6.6274 19.7731 5.97971 19.4017C5.92848 19.3718 5.92437 19.2985 5.9715 19.2635C6.1078 19.1613 6.24414 19.0551 6.37428 18.9478C6.39783 18.9282 6.43064 18.924 6.45833 18.9364C10.7134 20.8791 15.32 20.8791 19.5249 18.9364C19.5525 18.923 19.5854 18.9272 19.6099 18.9467C19.7401 19.054 19.8764 19.1613 20.0137 19.2635C20.0609 19.2985 20.0578 19.3718 20.0066 19.4017C19.3589 19.7804 18.6855 20.1002 17.9774 20.3674C17.9313 20.3849 17.9108 20.4386 17.9333 20.4829C18.3238 21.2392 18.7696 21.9593 19.2605 22.6423C19.281 22.6712 19.3179 22.6836 19.3517 22.6732C21.4761 22.0161 23.6303 21.0246 25.8542 19.3914C25.8737 19.377 25.886 19.3553 25.8881 19.3316C26.4302 13.7232 24.98 8.85156 22.0439 4.53286C22.0367 4.51843 22.0245 4.5081 22.0101 4.50191ZM8.68836 16.3768C7.40729 16.3768 6.35173 15.2007 6.35173 13.7563C6.35173 12.3119 7.38682 11.1358 8.68836 11.1358C10.0001 11.1358 11.0455 12.3222 11.025 13.7563C11.025 15.2007 9.98986 16.3768 8.68836 16.3768ZM17.3276 16.3768C16.0466 16.3768 14.991 15.2007 14.991 13.7563C14.991 12.3119 16.0261 11.1358 17.3276 11.1358C18.6394 11.1358 19.6847 12.3222 19.6643 13.7563C19.6643 15.2007 18.6394 16.3768 17.3276 16.3768Z" fill="#5865F2"/>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/assets/github.svg" "b/app/\050commonLayout\051/apps/assets/github.svg"
new file mode 100644
index 0000000..f03798b
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/github.svg"
@@ -0,0 +1,17 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_131_1011)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0003 0.5C9.15149 0.501478 6.39613 1.51046 4.22687 3.34652C2.05761 5.18259 0.615903 7.72601 0.159545 10.522C-0.296814 13.318 0.261927 16.1842 1.73587 18.6082C3.20981 21.0321 5.50284 22.8558 8.20493 23.753C8.80105 23.8636 9.0256 23.4941 9.0256 23.18C9.0256 22.8658 9.01367 21.955 9.0097 20.9592C5.6714 21.6804 4.96599 19.5505 4.96599 19.5505C4.42152 18.1674 3.63464 17.8039 3.63464 17.8039C2.54571 17.065 3.71611 17.0788 3.71611 17.0788C4.92227 17.1637 5.55616 18.3097 5.55616 18.3097C6.62521 20.1333 8.36389 19.6058 9.04745 19.2976C9.15475 18.5251 9.46673 17.9995 9.8105 17.7012C7.14383 17.4008 4.34204 16.3774 4.34204 11.8054C4.32551 10.6197 4.76802 9.47305 5.57801 8.60268C5.45481 8.30236 5.04348 7.08923 5.69524 5.44143C5.69524 5.44143 6.7027 5.12135 8.9958 6.66444C10.9627 6.12962 13.0379 6.12962 15.0047 6.66444C17.2958 5.12135 18.3013 5.44143 18.3013 5.44143C18.9551 7.08528 18.5437 8.29841 18.4205 8.60268C19.2331 9.47319 19.6765 10.6218 19.6585 11.8094C19.6585 16.3912 16.8507 17.4008 14.1801 17.6952C14.6093 18.0667 14.9928 18.7918 14.9928 19.9061C14.9928 21.5026 14.9789 22.7868 14.9789 23.18C14.9789 23.4981 15.1955 23.8695 15.8035 23.753C18.5059 22.8557 20.7992 21.0317 22.2731 18.6073C23.747 16.183 24.3055 13.3163 23.8486 10.5201C23.3917 7.7238 21.9493 5.18035 19.7793 3.34461C17.6093 1.50886 14.8533 0.500541 12.0042 0.5H12.0003Z" fill="#191717"/>
+<path d="M4.54444 17.6321C4.5186 17.6914 4.42322 17.7092 4.34573 17.6677C4.26823 17.6262 4.21061 17.5491 4.23843 17.4879C4.26625 17.4266 4.35964 17.4108 4.43714 17.4523C4.51463 17.4938 4.57424 17.5729 4.54444 17.6321Z" fill="#191717"/>
+<path d="M5.03123 18.1714C4.99008 18.192 4.943 18.1978 4.89805 18.1877C4.8531 18.1776 4.81308 18.1523 4.78483 18.1161C4.70734 18.0331 4.69143 17.9185 4.75104 17.8671C4.81066 17.8157 4.91797 17.8395 4.99546 17.9224C5.07296 18.0054 5.09084 18.12 5.03123 18.1714Z" fill="#191717"/>
+<path d="M5.50425 18.857C5.43072 18.9084 5.30553 18.857 5.23598 18.7543C5.21675 18.7359 5.20146 18.7138 5.19101 18.6893C5.18056 18.6649 5.17517 18.6386 5.17517 18.612C5.17517 18.5855 5.18056 18.5592 5.19101 18.5347C5.20146 18.5103 5.21675 18.4882 5.23598 18.4698C5.3095 18.4204 5.4347 18.4698 5.50425 18.5705C5.57379 18.6713 5.57578 18.8057 5.50425 18.857V18.857Z" fill="#191717"/>
+<path d="M6.14612 19.5207C6.08054 19.5939 5.94741 19.5741 5.83812 19.4753C5.72883 19.3765 5.70299 19.2422 5.76857 19.171C5.83414 19.0999 5.96727 19.1197 6.08054 19.2165C6.1938 19.3133 6.21566 19.4496 6.14612 19.5207V19.5207Z" fill="#191717"/>
+<path d="M7.04617 19.9081C7.01637 20.001 6.88124 20.0425 6.74612 20.003C6.611 19.9635 6.52158 19.8528 6.54741 19.758C6.57325 19.6631 6.71036 19.6197 6.84747 19.6631C6.98457 19.7066 7.07201 19.8113 7.04617 19.9081Z" fill="#191717"/>
+<path d="M8.02783 19.9752C8.02783 20.072 7.91656 20.155 7.77349 20.1569C7.63042 20.1589 7.51318 20.0799 7.51318 19.9831C7.51318 19.8863 7.62445 19.8033 7.76752 19.8013C7.91059 19.7993 8.02783 19.8764 8.02783 19.9752Z" fill="#191717"/>
+<path d="M8.9419 19.8232C8.95978 19.92 8.86042 20.0207 8.71735 20.0445C8.57428 20.0682 8.4491 20.0109 8.43121 19.916C8.41333 19.8212 8.51666 19.7185 8.65576 19.6928C8.79485 19.6671 8.92401 19.7264 8.9419 19.8232Z" fill="#191717"/>
+</g>
+<defs>
+<clipPath id="clip0_131_1011">
+<rect width="24" height="24" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/assets/link-gray.svg" "b/app/\050commonLayout\051/apps/assets/link-gray.svg"
new file mode 100644
index 0000000..a293cfc
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/link-gray.svg"
@@ -0,0 +1,3 @@
+<svg width="13" height="14" viewBox="0 0 13 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.41663 3.75033H3.24996C2.96264 3.75033 2.68709 3.86446 2.48393 4.06763C2.28076 4.27079 2.16663 4.54634 2.16663 4.83366V10.2503C2.16663 10.5376 2.28076 10.8132 2.48393 11.0164C2.68709 11.2195 2.96264 11.3337 3.24996 11.3337H8.66663C8.95394 11.3337 9.22949 11.2195 9.43266 11.0164C9.63582 10.8132 9.74996 10.5376 9.74996 10.2503V8.08366M7.58329 2.66699H10.8333M10.8333 2.66699V5.91699M10.8333 2.66699L5.41663 8.08366" stroke="#9CA3AF" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/assets/link.svg" "b/app/\050commonLayout\051/apps/assets/link.svg"
new file mode 100644
index 0000000..2926c28
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/link.svg"
@@ -0,0 +1,3 @@
+<svg width="13" height="14" viewBox="0 0 13 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.41663 3.75008H3.24996C2.96264 3.75008 2.68709 3.86422 2.48393 4.06738C2.28076 4.27055 2.16663 4.5461 2.16663 4.83341V10.2501C2.16663 10.5374 2.28076 10.8129 2.48393 11.0161C2.68709 11.2193 2.96264 11.3334 3.24996 11.3334H8.66663C8.95394 11.3334 9.22949 11.2193 9.43266 11.0161C9.63582 10.8129 9.74996 10.5374 9.74996 10.2501V8.08341M7.58329 2.66675H10.8333M10.8333 2.66675V5.91675M10.8333 2.66675L5.41663 8.08341" stroke="#1C64F2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/assets/right-arrow.svg" "b/app/\050commonLayout\051/apps/assets/right-arrow.svg"
new file mode 100644
index 0000000..a2c1ced
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/assets/right-arrow.svg"
@@ -0,0 +1,3 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7 2.5L10.5 6M10.5 6L7 9.5M10.5 6H1.5" stroke="#1C64F2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git "a/app/\050commonLayout\051/apps/hooks/useAppsQueryState.ts" "b/app/\050commonLayout\051/apps/hooks/useAppsQueryState.ts"
new file mode 100644
index 0000000..dc95a4b
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/hooks/useAppsQueryState.ts"
@@ -0,0 +1,60 @@
+import { type ReadonlyURLSearchParams, usePathname, useRouter, useSearchParams } from 'next/navigation'
+import { useCallback, useEffect, useMemo, useState } from 'react'
+
+type AppsQuery = {
+ tagIDs?: string[]
+ keywords?: string
+ isCreatedByMe?: boolean
+}
+
+// Parse the query parameters from the URL search string.
+function parseParams(params: ReadonlyURLSearchParams): AppsQuery {
+ const tagIDs = params.get('tagIDs')?.split(';')
+ const keywords = params.get('keywords') || undefined
+ const isCreatedByMe = params.get('isCreatedByMe') === 'true'
+ return { tagIDs, keywords, isCreatedByMe }
+}
+
+// Update the URL search string with the given query parameters.
+function updateSearchParams(query: AppsQuery, current: URLSearchParams) {
+ const { tagIDs, keywords, isCreatedByMe } = query || {}
+
+ if (tagIDs && tagIDs.length > 0)
+ current.set('tagIDs', tagIDs.join(';'))
+ else
+ current.delete('tagIDs')
+
+ if (keywords)
+ current.set('keywords', keywords)
+ else
+ current.delete('keywords')
+
+ if (isCreatedByMe)
+ current.set('isCreatedByMe', 'true')
+ else
+ current.delete('isCreatedByMe')
+}
+
+function useAppsQueryState() {
+ const searchParams = useSearchParams()
+ const [query, setQuery] = useState<AppsQuery>(() => parseParams(searchParams))
+
+ const router = useRouter()
+ const pathname = usePathname()
+ const syncSearchParams = useCallback((params: URLSearchParams) => {
+ const search = params.toString()
+ const query = search ? `?${search}` : ''
+ router.push(`${pathname}${query}`, { scroll: false })
+ }, [router, pathname])
+
+ // Update the URL search string whenever the query changes.
+ useEffect(() => {
+ const params = new URLSearchParams(searchParams)
+ updateSearchParams(query, params)
+ syncSearchParams(params)
+ }, [query, searchParams, syncSearchParams])
+
+ return useMemo(() => ({ query, setQuery }), [query])
+}
+
+export default useAppsQueryState
diff --git "a/app/\050commonLayout\051/apps/page.tsx" "b/app/\050commonLayout\051/apps/page.tsx"
new file mode 100644
index 0000000..4a146d9
--- /dev/null
+++ "b/app/\050commonLayout\051/apps/page.tsx"
@@ -0,0 +1,37 @@
+'use client'
+import { useContextSelector } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { RiDiscordFill, RiGithubFill } from '@remixicon/react'
+import Link from 'next/link'
+import style from '../list.module.css'
+import Apps from './Apps'
+import AppContext from '@/context/app-context'
+import { LicenseStatus } from '@/types/feature'
+import { useEducationInit } from '@/app/education-apply/hooks'
+
+const AppList = () => {
+ const { t } = useTranslation()
+ useEducationInit()
+
+ const systemFeatures = useContextSelector(AppContext, v => v.systemFeatures)
+
+ return (
+ <div className='relative flex h-0 shrink-0 grow flex-col overflow-y-auto bg-background-body'>
+ <Apps />
+ {systemFeatures.license.status === LicenseStatus.NONE && <footer className='shrink-0 grow-0 px-12 py-6'>
+ <h3 className='text-gradient text-xl font-semibold leading-tight'>{t('app.join')}</h3>
+ <p className='system-sm-regular mt-1 text-text-tertiary'>{t('app.communityIntro')}</p>
+ <div className='mt-3 flex items-center gap-2'>
+ <Link className={style.socialMediaLink} target='_blank' rel='noopener noreferrer' href='https://github.com/langgenius/dify'>
+ <RiGithubFill className='h-5 w-5 text-text-tertiary' />
+ </Link>
+ <Link className={style.socialMediaLink} target='_blank' rel='noopener noreferrer' href='https://discord.gg/FngNHpbcY7'>
+ <RiDiscordFill className='h-5 w-5 text-text-tertiary' />
+ </Link>
+ </div>
+ </footer>}
+ </div >
+ )
+}
+
+export default AppList
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/api/page.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/api/page.tsx"
new file mode 100644
index 0000000..167520c
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/api/page.tsx"
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const page = () => {
+ return (
+ <div>dataset detail api</div>
+ )
+}
+
+export default page
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/\133documentId\135/page.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/\133documentId\135/page.tsx"
new file mode 100644
index 0000000..1db6b66
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/\133documentId\135/page.tsx"
@@ -0,0 +1,21 @@
+import React from 'react'
+import MainDetail from '@/app/components/datasets/documents/detail'
+
+export type IDocumentDetailProps = {
+ params: Promise<{ datasetId: string; documentId: string }>
+}
+
+const DocumentDetail = async (props: IDocumentDetailProps) => {
+ const params = await props.params
+
+ const {
+ datasetId,
+ documentId,
+ } = params
+
+ return (
+ <MainDetail datasetId={datasetId} documentId={documentId} />
+ )
+}
+
+export default DocumentDetail
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/\133documentId\135/settings/page.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/\133documentId\135/settings/page.tsx"
new file mode 100644
index 0000000..5395214
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/\133documentId\135/settings/page.tsx"
@@ -0,0 +1,21 @@
+import React from 'react'
+import Settings from '@/app/components/datasets/documents/detail/settings'
+
+export type IProps = {
+ params: Promise<{ datasetId: string; documentId: string }>
+}
+
+const DocumentSettings = async (props: IProps) => {
+ const params = await props.params
+
+ const {
+ datasetId,
+ documentId,
+ } = params
+
+ return (
+ <Settings datasetId={datasetId} documentId={documentId} />
+ )
+}
+
+export default DocumentSettings
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/create/page.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/create/page.tsx"
new file mode 100644
index 0000000..8fd2caa
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/create/page.tsx"
@@ -0,0 +1,20 @@
+import React from 'react'
+import DatasetUpdateForm from '@/app/components/datasets/create'
+
+export type IProps = {
+ params: Promise<{ datasetId: string }>
+}
+
+const Create = async (props: IProps) => {
+ const params = await props.params
+
+ const {
+ datasetId,
+ } = params
+
+ return (
+ <DatasetUpdateForm datasetId={datasetId} />
+ )
+}
+
+export default Create
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/page.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/page.tsx"
new file mode 100644
index 0000000..2ff4631
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/page.tsx"
@@ -0,0 +1,20 @@
+import React from 'react'
+import Main from '@/app/components/datasets/documents'
+
+export type IProps = {
+ params: Promise<{ datasetId: string }>
+}
+
+const Documents = async (props: IProps) => {
+ const params = await props.params
+
+ const {
+ datasetId,
+ } = params
+
+ return (
+ <Main datasetId={datasetId} />
+ )
+}
+
+export default Documents
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/style.module.css" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/style.module.css"
new file mode 100644
index 0000000..67a9fe3
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/documents/style.module.css"
@@ -0,0 +1,9 @@
+.logTable td {
+ padding: 7px 8px;
+ box-sizing: border-box;
+ max-width: 200px;
+}
+
+.pagination li {
+ list-style: none;
+}
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/hitTesting/page.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/hitTesting/page.tsx"
new file mode 100644
index 0000000..9a701c6
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/hitTesting/page.tsx"
@@ -0,0 +1,20 @@
+import React from 'react'
+import Main from '@/app/components/datasets/hit-testing'
+
+type Props = {
+ params: Promise<{ datasetId: string }>
+}
+
+const HitTesting = async (props: Props) => {
+ const params = await props.params
+
+ const {
+ datasetId,
+ } = params
+
+ return (
+ <Main datasetId={datasetId} />
+ )
+}
+
+export default HitTesting
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/layout-main.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/layout-main.tsx"
new file mode 100644
index 0000000..5619b1e
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/layout-main.tsx"
@@ -0,0 +1,199 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useMemo } from 'react'
+import { usePathname } from 'next/navigation'
+import useSWR from 'swr'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import {
+ RiEqualizer2Fill,
+ RiEqualizer2Line,
+ RiFileTextFill,
+ RiFileTextLine,
+ RiFocus2Fill,
+ RiFocus2Line,
+} from '@remixicon/react'
+import {
+ PaperClipIcon,
+} from '@heroicons/react/24/outline'
+import { RiApps2AddLine, RiBookOpenLine, RiInformation2Line } from '@remixicon/react'
+import classNames from '@/utils/classnames'
+import { fetchDatasetDetail, fetchDatasetRelatedApps } from '@/service/datasets'
+import type { RelatedAppResponse } from '@/models/datasets'
+import AppSideBar from '@/app/components/app-sidebar'
+import Loading from '@/app/components/base/loading'
+import DatasetDetailContext from '@/context/dataset-detail'
+import { DataSourceType } from '@/models/datasets'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import { LanguagesSupported } from '@/i18n/language'
+import { useStore } from '@/app/components/app/store'
+import { getLocaleOnClient } from '@/i18n'
+import { useAppContext } from '@/context/app-context'
+import Tooltip from '@/app/components/base/tooltip'
+import LinkedAppsPanel from '@/app/components/base/linked-apps-panel'
+
+export type IAppDetailLayoutProps = {
+ children: React.ReactNode
+ params: { datasetId: string }
+}
+
+type IExtraInfoProps = {
+ isMobile: boolean
+ relatedApps?: RelatedAppResponse
+ expand: boolean
+}
+
+const ExtraInfo = ({ isMobile, relatedApps, expand }: IExtraInfoProps) => {
+ const locale = getLocaleOnClient()
+ const [isShowTips, { toggle: toggleTips, set: setShowTips }] = useBoolean(!isMobile)
+ const { t } = useTranslation()
+
+ const hasRelatedApps = relatedApps?.data && relatedApps?.data?.length > 0
+ const relatedAppsTotal = relatedApps?.data?.length || 0
+
+ useEffect(() => {
+ setShowTips(!isMobile)
+ }, [isMobile, setShowTips])
+
+ return <div>
+ {hasRelatedApps && (
+ <>
+ {!isMobile && (
+ <Tooltip
+ position='right'
+ noDecoration
+ needsDelay
+ popupContent={
+ <LinkedAppsPanel
+ relatedApps={relatedApps.data}
+ isMobile={isMobile}
+ />
+ }
+ >
+ <div className='system-xs-medium-uppercase inline-flex cursor-pointer items-center space-x-1 text-text-secondary'>
+ <span>{relatedAppsTotal || '--'} {t('common.datasetMenus.relatedApp')}</span>
+ <RiInformation2Line className='h-4 w-4' />
+ </div>
+ </Tooltip>
+ )}
+
+ {isMobile && <div className={classNames('uppercase text-xs text-text-tertiary font-medium pb-2 pt-4', 'flex items-center justify-center !px-0 gap-1')}>
+ {relatedAppsTotal || '--'}
+ <PaperClipIcon className='h-4 w-4 text-text-secondary' />
+ </div>}
+ </>
+ )}
+ {!hasRelatedApps && !expand && (
+ <Tooltip
+ position='right'
+ noDecoration
+ needsDelay
+ popupContent={
+ <div className='w-[240px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-4'>
+ <div className='inline-flex rounded-lg border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle p-2'>
+ <RiApps2AddLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div className='my-2 text-xs text-text-tertiary'>{t('common.datasetMenus.emptyTip')}</div>
+ <a
+ className='mt-2 inline-flex cursor-pointer items-center text-xs text-text-accent'
+ href={
+ locale === LanguagesSupported[1]
+ ? 'https://docs.dify.ai/zh-hans/guides/knowledge-base/integrate-knowledge-within-application'
+ : 'https://docs.dify.ai/guides/knowledge-base/integrate-knowledge-within-application'
+ }
+ target='_blank' rel='noopener noreferrer'
+ >
+ <RiBookOpenLine className='mr-1 text-text-accent' />
+ {t('common.datasetMenus.viewDoc')}
+ </a>
+ </div>
+ }
+ >
+ <div className='system-xs-medium-uppercase inline-flex cursor-pointer items-center space-x-1 text-text-secondary'>
+ <span>{t('common.datasetMenus.noRelatedApp')}</span>
+ <RiInformation2Line className='h-4 w-4' />
+ </div>
+ </Tooltip>
+ )}
+ </div>
+}
+
+const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
+ const {
+ children,
+ params: { datasetId },
+ } = props
+ const pathname = usePathname()
+ const hideSideBar = /documents\/create$/.test(pathname)
+ const { t } = useTranslation()
+ const { isCurrentWorkspaceDatasetOperator } = useAppContext()
+
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ const { data: datasetRes, error, mutate: mutateDatasetRes } = useSWR({
+ url: 'fetchDatasetDetail',
+ datasetId,
+ }, apiParams => fetchDatasetDetail(apiParams.datasetId))
+
+ const { data: relatedApps } = useSWR({
+ action: 'fetchDatasetRelatedApps',
+ datasetId,
+ }, apiParams => fetchDatasetRelatedApps(apiParams.datasetId))
+
+ const navigation = useMemo(() => {
+ const baseNavigation = [
+ { name: t('common.datasetMenus.hitTesting'), href: `/datasets/${datasetId}/hitTesting`, icon: RiFocus2Line, selectedIcon: RiFocus2Fill },
+ { name: t('common.datasetMenus.settings'), href: `/datasets/${datasetId}/settings`, icon: RiEqualizer2Line, selectedIcon: RiEqualizer2Fill },
+ ]
+
+ if (datasetRes?.provider !== 'external') {
+ baseNavigation.unshift({
+ name: t('common.datasetMenus.documents'),
+ href: `/datasets/${datasetId}/documents`,
+ icon: RiFileTextLine,
+ selectedIcon: RiFileTextFill,
+ })
+ }
+ return baseNavigation
+ }, [datasetRes?.provider, datasetId, t])
+
+ useEffect(() => {
+ if (datasetRes)
+ document.title = `${datasetRes.name || 'Dataset'} - Dify`
+ }, [datasetRes])
+
+ const setAppSiderbarExpand = useStore(state => state.setAppSiderbarExpand)
+
+ useEffect(() => {
+ const localeMode = localStorage.getItem('app-detail-collapse-or-expand') || 'expand'
+ const mode = isMobile ? 'collapse' : 'expand'
+ setAppSiderbarExpand(isMobile ? mode : localeMode)
+ }, [isMobile, setAppSiderbarExpand])
+
+ if (!datasetRes && !error)
+ return <Loading type='app' />
+
+ return (
+ <div className='flex grow overflow-hidden'>
+ {!hideSideBar && <AppSideBar
+ title={datasetRes?.name || '--'}
+ icon={datasetRes?.icon || 'https://static.dify.ai/images/dataset-default-icon.png'}
+ icon_background={datasetRes?.icon_background || '#F5F5F5'}
+ desc={datasetRes?.description || '--'}
+ isExternal={datasetRes?.provider === 'external'}
+ navigation={navigation}
+ extraInfo={!isCurrentWorkspaceDatasetOperator ? mode => <ExtraInfo isMobile={mode === 'collapse'} relatedApps={relatedApps} expand={mode === 'collapse'} /> : undefined}
+ iconType={datasetRes?.data_source_type === DataSourceType.NOTION ? 'notion' : 'dataset'}
+ />}
+ <DatasetDetailContext.Provider value={{
+ indexingTechnique: datasetRes?.indexing_technique,
+ dataset: datasetRes,
+ mutateDatasetRes: () => mutateDatasetRes(),
+ }}>
+ <div className="grow overflow-hidden bg-background-default-subtle">{children}</div>
+ </DatasetDetailContext.Provider>
+ </div>
+ )
+}
+export default React.memo(DatasetDetailLayout)
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/layout.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/layout.tsx"
new file mode 100644
index 0000000..a8772f7
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/layout.tsx"
@@ -0,0 +1,17 @@
+import Main from './layout-main'
+
+const DatasetDetailLayout = async (
+ props: {
+ children: React.ReactNode
+ params: Promise<{ datasetId: string }>
+ },
+) => {
+ const params = await props.params
+
+ const {
+ children,
+ } = props
+
+ return <Main params={(await params)}>{children}</Main>
+}
+export default DatasetDetailLayout
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/settings/page.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/settings/page.tsx"
new file mode 100644
index 0000000..d9a196d
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/\133datasetId\135/settings/page.tsx"
@@ -0,0 +1,20 @@
+import React from 'react'
+import { getLocaleOnServer, useTranslation as translate } from '@/i18n/server'
+import Form from '@/app/components/datasets/settings/form'
+
+const Settings = async () => {
+ const locale = await getLocaleOnServer()
+ const { t } = await translate(locale, 'dataset-settings')
+
+ return (
+ <div className='h-full overflow-y-auto'>
+ <div className='px-6 py-3'>
+ <div className='system-xl-semibold mb-1 text-text-primary'>{t('title')}</div>
+ <div className='system-sm-regular text-text-tertiary'>{t('desc')}</div>
+ </div>
+ <Form />
+ </div>
+ )
+}
+
+export default Settings
diff --git "a/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/layout.tsx" "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/layout.tsx"
new file mode 100644
index 0000000..ccbc58f
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/\050datasetDetailLayout\051/layout.tsx"
@@ -0,0 +1,16 @@
+import type { FC } from 'react'
+import React from 'react'
+
+export type IDatasetDetail = {
+ children: React.ReactNode
+}
+
+const AppDetail: FC<IDatasetDetail> = ({ children }) => {
+ return (
+ <>
+ {children}
+ </>
+ )
+}
+
+export default React.memo(AppDetail)
diff --git "a/app/\050commonLayout\051/datasets/Container.tsx" "b/app/\050commonLayout\051/datasets/Container.tsx"
new file mode 100644
index 0000000..b484c04
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/Container.tsx"
@@ -0,0 +1,141 @@
+'use client'
+
+// Libraries
+import { useEffect, useMemo, useRef, useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import { useBoolean, useDebounceFn } from 'ahooks'
+import { useQuery } from '@tanstack/react-query'
+
+// Components
+import ExternalAPIPanel from '../../components/datasets/external-api/external-api-panel'
+import Datasets from './Datasets'
+import DatasetFooter from './DatasetFooter'
+import ApiServer from '../../components/develop/ApiServer'
+import Doc from './Doc'
+import TabSliderNew from '@/app/components/base/tab-slider-new'
+import TagManagementModal from '@/app/components/base/tag-management'
+import TagFilter from '@/app/components/base/tag-management/filter'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
+import CheckboxWithLabel from '@/app/components/datasets/create/website/base/checkbox-with-label'
+
+// Services
+import { fetchDatasetApiBaseUrl } from '@/service/datasets'
+
+// Hooks
+import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
+import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
+import { useAppContext } from '@/context/app-context'
+import { useExternalApiPanel } from '@/context/external-api-panel-context'
+
+const Container = () => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const { currentWorkspace, isCurrentWorkspaceOwner } = useAppContext()
+ const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
+ const { showExternalApiPanel, setShowExternalApiPanel } = useExternalApiPanel()
+ const [includeAll, { toggle: toggleIncludeAll }] = useBoolean(false)
+
+ document.title = `${t('dataset.knowledge')} - Dify`
+
+ const options = useMemo(() => {
+ return [
+ { value: 'dataset', text: t('dataset.datasets') },
+ ...(currentWorkspace.role === 'dataset_operator' ? [] : [{ value: 'api', text: t('dataset.datasetsApi') }]),
+ ]
+ }, [currentWorkspace.role, t])
+
+ const [activeTab, setActiveTab] = useTabSearchParams({
+ defaultTab: 'dataset',
+ })
+ const containerRef = useRef<HTMLDivElement>(null)
+ const { data } = useQuery(
+ {
+ queryKey: ['datasetApiBaseInfo'],
+ queryFn: () => fetchDatasetApiBaseUrl('/datasets/api-base-info'),
+ enabled: activeTab !== 'dataset',
+ },
+ )
+
+ const [keywords, setKeywords] = useState('')
+ const [searchKeywords, setSearchKeywords] = useState('')
+ const { run: handleSearch } = useDebounceFn(() => {
+ setSearchKeywords(keywords)
+ }, { wait: 500 })
+ const handleKeywordsChange = (value: string) => {
+ setKeywords(value)
+ handleSearch()
+ }
+ const [tagFilterValue, setTagFilterValue] = useState<string[]>([])
+ const [tagIDs, setTagIDs] = useState<string[]>([])
+ const { run: handleTagsUpdate } = useDebounceFn(() => {
+ setTagIDs(tagFilterValue)
+ }, { wait: 500 })
+ const handleTagsChange = (value: string[]) => {
+ setTagFilterValue(value)
+ handleTagsUpdate()
+ }
+
+ useEffect(() => {
+ if (currentWorkspace.role === 'normal')
+ return router.replace('/apps')
+ }, [currentWorkspace, router])
+
+ return (
+ <div ref={containerRef} className='scroll-container relative flex grow flex-col overflow-y-auto bg-background-body'>
+ <div className='sticky top-0 z-10 flex flex-wrap items-center justify-between gap-y-2 bg-background-body px-12 pb-2 pt-4 leading-[56px]'>
+ <TabSliderNew
+ value={activeTab}
+ onChange={newActiveTab => setActiveTab(newActiveTab)}
+ options={options}
+ />
+ {activeTab === 'dataset' && (
+ <div className='flex items-center justify-center gap-2'>
+ {isCurrentWorkspaceOwner && <CheckboxWithLabel
+ isChecked={includeAll}
+ onChange={toggleIncludeAll}
+ label={t('dataset.allKnowledge')}
+ labelClassName='system-md-regular text-text-secondary'
+ className='mr-2'
+ tooltip={t('dataset.allKnowledgeDescription') as string}
+ />}
+ <TagFilter type='knowledge' value={tagFilterValue} onChange={handleTagsChange} />
+ <Input
+ showLeftIcon
+ showClearIcon
+ wrapperClassName='w-[200px]'
+ value={keywords}
+ onChange={e => handleKeywordsChange(e.target.value)}
+ onClear={() => handleKeywordsChange('')}
+ />
+ <div className="h-4 w-[1px] bg-divider-regular" />
+ <Button
+ className='shadows-shadow-xs gap-0.5'
+ onClick={() => setShowExternalApiPanel(true)}
+ >
+ <ApiConnectionMod className='h-4 w-4 text-components-button-secondary-text' />
+ <div className='system-sm-medium flex items-center justify-center gap-1 px-0.5 text-components-button-secondary-text'>{t('dataset.externalAPIPanelTitle')}</div>
+ </Button>
+ </div>
+ )}
+ {activeTab === 'api' && data && <ApiServer apiBaseUrl={data.api_base_url || ''} />}
+ </div>
+ {activeTab === 'dataset' && (
+ <>
+ <Datasets containerRef={containerRef} tags={tagIDs} keywords={searchKeywords} includeAll={includeAll} />
+ <DatasetFooter />
+ {showTagManagementModal && (
+ <TagManagementModal type='knowledge' show={showTagManagementModal} />
+ )}
+ </>
+ )}
+ {activeTab === 'api' && data && <Doc apiBaseUrl={data.api_base_url || ''} />}
+
+ {showExternalApiPanel && <ExternalAPIPanel onClose={() => setShowExternalApiPanel(false)} />}
+ </div>
+ )
+}
+
+export default Container
diff --git "a/app/\050commonLayout\051/datasets/DatasetCard.tsx" "b/app/\050commonLayout\051/datasets/DatasetCard.tsx"
new file mode 100644
index 0000000..e0012b4
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/DatasetCard.tsx"
@@ -0,0 +1,240 @@
+'use client'
+
+import { useContext } from 'use-context-selector'
+import { useRouter } from 'next/navigation'
+import { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiMoreFill } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import Confirm from '@/app/components/base/confirm'
+import { ToastContext } from '@/app/components/base/toast'
+import { checkIsUsedInApp, deleteDataset } from '@/service/datasets'
+import type { DataSet } from '@/models/datasets'
+import Tooltip from '@/app/components/base/tooltip'
+import { Folder } from '@/app/components/base/icons/src/vender/solid/files'
+import type { HtmlContentProps } from '@/app/components/base/popover'
+import CustomPopover from '@/app/components/base/popover'
+import Divider from '@/app/components/base/divider'
+import RenameDatasetModal from '@/app/components/datasets/rename-modal'
+import type { Tag } from '@/app/components/base/tag-management/constant'
+import TagSelector from '@/app/components/base/tag-management/selector'
+import CornerLabel from '@/app/components/base/corner-label'
+import { useAppContext } from '@/context/app-context'
+
+export type DatasetCardProps = {
+ dataset: DataSet
+ onSuccess?: () => void
+}
+
+const DatasetCard = ({
+ dataset,
+ onSuccess,
+}: DatasetCardProps) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const { push } = useRouter()
+ const EXTERNAL_PROVIDER = 'external' as const
+
+ const { isCurrentWorkspaceDatasetOperator } = useAppContext()
+ const [tags, setTags] = useState<Tag[]>(dataset.tags)
+
+ const [showRenameModal, setShowRenameModal] = useState(false)
+ const [showConfirmDelete, setShowConfirmDelete] = useState(false)
+ const [confirmMessage, setConfirmMessage] = useState<string>('')
+ const isExternalProvider = (provider: string): boolean => provider === EXTERNAL_PROVIDER
+ const detectIsUsedByApp = useCallback(async () => {
+ try {
+ const { is_using: isUsedByApp } = await checkIsUsedInApp(dataset.id)
+ setConfirmMessage(isUsedByApp ? t('dataset.datasetUsedByApp')! : t('dataset.deleteDatasetConfirmContent')!)
+ }
+ catch (e: any) {
+ const res = await e.json()
+ notify({ type: 'error', message: res?.message || 'Unknown error' })
+ }
+
+ setShowConfirmDelete(true)
+ }, [dataset.id, notify, t])
+ const onConfirmDelete = useCallback(async () => {
+ try {
+ await deleteDataset(dataset.id)
+ notify({ type: 'success', message: t('dataset.datasetDeleted') })
+ if (onSuccess)
+ onSuccess()
+ }
+ catch {
+ }
+ setShowConfirmDelete(false)
+ }, [dataset.id, notify, onSuccess, t])
+
+ const Operations = (props: HtmlContentProps & { showDelete: boolean }) => {
+ const onMouseLeave = async () => {
+ props.onClose?.()
+ }
+ const onClickRename = async (e: React.MouseEvent<HTMLDivElement>) => {
+ e.stopPropagation()
+ props.onClick?.()
+ e.preventDefault()
+ setShowRenameModal(true)
+ }
+ const onClickDelete = async (e: React.MouseEvent<HTMLDivElement>) => {
+ e.stopPropagation()
+ props.onClick?.()
+ e.preventDefault()
+ detectIsUsedByApp()
+ }
+ return (
+ <div className="relative w-full py-1" onMouseLeave={onMouseLeave}>
+ <div className='mx-1 flex h-8 cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover' onClick={onClickRename}>
+ <span className='text-sm text-text-secondary'>{t('common.operation.settings')}</span>
+ </div>
+ {props.showDelete && (
+ <>
+ <Divider className="!my-1" />
+ <div
+ className='group mx-1 flex h-8 cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-destructive-hover'
+ onClick={onClickDelete}
+ >
+ <span className={cn('text-sm text-text-secondary', 'group-hover:text-text-destructive')}>
+ {t('common.operation.delete')}
+ </span>
+ </div>
+ </>
+ )}
+ </div>
+ )
+ }
+
+ useEffect(() => {
+ setTags(dataset.tags)
+ }, [dataset])
+
+ return (
+ <>
+ <div
+ className='group relative col-span-1 flex min-h-[160px] cursor-pointer flex-col rounded-xl border-[0.5px] border-solid border-components-card-border bg-components-card-bg shadow-sm transition-all duration-200 ease-in-out hover:shadow-lg'
+ data-disable-nprogress={true}
+ onClick={(e) => {
+ e.preventDefault()
+ isExternalProvider(dataset.provider)
+ ? push(`/datasets/${dataset.id}/hitTesting`)
+ : push(`/datasets/${dataset.id}/documents`)
+ }}
+ >
+ {isExternalProvider(dataset.provider) && <CornerLabel label='External' className='absolute right-0' labelClassName='rounded-tr-xl' />}
+ <div className='flex h-[66px] shrink-0 grow-0 items-center gap-3 px-[14px] pb-3 pt-[14px]'>
+ <div className={cn(
+ 'flex shrink-0 items-center justify-center rounded-md border-[0.5px] border-[#E0EAFF] bg-[#F5F8FF] p-2.5',
+ !dataset.embedding_available && 'opacity-50 hover:opacity-100',
+ )}>
+ <Folder className='h-5 w-5 text-[#444CE7]' />
+ </div>
+ <div className='w-0 grow py-[1px]'>
+ <div className='flex items-center text-sm font-semibold leading-5 text-text-secondary'>
+ <div className={cn('truncate', !dataset.embedding_available && 'text-text-tertiary opacity-50 hover:opacity-100')} title={dataset.name}>{dataset.name}</div>
+ {!dataset.embedding_available && (
+ <Tooltip
+ popupContent={t('dataset.unavailableTip')}
+ >
+ <span className='ml-1 inline-flex w-max shrink-0 rounded-md border border-divider-regular px-1 text-xs font-normal leading-[18px] text-text-tertiary'>{t('dataset.unavailable')}</span>
+ </Tooltip>
+ )}
+ </div>
+ <div className='mt-[1px] flex items-center text-xs leading-[18px] text-text-tertiary'>
+ <div
+ className={cn('truncate', (!dataset.embedding_available || !dataset.document_count) && 'opacity-50')}
+ title={dataset.provider === 'external' ? `${dataset.app_count}${t('dataset.appCount')}` : `${dataset.document_count}${t('dataset.documentCount')} 路 ${Math.round(dataset.word_count / 1000)}${t('dataset.wordCount')} 路 ${dataset.app_count}${t('dataset.appCount')}`}
+ >
+ {dataset.provider === 'external'
+ ? <>
+ <span>{dataset.app_count}{t('dataset.appCount')}</span>
+ </>
+ : <>
+ <span>{dataset.document_count}{t('dataset.documentCount')}</span>
+ <span className='mx-0.5 w-1 shrink-0 text-text-tertiary'>路</span>
+ <span>{Math.round(dataset.word_count / 1000)}{t('dataset.wordCount')}</span>
+ <span className='mx-0.5 w-1 shrink-0 text-text-tertiary'>路</span>
+ <span>{dataset.app_count}{t('dataset.appCount')}</span>
+ </>
+ }
+ </div>
+ </div>
+ </div>
+ </div>
+ <div
+ className={cn(
+ 'mb-2 max-h-[72px] grow px-[14px] text-xs leading-normal text-text-tertiary group-hover:line-clamp-2 group-hover:max-h-[36px]',
+ tags.length ? 'line-clamp-2' : 'line-clamp-4',
+ !dataset.embedding_available && 'opacity-50 hover:opacity-100',
+ )}
+ title={dataset.description}>
+ {dataset.description}
+ </div>
+ <div className={cn(
+ 'mt-4 h-[42px] shrink-0 items-center pb-[6px] pl-[14px] pr-[6px] pt-1',
+ tags.length ? 'flex' : '!hidden group-hover:!flex',
+ )}>
+ <div className={cn('flex w-0 grow items-center gap-1', !dataset.embedding_available && 'opacity-50 hover:opacity-100')} onClick={(e) => {
+ e.stopPropagation()
+ e.preventDefault()
+ }}>
+ <div className={cn(
+ 'mr-[41px] w-full grow group-hover:!mr-0 group-hover:!block',
+ tags.length ? '!block' : '!hidden',
+ )}>
+ <TagSelector
+ position='bl'
+ type='knowledge'
+ targetID={dataset.id}
+ value={tags.map(tag => tag.id)}
+ selectedTags={tags}
+ onCacheUpdate={setTags}
+ onChange={onSuccess}
+ />
+ </div>
+ </div>
+ <div className='mx-1 !hidden h-[14px] w-[1px] shrink-0 bg-divider-regular group-hover:!flex' />
+ <div className='!hidden shrink-0 group-hover:!flex'>
+ <CustomPopover
+ htmlContent={<Operations showDelete={!isCurrentWorkspaceDatasetOperator} />}
+ position="br"
+ trigger="click"
+ btnElement={
+ <div
+ className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-md'
+ >
+ <RiMoreFill className='h-4 w-4 text-text-secondary' />
+ </div>
+ }
+ btnClassName={open =>
+ cn(
+ open ? '!bg-black/5 !shadow-none' : '!bg-transparent',
+ 'h-8 w-8 rounded-md border-none !p-2 hover:!bg-black/5',
+ )
+ }
+ className={'!z-20 h-fit !w-[128px]'}
+ />
+ </div>
+ </div>
+ </div>
+ {showRenameModal && (
+ <RenameDatasetModal
+ show={showRenameModal}
+ dataset={dataset}
+ onClose={() => setShowRenameModal(false)}
+ onSuccess={onSuccess}
+ />
+ )}
+ {showConfirmDelete && (
+ <Confirm
+ title={t('dataset.deleteDatasetConfirmTitle')}
+ content={confirmMessage}
+ isShow={showConfirmDelete}
+ onConfirm={onConfirmDelete}
+ onCancel={() => setShowConfirmDelete(false)}
+ />
+ )}
+ </>
+ )
+}
+
+export default DatasetCard
diff --git "a/app/\050commonLayout\051/datasets/DatasetFooter.tsx" "b/app/\050commonLayout\051/datasets/DatasetFooter.tsx"
new file mode 100644
index 0000000..1f29700
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/DatasetFooter.tsx"
@@ -0,0 +1,19 @@
+'use client'
+
+import { useTranslation } from 'react-i18next'
+
+const DatasetFooter = () => {
+ const { t } = useTranslation()
+
+ return (
+ <footer className='shrink-0 grow-0 px-12 py-6'>
+ <h3 className='text-gradient text-xl font-semibold leading-tight'>{t('dataset.didYouKnow')}</h3>
+ <p className='mt-1 text-sm font-normal leading-tight text-text-secondary'>
+ {t('dataset.intro1')}<span className='inline-flex items-center gap-1 text-text-accent'>{t('dataset.intro2')}</span>{t('dataset.intro3')}<br />
+ {t('dataset.intro4')}<span className='inline-flex items-center gap-1 text-text-accent'>{t('dataset.intro5')}</span>{t('dataset.intro6')}
+ </p>
+ </footer>
+ )
+}
+
+export default DatasetFooter
diff --git "a/app/\050commonLayout\051/datasets/Datasets.tsx" "b/app/\050commonLayout\051/datasets/Datasets.tsx"
new file mode 100644
index 0000000..6383513
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/Datasets.tsx"
@@ -0,0 +1,98 @@
+'use client'
+
+import { useCallback, useEffect, useRef } from 'react'
+import useSWRInfinite from 'swr/infinite'
+import { debounce } from 'lodash-es'
+import { useTranslation } from 'react-i18next'
+import NewDatasetCard from './NewDatasetCard'
+import DatasetCard from './DatasetCard'
+import type { DataSetListResponse, FetchDatasetsParams } from '@/models/datasets'
+import { fetchDatasets } from '@/service/datasets'
+import { useAppContext } from '@/context/app-context'
+
+const getKey = (
+ pageIndex: number,
+ previousPageData: DataSetListResponse,
+ tags: string[],
+ keyword: string,
+ includeAll: boolean,
+) => {
+ if (!pageIndex || previousPageData.has_more) {
+ const params: FetchDatasetsParams = {
+ url: 'datasets',
+ params: {
+ page: pageIndex + 1,
+ limit: 30,
+ include_all: includeAll,
+ },
+ }
+ if (tags.length)
+ params.params.tag_ids = tags
+ if (keyword)
+ params.params.keyword = keyword
+ return params
+ }
+ return null
+}
+
+type Props = {
+ containerRef: React.RefObject<HTMLDivElement>
+ tags: string[]
+ keywords: string
+ includeAll: boolean
+}
+
+const Datasets = ({
+ containerRef,
+ tags,
+ keywords,
+ includeAll,
+}: Props) => {
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const { data, isLoading, setSize, mutate } = useSWRInfinite(
+ (pageIndex: number, previousPageData: DataSetListResponse) => getKey(pageIndex, previousPageData, tags, keywords, includeAll),
+ fetchDatasets,
+ { revalidateFirstPage: false, revalidateAll: true },
+ )
+ const loadingStateRef = useRef(false)
+ const anchorRef = useRef<HTMLAnchorElement>(null)
+
+ const { t } = useTranslation()
+
+ useEffect(() => {
+ loadingStateRef.current = isLoading
+ document.title = `${t('dataset.knowledge')} - Dify`
+ }, [isLoading, t])
+
+ const onScroll = useCallback(
+ debounce(() => {
+ if (!loadingStateRef.current && containerRef.current && anchorRef.current) {
+ const { scrollTop, clientHeight } = containerRef.current
+ const anchorOffset = anchorRef.current.offsetTop
+ if (anchorOffset - scrollTop - clientHeight < 100)
+ setSize(size => size + 1)
+ }
+ }, 50),
+ [setSize],
+ )
+
+ useEffect(() => {
+ const currentContainer = containerRef.current
+ currentContainer?.addEventListener('scroll', onScroll)
+ return () => {
+ currentContainer?.removeEventListener('scroll', onScroll)
+ onScroll.cancel()
+ }
+ }, [onScroll])
+
+ return (
+ <nav className='grid shrink-0 grow grid-cols-1 content-start gap-4 px-12 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4'>
+ { isCurrentWorkspaceEditor && <NewDatasetCard ref={anchorRef} /> }
+ {data?.map(({ data: datasets }) => datasets.map(dataset => (
+ <DatasetCard key={dataset.id} dataset={dataset} onSuccess={mutate} />),
+ ))}
+ </nav>
+ )
+}
+
+export default Datasets
diff --git "a/app/\050commonLayout\051/datasets/Doc.tsx" "b/app/\050commonLayout\051/datasets/Doc.tsx"
new file mode 100644
index 0000000..efdfe15
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/Doc.tsx"
@@ -0,0 +1,131 @@
+'use client'
+
+import { useEffect, useMemo, useState } from 'react'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { RiListUnordered } from '@remixicon/react'
+import TemplateEn from './template/template.en.mdx'
+import TemplateZh from './template/template.zh.mdx'
+import TemplateJa from './template/template.ja.mdx'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+import useTheme from '@/hooks/use-theme'
+import { Theme } from '@/types/app'
+import cn from '@/utils/classnames'
+
+type DocProps = {
+ apiBaseUrl: string
+}
+
+const Doc = ({ apiBaseUrl }: DocProps) => {
+ const { locale } = useContext(I18n)
+ const { t } = useTranslation()
+ const [toc, setToc] = useState<Array<{ href: string; text: string }>>([])
+ const [isTocExpanded, setIsTocExpanded] = useState(false)
+ const { theme } = useTheme()
+
+ // Set initial TOC expanded state based on screen width
+ useEffect(() => {
+ const mediaQuery = window.matchMedia('(min-width: 1280px)')
+ setIsTocExpanded(mediaQuery.matches)
+ }, [])
+
+ // Extract TOC from article content
+ useEffect(() => {
+ const extractTOC = () => {
+ const article = document.querySelector('article')
+ if (article) {
+ const headings = article.querySelectorAll('h2')
+ const tocItems = Array.from(headings).map((heading) => {
+ const anchor = heading.querySelector('a')
+ if (anchor) {
+ return {
+ href: anchor.getAttribute('href') || '',
+ text: anchor.textContent || '',
+ }
+ }
+ return null
+ }).filter((item): item is { href: string; text: string } => item !== null)
+ setToc(tocItems)
+ }
+ }
+
+ setTimeout(extractTOC, 0)
+ }, [locale])
+
+ // Handle TOC item click
+ const handleTocClick = (e: React.MouseEvent<HTMLAnchorElement>, item: { href: string; text: string }) => {
+ e.preventDefault()
+ const targetId = item.href.replace('#', '')
+ const element = document.getElementById(targetId)
+ if (element) {
+ const scrollContainer = document.querySelector('.scroll-container')
+ if (scrollContainer) {
+ const headerOffset = -40
+ const elementTop = element.offsetTop - headerOffset
+ scrollContainer.scrollTo({
+ top: elementTop,
+ behavior: 'smooth',
+ })
+ }
+ }
+ }
+
+ const Template = useMemo(() => {
+ switch (locale) {
+ case LanguagesSupported[1]:
+ return <TemplateZh apiBaseUrl={apiBaseUrl} />
+ case LanguagesSupported[7]:
+ return <TemplateJa apiBaseUrl={apiBaseUrl} />
+ default:
+ return <TemplateEn apiBaseUrl={apiBaseUrl} />
+ }
+ }, [apiBaseUrl, locale])
+
+ return (
+ <div className="flex">
+ <div className={`fixed right-20 top-32 z-10 transition-all ${isTocExpanded ? 'w-64' : 'w-10'}`}>
+ {isTocExpanded
+ ? (
+ <nav className="toc max-h-[calc(100vh-150px)] w-full overflow-y-auto rounded-lg bg-components-panel-bg p-4 shadow-md">
+ <div className="mb-4 flex items-center justify-between">
+ <h3 className="text-lg font-semibold text-text-primary">{t('appApi.develop.toc')}</h3>
+ <button
+ onClick={() => setIsTocExpanded(false)}
+ className="text-text-tertiary hover:text-text-secondary"
+ >
+ 鉁�
+ </button>
+ </div>
+ <ul className="space-y-2">
+ {toc.map((item, index) => (
+ <li key={index}>
+ <a
+ href={item.href}
+ className="text-text-secondary transition-colors duration-200 hover:text-text-primary hover:underline"
+ onClick={e => handleTocClick(e, item)}
+ >
+ {item.text}
+ </a>
+ </li>
+ ))}
+ </ul>
+ </nav>
+ )
+ : (
+ <button
+ onClick={() => setIsTocExpanded(true)}
+ className="flex h-10 w-10 items-center justify-center rounded-full bg-components-button-secondary-bg shadow-md transition-colors duration-200 hover:bg-components-button-secondary-bg-hover"
+ >
+ <RiListUnordered className="h-6 w-6 text-components-button-secondary-text" />
+ </button>
+ )}
+ </div>
+ <article className={cn('prose-xl prose mx-1 rounded-t-xl bg-background-default px-4 pt-16 sm:mx-12', theme === Theme.dark && 'prose-invert')}>
+ {Template}
+ </article>
+ </div>
+ )
+}
+
+export default Doc
diff --git "a/app/\050commonLayout\051/datasets/NewDatasetCard.tsx" "b/app/\050commonLayout\051/datasets/NewDatasetCard.tsx"
new file mode 100644
index 0000000..ddc48c2
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/NewDatasetCard.tsx"
@@ -0,0 +1,42 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import Link from 'next/link'
+import {
+ RiAddLine,
+ RiArrowRightLine,
+} from '@remixicon/react'
+
+const CreateAppCard = (
+ {
+ ref,
+ ..._
+ },
+) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='bg-background-default-dimm flex min-h-[160px] flex-col rounded-xl border-[0.5px]
+ border-components-panel-border transition-all duration-200 ease-in-out'
+ >
+ <Link ref={ref} className='group flex grow cursor-pointer items-start p-4' href={'/datasets/create'}>
+ <div className='flex items-center gap-3'>
+ <div className='flex h-10 w-10 items-center justify-center rounded-lg border border-dashed border-divider-regular bg-background-default-lighter
+ p-2 group-hover:border-solid group-hover:border-effects-highlight group-hover:bg-background-default-dodge'
+ >
+ <RiAddLine className='h-4 w-4 text-text-tertiary group-hover:text-text-accent'/>
+ </div>
+ <div className='system-md-semibold text-text-secondary group-hover:text-text-accent'>{t('dataset.createDataset')}</div>
+ </div>
+ </Link>
+ <div className='system-xs-regular p-4 pt-0 text-text-tertiary'>{t('dataset.createDatasetIntro')}</div>
+ <Link className='group flex cursor-pointer items-center gap-1 rounded-b-xl border-t-[0.5px] border-divider-subtle p-4' href={'datasets/connect'}>
+ <div className='system-xs-medium text-text-tertiary group-hover:text-text-accent'>{t('dataset.connectDataset')}</div>
+ <RiArrowRightLine className='h-3.5 w-3.5 text-text-tertiary group-hover:text-text-accent' />
+ </Link>
+ </div>
+ )
+}
+
+CreateAppCard.displayName = 'CreateAppCard'
+
+export default CreateAppCard
diff --git "a/app/\050commonLayout\051/datasets/connect/page.tsx" "b/app/\050commonLayout\051/datasets/connect/page.tsx"
new file mode 100644
index 0000000..724c506
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/connect/page.tsx"
@@ -0,0 +1,8 @@
+import React from 'react'
+import ExternalKnowledgeBaseConnector from '@/app/components/datasets/external-knowledge-base/connector'
+
+const ExternalKnowledgeBaseCreation = () => {
+ return <ExternalKnowledgeBaseConnector />
+}
+
+export default ExternalKnowledgeBaseCreation
diff --git "a/app/\050commonLayout\051/datasets/create/page.tsx" "b/app/\050commonLayout\051/datasets/create/page.tsx"
new file mode 100644
index 0000000..663a830
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/create/page.tsx"
@@ -0,0 +1,12 @@
+import React from 'react'
+import DatasetUpdateForm from '@/app/components/datasets/create'
+
+type Props = {}
+
+const DatasetCreation = async (props: Props) => {
+ return (
+ <DatasetUpdateForm />
+ )
+}
+
+export default DatasetCreation
diff --git "a/app/\050commonLayout\051/datasets/layout.tsx" "b/app/\050commonLayout\051/datasets/layout.tsx"
new file mode 100644
index 0000000..aecb537
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/layout.tsx"
@@ -0,0 +1,14 @@
+'use client'
+
+import { ExternalApiPanelProvider } from '@/context/external-api-panel-context'
+import { ExternalKnowledgeApiProvider } from '@/context/external-knowledge-api-context'
+
+export default function DatasetsLayout({ children }: { children: React.ReactNode }) {
+ return (
+ <ExternalKnowledgeApiProvider>
+ <ExternalApiPanelProvider>
+ {children}
+ </ExternalApiPanelProvider>
+ </ExternalKnowledgeApiProvider>
+ )
+}
diff --git "a/app/\050commonLayout\051/datasets/page.tsx" "b/app/\050commonLayout\051/datasets/page.tsx"
new file mode 100644
index 0000000..678de47
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/page.tsx"
@@ -0,0 +1,7 @@
+import Container from './Container'
+
+const AppList = async () => {
+ return <Container />
+}
+
+export default AppList
diff --git "a/app/\050commonLayout\051/datasets/store.ts" "b/app/\050commonLayout\051/datasets/store.ts"
new file mode 100644
index 0000000..40b7b15
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/store.ts"
@@ -0,0 +1,11 @@
+import { create } from 'zustand'
+
+type DatasetStore = {
+ showExternalApiPanel: boolean
+ setShowExternalApiPanel: (show: boolean) => void
+}
+
+export const useDatasetStore = create<DatasetStore>(set => ({
+ showExternalApiPanel: false,
+ setShowExternalApiPanel: show => set({ showExternalApiPanel: show }),
+}))
diff --git "a/app/\050commonLayout\051/datasets/template/template.en.mdx" "b/app/\050commonLayout\051/datasets/template/template.en.mdx"
new file mode 100644
index 0000000..7f28610
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/template/template.en.mdx"
@@ -0,0 +1,2352 @@
+{/**
+ * @typedef Props
+ * @property {string} apiBaseUrl
+ */}
+
+import { CodeGroup } from '@/app/components/develop/code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstruction, Paragraph } from '@/app/components/develop/md.tsx'
+
+# Knowledge API
+
+<div>
+ ### Authentication
+
+ Service API of Dify authenticates using an `API-Key`.
+
+ It is suggested that developers store the `API-Key` in the backend instead of sharing or storing it in the client side to avoid the leakage of the `API-Key`, which may lead to property loss.
+
+ All API requests should include your `API-Key` in the **`Authorization`** HTTP Header, as shown below:
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/document/create-by-text'
+ method='POST'
+ title='Create a Document from Text'
+ name='#create-by-text'
+/>
+<Row>
+ <Col>
+ This API is based on an existing knowledge and creates a new document through text based on this knowledge.
+
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ Document name
+ </Property>
+ <Property name='text' type='string' key='text'>
+ Document content
+ </Property>
+ <Property name='indexing_technique' type='string' key='indexing_technique'>
+ Index mode
+ - <code>high_quality</code> High quality: embedding using embedding model, built as vector database index
+ - <code>economy</code> Economy: Build using inverted index of keyword table index
+ </Property>
+ <Property name='doc_form' type='string' key='doc_form'>
+ Format of indexed content
+ - <code>text_model</code> Text documents are directly embedded; `economy` mode defaults to using this form
+ - <code>hierarchical_model</code> Parent-child mode
+ - <code>qa_model</code> Q&A Mode: Generates Q&A pairs for segmented documents and then embeds the questions
+ </Property>
+ <Property name='doc_language' type='string' key='doc_language'>
+ In Q&A mode, specify the language of the document, for example: <code>English</code>, <code>Chinese</code>
+ </Property>
+ <Property name='process_rule' type='object' key='process_rule'>
+ Processing rules
+ - <code>mode</code> (string) Cleaning, segmentation mode, automatic / custom
+ - <code>rules</code> (object) Custom rules (in automatic mode, this field is empty)
+ - <code>pre_processing_rules</code> (array[object]) Preprocessing rules
+ - <code>id</code> (string) Unique identifier for the preprocessing rule
+ - enumerate
+ - <code>remove_extra_spaces</code> Replace consecutive spaces, newlines, tabs
+ - <code>remove_urls_emails</code> Delete URL, email address
+ - <code>enabled</code> (bool) Whether to select this rule or not. If no document ID is passed in, it represents the default value.
+ - <code>segmentation</code> (object) Segmentation rules
+ - <code>separator</code> Custom segment identifier, currently only allows one delimiter to be set. Default is \n
+ - <code>max_tokens</code> Maximum length (token) defaults to 1000
+ - <code>parent_mode</code> Retrieval mode of parent chunks: <code>full-doc</code> full text retrieval / <code>paragraph</code> paragraph retrieval
+ - <code>subchunk_segmentation</code> (object) Child chunk rules
+ - <code>separator</code> Segmentation identifier. Currently, only one delimiter is allowed. The default is <code>***</code>
+ - <code>max_tokens</code> The maximum length (tokens) must be validated to be shorter than the length of the parent chunk
+ - <code>chunk_overlap</code> Define the overlap between adjacent chunks (optional)
+ </Property>
+ <PropertyInstruction>When no parameters are set for the knowledge base, the first upload requires the following parameters to be provided; if not provided, the default parameters will be used.</PropertyInstruction>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ Retrieval model
+ - <code>search_method</code> (string) Search method
+ - <code>hybrid_search</code> Hybrid search
+ - <code>semantic_search</code> Semantic search
+ - <code>full_text_search</code> Full-text search
+ - <code>reranking_enable</code> (bool) Whether to enable reranking
+ - <code>reranking_mode</code> (object) Rerank model configuration
+ - <code>reranking_provider_name</code> (string) Rerank model provider
+ - <code>reranking_model_name</code> (string) Rerank model name
+ - <code>top_k</code> (int) Number of results to return
+ - <code>score_threshold_enabled</code> (bool) Whether to enable score threshold
+ - <code>score_threshold</code> (float) Score threshold
+ </Property>
+ <Property name='embedding_model' type='string' key='embedding_model'>
+ Embedding model name
+ </Property>
+ <Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
+ Embedding model provider
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/document/create-by-text"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"name": "text","text": "text","indexing_technique": "high_quality","process_rule": {"mode": "automatic"}}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-text' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "text",
+ "text": "text",
+ "indexing_technique": "high_quality",
+ "process_rule": {
+ "mode": "automatic"
+ }
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "text.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695690280,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/document/create-by-file'
+ method='POST'
+ title='Create a Document from a File'
+ name='#create-by-file'
+/>
+<Row>
+ <Col>
+ This API is based on an existing knowledge and creates a new document through a file based on this knowledge.
+
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='data' type='multipart/form-data json string' key='data'>
+ - <code>original_document_id</code> Source document ID (optional)
+ - Used to re-upload the document or modify the document cleaning and segmentation configuration. The missing information is copied from the source document
+ - The source document cannot be an archived document
+ - When original_document_id is passed in, the update operation is performed on behalf of the document. process_rule is a fillable item. If not filled in, the segmentation method of the source document will be used by default
+ - When original_document_id is not passed in, the new operation is performed on behalf of the document, and process_rule is required
+
+ - <code>indexing_technique</code> Index mode
+ - <code>high_quality</code> High quality: embedding using embedding model, built as vector database index
+ - <code>economy</code> Economy: Build using inverted index of keyword table index
+
+ - <code>doc_form</code> Format of indexed content
+ - <code>text_model</code> Text documents are directly embedded; `economy` mode defaults to using this form
+ - <code>hierarchical_model</code> Parent-child mode
+ - <code>qa_model</code> Q&A Mode: Generates Q&A pairs for segmented documents and then embeds the questions
+
+ - <code>doc_language</code> In Q&A mode, specify the language of the document, for example: <code>English</code>, <code>Chinese</code>
+
+ - <code>process_rule</code> Processing rules
+ - <code>mode</code> (string) Cleaning, segmentation mode, automatic / custom
+ - <code>rules</code> (object) Custom rules (in automatic mode, this field is empty)
+ - <code>pre_processing_rules</code> (array[object]) Preprocessing rules
+ - <code>id</code> (string) Unique identifier for the preprocessing rule
+ - enumerate
+ - <code>remove_extra_spaces</code> Replace consecutive spaces, newlines, tabs
+ - <code>remove_urls_emails</code> Delete URL, email address
+ - <code>enabled</code> (bool) Whether to select this rule or not. If no document ID is passed in, it represents the default value.
+ - <code>segmentation</code> (object) Segmentation rules
+ - <code>separator</code> Custom segment identifier, currently only allows one delimiter to be set. Default is \n
+ - <code>max_tokens</code> Maximum length (token) defaults to 1000
+ - <code>parent_mode</code> Retrieval mode of parent chunks: <code>full-doc</code> full text retrieval / <code>paragraph</code> paragraph retrieval
+ - <code>subchunk_segmentation</code> (object) Child chunk rules
+ - <code>separator</code> Segmentation identifier. Currently, only one delimiter is allowed. The default is <code>***</code>
+ - <code>max_tokens</code> The maximum length (tokens) must be validated to be shorter than the length of the parent chunk
+ - <code>chunk_overlap</code> Define the overlap between adjacent chunks (optional)
+ </Property>
+ <Property name='file' type='multipart/form-data' key='file'>
+ Files that need to be uploaded.
+ </Property>
+ <PropertyInstruction>When no parameters are set for the knowledge base, the first upload requires the following parameters to be provided; if not provided, the default parameters will be used.</PropertyInstruction>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ Retrieval model
+ - <code>search_method</code> (string) Search method
+ - <code>hybrid_search</code> Hybrid search
+ - <code>semantic_search</code> Semantic search
+ - <code>full_text_search</code> Full-text search
+ - <code>reranking_enable</code> (bool) Whether to enable reranking
+ - <code>reranking_mode</code> (object) Rerank model configuration
+ - <code>reranking_provider_name</code> (string) Rerank model provider
+ - <code>reranking_model_name</code> (string) Rerank model name
+ - <code>top_k</code> (int) Number of results to return
+ - <code>score_threshold_enabled</code> (bool) Whether to enable score threshold
+ - <code>score_threshold</code> (float) Score threshold
+ </Property>
+ <Property name='embedding_model' type='string' key='embedding_model'>
+ Embedding model name
+ </Property>
+ <Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
+ Embedding model provider
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/document/create-by-file"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'data="{"indexing_technique":"high_quality","process_rule":{"rules":{"pre_processing_rules":[{"id":"remove_extra_spaces","enabled":true},{"id":"remove_urls_emails","enabled":true}],"segmentation":{"separator":"###","max_tokens":500}},"mode":"custom"}}";type=text/plain' \\\n--form 'file=@"/path/to/file"'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-file' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \
+ --form 'file=@"/path/to/file"'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "Dify.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695308667,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets'
+ method='POST'
+ title='Create an Empty Knowledge Base'
+ name='#create_empty_dataset'
+/>
+<Row>
+ <Col>
+ ### Request Body
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ Knowledge name
+ </Property>
+ <Property name='description' type='string' key='description'>
+ Knowledge description (optional)
+ </Property>
+ <Property name='indexing_technique' type='string' key='indexing_technique'>
+ Index technique (optional)
+ If this is not set, embedding_model, embedding_model_provider and retrieval_model will be set to null
+ - <code>high_quality</code> High quality
+ - <code>economy</code> Economy
+ </Property>
+ <Property name='permission' type='string' key='permission'>
+ Permission
+ - <code>only_me</code> Only me
+ - <code>all_team_members</code> All team members
+ - <code>partial_members</code> Partial members
+ </Property>
+ <Property name='provider' type='string' key='provider'>
+ Provider (optional, default: vendor)
+ - <code>vendor</code> Vendor
+ - <code>external</code> External knowledge
+ </Property>
+ <Property name='external_knowledge_api_id' type='str' key='external_knowledge_api_id'>
+ External knowledge API ID (optional)
+ </Property>
+ <Property name='external_knowledge_id' type='str' key='external_knowledge_id'>
+ External knowledge ID (optional)
+ </Property>
+ <Property name='embedding_model' type='str' key='embedding_model'>
+ Embedding model name (optional)
+ </Property>
+ <Property name='embedding_model_provider' type='str' key='embedding_model_provider'>
+ Embedding model provider name (optional)
+ </Property>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ Retrieval model (optional)
+ - <code>search_method</code> (string) Search method
+ - <code>hybrid_search</code> Hybrid search
+ - <code>semantic_search</code> Semantic search
+ - <code>full_text_search</code> Full-text search
+ - <code>reranking_enable</code> (bool) Whether to enable reranking
+ - <code>reranking_model</code> (object) Rerank model configuration
+ - <code>reranking_provider_name</code> (string) Rerank model provider
+ - <code>reranking_model_name</code> (string) Rerank model name
+ - <code>top_k</code> (int) Number of results to return
+ - <code>score_threshold_enabled</code> (bool) Whether to enable score threshold
+ - <code>score_threshold</code> (float) Score threshold
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"name": "name", "permission": "only_me"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${apiBaseUrl}/v1/datasets' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "name",
+ "permission": "only_me"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "",
+ "name": "name",
+ "description": null,
+ "provider": "vendor",
+ "permission": "only_me",
+ "data_source_type": null,
+ "indexing_technique": null,
+ "app_count": 0,
+ "document_count": 0,
+ "word_count": 0,
+ "created_by": "",
+ "created_at": 1695636173,
+ "updated_by": "",
+ "updated_at": 1695636173,
+ "embedding_model": null,
+ "embedding_model_provider": null,
+ "embedding_available": null
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets'
+ method='GET'
+ title='Get Knowledge Base List'
+ name='#dataset_list'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ Search keyword, optional
+ </Property>
+ <Property name='tag_ids' type='array[string]' key='tag_ids'>
+ Tag ID list, optional
+ </Property>
+ <Property name='page' type='string' key='page'>
+ Page number, optional, default 1
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ Number of items returned, optional, default 20, range 1-100
+ </Property>
+ <Property name='include_all' type='boolean' key='include_all'>
+ Whether to include all datasets (only effective for owners), optional, defaults to false
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "",
+ "name": "name",
+ "description": "desc",
+ "permission": "only_me",
+ "data_source_type": "upload_file",
+ "indexing_technique": "",
+ "app_count": 2,
+ "document_count": 10,
+ "word_count": 1200,
+ "created_by": "",
+ "created_at": "",
+ "updated_by": "",
+ "updated_at": ""
+ },
+ ...
+ ],
+ "has_more": true,
+ "limit": 20,
+ "total": 50,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}'
+ method='GET'
+ title='Get knowledge base details by knowledge base ID'
+ name='#view_dataset'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge Base ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eaedb485-95ac-4ffd-ab1e-18da6d676a2f",
+ "name": "Test Knowledge Base",
+ "description": "",
+ "provider": "vendor",
+ "permission": "only_me",
+ "data_source_type": null,
+ "indexing_technique": null,
+ "app_count": 0,
+ "document_count": 0,
+ "word_count": 0,
+ "created_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6",
+ "created_at": 1735620612,
+ "updated_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6",
+ "updated_at": 1735620612,
+ "embedding_model": null,
+ "embedding_model_provider": null,
+ "embedding_available": true,
+ "retrieval_model_dict": {
+ "search_method": "semantic_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 2,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ },
+ "tags": [],
+ "doc_form": null,
+ "external_knowledge_info": {
+ "external_knowledge_id": null,
+ "external_knowledge_api_id": null,
+ "external_knowledge_api_name": null,
+ "external_knowledge_api_endpoint": null
+ },
+ "external_retrieval_model": {
+ "top_k": 2,
+ "score_threshold": 0.0,
+ "score_threshold_enabled": null
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}'
+ method='PATCH'
+ title='Update knowledge base'
+ name='#update_dataset'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge Base ID
+ </Property>
+ <Property name='indexing_technique' type='string' key='indexing_technique'>
+ Index technique (optional)
+ - <code>high_quality</code> High quality
+ - <code>economy</code> Economy
+ </Property>
+ <Property name='permission' type='string' key='permission'>
+ Permission
+ - <code>only_me</code> Only me
+ - <code>all_team_members</code> All team members
+ - <code>partial_members</code> Partial members
+ </Property>
+ <Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
+ Specified embedding model provider, must be set up in the system first, corresponding to the provider field(Optional)
+ </Property>
+ <Property name='embedding_model' type='string' key='embedding_model'>
+ Specified embedding model, corresponding to the model field(Optional)
+ </Property>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ Retrieval model (optional, if not filled, it will be recalled according to the default method)
+ - <code>search_method</code> (text) Search method: One of the following four keywords is required
+ - <code>keyword_search</code> Keyword search
+ - <code>semantic_search</code> Semantic search
+ - <code>full_text_search</code> Full-text search
+ - <code>hybrid_search</code> Hybrid search
+ - <code>reranking_enable</code> (bool) Whether to enable reranking, required if the search mode is semantic_search or hybrid_search (optional)
+ - <code>reranking_mode</code> (object) Rerank model configuration, required if reranking is enabled
+ - <code>reranking_provider_name</code> (string) Rerank model provider
+ - <code>reranking_model_name</code> (string) Rerank model name
+ - <code>weights</code> (float) Semantic search weight setting in hybrid search mode
+ - <code>top_k</code> (integer) Number of results to return (optional)
+ - <code>score_threshold_enabled</code> (bool) Whether to enable score threshold
+ - <code>score_threshold</code> (float) Score threshold
+ </Property>
+ <Property name='partial_member_list' type='array' key='partial_member_list'>
+ Partial member list(Optional)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PATCH"
+ label="/datasets/{dataset_id}"
+ targetCode={`curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{
+ "name": "Test Knowledge Base",
+ "indexing_technique": "high_quality",
+ "permission": "only_me",
+ "embedding_model_provider": "zhipuai",
+ "embedding_model": "embedding-3",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 1,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ },
+ "partial_member_list": []
+ }'
+ `}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "Test Knowledge Base",
+ "indexing_technique": "high_quality",
+ "permission": "only_me",
+ "embedding_model_provider": "zhipuai",
+ "embedding_model": "embedding-3",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 1,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ },
+ "partial_member_list": []
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eaedb485-95ac-4ffd-ab1e-18da6d676a2f",
+ "name": "Test Knowledge Base",
+ "description": "",
+ "provider": "vendor",
+ "permission": "only_me",
+ "data_source_type": null,
+ "indexing_technique": "high_quality",
+ "app_count": 0,
+ "document_count": 0,
+ "word_count": 0,
+ "created_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6",
+ "created_at": 1735620612,
+ "updated_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6",
+ "updated_at": 1735622679,
+ "embedding_model": "embedding-3",
+ "embedding_model_provider": "zhipuai",
+ "embedding_available": null,
+ "retrieval_model_dict": {
+ "search_method": "semantic_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 2,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ },
+ "tags": [],
+ "doc_form": null,
+ "external_knowledge_info": {
+ "external_knowledge_id": null,
+ "external_knowledge_api_id": null,
+ "external_knowledge_api_name": null,
+ "external_knowledge_api_endpoint": null
+ },
+ "external_retrieval_model": {
+ "top_k": 2,
+ "score_threshold": 0.0,
+ "score_threshold_enabled": null
+ },
+ "partial_member_list": []
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}'
+ method='DELETE'
+ title='Delete a Knowledge Base'
+ name='#delete_dataset'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/update-by-text'
+ method='POST'
+ title='Update a Document with Text'
+ name='#update-by-text'
+/>
+<Row>
+ <Col>
+ This API is based on an existing knowledge and updates the document through text based on this knowledge.
+
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ Document name (optional)
+ </Property>
+ <Property name='text' type='string' key='text'>
+ Document content (optional)
+ </Property>
+ <Property name='process_rule' type='object' key='process_rule'>
+ Processing rules
+ - <code>mode</code> (string) Cleaning, segmentation mode, automatic / custom
+ - <code>rules</code> (object) Custom rules (in automatic mode, this field is empty)
+ - <code>pre_processing_rules</code> (array[object]) Preprocessing rules
+ - <code>id</code> (string) Unique identifier for the preprocessing rule
+ - enumerate
+ - <code>remove_extra_spaces</code> Replace consecutive spaces, newlines, tabs
+ - <code>remove_urls_emails</code> Delete URL, email address
+ - <code>enabled</code> (bool) Whether to select this rule or not. If no document ID is passed in, it represents the default value.
+ - <code>segmentation</code> (object) Segmentation rules
+ - <code>separator</code> Custom segment identifier, currently only allows one delimiter to be set. Default is \n
+ - <code>max_tokens</code> Maximum length (token) defaults to 1000
+ - <code>parent_mode</code> Retrieval mode of parent chunks: <code>full-doc</code> full text retrieval / <code>paragraph</code> paragraph retrieval
+ - <code>subchunk_segmentation</code> (object) Child chunk rules
+ - <code>separator</code> Segmentation identifier. Currently, only one delimiter is allowed. The default is <code>***</code>
+ - <code>max_tokens</code> The maximum length (tokens) must be validated to be shorter than the length of the parent chunk
+ - <code>chunk_overlap</code> Define the overlap between adjacent chunks (optional)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/update-by-text"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"name": "name","text": "text"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-text' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "name",
+ "text": "text"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "name.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695308667,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/update-by-file'
+ method='POST'
+ title='Update a Document with a File'
+ name='#update-by-file'
+/>
+<Row>
+ <Col>
+ This API is based on an existing knowledge, and updates documents through files based on this knowledge
+
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ Document name (optional)
+ </Property>
+ <Property name='file' type='multipart/form-data' key='file'>
+ Files to be uploaded
+ </Property>
+ <Property name='process_rule' type='object' key='process_rule'>
+ Processing rules
+ - <code>mode</code> (string) Cleaning, segmentation mode, automatic / custom
+ - <code>rules</code> (object) Custom rules (in automatic mode, this field is empty)
+ - <code>pre_processing_rules</code> (array[object]) Preprocessing rules
+ - <code>id</code> (string) Unique identifier for the preprocessing rule
+ - enumerate
+ - <code>remove_extra_spaces</code> Replace consecutive spaces, newlines, tabs
+ - <code>remove_urls_emails</code> Delete URL, email address
+ - <code>enabled</code> (bool) Whether to select this rule or not. If no document ID is passed in, it represents the default value.
+ - <code>segmentation</code> (object) Segmentation rules
+ - <code>separator</code> Custom segment identifier, currently only allows one delimiter to be set. Default is \n
+ - <code>max_tokens</code> Maximum length (token) defaults to 1000
+ - <code>parent_mode</code> Retrieval mode of parent chunks: <code>full-doc</code> full text retrieval / <code>paragraph</code> paragraph retrieval
+ - <code>subchunk_segmentation</code> (object) Child chunk rules
+ - <code>separator</code> Segmentation identifier. Currently, only one delimiter is allowed. The default is <code>***</code>
+ - <code>max_tokens</code> The maximum length (tokens) must be validated to be shorter than the length of the parent chunk
+ - <code>chunk_overlap</code> Define the overlap between adjacent chunks (optional)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/update-by-file"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'data="{"name":"Dify","indexing_technique":"high_quality","process_rule":{"rules":{"pre_processing_rules":[{"id":"remove_extra_spaces","enabled":true},{"id":"remove_urls_emails","enabled":true}],"segmentation":{"separator":"###","max_tokens":500}},"mode":"custom"}}";type=text/plain' \\\n--form 'file=@"/path/to/file"'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-file' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \
+ --form 'file=@"/path/to/file"'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "Dify.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695308667,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": "20230921150427533684"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{batch}/indexing-status'
+ method='GET'
+ title='Get Document Embedding Status (Progress)'
+ name='#indexing_status'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='batch' type='string' key='batch'>
+ Batch number of uploaded documents
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{batch}/indexing-status"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{batch}/indexing-status' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{batch}/indexing-status' \
+ --header 'Authorization: Bearer {api_key}' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data":[{
+ "id": "",
+ "indexing_status": "indexing",
+ "processing_started_at": 1681623462.0,
+ "parsing_completed_at": 1681623462.0,
+ "cleaning_completed_at": 1681623462.0,
+ "splitting_completed_at": 1681623462.0,
+ "completed_at": null,
+ "paused_at": null,
+ "error": null,
+ "stopped_at": null,
+ "completed_segments": 24,
+ "total_segments": 100
+ }]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}'
+ method='DELETE'
+ title='Delete a Document'
+ name='#delete_document'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/documents/{document_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents'
+ method='GET'
+ title='Get the Document List of a Knowledge Base'
+ name='#dataset_document_list'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ Search keywords, currently only search document names (optional)
+ </Property>
+ <Property name='page' type='string' key='page'>
+ Page number (optional)
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ Number of items returned, default 20, range 1-100 (optional)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents' \
+ --header 'Authorization: Bearer {api_key}' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "",
+ "position": 1,
+ "data_source_type": "file_upload",
+ "data_source_info": null,
+ "dataset_process_rule_id": null,
+ "name": "dify",
+ "created_from": "",
+ "created_by": "",
+ "created_at": 1681623639,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false
+ },
+ ],
+ "has_more": false,
+ "limit": 20,
+ "total": 9,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments'
+ method='POST'
+ title='Add Chunks to a Document'
+ name='#create_new_segment'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='segments' type='object list' key='segments'>
+ - <code>content</code> (text) Text content / question content, required
+ - <code>answer</code> (text) Answer content, if the mode of the knowledge is Q&A mode, pass the value (optional)
+ - <code>keywords</code> (list) Keywords (optional)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"segments": [{"content": "1","answer": "1","keywords": ["a"]}]}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "segments": [
+ {
+ "content": "1",
+ "answer": "1",
+ "keywords": ["a"]
+ }
+ ]
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [{
+ "id": "",
+ "position": 1,
+ "document_id": "",
+ "content": "1",
+ "answer": "1",
+ "word_count": 25,
+ "tokens": 0,
+ "keywords": [
+ "a"
+ ],
+ "index_node_id": "",
+ "index_node_hash": "",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }],
+ "doc_form": "text_model"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments'
+ method='GET'
+ title='Get Chunks from a Document'
+ name='#get_segment'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ Keyword (optional)
+ </Property>
+ <Property name='status' type='string' key='status'>
+ Search status, completed
+ </Property>
+ <Property name='page' type='string' key='page'>
+ Page number (optional)
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ Number of items returned, default 20, range 1-100 (optional)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [{
+ "id": "",
+ "position": 1,
+ "document_id": "",
+ "content": "1",
+ "answer": "1",
+ "word_count": 25,
+ "tokens": 0,
+ "keywords": [
+ "a"
+ ],
+ "index_node_id": "",
+ "index_node_hash": "",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }],
+ "doc_form": "text_model",
+ "has_more": false,
+ "limit": 20,
+ "total": 9,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}'
+ method='DELETE'
+ title='Delete a Chunk in a Document'
+ name='#delete_segment'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ Document Segment ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}'
+ method='POST'
+ title='Update a Chunk in a Document'
+ name='#update_segment'
+/>
+<Row>
+ <Col>
+ ### POST
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ Document Segment ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='segment' type='object' key='segment'>
+ - <code>content</code> (text) Text content / question content, required
+ - <code>answer</code> (text) Answer content, passed if the knowledge is in Q&A mode (optional)
+ - <code>keywords</code> (list) Keyword (optional)
+ - <code>enabled</code> (bool) False / true (optional)
+ - <code>regenerate_child_chunks</code> (bool) Whether to regenerate child chunks (optional)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{\"segment\": {\"content\": \"1\",\"answer\": \"1\", \"keywords\": [\"a\"], \"enabled\": false}}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "segment": {
+ "content": "1",
+ "answer": "1",
+ "keywords": ["a"],
+ "enabled": false
+ }
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": {
+ "id": "",
+ "position": 1,
+ "document_id": "",
+ "content": "1",
+ "answer": "1",
+ "word_count": 25,
+ "tokens": 0,
+ "keywords": [
+ "a"
+ ],
+ "index_node_id": "",
+ "index_node_hash": "",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ },
+ "doc_form": "text_model"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks'
+ method='POST'
+ title='Create Child Chunk'
+ name='#create_child_chunk'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ Segment ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='content' type='string' key='content'>
+ Child chunk content
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"content": "Child chunk content"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "content": "Child chunk content"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": {
+ "id": "",
+ "segment_id": "",
+ "content": "Child chunk content",
+ "word_count": 25,
+ "tokens": 0,
+ "index_node_id": "",
+ "index_node_hash": "",
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks'
+ method='GET'
+ title='Get Child Chunks'
+ name='#get_child_chunks'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ Segment ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ Search keyword (optional)
+ </Property>
+ <Property name='page' type='integer' key='page'>
+ Page number (optional, default: 1)
+ </Property>
+ <Property name='limit' type='integer' key='limit'>
+ Items per page (optional, default: 20, max: 100)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [{
+ "id": "",
+ "segment_id": "",
+ "content": "Child chunk content",
+ "word_count": 25,
+ "tokens": 0,
+ "index_node_id": "",
+ "index_node_hash": "",
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }],
+ "total": 1,
+ "total_pages": 1,
+ "page": 1,
+ "limit": 20
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}'
+ method='DELETE'
+ title='Delete Child Chunk'
+ name='#delete_child_chunk'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ Segment ID
+ </Property>
+ <Property name='child_chunk_id' type='string' key='child_chunk_id'>
+ Child Chunk ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}'
+ method='PATCH'
+ title='Update Child Chunk'
+ name='#update_child_chunk'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ Segment ID
+ </Property>
+ <Property name='child_chunk_id' type='string' key='child_chunk_id'>
+ Child Chunk ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='content' type='string' key='content'>
+ Child chunk content
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PATCH"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}"
+ targetCode={`curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"content": "Updated child chunk content"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "content": "Updated child chunk content"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": {
+ "id": "",
+ "segment_id": "",
+ "content": "Updated child chunk content",
+ "word_count": 25,
+ "tokens": 0,
+ "index_node_id": "",
+ "index_node_hash": "",
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/upload-file'
+ method='GET'
+ title='Get Upload File'
+ name='#get_upload_file'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ Document ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{document_id}/upload-file"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "file_id",
+ "name": "file_name",
+ "size": 1024,
+ "extension": "txt",
+ "url": "preview_url",
+ "download_url": "download_url",
+ "mime_type": "text/plain",
+ "created_by": "user_id",
+ "created_at": 1728734540,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/retrieve'
+ method='POST'
+ title='Retrieve Chunks from a Knowledge Base'
+ name='#dataset_retrieval'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='query' type='string' key='query'>
+ Query keyword
+ </Property>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ Retrieval model (optional, if not filled, it will be recalled according to the default method)
+ - <code>search_method</code> (text) Search method: One of the following four keywords is required
+ - <code>keyword_search</code> Keyword search
+ - <code>semantic_search</code> Semantic search
+ - <code>full_text_search</code> Full-text search
+ - <code>hybrid_search</code> Hybrid search
+ - <code>reranking_enable</code> (bool) Whether to enable reranking, required if the search mode is semantic_search or hybrid_search (optional)
+ - <code>reranking_mode</code> (object) Rerank model configuration, required if reranking is enabled
+ - <code>reranking_provider_name</code> (string) Rerank model provider
+ - <code>reranking_model_name</code> (string) Rerank model name
+ - <code>weights</code> (float) Semantic search weight setting in hybrid search mode
+ - <code>top_k</code> (integer) Number of results to return (optional)
+ - <code>score_threshold_enabled</code> (bool) Whether to enable score threshold
+ - <code>score_threshold</code> (float) Score threshold
+ </Property>
+ <Property name='external_retrieval_model' type='object' key='external_retrieval_model'>
+ Unused field
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/retrieve"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/retrieve' \\\n--header 'Authorization: Bearer {api_key}'\\\n--header 'Content-Type: application/json'\\\n--data-raw '{
+ "query": "test",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 1,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ }
+}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/retrieve' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "query": "test",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 2,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ }
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "query": {
+ "content": "test"
+ },
+ "records": [
+ {
+ "segment": {
+ "id": "7fa6f24f-8679-48b3-bc9d-bdf28d73f218",
+ "position": 1,
+ "document_id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2",
+ "content": "Operation guide",
+ "answer": null,
+ "word_count": 847,
+ "tokens": 280,
+ "keywords": [
+ "install",
+ "java",
+ "base",
+ "scripts",
+ "jdk",
+ "manual",
+ "internal",
+ "opens",
+ "add",
+ "vmoptions"
+ ],
+ "index_node_id": "39dd8443-d960-45a8-bb46-7275ad7fbc8e",
+ "index_node_hash": "0189157697b3c6a418ccf8264a09699f25858975578f3467c76d6bfc94df1d73",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "dbcb1ab5-90c8-41a7-8b78-73b235eb6f6f",
+ "created_at": 1728734540,
+ "indexing_at": 1728734552,
+ "completed_at": 1728734584,
+ "error": null,
+ "stopped_at": null,
+ "document": {
+ "id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2",
+ "data_source_type": "upload_file",
+ "name": "readme.txt",
+ }
+ },
+ "score": 3.730463140527718e-05,
+ "tsne_position": null
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata'
+ method='POST'
+ title='Create a Knowledge Metadata'
+ name='#create_metadata'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='segment' type='object' key='segment'>
+ - <code>type</code> (string) Metadata type, required
+ - <code>name</code> (string) Metadata name, required
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/metadata"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/metadata' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"type": "string", "name": "test"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "abc",
+ "type": "string",
+ "name": "test",
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata/{metadata_id}'
+ method='PATCH'
+ title='Update a Knowledge Metadata'
+ name='#update_metadata'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='metadata_id' type='string' key='metadata_id'>
+ Metadata ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='segment' type='object' key='segment'>
+ - <code>name</code> (string) Metadata name, required
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PATCH"
+ label="/datasets/{dataset_id}/metadata/{metadata_id}"
+ targetCode={`curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/metadata/{metadata_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"name": "test"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "abc",
+ "type": "string",
+ "name": "test",
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata/{metadata_id}'
+ method='DELETE'
+ title='Delete a Knowledge Metadata'
+ name='#delete_metadata'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='metadata_id' type='string' key='metadata_id'>
+ Metadata ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/metadata/{metadata_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/metadata/{metadata_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata/built-in/{action}'
+ method='POST'
+ title='Disable Or Enable Built-in Metadata'
+ name='#toggle_metadata'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ <Property name='action' type='string' key='action'>
+ disable/enable
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/metadata/built-in/{action}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/metadata/built-in/{action}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/metadata'
+ method='POST'
+ title='Update Documents Metadata'
+ name='#update_documents_metadata'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='operation_data' type='object list' key='segments'>
+ - <code>document_id</code> (string) Document ID
+ - <code>metadata_list</code> (list) Metadata list
+ - <code>id</code> (string) Metadata ID
+ - <code>value</code> (string) Metadata value
+ - <code>name</code> (string) Metadata name
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/metadata"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/metadata' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"operation_data": [{"document_id": "document_id", "metadata_list": [{"id": "id", "value": "value", "name": "name"}]}]}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata'
+ method='GET'
+ title='Get Knowledge Metadata List'
+ name='#dataset_metadata_list'
+/>
+<Row>
+ <Col>
+ ### Params
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ Knowledge ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/metadata"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/metadata' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "doc_metadata": [
+ {
+ "id": "",
+ "name": "name",
+ "type": "string",
+ "use_count": 0,
+ },
+ ...
+ ],
+ "built_in_field_enabled": true
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/workspaces/current/models/model-types/text-embedding'
+ method='GET'
+ title='Get available embedding models'
+ name='#model_type_list'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}"
+ targetCode={`curl --location --location --request GET '${props.apiBaseUrl}/workspaces/current/models/model-types/text-embedding' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' `}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/workspaces/current/models/model-types/text-embedding' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "provider": "zhipuai",
+ "label": {
+ "zh_Hans": "鏅鸿氨 AI",
+ "en_US": "ZHIPU AI"
+ },
+ "icon_small": {
+ "zh_Hans": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_small/zh_Hans",
+ "en_US": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_small/en_US"
+ },
+ "icon_large": {
+ "zh_Hans": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_large/zh_Hans",
+ "en_US": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_large/en_US"
+ },
+ "status": "active",
+ "models": [
+ {
+ "model": "embedding-3",
+ "label": {
+ "zh_Hans": "embedding-3",
+ "en_US": "embedding-3"
+ },
+ "model_type": "text-embedding",
+ "features": null,
+ "fetch_from": "predefined-model",
+ "model_properties": {
+ "context_size": 8192
+ },
+ "deprecated": false,
+ "status": "active",
+ "load_balancing_enabled": false
+ },
+ {
+ "model": "embedding-2",
+ "label": {
+ "zh_Hans": "embedding-2",
+ "en_US": "embedding-2"
+ },
+ "model_type": "text-embedding",
+ "features": null,
+ "fetch_from": "predefined-model",
+ "model_properties": {
+ "context_size": 8192
+ },
+ "deprecated": false,
+ "status": "active",
+ "load_balancing_enabled": false
+ },
+ {
+ "model": "text_embedding",
+ "label": {
+ "zh_Hans": "text_embedding",
+ "en_US": "text_embedding"
+ },
+ "model_type": "text-embedding",
+ "features": null,
+ "fetch_from": "predefined-model",
+ "model_properties": {
+ "context_size": 512
+ },
+ "deprecated": false,
+ "status": "active",
+ "load_balancing_enabled": false
+ }
+ ]
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Row>
+ <Col>
+ ### Error message
+ <Properties>
+ <Property name='code' type='string' key='code'>
+ Error code
+ </Property>
+ </Properties>
+ <Properties>
+ <Property name='status' type='number' key='status'>
+ Error status
+ </Property>
+ </Properties>
+ <Properties>
+ <Property name='message' type='string' key='message'>
+ Error message
+ </Property>
+ </Properties>
+ </Col>
+ <Col>
+ <CodeGroup title="Example">
+ ```json {{ title: 'Response' }}
+ {
+ "code": "no_file_uploaded",
+ "message": "Please upload your file.",
+ "status": 400
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+<table className="max-w-auto border-collapse border border-slate-400" style={{ maxWidth: 'none', width: 'auto' }}>
+ <thead style={{ background: '#f9fafc' }}>
+ <tr>
+ <th className="p-2 border border-slate-300">code</th>
+ <th className="p-2 border border-slate-300">status</th>
+ <th className="p-2 border border-slate-300">message</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td className="p-2 border border-slate-300">no_file_uploaded</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Please upload your file.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">too_many_files</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Only one file is allowed.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">file_too_large</td>
+ <td className="p-2 border border-slate-300">413</td>
+ <td className="p-2 border border-slate-300">File size exceeded.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">unsupported_file_type</td>
+ <td className="p-2 border border-slate-300">415</td>
+ <td className="p-2 border border-slate-300">File type not allowed.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">high_quality_dataset_only</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Current operation only supports 'high-quality' datasets.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">dataset_not_initialized</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The dataset is still being initialized or indexing. Please wait a moment.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">archived_document_immutable</td>
+ <td className="p-2 border border-slate-300">403</td>
+ <td className="p-2 border border-slate-300">The archived document is not editable.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">dataset_name_duplicate</td>
+ <td className="p-2 border border-slate-300">409</td>
+ <td className="p-2 border border-slate-300">The dataset name already exists. Please modify your dataset name.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">invalid_action</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Invalid action.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">document_already_finished</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The document has been processed. Please refresh the page or go to the document details.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">document_indexing</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The document is being processed and cannot be edited.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">invalid_metadata</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The metadata content is incorrect. Please check and verify.</td>
+ </tr>
+ </tbody>
+</table>
+<div className="pb-4" />
diff --git "a/app/\050commonLayout\051/datasets/template/template.ja.mdx" "b/app/\050commonLayout\051/datasets/template/template.ja.mdx"
new file mode 100644
index 0000000..defd488
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/template/template.ja.mdx"
@@ -0,0 +1,2005 @@
+{/**
+ * @typedef Props
+ * @property {string} apiBaseUrl
+ */}
+
+import { CodeGroup } from '@/app/components/develop/code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstruction, Paragraph } from '@/app/components/develop/md.tsx'
+
+# 銉娿儸銉冦偢 API
+
+<div>
+ ### 瑾嶈
+
+ Dify 銇偟銉笺儞銈� API 銇� `API-Key` 銈掍娇鐢ㄣ仐銇﹁獚瑷笺仐銇俱仚銆�
+
+ 闁嬬櫤鑰呫伅銆乣API-Key` 銈掋偗銉┿偆銈€兂銉堝伌銇у叡鏈夈伨銇熴伅淇濆瓨銇欍倠銇仹銇仾銇忋�併儛銉冦偗銈ㄣ兂銉夈伀淇濆瓨銇欍倠銇撱仺銈掓帹濂ㄣ仐銇俱仚銆傘亾銈屻伀銈堛倞銆乣API-Key` 銇紡娲┿伀銈堛倠璨$敚鎼嶅け銈掗槻銇愩亾銇ㄣ亴銇с亶銇俱仚銆�
+
+ 銇欍伖銇︺伄 API 銉偗銈ㄣ偣銉堛伀銇�佷互涓嬨伄銈堛亞銇� **`Authorization`** HTTP 銉樸儍銉�銉笺伀 `API-Key` 銈掑惈銈併倠蹇呰銇屻亗銈娿伨銇欙細
+
+ <CodeGroup title="銈炽兗銉�">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/document/create-by-text'
+ method='POST'
+ title='銉嗐偔銈广儓銇嬨倝銉夈偔銉ャ儭銉炽儓銈掍綔鎴�'
+ name='#create-by-text'
+/>
+<Row>
+ <Col>
+ 銇撱伄 API 銇棦瀛樸伄銉娿儸銉冦偢銇熀銇ャ亜銇︺亰銈娿�併亾銇儕銉儍銈搞倰鍩恒伀銉嗐偔銈广儓銈掍娇鐢ㄣ仐銇︽柊銇椼亜銉夈偔銉ャ儭銉炽儓銈掍綔鎴愩仐銇俱仚銆�
+
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 銉夈偔銉ャ儭銉炽儓鍚�
+ </Property>
+ <Property name='text' type='string' key='text'>
+ 銉夈偔銉ャ儭銉炽儓鍐呭
+ </Property>
+ <Property name='indexing_technique' type='string' key='indexing_technique'>
+ 銈ゃ兂銉囥儍銈偣銉€兗銉�
+ - <code>high_quality</code> 楂樺搧璩�: 鍩嬨倎杈笺伩銉€儑銉倰浣跨敤銇椼仸銉欍偗銉堛儷銉囥兗銈裤儥銉笺偣銈ゃ兂銉囥儍銈偣銈掓绡�
+ - <code>economy</code> 绲屾笀: 銈兗銉兗銉夈儐銉笺儢銉偆銉炽儑銉冦偗銈广伄鍙嶈虎銈ゃ兂銉囥儍銈偣銈掓绡�
+ </Property>
+ <Property name='doc_form' type='string' key='doc_form'>
+ 銈ゃ兂銉囥儍銈偣鍖栥仌銈屻仧鍐呭銇舰寮�
+ - <code>text_model</code> 銉嗐偔銈广儓銉夈偔銉ャ儭銉炽儓銇洿鎺ュ煁銈佽炯銇俱倢銇俱仚; `economy` 銉€兗銉夈仹銇亾銇舰寮忋亴銉囥儠銈┿儷銉�
+ - <code>hierarchical_model</code> 瑕瓙銉€兗銉�
+ - <code>qa_model</code> Q&A 銉€兗銉�: 鍒嗗壊銇曘倢銇熴儔銈儱銉°兂銉堛伄璩晱銇ㄥ洖绛斻儦銈€倰鐢熸垚銇椼�佽唱鍟忋倰鍩嬨倎杈笺伩銇俱仚
+ </Property>
+ <Property name='doc_language' type='string' key='doc_language'>
+ Q&A 銉€兗銉夈仹銇�併儔銈儱銉°兂銉堛伄瑷�瑾炪倰鎸囧畾銇椼伨銇欍�備緥: <code>English</code>, <code>Chinese</code>
+ </Property>
+ <Property name='process_rule' type='object' key='process_rule'>
+ 鍑︾悊銉兗銉�
+ - <code>mode</code> (string) 銈儶銉笺儖銉炽偘銆併偦銈般儭銉炽儐銉笺偡銉с兂銉€兗銉夈�佽嚜鍕� / 銈偣銈裤儬
+ - <code>rules</code> (object) 銈偣銈裤儬銉兗銉� (鑷嫊銉€兗銉夈仹銇�併亾銇儠銈c兗銉儔銇┖)
+ - <code>pre_processing_rules</code> (array[object]) 鍓嶅嚘鐞嗐儷銉笺儷
+ - <code>id</code> (string) 鍓嶅嚘鐞嗐儷銉笺儷銇竴鎰忚瓨鍒ュ瓙
+ - 鍒楁寵
+ - <code>remove_extra_spaces</code> 閫g稓銇欍倠銈广儦銉笺偣銆佹敼琛屻�併偪銉栥倰缃彌
+ - <code>remove_urls_emails</code> URL銆併儭銉笺儷銈€儔銉偣銈掑墛闄�
+ - <code>enabled</code> (bool) 銇撱伄銉兗銉倰閬告姙銇欍倠銇嬨仼銇嗐亱銆傘儔銈儱銉°兂銉� ID 銇屾浮銇曘倢銇亜鍫村悎銆併儑銉曘偐銉儓鍊ゃ倰琛ㄣ仐銇俱仚銆�
+ - <code>segmentation</code> (object) 銈汇偘銉°兂銉嗐兗銈枫儳銉炽儷銉笺儷
+ - <code>separator</code> 銈偣銈裤儬銈汇偘銉°兂銉堣瓨鍒ュ瓙銆傜従鍦ㄣ伅 1 銇ゃ伄鍖哄垏銈婃枃瀛椼伄銇胯ō瀹氬彲鑳姐�傘儑銉曘偐銉儓銇� \n
+ - <code>max_tokens</code> 鏈�澶ч暦 (銉堛兗銈兂) 銉囥儠銈┿儷銉堛伅 1000
+ - <code>parent_mode</code> 瑕儊銉c兂銈伄妞滅储銉€兗銉�: <code>full-doc</code> 鍏ㄦ枃妞滅储 / <code>paragraph</code> 娈佃惤妞滅储
+ - <code>subchunk_segmentation</code> (object) 瀛愩儊銉c兂銈儷銉笺儷
+ - <code>separator</code> 銈汇偘銉°兂銉嗐兗銈枫儳銉宠瓨鍒ュ瓙銆傜従鍦ㄣ伅 1 銇ゃ伄鍖哄垏銈婃枃瀛椼伄銇胯ū鍙�傘儑銉曘偐銉儓銇� <code>***</code>
+ - <code>max_tokens</code> 鏈�澶ч暦 (銉堛兗銈兂) 銇Κ銉併儯銉炽偗銇暦銇曘倛銈婄煭銇勩亾銇ㄣ倰妞滆銇欍倠蹇呰銇屻亗銈娿伨銇�
+ - <code>chunk_overlap</code> 闅f帴銇欍倠銉併儯銉炽偗闁撱伄閲嶈銈掑畾缇� (銈儣銈枫儳銉�)
+ </Property>
+ <PropertyInstruction>銉娿儸銉冦偢銉欍兗銈广伀銉戙儵銉°兗銈裤亴瑷畾銇曘倢銇︺亜銇亜鍫村悎銆佹渶鍒濄伄銈€儍銉椼儹銉笺儔銇伅浠ヤ笅銇儜銉┿儭銉笺偪銈掓彁渚涖仚銈嬪繀瑕併亴銇傘倞銇俱仚銆傛彁渚涖仌銈屻仾銇勫牬鍚堛�併儑銉曘偐銉儓銉戙儵銉°兗銈裤亴浣跨敤銇曘倢銇俱仚銆�</PropertyInstruction>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ 妞滅储銉€儑銉�
+ - <code>search_method</code> (string) 妞滅储鏂规硶
+ - <code>hybrid_search</code> 銉忋偆銉栥儶銉冦儔妞滅储
+ - <code>semantic_search</code> 銈汇優銉炽儐銈c儍銈绱�
+ - <code>full_text_search</code> 鍏ㄦ枃妞滅储
+ - <code>reranking_enable</code> (bool) 鍐嶃儵銉炽偔銉炽偘銈掓湁鍔广伀銇欍倠銇嬨仼銇嗐亱
+ - <code>reranking_mode</code> (object) 鍐嶃儵銉炽偔銉炽偘銉€儑銉鎴�
+ - <code>reranking_provider_name</code> (string) 鍐嶃儵銉炽偔銉炽偘銉€儑銉儣銉儛銈ゃ儉銉�
+ - <code>reranking_model_name</code> (string) 鍐嶃儵銉炽偔銉炽偘銉€儑銉悕
+ - <code>top_k</code> (int) 杩斻仌銈屻倠绲愭灉銇暟
+ - <code>score_threshold_enabled</code> (bool) 銈广偝銈㈤柧鍊ゃ倰鏈夊姽銇仚銈嬨亱銇┿亞銇�
+ - <code>score_threshold</code> (float) 銈广偝銈㈤柧鍊�
+ </Property>
+ <Property name='embedding_model' type='string' key='embedding_model'>
+ 鍩嬨倎杈笺伩銉€儑銉悕
+ </Property>
+ <Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
+ 鍩嬨倎杈笺伩銉€儑銉儣銉儛銈ゃ儉銉�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/document/create-by-text"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"name": "text","text": "text","indexing_technique": "high_quality","process_rule": {"mode": "automatic"}}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-text' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "text",
+ "text": "text",
+ "indexing_technique": "high_quality",
+ "process_rule": {
+ "mode": "automatic"
+ }
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "text.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695690280,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/document/create-by-file'
+ method='POST'
+ title='銉曘偂銈ゃ儷銇嬨倝銉夈偔銉ャ儭銉炽儓銈掍綔鎴�'
+ name='#create-by-file'
+/>
+<Row>
+ <Col>
+ 銇撱伄 API 銇棦瀛樸伄銉娿儸銉冦偢銇熀銇ャ亜銇︺亰銈娿�併亾銇儕銉儍銈搞倰鍩恒伀銉曘偂銈ゃ儷銈掍娇鐢ㄣ仐銇︽柊銇椼亜銉夈偔銉ャ儭銉炽儓銈掍綔鎴愩仐銇俱仚銆�
+
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='data' type='multipart/form-data json string' key='data'>
+ - <code>original_document_id</code> 鍏冦伄銉夈偔銉ャ儭銉炽儓 ID (銈儣銈枫儳銉�)
+ - 銉夈偔銉ャ儭銉炽儓銈掑啀銈€儍銉椼儹銉笺儔銇俱仧銇偗銉兗銉嬨兂銈般仺銈汇偘銉°兂銉嗐兗銈枫儳銉虫鎴愩倰澶夋洿銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍�傛瑺钀姐仐銇︺亜銈嬫儏鍫便伅鍏冦伄銉夈偔銉ャ儭銉炽儓銇嬨倝銈炽償銉笺仌銈屻伨銇欍��
+ - 鍏冦伄銉夈偔銉ャ儭銉炽儓銇偄銉笺偒銈ゃ儢銇曘倢銇熴儔銈儱銉°兂銉堛仹銇傘仯銇︺伅銇倞銇俱仜銈撱��
+ - original_document_id 銇屾浮銇曘倢銇熷牬鍚堛�佹洿鏂版搷浣溿亴瀹熻銇曘倢銇俱仚銆俻rocess_rule 銇叆鍔涘彲鑳姐仾闋呯洰銇с仚銆傚叆鍔涖仌銈屻仾銇勫牬鍚堛�佸厓銇儔銈儱銉°兂銉堛伄銈汇偘銉°兂銉嗐兗銈枫儳銉虫柟娉曘亴銉囥儠銈┿儷銉堛仹浣跨敤銇曘倢銇俱仚銆�
+ - original_document_id 銇屾浮銇曘倢銇亜鍫村悎銆佹柊銇椼亜鎿嶄綔銇屽疅琛屻仌銈屻�乸rocess_rule 銇屽繀瑕併仹銇欍��
+
+ - <code>indexing_technique</code> 銈ゃ兂銉囥儍銈偣銉€兗銉�
+ - <code>high_quality</code> 楂樺搧璩�: 鍩嬨倎杈笺伩銉€儑銉倰浣跨敤銇椼仸銉欍偗銉堛儷銉囥兗銈裤儥銉笺偣銈ゃ兂銉囥儍銈偣銈掓绡�
+ - <code>economy</code> 绲屾笀: 銈兗銉兗銉夈儐銉笺儢銉偆銉炽儑銉冦偗銈广伄鍙嶈虎銈ゃ兂銉囥儍銈偣銈掓绡�
+
+ - <code>doc_form</code> 銈ゃ兂銉囥儍銈偣鍖栥仌銈屻仧鍐呭銇舰寮�
+ - <code>text_model</code> 銉嗐偔銈广儓銉夈偔銉ャ儭銉炽儓銇洿鎺ュ煁銈佽炯銇俱倢銇俱仚; `economy` 銉€兗銉夈仹銇亾銇舰寮忋亴銉囥儠銈┿儷銉�
+ - <code>hierarchical_model</code> 瑕瓙銉€兗銉�
+ - <code>qa_model</code> Q&A 銉€兗銉�: 鍒嗗壊銇曘倢銇熴儔銈儱銉°兂銉堛伄璩晱銇ㄥ洖绛斻儦銈€倰鐢熸垚銇椼�佽唱鍟忋倰鍩嬨倎杈笺伩銇俱仚
+
+ - <code>doc_language</code> Q&A 銉€兗銉夈仹銇�併儔銈儱銉°兂銉堛伄瑷�瑾炪倰鎸囧畾銇椼伨銇欍�備緥: <code>English</code>, <code>Chinese</code>
+
+ - <code>process_rule</code> 鍑︾悊銉兗銉�
+ - <code>mode</code> (string) 銈儶銉笺儖銉炽偘銆併偦銈般儭銉炽儐銉笺偡銉с兂銉€兗銉夈�佽嚜鍕� / 銈偣銈裤儬
+ - <code>rules</code> (object) 銈偣銈裤儬銉兗銉� (鑷嫊銉€兗銉夈仹銇�併亾銇儠銈c兗銉儔銇┖)
+ - <code>pre_processing_rules</code> (array[object]) 鍓嶅嚘鐞嗐儷銉笺儷
+ - <code>id</code> (string) 鍓嶅嚘鐞嗐儷銉笺儷銇竴鎰忚瓨鍒ュ瓙
+ - 鍒楁寵
+ - <code>remove_extra_spaces</code> 閫g稓銇欍倠銈广儦銉笺偣銆佹敼琛屻�併偪銉栥倰缃彌
+ - <code>remove_urls_emails</code> URL銆併儭銉笺儷銈€儔銉偣銈掑墛闄�
+ - <code>enabled</code> (bool) 銇撱伄銉兗銉倰閬告姙銇欍倠銇嬨仼銇嗐亱銆傘儔銈儱銉°兂銉� ID 銇屾浮銇曘倢銇亜鍫村悎銆併儑銉曘偐銉儓鍊ゃ倰琛ㄣ仐銇俱仚銆�
+ - <code>segmentation</code> (object) 銈汇偘銉°兂銉嗐兗銈枫儳銉炽儷銉笺儷
+ - <code>separator</code> 銈偣銈裤儬銈汇偘銉°兂銉堣瓨鍒ュ瓙銆傜従鍦ㄣ伅 1 銇ゃ伄鍖哄垏銈婃枃瀛椼伄銇胯ō瀹氬彲鑳姐�傘儑銉曘偐銉儓銇� \n
+ - <code>max_tokens</code> 鏈�澶ч暦 (銉堛兗銈兂) 銉囥儠銈┿儷銉堛伅 1000
+ - <code>parent_mode</code> 瑕儊銉c兂銈伄妞滅储銉€兗銉�: <code>full-doc</code> 鍏ㄦ枃妞滅储 / <code>paragraph</code> 娈佃惤妞滅储
+ - <code>subchunk_segmentation</code> (object) 瀛愩儊銉c兂銈儷銉笺儷
+ - <code>separator</code> 銈汇偘銉°兂銉嗐兗銈枫儳銉宠瓨鍒ュ瓙銆傜従鍦ㄣ伅 1 銇ゃ伄鍖哄垏銈婃枃瀛椼伄銇胯ū鍙�傘儑銉曘偐銉儓銇� <code>***</code>
+ - <code>max_tokens</code> 鏈�澶ч暦 (銉堛兗銈兂) 銇Κ銉併儯銉炽偗銇暦銇曘倛銈婄煭銇勩亾銇ㄣ倰妞滆銇欍倠蹇呰銇屻亗銈娿伨銇�
+ - <code>chunk_overlap</code> 闅f帴銇欍倠銉併儯銉炽偗闁撱伄閲嶈銈掑畾缇� (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='file' type='multipart/form-data' key='file'>
+ 銈€儍銉椼儹銉笺儔銇欍倠蹇呰銇屻亗銈嬨儠銈°偆銉��
+ </Property>
+ <PropertyInstruction>銉娿儸銉冦偢銉欍兗銈广伀銉戙儵銉°兗銈裤亴瑷畾銇曘倢銇︺亜銇亜鍫村悎銆佹渶鍒濄伄銈€儍銉椼儹銉笺儔銇伅浠ヤ笅銇儜銉┿儭銉笺偪銈掓彁渚涖仚銈嬪繀瑕併亴銇傘倞銇俱仚銆傛彁渚涖仌銈屻仾銇勫牬鍚堛�併儑銉曘偐銉儓銉戙儵銉°兗銈裤亴浣跨敤銇曘倢銇俱仚銆�</PropertyInstruction>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ 妞滅储銉€儑銉�
+ - <code>search_method</code> (string) 妞滅储鏂规硶
+ - <code>hybrid_search</code> 銉忋偆銉栥儶銉冦儔妞滅储
+ - <code>semantic_search</code> 銈汇優銉炽儐銈c儍銈绱�
+ - <code>full_text_search</code> 鍏ㄦ枃妞滅储
+ - <code>reranking_enable</code> (bool) 鍐嶃儵銉炽偔銉炽偘銈掓湁鍔广伀銇欍倠銇嬨仼銇嗐亱
+ - <code>reranking_mode</code> (object) 鍐嶃儵銉炽偔銉炽偘銉€儑銉鎴�
+ - <code>reranking_provider_name</code> (string) 鍐嶃儵銉炽偔銉炽偘銉€儑銉儣銉儛銈ゃ儉銉�
+ - <code>reranking_model_name</code> (string) 鍐嶃儵銉炽偔銉炽偘銉€儑銉悕
+ - <code>top_k</code> (int) 杩斻仌銈屻倠绲愭灉銇暟
+ - <code>score_threshold_enabled</code> (bool) 銈广偝銈㈤柧鍊ゃ倰鏈夊姽銇仚銈嬨亱銇┿亞銇�
+ - <code>score_threshold</code> (float) 銈广偝銈㈤柧鍊�
+ </Property>
+ <Property name='embedding_model' type='string' key='embedding_model'>
+ 鍩嬨倎杈笺伩銉€儑銉悕
+ </Property>
+ <Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
+ 鍩嬨倎杈笺伩銉€儑銉儣銉儛銈ゃ儉銉�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/document/create-by-file"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'data="{"indexing_technique":"high_quality","process_rule":{"rules":{"pre_processing_rules":[{"id":"remove_extra_spaces","enabled":true},{"id":"remove_urls_emails","enabled":true}],"segmentation":{"separator":"###","max_tokens":500}},"mode":"custom"}}";type=text/plain' \\\n--form 'file=@"/path/to/file"'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-file' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \
+ --form 'file=@"/path/to/file"'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "Dify.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695308667,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets'
+ method='POST'
+ title='绌恒伄銉娿儸銉冦偢銉欍兗銈广倰浣滄垚'
+ name='#create_empty_dataset'
+/>
+<Row>
+ <Col>
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 銉娿儸銉冦偢鍚�
+ </Property>
+ <Property name='description' type='string' key='description'>
+ 銉娿儸銉冦偢銇鏄� (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='indexing_technique' type='string' key='indexing_technique'>
+ 銈ゃ兂銉囥儍銈偣鎶�琛� (銈儣銈枫儳銉�)
+ - <code>high_quality</code> 楂樺搧璩�
+ - <code>economy</code> 绲屾笀
+ </Property>
+ <Property name='permission' type='string' key='permission'>
+ 妯╅檺
+ - <code>only_me</code> 鑷垎銇伩
+ - <code>all_team_members</code> 銇欍伖銇︺伄銉併兗銉犮儭銉炽儛銉�
+ - <code>partial_members</code> 涓�閮ㄣ伄銉°兂銉愩兗
+ </Property>
+ <Property name='provider' type='string' key='provider'>
+ 銉椼儹銉愩偆銉�銉� (銈儣銈枫儳銉炽�併儑銉曘偐銉儓: vendor)
+ - <code>vendor</code> 銉欍兂銉�銉�
+ - <code>external</code> 澶栭儴銉娿儸銉冦偢
+ </Property>
+ <Property name='external_knowledge_api_id' type='str' key='external_knowledge_api_id'>
+ 澶栭儴銉娿儸銉冦偢 API ID (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='external_knowledge_id' type='str' key='external_knowledge_id'>
+ 澶栭儴銉娿儸銉冦偢 ID (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='embedding_model' type='str' key='embedding_model'>
+ 鍩嬨倎杈笺伩銉€儑銉悕锛堜换鎰忥級
+ </Property>
+ <Property name='embedding_model_provider' type='str' key='embedding_model_provider'>
+ 鍩嬨倎杈笺伩銉€儑銉伄銉椼儹銉愩偆銉�鍚嶏紙浠绘剰锛�
+ </Property>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ 妞滅储銉€儑銉紙浠绘剰锛�
+ - <code>search_method</code> (鏂囧瓧鍒�) 妞滅储鏂规硶
+ - <code>hybrid_search</code> 銉忋偆銉栥儶銉冦儔妞滅储
+ - <code>semantic_search</code> 銈汇優銉炽儐銈c儍銈绱�
+ - <code>full_text_search</code> 鍏ㄦ枃妞滅储
+ - <code>reranking_enable</code> (銉栥兗銉��) 銉儵銉炽偔銉炽偘銈掓湁鍔广伀銇欍倠銇嬨仼銇嗐亱
+ - <code>reranking_model</code> (銈儢銈搞偋銈儓) 銉儵銉炽偗銉€儑銉伄瑷畾
+ - <code>reranking_provider_name</code> (鏂囧瓧鍒�) 銉儵銉炽偗銉€儑銉伄銉椼儹銉愩偆銉�
+ - <code>reranking_model_name</code> (鏂囧瓧鍒�) 銉儵銉炽偗銉€儑銉悕
+ - <code>top_k</code> (鏁存暟) 杩斻仌銈屻倠绲愭灉銇暟
+ - <code>score_threshold_enabled</code> (銉栥兗銉��) 銈广偝銈㈤柧鍊ゃ倰鏈夊姽銇仚銈嬨亱銇┿亞銇�
+ - <code>score_threshold</code> (娴嫊灏忔暟鐐规暟) 銈广偝銈㈤柧鍊�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"name": "name", "permission": "only_me"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${apiBaseUrl}/v1/datasets' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "name",
+ "permission": "only_me"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "",
+ "name": "name",
+ "description": null,
+ "provider": "vendor",
+ "permission": "only_me",
+ "data_source_type": null,
+ "indexing_technique": null,
+ "app_count": 0,
+ "document_count": 0,
+ "word_count": 0,
+ "created_by": "",
+ "created_at": 1695636173,
+ "updated_by": "",
+ "updated_at": 1695636173,
+ "embedding_model": null,
+ "embedding_model_provider": null,
+ "embedding_available": null
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets'
+ method='GET'
+ title='銉娿儸銉冦偢銉欍兗銈广儶銈广儓銈掑彇寰�'
+ name='#dataset_list'
+/>
+<Row>
+ <Col>
+ ### 銈偍銉�
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 妞滅储銈兗銉兗銉夈�併偑銉椼偡銉с兂
+ </Property>
+ <Property name='tag_ids' type='array[string]' key='tag_ids'>
+ 銈裤偘ID銉偣銉堛�併偑銉椼偡銉с兂
+ </Property>
+ <Property name='page' type='string' key='page'>
+ 銉氥兗銈哥暘鍙枫�併偑銉椼偡銉с兂銆併儑銉曘偐銉儓1
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ 杩斻仌銈屻倠銈€偆銉嗐儬鏁般�併偑銉椼偡銉с兂銆併儑銉曘偐銉儓20銆佺瘎鍥�1-100
+ </Property>
+ <Property name='include_all' type='boolean' key='include_all'>
+ 銇欍伖銇︺伄銉囥兗銈裤偦銉冦儓銈掑惈銈併倠銇嬨仼銇嗐亱锛堟墍鏈夎�呫伄銇挎湁鍔癸級銆併偑銉椼偡銉с兂銆併儑銉曘偐銉儓銇痜alse
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="GET"
+ label="/datasets"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "",
+ "name": "name",
+ "description": "desc",
+ "permission": "only_me",
+ "data_source_type": "upload_file",
+ "indexing_technique": "",
+ "app_count": 2,
+ "document_count": 10,
+ "word_count": 1200,
+ "created_by": "",
+ "created_at": "",
+ "updated_by": "",
+ "updated_at": ""
+ },
+ ...
+ ],
+ "has_more": true,
+ "limit": 20,
+ "total": 50,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}'
+ method='DELETE'
+ title='銉娿儸銉冦偢銉欍兗銈广倰鍓婇櫎'
+ name='#delete_dataset'
+/>
+<Row>
+ <Col>
+ ### 銉戙儵銉°兗銈�
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="DELETE"
+ label="/datasets/{dataset_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```text {{ title: '銉偣銉濄兂銈�' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/update-by-text'
+ method='POST'
+ title='銉嗐偔銈广儓銇с儔銈儱銉°兂銉堛倰鏇存柊'
+ name='#update-by-text'
+/>
+<Row>
+ <Col>
+ 銇撱伄 API 銇棦瀛樸伄銉娿儸銉冦偢銇熀銇ャ亜銇︺亰銈娿�併亾銇儕銉儍銈搞倰鍩恒伀銉嗐偔銈广儓銈掍娇鐢ㄣ仐銇︺儔銈儱銉°兂銉堛倰鏇存柊銇椼伨銇欍��
+
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 銉夈偔銉ャ儭銉炽儓鍚� (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='text' type='string' key='text'>
+ 銉夈偔銉ャ儭銉炽儓鍐呭 (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='process_rule' type='object' key='process_rule'>
+ 鍑︾悊銉兗銉�
+ - <code>mode</code> (string) 銈儶銉笺儖銉炽偘銆併偦銈般儭銉炽儐銉笺偡銉с兂銉€兗銉夈�佽嚜鍕� / 銈偣銈裤儬
+ - <code>rules</code> (object) 銈偣銈裤儬銉兗銉� (鑷嫊銉€兗銉夈仹銇�併亾銇儠銈c兗銉儔銇┖)
+ - <code>pre_processing_rules</code> (array[object]) 鍓嶅嚘鐞嗐儷銉笺儷
+ - <code>id</code> (string) 鍓嶅嚘鐞嗐儷銉笺儷銇竴鎰忚瓨鍒ュ瓙
+ - 鍒楁寵
+ - <code>remove_extra_spaces</code> 閫g稓銇欍倠銈广儦銉笺偣銆佹敼琛屻�併偪銉栥倰缃彌
+ - <code>remove_urls_emails</code> URL銆併儭銉笺儷銈€儔銉偣銈掑墛闄�
+ - <code>enabled</code> (bool) 銇撱伄銉兗銉倰閬告姙銇欍倠銇嬨仼銇嗐亱銆傘儔銈儱銉°兂銉� ID 銇屾浮銇曘倢銇亜鍫村悎銆併儑銉曘偐銉儓鍊ゃ倰琛ㄣ仐銇俱仚銆�
+ - <code>segmentation</code> (object) 銈汇偘銉°兂銉嗐兗銈枫儳銉炽儷銉笺儷
+ - <code>separator</code> 銈偣銈裤儬銈汇偘銉°兂銉堣瓨鍒ュ瓙銆傜従鍦ㄣ伅 1 銇ゃ伄鍖哄垏銈婃枃瀛椼伄銇胯ō瀹氬彲鑳姐�傘儑銉曘偐銉儓銇� \n
+ - <code>max_tokens</code> 鏈�澶ч暦 (銉堛兗銈兂) 銉囥儠銈┿儷銉堛伅 1000
+ - <code>parent_mode</code> 瑕儊銉c兂銈伄妞滅储銉€兗銉�: <code>full-doc</code> 鍏ㄦ枃妞滅储 / <code>paragraph</code> 娈佃惤妞滅储
+ - <code>subchunk_segmentation</code> (object) 瀛愩儊銉c兂銈儷銉笺儷
+ - <code>separator</code> 銈汇偘銉°兂銉嗐兗銈枫儳銉宠瓨鍒ュ瓙銆傜従鍦ㄣ伅 1 銇ゃ伄鍖哄垏銈婃枃瀛椼伄銇胯ū鍙�傘儑銉曘偐銉儓銇� <code>***</code>
+ - <code>max_tokens</code> 鏈�澶ч暦 (銉堛兗銈兂) 銇Κ銉併儯銉炽偗銇暦銇曘倛銈婄煭銇勩亾銇ㄣ倰妞滆銇欍倠蹇呰銇屻亗銈娿伨銇�
+ - <code>chunk_overlap</code> 闅f帴銇欍倠銉併儯銉炽偗闁撱伄閲嶈銈掑畾缇� (銈儣銈枫儳銉�)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/update-by-text"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"name": "name","text": "text"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-text' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "name",
+ "text": "text"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "name.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695308667,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/update-by-file'
+ method='POST'
+ title='銉曘偂銈ゃ儷銇с儔銈儱銉°兂銉堛倰鏇存柊'
+ name='#update-by-file'
+/>
+<Row>
+ <Col>
+ 銇撱伄 API 銇棦瀛樸伄銉娿儸銉冦偢銇熀銇ャ亜銇︺亰銈娿�併亾銇儕銉儍銈搞倰鍩恒伀銉曘偂銈ゃ儷銈掍娇鐢ㄣ仐銇︺儔銈儱銉°兂銉堛倰鏇存柊銇椼伨銇欍��
+
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 銉夈偔銉ャ儭銉炽儓鍚� (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='file' type='multipart/form-data' key='file'>
+ 銈€儍銉椼儹銉笺儔銇欍倠銉曘偂銈ゃ儷
+ </Property>
+ <Property name='process_rule' type='object' key='process_rule'>
+ 鍑︾悊銉兗銉�
+ - <code>mode</code> (string) 銈儶銉笺儖銉炽偘銆併偦銈般儭銉炽儐銉笺偡銉с兂銉€兗銉夈�佽嚜鍕� / 銈偣銈裤儬
+ - <code>rules</code> (object) 銈偣銈裤儬銉兗銉� (鑷嫊銉€兗銉夈仹銇�併亾銇儠銈c兗銉儔銇┖)
+ - <code>pre_processing_rules</code> (array[object]) 鍓嶅嚘鐞嗐儷銉笺儷
+ - <code>id</code> (string) 鍓嶅嚘鐞嗐儷銉笺儷銇竴鎰忚瓨鍒ュ瓙
+ - 鍒楁寵
+ - <code>remove_extra_spaces</code> 閫g稓銇欍倠銈广儦銉笺偣銆佹敼琛屻�併偪銉栥倰缃彌
+ - <code>remove_urls_emails</code> URL銆併儭銉笺儷銈€儔銉偣銈掑墛闄�
+ - <code>enabled</code> (bool) 銇撱伄銉兗銉倰閬告姙銇欍倠銇嬨仼銇嗐亱銆傘儔銈儱銉°兂銉� ID 銇屾浮銇曘倢銇亜鍫村悎銆併儑銉曘偐銉儓鍊ゃ倰琛ㄣ仐銇俱仚銆�
+ - <code>segmentation</code> (object) 銈汇偘銉°兂銉嗐兗銈枫儳銉炽儷銉笺儷
+ - <code>separator</code> 銈偣銈裤儬銈汇偘銉°兂銉堣瓨鍒ュ瓙銆傜従鍦ㄣ伅 1 銇ゃ伄鍖哄垏銈婃枃瀛椼伄銇胯ō瀹氬彲鑳姐�傘儑銉曘偐銉儓銇� \n
+ - <code>max_tokens</code> 鏈�澶ч暦 (銉堛兗銈兂) 銉囥儠銈┿儷銉堛伅 1000
+ - <code>parent_mode</code> 瑕儊銉c兂銈伄妞滅储銉€兗銉�: <code>full-doc</code> 鍏ㄦ枃妞滅储 / <code>paragraph</code> 娈佃惤妞滅储
+ - <code>subchunk_segmentation</code> (object) 瀛愩儊銉c兂銈儷銉笺儷
+ - <code>separator</code> 銈汇偘銉°兂銉嗐兗銈枫儳銉宠瓨鍒ュ瓙銆傜従鍦ㄣ伅 1 銇ゃ伄鍖哄垏銈婃枃瀛椼伄銇胯ū鍙�傘儑銉曘偐銉儓銇� <code>***</code>
+ - <code>max_tokens</code> 鏈�澶ч暦 (銉堛兗銈兂) 銇Κ銉併儯銉炽偗銇暦銇曘倛銈婄煭銇勩亾銇ㄣ倰妞滆銇欍倠蹇呰銇屻亗銈娿伨銇�
+ - <code>chunk_overlap</code> 闅f帴銇欍倠銉併儯銉炽偗闁撱伄閲嶈銈掑畾缇� (銈儣銈枫儳銉�)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/update-by-file"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'data="{"name":"Dify","indexing_technique":"high_quality","process_rule":{"rules":{"pre_processing_rules":[{"id":"remove_extra_spaces","enabled":true},{"id":"remove_urls_emails","enabled":true}],"segmentation":{"separator":"###","max_tokens":500}},"mode":"custom"}}";type=text/plain' \\\n--form 'file=@"/path/to/file"'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-file' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \
+ --form 'file=@"/path/to/file"'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "Dify.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695308667,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": "20230921150427533684"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{batch}/indexing-status'
+ method='GET'
+ title='銉夈偔銉ャ儭銉炽儓銇煁銈佽炯銇裤偣銉嗐兗銈裤偣 (閫茶鐘舵硜) 銈掑彇寰�'
+ name='#indexing_status'
+/>
+<Row>
+ <Col>
+ ### 銉戙儵銉°兗銈�
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='batch' type='string' key='batch'>
+ 銈€儍銉椼儹銉笺儔銇曘倢銇熴儔銈儱銉°兂銉堛伄銉愩儍銉佺暘鍙�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{batch}/indexing-status"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{batch}/indexing-status' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{batch}/indexing-status' \
+ --header 'Authorization: Bearer {api_key}' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "data":[{
+ "id": "",
+ "indexing_status": "indexing",
+ "processing_started_at": 1681623462.0,
+ "parsing_completed_at": 1681623462.0,
+ "cleaning_completed_at": 1681623462.0,
+ "splitting_completed_at": 1681623462.0,
+ "completed_at": null,
+ "paused_at": null,
+ "error": null,
+ "stopped_at": null,
+ "completed_segments": 24,
+ "total_segments": 100
+ }]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}'
+ method='DELETE'
+ title='銉夈偔銉ャ儭銉炽儓銈掑墛闄�'
+ name='#delete_document'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/documents/{document_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```text {{ title: '銉偣銉濄兂銈�' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents'
+ method='GET'
+ title='銉娿儸銉冦偢銉欍兗銈广伄銉夈偔銉ャ儭銉炽儓銉偣銉堛倰鍙栧緱'
+ name='#dataset_document_list'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ </Properties>
+
+ ### 銈偍銉�
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 妞滅储銈兗銉兗銉夈�佺従鍦ㄣ伅銉夈偔銉ャ儭銉炽儓鍚嶃伄銇挎绱� (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='page' type='string' key='page'>
+ 銉氥兗銈哥暘鍙� (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ 杩斻仌銈屻倠銈€偆銉嗐儬鏁般�併儑銉曘偐銉儓銇� 20銆佺瘎鍥层伅 1-100 (銈儣銈枫儳銉�)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents' \
+ --header 'Authorization: Bearer {api_key}' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "",
+ "position": 1,
+ "data_source_type": "file_upload",
+ "data_source_info": null,
+ "dataset_process_rule_id": null,
+ "name": "dify",
+ "created_from": "",
+ "created_by": "",
+ "created_at": 1681623639,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false
+ },
+ ],
+ "has_more": false,
+ "limit": 20,
+ "total": 9,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments'
+ method='POST'
+ title='銉夈偔銉ャ儭銉炽儓銇儊銉c兂銈倰杩藉姞'
+ name='#create_new_segment'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='segments' type='object list' key='segments'>
+ - <code>content</code> (text) 銉嗐偔銈广儓鍐呭 / 璩晱鍐呭銆佸繀闋�
+ - <code>answer</code> (text) 鍥炵瓟鍐呭銆併儕銉儍銈搞伄銉€兗銉夈亴 Q&A 銉€兗銉夈伄鍫村悎銇�ゃ倰娓°仐銇俱仚 (銈儣銈枫儳銉�)
+ - <code>keywords</code> (list) 銈兗銉兗銉� (銈儣銈枫儳銉�)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"segments": [{"content": "1","answer": "1","keywords": ["a"]}]}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "segments": [
+ {
+ "content": "1",
+ "answer": "1",
+ "keywords": ["a"]
+ }
+ ]
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [{
+ "id": "",
+ "position": 1,
+ "document_id": "",
+ "content": "1",
+ "answer": "1",
+ "word_count": 25,
+ "tokens": 0,
+ "keywords": [
+ "a"
+ ],
+ "index_node_id": "",
+ "index_node_hash": "",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }],
+ "doc_form": "text_model"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments'
+ method='GET'
+ title='銉夈偔銉ャ儭銉炽儓銇嬨倝銉併儯銉炽偗銈掑彇寰�'
+ name='#get_segment'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ </Properties>
+
+ ### 銈偍銉�
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 銈兗銉兗銉� (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='status' type='string' key='status'>
+ 妞滅储銈广儐銉笺偪銈广�乧ompleted
+ </Property>
+ <Property name='page' type='string' key='page'>
+ 銉氥兗銈哥暘鍙� (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ 杩斻仌銈屻倠銈€偆銉嗐儬鏁般�併儑銉曘偐銉儓銇� 20銆佺瘎鍥层伅 1-100 (銈儣銈枫儳銉�)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [{
+ "id": "",
+ "position": 1,
+ "document_id": "",
+ "content": "1",
+ "answer": "1",
+ "word_count": 25,
+ "tokens": 0,
+ "keywords": [
+ "a"
+ ],
+ "index_node_id": "",
+ "index_node_hash": "",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }],
+ "doc_form": "text_model",
+ "has_more": false,
+ "limit": 20,
+ "total": 9,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}'
+ method='DELETE'
+ title='銉夈偔銉ャ儭銉炽儓鍐呫伄銉併儯銉炽偗銈掑墛闄�'
+ name='#delete_segment'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 銉夈偔銉ャ儭銉炽儓銈汇偘銉°兂銉� ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```text {{ title: '銉偣銉濄兂銈�' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}'
+ method='POST'
+ title='銉夈偔銉ャ儭銉炽儓鍐呫伄銉併儯銉炽偗銈掓洿鏂�'
+ name='#update_segment'
+/>
+<Row>
+ <Col>
+ ### POST
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 銉夈偔銉ャ儭銉炽儓銈汇偘銉°兂銉� ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='segment' type='object' key='segment'>
+ - <code>content</code> (text) 銉嗐偔銈广儓鍐呭 / 璩晱鍐呭銆佸繀闋�
+ - <code>answer</code> (text) 鍥炵瓟鍐呭銆併儕銉儍銈搞亴 Q&A 銉€兗銉夈伄鍫村悎銇�ゃ倰娓°仐銇俱仚 (銈儣銈枫儳銉�)
+ - <code>keywords</code> (list) 銈兗銉兗銉� (銈儣銈枫儳銉�)
+ - <code>enabled</code> (bool) False / true (銈儣銈枫儳銉�)
+ - <code>regenerate_child_chunks</code> (bool) 瀛愩儊銉c兂銈倰鍐嶇敓鎴愩仚銈嬨亱銇┿亞銇� (銈儣銈枫儳銉�)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{\"segment\": {\"content\": \"1\",\"answer\": \"1\", \"keywords\": [\"a\"], \"enabled\": false}}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "segment": {
+ "content": "1",
+ "answer": "1",
+ "keywords": ["a"],
+ "enabled": false
+ }
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "data": {
+ "id": "",
+ "position": 1,
+ "document_id": "",
+ "content": "1",
+ "answer": "1",
+ "word_count": 25,
+ "tokens": 0,
+ "keywords": [
+ "a"
+ ],
+ "index_node_id": "",
+ "index_node_hash": "",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ },
+ "doc_form": "text_model"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks'
+ method='POST'
+ title='瀛愩儊銉c兂銈倰浣滄垚'
+ name='#create_child_chunk'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 銈汇偘銉°兂銉� ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='content' type='string' key='content'>
+ 瀛愩儊銉c兂銈伄鍐呭
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"content": "Child chunk content"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "content": "Child chunk content"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "data": {
+ "id": "",
+ "segment_id": "",
+ "content": "Child chunk content",
+ "word_count": 25,
+ "tokens": 0,
+ "index_node_id": "",
+ "index_node_hash": "",
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks'
+ method='GET'
+ title='瀛愩儊銉c兂銈倰鍙栧緱'
+ name='#get_child_chunks'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 銈汇偘銉°兂銉� ID
+ </Property>
+ </Properties>
+
+ ### 銈偍銉�
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 妞滅储銈兗銉兗銉� (銈儣銈枫儳銉�)
+ </Property>
+ <Property name='page' type='integer' key='page'>
+ 銉氥兗銈哥暘鍙� (銈儣銈枫儳銉炽�併儑銉曘偐銉儓: 1)
+ </Property>
+ <Property name='limit' type='integer' key='limit'>
+ 銉氥兗銈搞亗銇熴倞銇偄銈ゃ儐銉犳暟 (銈儣銈枫儳銉炽�併儑銉曘偐銉儓: 20銆佹渶澶�: 100)
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [{
+ "id": "",
+ "segment_id": "",
+ "content": "Child chunk content",
+ "word_count": 25,
+ "tokens": 0,
+ "index_node_id": "",
+ "index_node_hash": "",
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }],
+ "total": 1,
+ "total_pages": 1,
+ "page": 1,
+ "limit": 20
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}'
+ method='DELETE'
+ title='瀛愩儊銉c兂銈倰鍓婇櫎'
+ name='#delete_child_chunk'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 銈汇偘銉°兂銉� ID
+ </Property>
+ <Property name='child_chunk_id' type='string' key='child_chunk_id'>
+ 瀛愩儊銉c兂銈� ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```text {{ title: '銉偣銉濄兂銈�' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}'
+ method='PATCH'
+ title='瀛愩儊銉c兂銈倰鏇存柊'
+ name='#update_child_chunk'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 銈汇偘銉°兂銉� ID
+ </Property>
+ <Property name='child_chunk_id' type='string' key='child_chunk_id'>
+ 瀛愩儊銉c兂銈� ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='content' type='string' key='content'>
+ 瀛愩儊銉c兂銈伄鍐呭
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="PATCH"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}"
+ targetCode={`curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"content": "Updated child chunk content"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "content": "Updated child chunk content"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "data": {
+ "id": "",
+ "segment_id": "",
+ "content": "Updated child chunk content",
+ "word_count": 25,
+ "tokens": 0,
+ "index_node_id": "",
+ "index_node_hash": "",
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/upload-file'
+ method='GET'
+ title='銈€儍銉椼儹銉笺儔銉曘偂銈ゃ儷銈掑彇寰�'
+ name='#get_upload_file'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 銉夈偔銉ャ儭銉炽儓 ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{document_id}/upload-file"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "file_id",
+ "name": "file_name",
+ "size": 1024,
+ "extension": "txt",
+ "url": "preview_url",
+ "download_url": "download_url",
+ "mime_type": "text/plain",
+ "created_by": "user_id",
+ "created_at": 1728734540,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/retrieve'
+ method='POST'
+ title='銉娿儸銉冦偢銉欍兗銈广亱銈夈儊銉c兂銈倰鍙栧緱'
+ name='#dataset_retrieval'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='query' type='string' key='query'>
+ 銈偍銉偔銉笺儻銉笺儔
+ </Property>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ 妞滅储銉€儑銉� (銈儣銈枫儳銉炽�佸叆鍔涖仌銈屻仾銇勫牬鍚堛伅銉囥儠銈┿儷銉堛伄鏂规硶銇с儶銈炽兗銉仌銈屻伨銇�)
+ - <code>search_method</code> (text) 妞滅储鏂规硶: 浠ヤ笅銇� 4 銇ゃ伄銈兗銉兗銉夈伄銇勩仛銈屻亱銇屽繀瑕併仹銇�
+ - <code>keyword_search</code> 銈兗銉兗銉夋绱�
+ - <code>semantic_search</code> 銈汇優銉炽儐銈c儍銈绱�
+ - <code>full_text_search</code> 鍏ㄦ枃妞滅储
+ - <code>hybrid_search</code> 銉忋偆銉栥儶銉冦儔妞滅储
+ - <code>reranking_enable</code> (bool) 鍐嶃儵銉炽偔銉炽偘銈掓湁鍔广伀銇欍倠銇嬨仼銇嗐亱銆佹绱€儮銉笺儔銇� semantic_search 銇俱仧銇� hybrid_search 銇牬鍚堛伀蹇呴爤 (銈儣銈枫儳銉�)
+ - <code>reranking_mode</code> (object) 鍐嶃儵銉炽偔銉炽偘銉€儑銉鎴愩�佸啀銉┿兂銈兂銈般亴鏈夊姽銇牬鍚堛伀蹇呴爤
+ - <code>reranking_provider_name</code> (string) 鍐嶃儵銉炽偔銉炽偘銉€儑銉儣銉儛銈ゃ儉銉�
+ - <code>reranking_model_name</code> (string) 鍐嶃儵銉炽偔銉炽偘銉€儑銉悕
+ - <code>weights</code> (float) 銉忋偆銉栥儶銉冦儔妞滅储銉€兗銉夈仹銇偦銉炪兂銉嗐偅銉冦偗妞滅储銇噸銇胯ō瀹�
+ - <code>top_k</code> (integer) 杩斻仌銈屻倠绲愭灉銇暟 (銈儣銈枫儳銉�)
+ - <code>score_threshold_enabled</code> (bool) 銈广偝銈㈤柧鍊ゃ倰鏈夊姽銇仚銈嬨亱銇┿亞銇�
+ - <code>score_threshold</code> (float) 銈广偝銈㈤柧鍊�
+ </Property>
+ <Property name='external_retrieval_model' type='object' key='external_retrieval_model'>
+ 鏈娇鐢ㄣ儠銈c兗銉儔
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/retrieve"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/retrieve' \\\n--header 'Authorization: Bearer {api_key}'\\\n--header 'Content-Type: application/json'\\\n--data-raw '{
+ "query": "test",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 1,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ }
+}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/retrieve' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "query": "test",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 2,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ }
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "query": {
+ "content": "test"
+ },
+ "records": [
+ {
+ "segment": {
+ "id": "7fa6f24f-8679-48b3-bc9d-bdf28d73f218",
+ "position": 1,
+ "document_id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2",
+ "content": "Operation guide",
+ "answer": null,
+ "word_count": 847,
+ "tokens": 280,
+ "keywords": [
+ "install",
+ "java",
+ "base",
+ "scripts",
+ "jdk",
+ "manual",
+ "internal",
+ "opens",
+ "add",
+ "vmoptions"
+ ],
+ "index_node_id": "39dd8443-d960-45a8-bb46-7275ad7fbc8e",
+ "index_node_hash": "0189157697b3c6a418ccf8264a09699f25858975578f3467c76d6bfc94df1d73",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "dbcb1ab5-90c8-41a7-8b78-73b235eb6f6f",
+ "created_at": 1728734540,
+ "indexing_at": 1728734552,
+ "completed_at": 1728734584,
+ "error": null,
+ "stopped_at": null,
+ "document": {
+ "id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2",
+ "data_source_type": "upload_file",
+ "name": "readme.txt",
+ }
+ },
+ "score": 3.730463140527718e-05,
+ "tsne_position": null
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata'
+ method='POST'
+ title='銉娿儸銉冦偢銉°偪銉囥兗銈裤倰浣滄垚'
+ name='#create_metadata'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='segment' type='object' key='segment'>
+ - <code>type</code> (string) 銉°偪銉囥兗銈裤伄绋銆佸繀闋�
+ - <code>name</code> (string) 銉°偪銉囥兗銈裤伄鍚嶅墠銆佸繀闋�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/metadata"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/metadata' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"type": "string", "name": "test"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "abc",
+ "type": "string",
+ "name": "test",
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata/{metadata_id}'
+ method='PATCH'
+ title='銉娿儸銉冦偢銉°偪銉囥兗銈裤倰鏇存柊'
+ name='#update_metadata'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='metadata_id' type='string' key='metadata_id'>
+ 銉°偪銉囥兗銈� ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='segment' type='object' key='segment'>
+ - <code>name</code> (string) 銉°偪銉囥兗銈裤伄鍚嶅墠銆佸繀闋�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="PATCH"
+ label="/datasets/{dataset_id}/metadata/{metadata_id}"
+ targetCode={`curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/metadata/{metadata_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"name": "test"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "abc",
+ "type": "string",
+ "name": "test",
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata/{metadata_id}'
+ method='DELETE'
+ title='銉娿儸銉冦偢銉°偪銉囥兗銈裤倰鍓婇櫎'
+ name='#delete_metadata'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='metadata_id' type='string' key='metadata_id'>
+ 銉°偪銉囥兗銈� ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/metadata/{metadata_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/metadata/{metadata_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata/built-in/{action}'
+ method='POST'
+ title='绲勩伩杈笺伩銉°偪銉囥兗銈裤倰鐒″姽鍖栥伨銇熴伅鏈夊姽鍖�'
+ name='#toggle_metadata'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ <Property name='action' type='string' key='action'>
+ disable/enable
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/metadata/built-in/{action}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/metadata/built-in/{action}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/metadata'
+ method='POST'
+ title='銉夈偔銉ャ儭銉炽儓銉°偪銉囥兗銈裤倰鏇存柊'
+ name='#update_documents_metadata'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ <Properties>
+ <Property name='operation_data' type='object list' key='segments'>
+ - <code>document_id</code> (string) 銉夈偔銉ャ儭銉炽儓 ID
+ - <code>metadata_list</code> (list) 銉°偪銉囥兗銈裤儶銈广儓
+ - <code>id</code> (string) 銉°偪銉囥兗銈� ID
+ - <code>value</code> (string) 銉°偪銉囥兗銈裤伄鍊�
+ - <code>name</code> (string) 銉°偪銉囥兗銈裤伄鍚嶅墠
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/metadata"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/metadata' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"operation_data": [{"document_id": "document_id", "metadata_list": [{"id": "id", "value": "value", "name": "name"}]}]}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata'
+ method='GET'
+ title='銉娿儸銉冦偢銉°偪銉囥兗銈裤儶銈广儓銈掑彇寰�'
+ name='#dataset_metadata_list'
+/>
+<Row>
+ <Col>
+ ### 銉戙偣
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 銉娿儸銉冦偢 ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="銉偗銈ㄣ偣銉�"
+ tag="GET"
+ label="/datasets/{dataset_id}/metadata"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/metadata' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉偣銉濄兂銈�">
+ ```json {{ title: 'Response' }}
+ {
+ "doc_metadata": [
+ {
+ "id": "",
+ "name": "name",
+ "type": "string",
+ "use_count": 0,
+ },
+ ...
+ ],
+ "built_in_field_enabled": true
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Row>
+ <Col>
+ ### 銈ㄣ儵銉笺儭銉冦偦銉笺偢
+ <Properties>
+ <Property name='code' type='string' key='code'>
+ 銈ㄣ儵銉笺偝銉笺儔
+ </Property>
+ </Properties>
+ <Properties>
+ <Property name='status' type='number' key='status'>
+ 銈ㄣ儵銉笺偣銉嗐兗銈裤偣
+ </Property>
+ </Properties>
+ <Properties>
+ <Property name='message' type='string' key='message'>
+ 銈ㄣ儵銉笺儭銉冦偦銉笺偢
+ </Property>
+ </Properties>
+ </Col>
+ <Col>
+ <CodeGroup title="渚�">
+ ```json {{ title: 'Response' }}
+ {
+ "code": "no_file_uploaded",
+ "message": "Please upload your file.",
+ "status": 400
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+<table className="max-w-auto border-collapse border border-slate-400" style={{ maxWidth: 'none', width: 'auto' }}>
+ <thead style={{ background: '#f9fafc' }}>
+ <tr>
+ <th className="p-2 border border-slate-300">code</th>
+ <th className="p-2 border border-slate-300">status</th>
+ <th className="p-2 border border-slate-300">message</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td className="p-2 border border-slate-300">no_file_uploaded</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Please upload your file.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">too_many_files</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Only one file is allowed.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">file_too_large</td>
+ <td className="p-2 border border-slate-300">413</td>
+ <td className="p-2 border border-slate-300">File size exceeded.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">unsupported_file_type</td>
+ <td className="p-2 border border-slate-300">415</td>
+ <td className="p-2 border border-slate-300">File type not allowed.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">high_quality_dataset_only</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Current operation only supports 'high-quality' datasets.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">dataset_not_initialized</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The dataset is still being initialized or indexing. Please wait a moment.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">archived_document_immutable</td>
+ <td className="p-2 border border-slate-300">403</td>
+ <td className="p-2 border border-slate-300">The archived document is not editable.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">dataset_name_duplicate</td>
+ <td className="p-2 border border-slate-300">409</td>
+ <td className="p-2 border border-slate-300">The dataset name already exists. Please modify your dataset name.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">invalid_action</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Invalid action.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">document_already_finished</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The document has been processed. Please refresh the page or go to the document details.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">document_indexing</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The document is being processed and cannot be edited.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">invalid_metadata</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The metadata content is incorrect. Please check and verify.</td>
+ </tr>
+ </tbody>
+</table>
+<div className="pb-4" />
diff --git "a/app/\050commonLayout\051/datasets/template/template.zh.mdx" "b/app/\050commonLayout\051/datasets/template/template.zh.mdx"
new file mode 100644
index 0000000..e3c716e
--- /dev/null
+++ "b/app/\050commonLayout\051/datasets/template/template.zh.mdx"
@@ -0,0 +1,2394 @@
+{/**
+ * @typedef Props
+ * @property {string} apiBaseUrl
+ */}
+
+import { CodeGroup } from '@/app/components/develop/code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstruction, Paragraph } from '@/app/components/develop/md.tsx'
+
+# 鐭ヨ瘑搴� API
+
+<div>
+ ### 閴存潈
+
+ Dify Service API 浣跨敤 `API-Key` 杩涜閴存潈銆�
+
+ 寤鸿寮�鍙戣�呮妸 `API-Key` 鏀惧湪鍚庣瀛樺偍锛岃�岄潪鍒嗕韩鎴栬�呮斁鍦ㄥ鎴风瀛樺偍锛屼互鍏� `API-Key` 娉勯湶锛屽鑷磋储浜ф崯澶便��
+
+ 鎵�鏈� API 璇锋眰閮藉簲鍦� **`Authorization`** HTTP Header 涓寘鍚偍鐨� `API-Key`锛屽涓嬫墍绀猴細
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/document/create-by-text'
+ method='POST'
+ title='閫氳繃鏂囨湰鍒涘缓鏂囨。'
+ name='#create-by-text'
+/>
+<Row>
+ <Col>
+ 姝ゆ帴鍙e熀浜庡凡瀛樺湪鐭ヨ瘑搴擄紝鍦ㄦ鐭ヨ瘑搴撶殑鍩虹涓婇�氳繃鏂囨湰鍒涘缓鏂扮殑鏂囨。
+
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 鏂囨。鍚嶇О
+ </Property>
+ <Property name='text' type='string' key='text'>
+ 鏂囨。鍐呭
+ </Property>
+ <Property name='indexing_technique' type='string' key='indexing_technique'>
+ 绱㈠紩鏂瑰紡
+ - <code>high_quality</code> 楂樿川閲忥細浣跨敤
+ ding 妯″瀷杩涜宓屽叆锛屾瀯寤轰负鍚戦噺鏁版嵁搴撶储寮�
+ - <code>economy</code> 缁忔祹锛氫娇鐢� keyword table index 鐨勫�掓帓绱㈠紩杩涜鏋勫缓
+ </Property>
+ <Property name='doc_form' type='string' key='doc_form'>
+ 绱㈠紩鍐呭鐨勫舰寮�
+ - <code>text_model</code> text 鏂囨。鐩存帴 embedding锛岀粡娴庢ā寮忛粯璁や负璇ユā寮�
+ - <code>hierarchical_model</code> parent-child 妯″紡
+ - <code>qa_model</code> Q&A 妯″紡锛氫负鍒嗙墖鏂囨。鐢熸垚 Q&A 瀵癸紝鐒跺悗瀵归棶棰樿繘琛� embedding
+ </Property>
+ <Property name='doc_language' type='string' key='doc_language'>
+ 鍦� Q&A 妯″紡涓嬶紝鎸囧畾鏂囨。鐨勮瑷�锛屼緥濡傦細<code>English</code>銆�<code>Chinese</code>
+ </Property>
+ <Property name='process_rule' type='object' key='process_rule'>
+ 澶勭悊瑙勫垯
+ - <code>mode</code> (string) 娓呮礂銆佸垎娈垫ā寮� 锛宎utomatic 鑷姩 / custom 鑷畾涔�
+ - <code>rules</code> (object) 鑷畾涔夎鍒欙紙鑷姩妯″紡涓嬶紝璇ュ瓧娈典负绌猴級
+ - <code>pre_processing_rules</code> (array[object]) 棰勫鐞嗚鍒�
+ - <code>id</code> (string) 棰勫鐞嗚鍒欑殑鍞竴鏍囪瘑绗�
+ - 鏋氫妇锛�
+ - <code>remove_extra_spaces</code> 鏇挎崲杩炵画绌烘牸銆佹崲琛岀銆佸埗琛ㄧ
+ - <code>remove_urls_emails</code> 鍒犻櫎 URL銆佺數瀛愰偖浠跺湴鍧�
+ - <code>enabled</code> (bool) 鏄惁閫変腑璇ヨ鍒欙紝涓嶄紶鍏ユ枃妗� ID 鏃朵唬琛ㄩ粯璁ゅ��
+ - <code>segmentation</code> (object) 鍒嗘瑙勫垯
+ - <code>separator</code> 鑷畾涔夊垎娈垫爣璇嗙锛岀洰鍓嶄粎鍏佽璁剧疆涓�涓垎闅旂銆傞粯璁や负 <code>\n</code>
+ - <code>max_tokens</code> 鏈�澶ч暱搴︼紙token锛夐粯璁や负 1000
+ - <code>parent_mode</code> 鐖跺垎娈电殑鍙洖妯″紡 <code>full-doc</code> 鍏ㄦ枃鍙洖 / <code>paragraph</code> 娈佃惤鍙洖
+ - <code>subchunk_segmentation</code> (object) 瀛愬垎娈佃鍒�
+ - <code>separator</code> 鍒嗘鏍囪瘑绗︼紝鐩墠浠呭厑璁歌缃竴涓垎闅旂銆傞粯璁や负 <code>***</code>
+ - <code>max_tokens</code> 鏈�澶ч暱搴� (token) 闇�瑕佹牎楠屽皬浜庣埗绾х殑闀垮害
+ - <code>chunk_overlap</code> 鍒嗘閲嶅彔鎸囩殑鏄湪瀵规暟鎹繘琛屽垎娈垫椂锛屾涓庢涔嬮棿瀛樺湪涓�瀹氱殑閲嶅彔閮ㄥ垎锛堥�夊~锛�
+ </Property>
+ <PropertyInstruction>褰撶煡璇嗗簱鏈缃换浣曞弬鏁扮殑鏃跺�欙紝棣栨涓婁紶闇�瑕佹彁渚涗互涓嬪弬鏁帮紝鏈彁渚涘垯浣跨敤榛樿閫夐」锛�</PropertyInstruction>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ 妫�绱㈡ā寮�
+ - <code>search_method</code> (string) 妫�绱㈡柟娉�
+ - <code>hybrid_search</code> 娣峰悎妫�绱�
+ - <code>semantic_search</code> 璇箟妫�绱�
+ - <code>full_text_search</code> 鍏ㄦ枃妫�绱�
+ - <code>reranking_enable</code> (bool) 鏄惁寮�鍚痳erank
+ - <code>reranking_mode</code> (String) 娣峰悎妫�绱�
+ - <code>weighted_score</code> 鏉冮噸璁剧疆
+ - <code>reranking_model</code> Rerank 妯″瀷
+ - <code>reranking_model</code> (object) Rerank 妯″瀷閰嶇疆
+ - <code>reranking_provider_name</code> (string) Rerank 妯″瀷鐨勬彁渚涘晢
+ - <code>reranking_model_name</code> (string) Rerank 妯″瀷鐨勫悕绉�
+ - <code>top_k</code> (int) 鍙洖鏉℃暟
+ - <code>score_threshold_enabled</code> (bool)鏄惁寮�鍚彫鍥炲垎鏁伴檺鍒�
+ - <code>score_threshold</code> (float) 鍙洖鍒嗘暟闄愬埗
+ </Property>
+ <Property name='embedding_model' type='string' key='embedding_model'>
+ Embedding 妯″瀷鍚嶇О
+ </Property>
+ <Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
+ Embedding 妯″瀷渚涘簲鍟�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/document/create-by-text"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"name": "text","text": "text","indexing_technique": "high_quality","process_rule": {"mode": "automatic"}}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-text' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "text",
+ "text": "text",
+ "indexing_technique": "high_quality",
+ "process_rule": {
+ "mode": "automatic"
+ }
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "text.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695690280,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/document/create-by-file'
+ method='POST'
+ title='閫氳繃鏂囦欢鍒涘缓鏂囨。 '
+ name='#create-by-file'
+/>
+<Row>
+ <Col>
+ 姝ゆ帴鍙e熀浜庡凡瀛樺湪鐭ヨ瘑搴擄紝鍦ㄦ鐭ヨ瘑搴撶殑鍩虹涓婇�氳繃鏂囦欢鍒涘缓鏂扮殑鏂囨。
+
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='data' type='multipart/form-data json string' key='data'>
+ - <code>original_document_id</code> 婧愭枃妗� ID锛堥�夊~锛�
+ - 鐢ㄤ簬閲嶆柊涓婁紶鏂囨。鎴栦慨鏀规枃妗f竻娲椼�佸垎娈甸厤缃紝缂哄け鐨勪俊鎭粠婧愭枃妗e鍒�
+ - 婧愭枃妗d笉鍙负褰掓。鐨勬枃妗�
+ - 褰撲紶鍏� <code>original_document_id</code> 鏃讹紝浠h〃鏂囨。杩涜鏇存柊鎿嶄綔锛�<code>process_rule</code> 涓哄彲濉」鐩紝涓嶅~榛樿浣跨敤婧愭枃妗g殑鍒嗘鏂瑰紡
+ - 鏈紶鍏� <code>original_document_id</code> 鏃讹紝浠h〃鏂囨。杩涜鏂板鎿嶄綔锛�<code>process_rule</code> 涓哄繀濉�
+
+ - <code>indexing_technique</code> 绱㈠紩鏂瑰紡
+ - <code>high_quality</code> 楂樿川閲忥細浣跨敤 embedding 妯″瀷杩涜宓屽叆锛屾瀯寤轰负鍚戦噺鏁版嵁搴撶储寮�
+ - <code>economy</code> 缁忔祹锛氫娇鐢� keyword table index 鐨勫�掓帓绱㈠紩杩涜鏋勫缓
+
+ - <code>doc_form</code> 绱㈠紩鍐呭鐨勫舰寮�
+ - <code>text_model</code> text 鏂囨。鐩存帴 embedding锛岀粡娴庢ā寮忛粯璁や负璇ユā寮�
+ - <code>hierarchical_model</code> parent-child 妯″紡
+ - <code>qa_model</code> Q&A 妯″紡锛氫负鍒嗙墖鏂囨。鐢熸垚 Q&A 瀵癸紝鐒跺悗瀵归棶棰樿繘琛� embedding
+
+ - <code>doc_language</code> 鍦� Q&A 妯″紡涓嬶紝鎸囧畾鏂囨。鐨勮瑷�锛屼緥濡傦細<code>English</code>銆�<code>Chinese</code>
+
+ - <code>process_rule</code> 澶勭悊瑙勫垯
+ - <code>mode</code> (string) 娓呮礂銆佸垎娈垫ā寮� 锛宎utomatic 鑷姩 / custom 鑷畾涔�
+ - <code>rules</code> (object) 鑷畾涔夎鍒欙紙鑷姩妯″紡涓嬶紝璇ュ瓧娈典负绌猴級
+ - <code>pre_processing_rules</code> (array[object]) 棰勫鐞嗚鍒�
+ - <code>id</code> (string) 棰勫鐞嗚鍒欑殑鍞竴鏍囪瘑绗�
+ - 鏋氫妇锛�
+ - <code>remove_extra_spaces</code> 鏇挎崲杩炵画绌烘牸銆佹崲琛岀銆佸埗琛ㄧ
+ - <code>remove_urls_emails</code> 鍒犻櫎 URL銆佺數瀛愰偖浠跺湴鍧�
+ - <code>enabled</code> (bool) 鏄惁閫変腑璇ヨ鍒欙紝涓嶄紶鍏ユ枃妗� ID 鏃朵唬琛ㄩ粯璁ゅ��
+ - <code>segmentation</code> (object) 鍒嗘瑙勫垯
+ - <code>separator</code> 鑷畾涔夊垎娈垫爣璇嗙锛岀洰鍓嶄粎鍏佽璁剧疆涓�涓垎闅旂銆傞粯璁や负 \n
+ - <code>max_tokens</code> 鏈�澶ч暱搴︼紙token锛夐粯璁や负 1000
+ - <code>parent_mode</code> 鐖跺垎娈电殑鍙洖妯″紡 <code>full-doc</code> 鍏ㄦ枃鍙洖 / <code>paragraph</code> 娈佃惤鍙洖
+ - <code>subchunk_segmentation</code> (object) 瀛愬垎娈佃鍒�
+ - <code>separator</code> 鍒嗘鏍囪瘑绗︼紝鐩墠浠呭厑璁歌缃竴涓垎闅旂銆傞粯璁や负 <code>***</code>
+ - <code>max_tokens</code> 鏈�澶ч暱搴� (token) 闇�瑕佹牎楠屽皬浜庣埗绾х殑闀垮害
+ - <code>chunk_overlap</code> 鍒嗘閲嶅彔鎸囩殑鏄湪瀵规暟鎹繘琛屽垎娈垫椂锛屾涓庢涔嬮棿瀛樺湪涓�瀹氱殑閲嶅彔閮ㄥ垎锛堥�夊~锛�
+ </Property>
+ <Property name='file' type='multipart/form-data' key='file'>
+ 闇�瑕佷笂浼犵殑鏂囦欢銆�
+ </Property>
+ <PropertyInstruction>褰撶煡璇嗗簱鏈缃换浣曞弬鏁扮殑鏃跺�欙紝棣栨涓婁紶闇�瑕佹彁渚涗互涓嬪弬鏁帮紝鏈彁渚涘垯浣跨敤榛樿閫夐」锛�</PropertyInstruction>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ 妫�绱㈡ā寮�
+ - <code>search_method</code> (string) 妫�绱㈡柟娉�
+ - <code>hybrid_search</code> 娣峰悎妫�绱�
+ - <code>semantic_search</code> 璇箟妫�绱�
+ - <code>full_text_search</code> 鍏ㄦ枃妫�绱�
+ - <code>reranking_enable</code> (bool) 鏄惁寮�鍚痳erank
+ - <code>reranking_model</code> (object) Rerank 妯″瀷閰嶇疆
+ - <code>reranking_provider_name</code> (string) Rerank 妯″瀷鐨勬彁渚涘晢
+ - <code>reranking_model_name</code> (string) Rerank 妯″瀷鐨勫悕绉�
+ - <code>top_k</code> (int) 鍙洖鏉℃暟
+ - <code>score_threshold_enabled</code> (bool)鏄惁寮�鍚彫鍥炲垎鏁伴檺鍒�
+ - <code>score_threshold</code> (float) 鍙洖鍒嗘暟闄愬埗
+ </Property>
+ <Property name='embedding_model' type='string' key='embedding_model'>
+ Embedding 妯″瀷鍚嶇О
+ </Property>
+ <Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
+ Embedding 妯″瀷渚涘簲鍟�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/document/create-by-file"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'data="{"indexing_technique":"high_quality","process_rule":{"rules":{"pre_processing_rules":[{"id":"remove_extra_spaces","enabled":true},{"id":"remove_urls_emails","enabled":true}],"segmentation":{"separator":"###","max_tokens":500}},"mode":"custom"}}";type=text/plain' \\\n--form 'file=@"/path/to/file"'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-file' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \
+ --form 'file=@"/path/to/file"'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "Dify.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695308667,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets'
+ method='POST'
+ title='鍒涘缓绌虹煡璇嗗簱'
+ name='#create_empty_dataset'
+/>
+<Row>
+ <Col>
+ ### Request Body
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 鐭ヨ瘑搴撳悕绉帮紙蹇呭~锛�
+ </Property>
+ <Property name='description' type='string' key='description'>
+ 鐭ヨ瘑搴撴弿杩帮紙閫夊~锛�
+ </Property>
+ <Property name='indexing_technique' type='string' key='indexing_technique'>
+ 绱㈠紩妯″紡锛堥�夊~锛屽缓璁~鍐欙級
+ - <code>high_quality</code> 楂樿川閲�
+ - <code>economy</code> 缁忔祹
+ </Property>
+ <Property name='permission' type='string' key='permission'>
+ 鏉冮檺锛堥�夊~锛岄粯璁� only_me锛�
+ - <code>only_me</code> 浠呰嚜宸�
+ - <code>all_team_members</code> 鎵�鏈夊洟闃熸垚鍛�
+ - <code>partial_members</code> 閮ㄥ垎鍥㈤槦鎴愬憳
+ </Property>
+ <Property name='provider' type='string' key='provider'>
+ Provider锛堥�夊~锛岄粯璁� vendor锛�
+ - <code>vendor</code> 涓婁紶鏂囦欢
+ - <code>external</code> 澶栭儴鐭ヨ瘑搴�
+ </Property>
+ <Property name='external_knowledge_api_id' type='str' key='external_knowledge_api_id'>
+ 澶栭儴鐭ヨ瘑搴� API_ID锛堥�夊~锛�
+ </Property>
+ <Property name='external_knowledge_id' type='str' key='external_knowledge_id'>
+ 澶栭儴鐭ヨ瘑搴� ID锛堥�夊~锛�
+ </Property>
+ <Property name='embedding_model' type='str' key='embedding_model'>
+ Embedding 妯″瀷鍚嶇О
+ </Property>
+ <Property name='embedding_model_provider' type='str' key='embedding_model_provider'>
+ Embedding 妯″瀷渚涘簲鍟�
+ </Property>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ 妫�绱㈡ā寮�
+ - <code>search_method</code> (string) 妫�绱㈡柟娉�
+ - <code>hybrid_search</code> 娣峰悎妫�绱�
+ - <code>semantic_search</code> 璇箟妫�绱�
+ - <code>full_text_search</code> 鍏ㄦ枃妫�绱�
+ - <code>reranking_enable</code> (bool) 鏄惁寮�鍚痳erank
+ - <code>reranking_model</code> (object) Rerank 妯″瀷閰嶇疆
+ - <code>reranking_provider_name</code> (string) Rerank 妯″瀷鐨勬彁渚涘晢
+ - <code>reranking_model_name</code> (string) Rerank 妯″瀷鐨勫悕绉�
+ - <code>top_k</code> (int) 鍙洖鏉℃暟
+ - <code>score_threshold_enabled</code> (bool)鏄惁寮�鍚彫鍥炲垎鏁伴檺鍒�
+ - <code>score_threshold</code> (float) 鍙洖鍒嗘暟闄愬埗
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"name": "name", "permission": "only_me"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "name",
+ "permission": "only_me"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "",
+ "name": "name",
+ "description": null,
+ "provider": "vendor",
+ "permission": "only_me",
+ "data_source_type": null,
+ "indexing_technique": null,
+ "app_count": 0,
+ "document_count": 0,
+ "word_count": 0,
+ "created_by": "",
+ "created_at": 1695636173,
+ "updated_by": "",
+ "updated_at": 1695636173,
+ "embedding_model": null,
+ "embedding_model_provider": null,
+ "embedding_available": null
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets'
+ method='GET'
+ title='鐭ヨ瘑搴撳垪琛�'
+ name='#dataset_list'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 鎼滅储鍏抽敭璇嶏紝鍙��
+ </Property>
+ <Property name='tag_ids' type='array[string]' key='tag_ids'>
+ 鏍囩 ID 鍒楄〃锛屽彲閫�
+ </Property>
+ <Property name='page' type='integer' key='page'>
+ 椤电爜锛屽彲閫夛紝榛樿涓� 1
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ 杩斿洖鏉℃暟锛屽彲閫夛紝榛樿 20锛岃寖鍥� 1-100
+ </Property>
+ <Property name='include_all' type='boolean' key='include_all'>
+ 鏄惁鍖呭惈鎵�鏈夋暟鎹泦锛堜粎瀵规墍鏈夎�呯敓鏁堬級锛屽彲閫夛紝榛樿涓� false
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "",
+ "name": "鐭ヨ瘑搴撳悕绉�",
+ "description": "鎻忚堪淇℃伅",
+ "permission": "only_me",
+ "data_source_type": "upload_file",
+ "indexing_technique": "",
+ "app_count": 2,
+ "document_count": 10,
+ "word_count": 1200,
+ "created_by": "",
+ "created_at": "",
+ "updated_by": "",
+ "updated_at": ""
+ },
+ ...
+ ],
+ "has_more": true,
+ "limit": 20,
+ "total": 50,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}'
+ method='GET'
+ title='鏌ョ湅鐭ヨ瘑搴撹鎯�'
+ name='#view_dataset'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eaedb485-95ac-4ffd-ab1e-18da6d676a2f",
+ "name": "Test Knowledge Base",
+ "description": "",
+ "provider": "vendor",
+ "permission": "only_me",
+ "data_source_type": null,
+ "indexing_technique": null,
+ "app_count": 0,
+ "document_count": 0,
+ "word_count": 0,
+ "created_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6",
+ "created_at": 1735620612,
+ "updated_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6",
+ "updated_at": 1735620612,
+ "embedding_model": null,
+ "embedding_model_provider": null,
+ "embedding_available": true,
+ "retrieval_model_dict": {
+ "search_method": "semantic_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 2,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ },
+ "tags": [],
+ "doc_form": null,
+ "external_knowledge_info": {
+ "external_knowledge_id": null,
+ "external_knowledge_api_id": null,
+ "external_knowledge_api_name": null,
+ "external_knowledge_api_endpoint": null
+ },
+ "external_retrieval_model": {
+ "top_k": 2,
+ "score_threshold": 0.0,
+ "score_threshold_enabled": null
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}'
+ method='PATCH'
+ title='淇敼鐭ヨ瘑搴撹鎯�'
+ name='#update_dataset'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='indexing_technique' type='string' key='indexing_technique'>
+ 绱㈠紩妯″紡锛堥�夊~锛屽缓璁~鍐欙級
+ - <code>high_quality</code> 楂樿川閲�
+ - <code>economy</code> 缁忔祹
+ </Property>
+ <Property name='permission' type='string' key='permission'>
+ 鏉冮檺锛堥�夊~锛岄粯璁� only_me锛�
+ - <code>only_me</code> 浠呰嚜宸�
+ - <code>all_team_members</code> 鎵�鏈夊洟闃熸垚鍛�
+ - <code>partial_members</code> 閮ㄥ垎鍥㈤槦鎴愬憳
+ </Property>
+ <Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
+ 宓屽叆妯″瀷鎻愪緵鍟嗭紙閫夊~锛�, 蹇呴』鍏堝湪绯荤粺鍐呰瀹氬ソ鎺ュ叆鐨勬ā鍨嬶紝瀵瑰簲鐨勬槸provider瀛楁
+ </Property>
+ <Property name='embedding_model' type='string' key='embedding_model'>
+ 宓屽叆妯″瀷锛堥�夊~锛�
+ </Property>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ 妫�绱㈠弬鏁帮紙閫夊~锛屽涓嶅~锛屾寜鐓ч粯璁ゆ柟寮忓彫鍥烇級
+ - <code>search_method</code> (text) 妫�绱㈡柟娉曪細浠ヤ笅鍥涗釜鍏抽敭瀛椾箣涓�锛屽繀濉�
+ - <code>keyword_search</code> 鍏抽敭瀛楁绱�
+ - <code>semantic_search</code> 璇箟妫�绱�
+ - <code>full_text_search</code> 鍏ㄦ枃妫�绱�
+ - <code>hybrid_search</code> 娣峰悎妫�绱�
+ - <code>reranking_enable</code> (bool) 鏄惁鍚敤 Reranking锛岄潪蹇呭~锛屽鏋滄绱㈡ā寮忎负 semantic_search 妯″紡鎴栬�� hybrid_search 鍒欎紶鍊�
+ - <code>reranking_mode</code> (object) Rerank 妯″瀷閰嶇疆锛岄潪蹇呭~锛屽鏋滃惎鐢ㄤ簡 reranking 鍒欎紶鍊�
+ - <code>reranking_provider_name</code> (string) Rerank 妯″瀷鎻愪緵鍟�
+ - <code>reranking_model_name</code> (string) Rerank 妯″瀷鍚嶇О
+ - <code>weights</code> (float) 娣峰悎妫�绱㈡ā寮忎笅璇剰妫�绱㈢殑鏉冮噸璁剧疆
+ - <code>top_k</code> (integer) 杩斿洖缁撴灉鏁伴噺锛岄潪蹇呭~
+ - <code>score_threshold_enabled</code> (bool) 鏄惁寮�鍚� score 闃堝��
+ - <code>score_threshold</code> (float) Score 闃堝��
+ </Property>
+ <Property name='partial_member_list' type='array' key='partial_member_list'>
+ 閮ㄥ垎鍥㈤槦鎴愬憳 ID 鍒楄〃锛堥�夊~锛�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PATCH"
+ label="/datasets/{dataset_id}"
+ targetCode={`curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{
+ "name": "Test Knowledge Base",
+ "indexing_technique": "high_quality",
+ "permission": "only_me",
+ "embedding_model_provider": "zhipuai",
+ "embedding_model": "embedding-3",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 1,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ },
+ "partial_member_list": []
+ }'
+ `}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "Test Knowledge Base",
+ "indexing_technique": "high_quality",
+ "permission": "only_me",
+ "embedding_model_provider": "zhipuai",
+ "embedding_model": "embedding-3",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 1,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ },
+ "partial_member_list": []
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eaedb485-95ac-4ffd-ab1e-18da6d676a2f",
+ "name": "Test Knowledge Base",
+ "description": "",
+ "provider": "vendor",
+ "permission": "only_me",
+ "data_source_type": null,
+ "indexing_technique": "high_quality",
+ "app_count": 0,
+ "document_count": 0,
+ "word_count": 0,
+ "created_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6",
+ "created_at": 1735620612,
+ "updated_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6",
+ "updated_at": 1735622679,
+ "embedding_model": "embedding-3",
+ "embedding_model_provider": "zhipuai",
+ "embedding_available": null,
+ "retrieval_model_dict": {
+ "search_method": "semantic_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 2,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ },
+ "tags": [],
+ "doc_form": null,
+ "external_knowledge_info": {
+ "external_knowledge_id": null,
+ "external_knowledge_api_id": null,
+ "external_knowledge_api_name": null,
+ "external_knowledge_api_endpoint": null
+ },
+ "external_retrieval_model": {
+ "top_k": 2,
+ "score_threshold": 0.0,
+ "score_threshold_enabled": null
+ },
+ "partial_member_list": []
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}'
+ method='DELETE'
+ title='鍒犻櫎鐭ヨ瘑搴�'
+ name='#delete_dataset'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/update-by-text'
+ method='POST'
+ title='閫氳繃鏂囨湰鏇存柊鏂囨。'
+ name='#update-by-text'
+/>
+<Row>
+ <Col>
+ 姝ゆ帴鍙e熀浜庡凡瀛樺湪鐭ヨ瘑搴擄紝鍦ㄦ鐭ヨ瘑搴撶殑鍩虹涓婇�氳繃鏂囨湰鏇存柊鏂囨。
+
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 鏂囨。鍚嶇О锛堥�夊~锛�
+ </Property>
+ <Property name='text' type='string' key='text'>
+ 鏂囨。鍐呭锛堥�夊~锛�
+ </Property>
+ <Property name='process_rule' type='object' key='process_rule'>
+ 澶勭悊瑙勫垯锛堥�夊~锛�
+ - <code>mode</code> (string) 娓呮礂銆佸垎娈垫ā寮� 锛宎utomatic 鑷姩 / custom 鑷畾涔�
+ - <code>rules</code> (object) 鑷畾涔夎鍒欙紙鑷姩妯″紡涓嬶紝璇ュ瓧娈典负绌猴級
+ - <code>pre_processing_rules</code> (array[object]) 棰勫鐞嗚鍒�
+ - <code>id</code> (string) 棰勫鐞嗚鍒欑殑鍞竴鏍囪瘑绗�
+ - 鏋氫妇锛�
+ - <code>remove_extra_spaces</code> 鏇挎崲杩炵画绌烘牸銆佹崲琛岀銆佸埗琛ㄧ
+ - <code>remove_urls_emails</code> 鍒犻櫎 URL銆佺數瀛愰偖浠跺湴鍧�
+ - <code>enabled</code> (bool) 鏄惁閫変腑璇ヨ鍒欙紝涓嶄紶鍏ユ枃妗� ID 鏃朵唬琛ㄩ粯璁ゅ��
+ - <code>segmentation</code> (object) 鍒嗘瑙勫垯
+ - <code>separator</code> 鑷畾涔夊垎娈垫爣璇嗙锛岀洰鍓嶄粎鍏佽璁剧疆涓�涓垎闅旂銆傞粯璁や负 \n
+ - <code>max_tokens</code> 鏈�澶ч暱搴︼紙token锛夐粯璁や负 1000
+ - <code>parent_mode</code> 鐖跺垎娈电殑鍙洖妯″紡 <code>full-doc</code> 鍏ㄦ枃鍙洖 / <code>paragraph</code> 娈佃惤鍙洖
+ - <code>subchunk_segmentation</code> (object) 瀛愬垎娈佃鍒�
+ - <code>separator</code> 鍒嗘鏍囪瘑绗︼紝鐩墠浠呭厑璁歌缃竴涓垎闅旂銆傞粯璁や负 <code>***</code>
+ - <code>max_tokens</code> 鏈�澶ч暱搴� (token) 闇�瑕佹牎楠屽皬浜庣埗绾х殑闀垮害
+ - <code>chunk_overlap</code> 鍒嗘閲嶅彔鎸囩殑鏄湪瀵规暟鎹繘琛屽垎娈垫椂锛屾涓庢涔嬮棿瀛樺湪涓�瀹氱殑閲嶅彔閮ㄥ垎锛堥�夊~锛�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/update-by-text"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"name": "name","text": "text"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-text' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "name",
+ "text": "text"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "name.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695308667,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/update-by-file'
+ method='POST'
+ title='閫氳繃鏂囦欢鏇存柊鏂囨。'
+ name='#update-by-file'
+/>
+<Row>
+ <Col>
+ 姝ゆ帴鍙e熀浜庡凡瀛樺湪鐭ヨ瘑搴擄紝鍦ㄦ鐭ヨ瘑搴撶殑鍩虹涓婇�氳繃鏂囦欢鏇存柊鏂囨。鐨勬搷浣溿��
+
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 鏂囨。鍚嶇О锛堥�夊~锛�
+ </Property>
+ <Property name='file' type='multipart/form-data' key='file'>
+ 闇�瑕佷笂浼犵殑鏂囦欢
+ </Property>
+ <Property name='process_rule' type='object' key='process_rule'>
+ 澶勭悊瑙勫垯锛堥�夊~锛�
+ - <code>mode</code> (string) 娓呮礂銆佸垎娈垫ā寮� 锛宎utomatic 鑷姩 / custom 鑷畾涔�
+ - <code>rules</code> (object) 鑷畾涔夎鍒欙紙鑷姩妯″紡涓嬶紝璇ュ瓧娈典负绌猴級
+ - <code>pre_processing_rules</code> (array[object]) 棰勫鐞嗚鍒�
+ - <code>id</code> (string) 棰勫鐞嗚鍒欑殑鍞竴鏍囪瘑绗�
+ - 鏋氫妇锛�
+ - <code>remove_extra_spaces</code> 鏇挎崲杩炵画绌烘牸銆佹崲琛岀銆佸埗琛ㄧ
+ - <code>remove_urls_emails</code> 鍒犻櫎 URL銆佺數瀛愰偖浠跺湴鍧�
+ - <code>enabled</code> (bool) 鏄惁閫変腑璇ヨ鍒欙紝涓嶄紶鍏ユ枃妗� ID 鏃朵唬琛ㄩ粯璁ゅ��
+ - <code>segmentation</code> (object) 鍒嗘瑙勫垯
+ - <code>separator</code> 鑷畾涔夊垎娈垫爣璇嗙锛岀洰鍓嶄粎鍏佽璁剧疆涓�涓垎闅旂銆傞粯璁や负 \n
+ - <code>max_tokens</code> 鏈�澶ч暱搴︼紙token锛夐粯璁や负 1000
+ - <code>parent_mode</code> 鐖跺垎娈电殑鍙洖妯″紡 <code>full-doc</code> 鍏ㄦ枃鍙洖 / <code>paragraph</code> 娈佃惤鍙洖
+ - <code>subchunk_segmentation</code> (object) 瀛愬垎娈佃鍒�
+ - <code>separator</code> 鍒嗘鏍囪瘑绗︼紝鐩墠浠呭厑璁歌缃竴涓垎闅旂銆傞粯璁や负 <code>***</code>
+ - <code>max_tokens</code> 鏈�澶ч暱搴� (token) 闇�瑕佹牎楠屽皬浜庣埗绾х殑闀垮害
+ - <code>chunk_overlap</code> 鍒嗘閲嶅彔鎸囩殑鏄湪瀵规暟鎹繘琛屽垎娈垫椂锛屾涓庢涔嬮棿瀛樺湪涓�瀹氱殑閲嶅彔閮ㄥ垎锛堥�夊~锛�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/update-by-file"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'data="{"name":"Dify","indexing_technique":"high_quality","process_rule":{"rules":{"pre_processing_rules":[{"id":"remove_extra_spaces","enabled":true},{"id":"remove_urls_emails","enabled":true}],"segmentation":{"separator":"###","max_tokens":500}},"mode":"custom"}}";type=text/plain' \\\n--form 'file=@"/path/to/file"'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-file' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \
+ --form 'file=@"/path/to/file"'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "document": {
+ "id": "",
+ "position": 1,
+ "data_source_type": "upload_file",
+ "data_source_info": {
+ "upload_file_id": ""
+ },
+ "dataset_process_rule_id": "",
+ "name": "Dify.txt",
+ "created_from": "api",
+ "created_by": "",
+ "created_at": 1695308667,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false,
+ "display_status": "queuing",
+ "word_count": 0,
+ "hit_count": 0,
+ "doc_form": "text_model"
+ },
+ "batch": "20230921150427533684"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{batch}/indexing-status'
+ method='GET'
+ title='鑾峰彇鏂囨。宓屽叆鐘舵�侊紙杩涘害锛�'
+ name='#indexing_status'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='batch' type='string' key='batch'>
+ 涓婁紶鏂囨。鐨勬壒娆″彿
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{batch}/indexing-status"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{batch}/indexing-status' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{batch}/indexing-status' \
+ --header 'Authorization: Bearer {api_key}' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data":[{
+ "id": "",
+ "indexing_status": "indexing",
+ "processing_started_at": 1681623462.0,
+ "parsing_completed_at": 1681623462.0,
+ "cleaning_completed_at": 1681623462.0,
+ "splitting_completed_at": 1681623462.0,
+ "completed_at": null,
+ "paused_at": null,
+ "error": null,
+ "stopped_at": null,
+ "completed_segments": 24,
+ "total_segments": 100
+ }]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}'
+ method='DELETE'
+ title='鍒犻櫎鏂囨。'
+ name='#delete_document'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/documents/{document_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents'
+ method='GET'
+ title='鐭ヨ瘑搴撴枃妗e垪琛�'
+ name='#dataset_document_list'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 鎼滅储鍏抽敭璇嶏紝鍙�夛紝鐩墠浠呮悳绱㈡枃妗e悕绉�
+ </Property>
+ <Property name='page' type='string' key='page'>
+ 椤电爜锛屽彲閫�
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ 杩斿洖鏉℃暟锛屽彲閫夛紝榛樿 20锛岃寖鍥� 1-100
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents' \
+ --header 'Authorization: Bearer {api_key}' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "",
+ "position": 1,
+ "data_source_type": "file_upload",
+ "data_source_info": null,
+ "dataset_process_rule_id": null,
+ "name": "dify",
+ "created_from": "",
+ "created_by": "",
+ "created_at": 1681623639,
+ "tokens": 0,
+ "indexing_status": "waiting",
+ "error": null,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "archived": false
+ },
+ ],
+ "has_more": false,
+ "limit": 20,
+ "total": 9,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments'
+ method='POST'
+ title='鏂板鍒嗘'
+ name='#create_new_segment'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='segments' type='object list' key='segments'>
+ - <code>content</code> (text) 鏂囨湰鍐呭/闂鍐呭锛屽繀濉�
+ - <code>answer</code> (text) 绛旀鍐呭锛岄潪蹇呭~锛屽鏋滅煡璇嗗簱鐨勬ā寮忎负 Q&A 妯″紡鍒欎紶鍊�
+ - <code>keywords</code> (list) 鍏抽敭瀛楋紝闈炲繀濉�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"segments": [{"content": "1","answer": "1","keywords": ["a"]}]}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "segments": [
+ {
+ "content": "1",
+ "answer": "1",
+ "keywords": ["a"]
+ }
+ ]
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [{
+ "id": "",
+ "position": 1,
+ "document_id": "",
+ "content": "1",
+ "answer": "1",
+ "word_count": 25,
+ "tokens": 0,
+ "keywords": [
+ "a"
+ ],
+ "index_node_id": "",
+ "index_node_hash": "",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }],
+ "doc_form": "text_model"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments'
+ method='GET'
+ title='鏌ヨ鏂囨。鍒嗘'
+ name='#get_segment'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 鎼滅储鍏抽敭璇嶏紝鍙��
+ </Property>
+ <Property name='status' type='string' key='status'>
+ 鎼滅储鐘舵�侊紝completed
+ </Property>
+ <Property name='page' type='string' key='page'>
+ 椤电爜锛屽彲閫�
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ 杩斿洖鏉℃暟锛屽彲閫夛紝榛樿 20锛岃寖鍥� 1-100
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [{
+ "id": "",
+ "position": 1,
+ "document_id": "",
+ "content": "1",
+ "answer": "1",
+ "word_count": 25,
+ "tokens": 0,
+ "keywords": [
+ "a"
+ ],
+ "index_node_id": "",
+ "index_node_hash": "",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }],
+ "doc_form": "text_model",
+ "has_more": false,
+ "limit": 20,
+ "total": 9,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}'
+ method='DELETE'
+ title='鍒犻櫎鏂囨。鍒嗘'
+ name='#delete_segment'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 鏂囨。鍒嗘ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}'
+ method='POST'
+ title='鏇存柊鏂囨。鍒嗘'
+ name='#update_segment'
+/>
+<Row>
+ <Col>
+ ### POST
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 鏂囨。鍒嗘ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='segment' type='object' key='segment'>
+ - <code>content</code> (text) 鏂囨湰鍐呭/闂鍐呭锛屽繀濉�
+ - <code>answer</code> (text) 绛旀鍐呭锛岄潪蹇呭~锛屽鏋滅煡璇嗗簱鐨勬ā寮忎负 Q&A 妯″紡鍒欎紶鍊�
+ - <code>keywords</code> (list) 鍏抽敭瀛楋紝闈炲繀濉�
+ - <code>enabled</code> (bool) false/true锛岄潪蹇呭~
+ - <code>regenerate_child_chunks</code> (bool) 鏄惁閲嶆柊鐢熸垚瀛愬垎娈碉紝闈炲繀濉�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{\"segment\": {\"content\": \"1\",\"answer\": \"1\", \"keywords\": [\"a\"], \"enabled\": false}}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "segment": {
+ "content": "1",
+ "answer": "1",
+ "keywords": ["a"],
+ "enabled": false
+ }
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": {
+ "id": "",
+ "position": 1,
+ "document_id": "",
+ "content": "1",
+ "answer": "1",
+ "word_count": 25,
+ "tokens": 0,
+ "keywords": [
+ "a"
+ ],
+ "index_node_id": "",
+ "index_node_hash": "",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ },
+ "doc_form": "text_model"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks'
+ method='POST'
+ title='鏂板鏂囨。瀛愬垎娈�'
+ name='#create_child_chunk'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 鍒嗘 ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='content' type='string' key='content'>
+ 瀛愬垎娈靛唴瀹�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"content": "瀛愬垎娈靛唴瀹�"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "content": "瀛愬垎娈靛唴瀹�"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": {
+ "id": "",
+ "segment_id": "",
+ "content": "瀛愬垎娈靛唴瀹�",
+ "word_count": 25,
+ "tokens": 0,
+ "index_node_id": "",
+ "index_node_hash": "",
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks'
+ method='GET'
+ title='鏌ヨ鏂囨。瀛愬垎娈�'
+ name='#get_child_chunks'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 鍒嗘 ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 鎼滅储鍏抽敭璇嶏紙閫夊~锛�
+ </Property>
+ <Property name='page' type='integer' key='page'>
+ 椤电爜锛堥�夊~锛岄粯璁�1锛�
+ </Property>
+ <Property name='limit' type='integer' key='limit'>
+ 姣忛〉鏁伴噺锛堥�夊~锛岄粯璁�20锛屾渶澶�100锛�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [{
+ "id": "",
+ "segment_id": "",
+ "content": "瀛愬垎娈靛唴瀹�",
+ "word_count": 25,
+ "tokens": 0,
+ "index_node_id": "",
+ "index_node_hash": "",
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }],
+ "total": 1,
+ "total_pages": 1,
+ "page": 1,
+ "limit": 20
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}'
+ method='DELETE'
+ title='鍒犻櫎鏂囨。瀛愬垎娈�'
+ name='#delete_child_chunk'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 鍒嗘 ID
+ </Property>
+ <Property name='child_chunk_id' type='string' key='child_chunk_id'>
+ 瀛愬垎娈� ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Row>
+ <Col>
+ ### 閿欒淇℃伅
+ <Properties>
+ <Property name='code' type='string' key='code'>
+ 杩斿洖鐨勯敊璇唬鐮�
+ </Property>
+ </Properties>
+ <Properties>
+ <Property name='status' type='number' key='status'>
+ 杩斿洖鐨勯敊璇姸鎬�
+ </Property>
+ </Properties>
+ <Properties>
+ <Property name='message' type='string' key='message'>
+ 杩斿洖鐨勯敊璇俊鎭�
+ </Property>
+ </Properties>
+ </Col>
+ <Col>
+ <CodeGroup title="Example">
+ ```json {{ title: 'Response' }}
+ {
+ "code": "no_file_uploaded",
+ "message": "Please upload your file.",
+ "status": 400
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}'
+ method='PATCH'
+ title='鏇存柊鏂囨。瀛愬垎娈�'
+ name='#update_child_chunk'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ <Property name='segment_id' type='string' key='segment_id'>
+ 鍒嗘 ID
+ </Property>
+ <Property name='child_chunk_id' type='string' key='child_chunk_id'>
+ 瀛愬垎娈� ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='content' type='string' key='content'>
+ 瀛愬垎娈靛唴瀹�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PATCH"
+ label="/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}"
+ targetCode={`curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"content": "鏇存柊鐨勫瓙鍒嗘鍐呭"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "content": "鏇存柊鐨勫瓙鍒嗘鍐呭"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": {
+ "id": "",
+ "segment_id": "",
+ "content": "鏇存柊鐨勫瓙鍒嗘鍐呭",
+ "word_count": 25,
+ "tokens": 0,
+ "index_node_id": "",
+ "index_node_hash": "",
+ "status": "completed",
+ "created_by": "",
+ "created_at": 1695312007,
+ "indexing_at": 1695312007,
+ "completed_at": 1695312007,
+ "error": null,
+ "stopped_at": null
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/{document_id}/upload-file'
+ method='GET'
+ title='鑾峰彇涓婁紶鏂囦欢'
+ name='#get_upload_file'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='document_id' type='string' key='document_id'>
+ 鏂囨。 ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/documents/{document_id}/upload-file"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/upload-file' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "file_id",
+ "name": "file_name",
+ "size": 1024,
+ "extension": "txt",
+ "url": "preview_url",
+ "download_url": "download_url",
+ "mime_type": "text/plain",
+ "created_by": "user_id",
+ "created_at": 1728734540,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/retrieve'
+ method='POST'
+ title='妫�绱㈢煡璇嗗簱'
+ name='#dataset_retrieval'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='query' type='string' key='query'>
+ 妫�绱㈠叧閿瘝
+ </Property>
+ <Property name='retrieval_model' type='object' key='retrieval_model'>
+ 妫�绱㈠弬鏁帮紙閫夊~锛屽涓嶅~锛屾寜鐓ч粯璁ゆ柟寮忓彫鍥烇級
+ - <code>search_method</code> (text) 妫�绱㈡柟娉曪細浠ヤ笅鍥涗釜鍏抽敭瀛椾箣涓�锛屽繀濉�
+ - <code>keyword_search</code> 鍏抽敭瀛楁绱�
+ - <code>semantic_search</code> 璇箟妫�绱�
+ - <code>full_text_search</code> 鍏ㄦ枃妫�绱�
+ - <code>hybrid_search</code> 娣峰悎妫�绱�
+ - <code>reranking_enable</code> (bool) 鏄惁鍚敤 Reranking锛岄潪蹇呭~锛屽鏋滄绱㈡ā寮忎负 semantic_search 妯″紡鎴栬�� hybrid_search 鍒欎紶鍊�
+ - <code>reranking_mode</code> (object) Rerank 妯″瀷閰嶇疆锛岄潪蹇呭~锛屽鏋滃惎鐢ㄤ簡 reranking 鍒欎紶鍊�
+ - <code>reranking_provider_name</code> (string) Rerank 妯″瀷鎻愪緵鍟�
+ - <code>reranking_model_name</code> (string) Rerank 妯″瀷鍚嶇О
+ - <code>weights</code> (float) 娣峰悎妫�绱㈡ā寮忎笅璇剰妫�绱㈢殑鏉冮噸璁剧疆
+ - <code>top_k</code> (integer) 杩斿洖缁撴灉鏁伴噺锛岄潪蹇呭~
+ - <code>score_threshold_enabled</code> (bool) 鏄惁寮�鍚� score 闃堝��
+ - <code>score_threshold</code> (float) Score 闃堝��
+ </Property>
+ <Property name='external_retrieval_model' type='object' key='external_retrieval_model'>
+ 鏈惎鐢ㄥ瓧娈�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/retrieve"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/retrieve' \\\n--header 'Authorization: Bearer {api_key}'\\\n--header 'Content-Type: application/json'\\\n--data-raw '{
+ "query": "test",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 1,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ }
+}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/retrieve' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "query": "test",
+ "retrieval_model": {
+ "search_method": "keyword_search",
+ "reranking_enable": false,
+ "reranking_mode": null,
+ "reranking_model": {
+ "reranking_provider_name": "",
+ "reranking_model_name": ""
+ },
+ "weights": null,
+ "top_k": 2,
+ "score_threshold_enabled": false,
+ "score_threshold": null
+ }
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "query": {
+ "content": "test"
+ },
+ "records": [
+ {
+ "segment": {
+ "id": "7fa6f24f-8679-48b3-bc9d-bdf28d73f218",
+ "position": 1,
+ "document_id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2",
+ "content": "Operation guide",
+ "answer": null,
+ "word_count": 847,
+ "tokens": 280,
+ "keywords": [
+ "install",
+ "java",
+ "base",
+ "scripts",
+ "jdk",
+ "manual",
+ "internal",
+ "opens",
+ "add",
+ "vmoptions"
+ ],
+ "index_node_id": "39dd8443-d960-45a8-bb46-7275ad7fbc8e",
+ "index_node_hash": "0189157697b3c6a418ccf8264a09699f25858975578f3467c76d6bfc94df1d73",
+ "hit_count": 0,
+ "enabled": true,
+ "disabled_at": null,
+ "disabled_by": null,
+ "status": "completed",
+ "created_by": "dbcb1ab5-90c8-41a7-8b78-73b235eb6f6f",
+ "created_at": 1728734540,
+ "indexing_at": 1728734552,
+ "completed_at": 1728734584,
+ "error": null,
+ "stopped_at": null,
+ "document": {
+ "id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2",
+ "data_source_type": "upload_file",
+ "name": "readme.txt",
+ }
+ },
+ "score": 3.730463140527718e-05,
+ "tsne_position": null
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata'
+ method='POST'
+ title='鏂板鍏冩暟鎹�'
+ name='#create_metadata'
+/>
+<Row>
+ <Col>
+ ### Params
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='segment' type='object' key='segment'>
+ - <code>type</code> (string) 鍏冩暟鎹被鍨嬶紝蹇呭~
+ - <code>name</code> (string) 鍏冩暟鎹悕绉帮紝蹇呭~
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/metadata"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/metadata' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"type": "string", "name": "test"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "abc",
+ "type": "string",
+ "name": "test",
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata/{metadata_id}'
+ method='PATCH'
+ title='鏇存柊鍏冩暟鎹�'
+ name='#update_metadata'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='metadata_id' type='string' key='metadata_id'>
+ 鍏冩暟鎹� ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='segment' type='object' key='segment'>
+ - <code>name</code> (string) 鍏冩暟鎹悕绉帮紝蹇呭~
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PATCH"
+ label="/datasets/{dataset_id}/metadata/{metadata_id}"
+ targetCode={`curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/metadata/{metadata_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"name": "test"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "abc",
+ "type": "string",
+ "name": "test",
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata/{metadata_id}'
+ method='DELETE'
+ title='鍒犻櫎鍏冩暟鎹�'
+ name='#delete_metadata'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='metadata_id' type='string' key='metadata_id'>
+ 鍏冩暟鎹� ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="DELETE"
+ label="/datasets/{dataset_id}/metadata/{metadata_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/metadata/{metadata_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata/built-in/{action}'
+ method='POST'
+ title='鍚敤/绂佺敤鍐呯疆鍏冩暟鎹�'
+ name='#toggle_metadata'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ <Property name='action' type='string' key='action'>
+ disable/enable
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/metadata/built-in/{action}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/metadata/built-in/{action}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/documents/metadata'
+ method='POST'
+ title='鏇存柊鏂囨。鍏冩暟鎹�'
+ name='#update_documents_metadata'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+ <Properties>
+ <Property name='operation_data' type='object list' key='segments'>
+ - <code>document_id</code> (string) 鏂囨。 ID
+ - <code>metadata_list</code> (list) 鍏冩暟鎹垪琛�
+ - <code>id</code> (string) 鍏冩暟鎹� ID
+ - <code>type</code> (string) 鍏冩暟鎹被鍨�
+ - <code>name</code> (string) 鍏冩暟鎹悕绉�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/datasets/{dataset_id}/documents/metadata"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/metadata' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"operation_data": [{"document_id": "document_id", "metadata_list": [{"id": "id", "value": "value", "name": "name"}]}]}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/datasets/{dataset_id}/metadata'
+ method='GET'
+ title='鏌ヨ鐭ヨ瘑搴撳厓鏁版嵁鍒楄〃'
+ name='#dataset_metadata_list'
+/>
+<Row>
+ <Col>
+ ### Path
+ <Properties>
+ <Property name='dataset_id' type='string' key='dataset_id'>
+ 鐭ヨ瘑搴� ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}/metadata"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/metadata' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "doc_metadata": [
+ {
+ "id": "",
+ "name": "name",
+ "type": "string",
+ "use_count": 0,
+ },
+ ...
+ ],
+ "built_in_field_enabled": true
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Heading
+ url='/workspaces/current/models/model-types/text-embedding'
+ method='GET'
+ title='鑾峰彇宓屽叆妯″瀷鍒楄〃'
+ name='#model_type_list'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/datasets/{dataset_id}"
+ targetCode={`curl --location --location --request GET '${props.apiBaseUrl}/workspaces/current/models/model-types/text-embedding' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' `}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/workspaces/current/models/model-types/text-embedding' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "provider": "zhipuai",
+ "label": {
+ "zh_Hans": "鏅鸿氨 AI",
+ "en_US": "ZHIPU AI"
+ },
+ "icon_small": {
+ "zh_Hans": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_small/zh_Hans",
+ "en_US": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_small/en_US"
+ },
+ "icon_large": {
+ "zh_Hans": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_large/zh_Hans",
+ "en_US": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_large/en_US"
+ },
+ "status": "active",
+ "models": [
+ {
+ "model": "embedding-3",
+ "label": {
+ "zh_Hans": "embedding-3",
+ "en_US": "embedding-3"
+ },
+ "model_type": "text-embedding",
+ "features": null,
+ "fetch_from": "predefined-model",
+ "model_properties": {
+ "context_size": 8192
+ },
+ "deprecated": false,
+ "status": "active",
+ "load_balancing_enabled": false
+ },
+ {
+ "model": "embedding-2",
+ "label": {
+ "zh_Hans": "embedding-2",
+ "en_US": "embedding-2"
+ },
+ "model_type": "text-embedding",
+ "features": null,
+ "fetch_from": "predefined-model",
+ "model_properties": {
+ "context_size": 8192
+ },
+ "deprecated": false,
+ "status": "active",
+ "load_balancing_enabled": false
+ },
+ {
+ "model": "text_embedding",
+ "label": {
+ "zh_Hans": "text_embedding",
+ "en_US": "text_embedding"
+ },
+ "model_type": "text-embedding",
+ "features": null,
+ "fetch_from": "predefined-model",
+ "model_properties": {
+ "context_size": 512
+ },
+ "deprecated": false,
+ "status": "active",
+ "load_balancing_enabled": false
+ }
+ ]
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+<hr className='ml-0 mr-0' />
+
+<Row>
+ <Col>
+ ### 閿欒淇℃伅
+ <Properties>
+ <Property name='code' type='string' key='code'>
+ 杩斿洖鐨勯敊璇唬鐮�
+ </Property>
+ </Properties>
+ <Properties>
+ <Property name='status' type='number' key='status'>
+ 杩斿洖鐨勯敊璇姸鎬�
+ </Property>
+ </Properties>
+ <Properties>
+ <Property name='message' type='string' key='message'>
+ 杩斿洖鐨勯敊璇俊鎭�
+ </Property>
+ </Properties>
+ </Col>
+ <Col>
+ <CodeGroup title="Example">
+ ```json {{ title: 'Response' }}
+ {
+ "code": "no_file_uploaded",
+ "message": "Please upload your file.",
+ "status": 400
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+<table className="max-w-auto border-collapse border border-slate-400" style={{ maxWidth: 'none', width: 'auto' }}>
+ <thead style={{ background: '#f9fafc' }}>
+ <tr>
+ <th className="p-2 border border-slate-300">code</th>
+ <th className="p-2 border border-slate-300">status</th>
+ <th className="p-2 border border-slate-300">message</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td className="p-2 border border-slate-300">no_file_uploaded</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Please upload your file.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">too_many_files</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Only one file is allowed.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">file_too_large</td>
+ <td className="p-2 border border-slate-300">413</td>
+ <td className="p-2 border border-slate-300">File size exceeded.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">unsupported_file_type</td>
+ <td className="p-2 border border-slate-300">415</td>
+ <td className="p-2 border border-slate-300">File type not allowed.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">high_quality_dataset_only</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Current operation only supports 'high-quality' datasets.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">dataset_not_initialized</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The dataset is still being initialized or indexing. Please wait a moment.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">archived_document_immutable</td>
+ <td className="p-2 border border-slate-300">403</td>
+ <td className="p-2 border border-slate-300">The archived document is not editable.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">dataset_name_duplicate</td>
+ <td className="p-2 border border-slate-300">409</td>
+ <td className="p-2 border border-slate-300">The dataset name already exists. Please modify your dataset name.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">invalid_action</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">Invalid action.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">document_already_finished</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The document has been processed. Please refresh the page or go to the document details.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">document_indexing</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The document is being processed and cannot be edited.</td>
+ </tr>
+ <tr>
+ <td className="p-2 border border-slate-300">invalid_metadata</td>
+ <td className="p-2 border border-slate-300">400</td>
+ <td className="p-2 border border-slate-300">The metadata content is incorrect. Please check and verify.</td>
+ </tr>
+ </tbody>
+</table>
+<div className="pb-4" />
diff --git "a/app/\050commonLayout\051/education-apply/page.tsx" "b/app/\050commonLayout\051/education-apply/page.tsx"
new file mode 100644
index 0000000..8730344
--- /dev/null
+++ "b/app/\050commonLayout\051/education-apply/page.tsx"
@@ -0,0 +1,29 @@
+'use client'
+
+import {
+ useEffect,
+ useMemo,
+} from 'react'
+import {
+ useRouter,
+ useSearchParams,
+} from 'next/navigation'
+import EducationApplyPage from '@/app/education-apply/education-apply-page'
+import { useProviderContext } from '@/context/provider-context'
+
+export default function EducationApply() {
+ const router = useRouter()
+ const { enableEducationPlan, isEducationAccount } = useProviderContext()
+ const searchParams = useSearchParams()
+ const token = searchParams.get('token')
+ const showEducationApplyPage = useMemo(() => {
+ return enableEducationPlan && !isEducationAccount && token
+ }, [enableEducationPlan, isEducationAccount, token])
+
+ useEffect(() => {
+ if (!showEducationApplyPage)
+ router.replace('/')
+ }, [showEducationApplyPage, router])
+
+ return <EducationApplyPage />
+}
diff --git "a/app/\050commonLayout\051/explore/apps/page.tsx" "b/app/\050commonLayout\051/explore/apps/page.tsx"
new file mode 100644
index 0000000..b243060
--- /dev/null
+++ "b/app/\050commonLayout\051/explore/apps/page.tsx"
@@ -0,0 +1,8 @@
+import React from 'react'
+import AppList from '@/app/components/explore/app-list'
+
+const Apps = () => {
+ return <AppList />
+}
+
+export default React.memo(Apps)
diff --git "a/app/\050commonLayout\051/explore/installed/\133appId\135/page.tsx" "b/app/\050commonLayout\051/explore/installed/\133appId\135/page.tsx"
new file mode 100644
index 0000000..938a039
--- /dev/null
+++ "b/app/\050commonLayout\051/explore/installed/\133appId\135/page.tsx"
@@ -0,0 +1,16 @@
+import type { FC } from 'react'
+import React from 'react'
+import Main from '@/app/components/explore/installed-app'
+
+export type IInstalledAppProps = {
+ params: Promise<{
+ appId: string
+ }>
+}
+
+const InstalledApp: FC<IInstalledAppProps> = async ({ params }) => {
+ return (
+ <Main id={(await params).appId} />
+ )
+}
+export default React.memo(InstalledApp)
diff --git "a/app/\050commonLayout\051/explore/layout.tsx" "b/app/\050commonLayout\051/explore/layout.tsx"
new file mode 100644
index 0000000..3af7bb1
--- /dev/null
+++ "b/app/\050commonLayout\051/explore/layout.tsx"
@@ -0,0 +1,16 @@
+import type { FC } from 'react'
+import React from 'react'
+import ExploreClient from '@/app/components/explore'
+export type IAppDetail = {
+ children: React.ReactNode
+}
+
+const AppDetail: FC<IAppDetail> = ({ children }) => {
+ return (
+ <ExploreClient>
+ {children}
+ </ExploreClient>
+ )
+}
+
+export default React.memo(AppDetail)
diff --git "a/app/\050commonLayout\051/layout.tsx" "b/app/\050commonLayout\051/layout.tsx"
new file mode 100644
index 0000000..af36d4d
--- /dev/null
+++ "b/app/\050commonLayout\051/layout.tsx"
@@ -0,0 +1,38 @@
+import React from 'react'
+import type { ReactNode } from 'react'
+import SwrInitor from '@/app/components/swr-initor'
+import { AppContextProvider } from '@/context/app-context'
+import GA, { GaType } from '@/app/components/base/ga'
+import HeaderWrapper from '@/app/components/header/header-wrapper'
+import Header from '@/app/components/header'
+import { EventEmitterContextProvider } from '@/context/event-emitter'
+import { ProviderContextProvider } from '@/context/provider-context'
+import { ModalContextProvider } from '@/context/modal-context'
+
+const Layout = ({ children }: { children: ReactNode }) => {
+ return (
+ <>
+ <GA gaType={GaType.admin} />
+ <SwrInitor>
+ <AppContextProvider>
+ <EventEmitterContextProvider>
+ <ProviderContextProvider>
+ <ModalContextProvider>
+ <HeaderWrapper>
+ <Header />
+ </HeaderWrapper>
+ {children}
+ </ModalContextProvider>
+ </ProviderContextProvider>
+ </EventEmitterContextProvider>
+ </AppContextProvider>
+ </SwrInitor>
+ </>
+ )
+}
+
+export const metadata = {
+ title: 'Dify',
+}
+
+export default Layout
diff --git "a/app/\050commonLayout\051/list.module.css" "b/app/\050commonLayout\051/list.module.css"
new file mode 100644
index 0000000..c4d3aec
--- /dev/null
+++ "b/app/\050commonLayout\051/list.module.css"
@@ -0,0 +1,217 @@
+.listItem {
+ @apply col-span-1 bg-white border-2 border-solid border-transparent rounded-xl shadow-xs min-h-[160px] flex flex-col transition-all duration-200 ease-in-out cursor-pointer hover:shadow-lg;
+}
+
+.listItem.newItemCard {
+ @apply outline outline-1 outline-gray-200 -outline-offset-1 hover:shadow-sm hover:bg-white;
+ background-color: rgba(229, 231, 235, 0.5);
+}
+
+.listItem.selectable {
+ @apply relative bg-gray-50 outline outline-1 outline-gray-200 -outline-offset-1 shadow-none hover:bg-none hover:shadow-none hover:outline-primary-200 transition-colors;
+}
+
+.listItem.selectable * {
+ @apply relative;
+}
+
+.listItem.selectable::before {
+ content: "";
+ @apply absolute top-0 left-0 block w-full h-full rounded-lg pointer-events-none opacity-0 transition-opacity duration-200 ease-in-out hover:opacity-100;
+ background: linear-gradient(0deg,
+ rgba(235, 245, 255, 0.5),
+ rgba(235, 245, 255, 0.5)),
+ #ffffff;
+}
+
+.listItem.selectable:hover::before {
+ @apply opacity-100;
+}
+
+.listItem.selected {
+ @apply border-primary-600 hover:border-primary-600 border-2;
+}
+
+.listItem.selected::before {
+ @apply opacity-100;
+}
+
+.appIcon {
+ @apply flex items-center justify-center w-8 h-8 bg-pink-100 rounded-lg grow-0 shrink-0;
+}
+
+.appIcon.medium {
+ @apply w-9 h-9;
+}
+
+.appIcon.large {
+ @apply w-10 h-10;
+}
+
+.newItemIcon {
+ @apply flex items-center justify-center w-8 h-8 transition-colors duration-200 ease-in-out border border-gray-200 rounded-lg hover:bg-white grow-0 shrink-0;
+}
+
+.listItem:hover .newItemIcon {
+ @apply bg-gray-50 border-primary-100;
+}
+
+.newItemCard .newItemIcon {
+ @apply bg-gray-100;
+}
+
+.newItemCard:hover .newItemIcon {
+ @apply bg-white;
+}
+
+.selectable .newItemIcon {
+ @apply bg-gray-50;
+}
+
+.selectable:hover .newItemIcon {
+ @apply bg-primary-50;
+}
+
+.newItemIconImage {
+ @apply grow-0 shrink-0 block w-4 h-4 bg-center bg-contain transition-colors duration-200 ease-in-out;
+ color: #1f2a37;
+}
+
+.listItem:hover .newIconImage {
+ @apply text-primary-600;
+}
+
+.newItemIconAdd {
+ background-image: url("./apps/assets/add.svg");
+}
+
+/* .newItemIconChat {
+ background-image: url("~@/app/components/base/icons/assets/public/header-nav/studio/Robot.svg");
+}
+
+.selected .newItemIconChat {
+ background-image: url("~@/app/components/base/icons/assets/public/header-nav/studio/Robot-Active.svg");
+} */
+
+.newItemIconComplete {
+ background-image: url("./apps/assets/completion.svg");
+}
+
+.listItemTitle {
+ @apply flex pt-[14px] px-[14px] pb-3 h-[66px] items-center gap-3 grow-0 shrink-0;
+}
+
+.listItemHeading {
+ @apply relative h-8 text-sm font-medium leading-8 grow;
+}
+
+.listItemHeadingContent {
+ @apply absolute top-0 left-0 w-full h-full overflow-hidden text-ellipsis whitespace-nowrap;
+}
+
+.actionIconWrapper {
+ @apply hidden h-8 w-8 p-2 rounded-md border-none hover:bg-gray-100 !important;
+}
+
+.listItem:hover .actionIconWrapper {
+ @apply !inline-flex;
+}
+
+.deleteDatasetIcon {
+ @apply hidden grow-0 shrink-0 basis-8 w-8 h-8 rounded-lg transition-colors duration-200 ease-in-out bg-white border border-gray-200 hover:bg-gray-100 bg-center bg-no-repeat;
+ background-size: 16px;
+ background-image: url('~@/assets/delete.svg');
+}
+
+.listItem:hover .deleteDatasetIcon {
+ @apply block;
+}
+
+.listItemDescription {
+ @apply mb-3 px-[14px] h-9 text-xs leading-normal text-gray-500 line-clamp-2;
+}
+
+.listItemDescription.noClip {
+ @apply line-clamp-none;
+}
+
+.listItemFooter {
+ @apply flex items-center flex-wrap min-h-[42px] px-[14px] pt-2 pb-[10px];
+}
+
+.listItemFooter.datasetCardFooter {
+ @apply flex items-center gap-4 text-xs text-gray-500;
+}
+
+.listItemStats {
+ @apply flex items-center gap-1;
+}
+
+.listItemFooterIcon {
+ @apply block w-3 h-3 bg-center bg-contain;
+}
+
+.solidChatIcon {
+ background-image: url("./apps/assets/chat-solid.svg");
+}
+
+.solidCompletionIcon {
+ background-image: url("./apps/assets/completion-solid.svg");
+}
+
+.newItemCardHeading {
+ @apply transition-colors duration-200 ease-in-out;
+}
+
+.listItem:hover .newItemCardHeading {
+ @apply text-primary-600;
+}
+
+.listItemLink {
+ @apply inline-flex items-center gap-1 text-xs text-gray-400 transition-colors duration-200 ease-in-out;
+}
+
+.listItem:hover .listItemLink {
+ @apply text-primary-600;
+}
+
+.linkIcon {
+ @apply block w-[13px] h-[13px] bg-center bg-contain;
+ background-image: url("./apps/assets/link.svg");
+}
+
+.linkIcon.grayLinkIcon {
+ background-image: url("./apps/assets/link-gray.svg");
+}
+
+.listItem:hover .grayLinkIcon {
+ background-image: url("./apps/assets/link.svg");
+}
+
+.rightIcon {
+ @apply block w-[13px] h-[13px] bg-center bg-contain;
+ background-image: url("./apps/assets/right-arrow.svg");
+}
+
+.socialMediaLink {
+ @apply flex items-center justify-center w-8 h-8 cursor-pointer hover:opacity-80 transition-opacity duration-200 ease-in-out;
+}
+
+.socialMediaIcon {
+ @apply block w-6 h-6 bg-center bg-contain;
+}
+
+/* #region new app dialog */
+.newItemCaption {
+ @apply inline-flex items-center mb-2 text-sm font-medium;
+}
+
+/* #endregion new app dialog */
+
+.unavailable {
+ @apply opacity-50;
+}
+
+.listItem:hover .unavailable {
+ @apply opacity-100;
+}
diff --git "a/app/\050commonLayout\051/plugins/page.tsx" "b/app/\050commonLayout\051/plugins/page.tsx"
new file mode 100644
index 0000000..47f2791
--- /dev/null
+++ "b/app/\050commonLayout\051/plugins/page.tsx"
@@ -0,0 +1,16 @@
+import PluginPage from '@/app/components/plugins/plugin-page'
+import PluginsPanel from '@/app/components/plugins/plugin-page/plugins-panel'
+import Marketplace from '@/app/components/plugins/marketplace'
+import { getLocaleOnServer } from '@/i18n/server'
+
+const PluginList = async () => {
+ const locale = await getLocaleOnServer()
+ return (
+ <PluginPage
+ plugins={<PluginsPanel />}
+ marketplace={<Marketplace locale={locale} pluginTypeSwitchClassName='top-[60px]' searchBoxAutoAnimate={false} showSearchParams={false} />}
+ />
+ )
+}
+
+export default PluginList
diff --git "a/app/\050commonLayout\051/tools/page.tsx" "b/app/\050commonLayout\051/tools/page.tsx"
new file mode 100644
index 0000000..1b08d54
--- /dev/null
+++ "b/app/\050commonLayout\051/tools/page.tsx"
@@ -0,0 +1,28 @@
+'use client'
+import type { FC } from 'react'
+import { useRouter } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import React, { useEffect } from 'react'
+import ToolProviderList from '@/app/components/tools/provider-list'
+import { useAppContext } from '@/context/app-context'
+
+const Layout: FC = () => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const { isCurrentWorkspaceDatasetOperator } = useAppContext()
+
+ useEffect(() => {
+ if (typeof window !== 'undefined')
+ document.title = `${t('tools.title')} - Dify`
+ if (isCurrentWorkspaceDatasetOperator)
+ return router.replace('/datasets')
+ }, [isCurrentWorkspaceDatasetOperator, router, t])
+
+ useEffect(() => {
+ if (isCurrentWorkspaceDatasetOperator)
+ return router.replace('/datasets')
+ }, [isCurrentWorkspaceDatasetOperator, router])
+
+ return <ToolProviderList />
+}
+export default React.memo(Layout)
diff --git "a/app/\050shareLayout\051/chat/\133token\135/page.tsx" "b/app/\050shareLayout\051/chat/\133token\135/page.tsx"
new file mode 100644
index 0000000..640c403
--- /dev/null
+++ "b/app/\050shareLayout\051/chat/\133token\135/page.tsx"
@@ -0,0 +1,11 @@
+'use client'
+import React from 'react'
+import ChatWithHistoryWrap from '@/app/components/base/chat/chat-with-history'
+
+const Chat = () => {
+ return (
+ <ChatWithHistoryWrap />
+ )
+}
+
+export default React.memo(Chat)
diff --git "a/app/\050shareLayout\051/chatbot/\133token\135/page.tsx" "b/app/\050shareLayout\051/chatbot/\133token\135/page.tsx"
new file mode 100644
index 0000000..6196afe
--- /dev/null
+++ "b/app/\050shareLayout\051/chatbot/\133token\135/page.tsx"
@@ -0,0 +1,11 @@
+'use client'
+import React from 'react'
+import EmbeddedChatbot from '@/app/components/base/chat/embedded-chatbot'
+
+const Chatbot = () => {
+ return (
+ <EmbeddedChatbot />
+ )
+}
+
+export default React.memo(Chatbot)
diff --git "a/app/\050shareLayout\051/completion/\133token\135/page.tsx" "b/app/\050shareLayout\051/completion/\133token\135/page.tsx"
new file mode 100644
index 0000000..e8bc9d7
--- /dev/null
+++ "b/app/\050shareLayout\051/completion/\133token\135/page.tsx"
@@ -0,0 +1,10 @@
+import React from 'react'
+import Main from '@/app/components/share/text-generation'
+
+const Completion = () => {
+ return (
+ <Main />
+ )
+}
+
+export default React.memo(Completion)
diff --git "a/app/\050shareLayout\051/layout.tsx" "b/app/\050shareLayout\051/layout.tsx"
new file mode 100644
index 0000000..83adbd3
--- /dev/null
+++ "b/app/\050shareLayout\051/layout.tsx"
@@ -0,0 +1,19 @@
+import React from 'react'
+import type { FC } from 'react'
+import type { Metadata } from 'next'
+
+export const metadata: Metadata = {
+ icons: 'data:,', // prevent browser from using default favicon
+}
+
+const Layout: FC<{
+ children: React.ReactNode
+}> = ({ children }) => {
+ return (
+ <div className="h-full min-w-[300px] pb-[env(safe-area-inset-bottom)]">
+ {children}
+ </div>
+ )
+}
+
+export default Layout
diff --git "a/app/\050shareLayout\051/webapp-signin/page.tsx" "b/app/\050shareLayout\051/webapp-signin/page.tsx"
new file mode 100644
index 0000000..d58fafa
--- /dev/null
+++ "b/app/\050shareLayout\051/webapp-signin/page.tsx"
@@ -0,0 +1,103 @@
+'use client'
+import { useRouter, useSearchParams } from 'next/navigation'
+import type { FC } from 'react'
+import React, { useEffect } from 'react'
+import cn from '@/utils/classnames'
+import Toast from '@/app/components/base/toast'
+import { fetchSystemFeatures, fetchWebOAuth2SSOUrl, fetchWebOIDCSSOUrl, fetchWebSAMLSSOUrl } from '@/service/share'
+import { setAccessToken } from '@/app/components/share/utils'
+import Loading from '@/app/components/base/loading'
+
+const WebSSOForm: FC = () => {
+ const searchParams = useSearchParams()
+ const router = useRouter()
+
+ const redirectUrl = searchParams.get('redirect_url')
+ const tokenFromUrl = searchParams.get('web_sso_token')
+ const message = searchParams.get('message')
+
+ const showErrorToast = (message: string) => {
+ Toast.notify({
+ type: 'error',
+ message,
+ })
+ }
+
+ const getAppCodeFromRedirectUrl = () => {
+ const appCode = redirectUrl?.split('/').pop()
+ if (!appCode)
+ return null
+
+ return appCode
+ }
+
+ const processTokenAndRedirect = async () => {
+ const appCode = getAppCodeFromRedirectUrl()
+ if (!appCode || !tokenFromUrl || !redirectUrl) {
+ showErrorToast('redirect url or app code or token is invalid.')
+ return
+ }
+
+ await setAccessToken(appCode, tokenFromUrl)
+ router.push(redirectUrl)
+ }
+
+ const handleSSOLogin = async (protocol: string) => {
+ const appCode = getAppCodeFromRedirectUrl()
+ if (!appCode || !redirectUrl) {
+ showErrorToast('redirect url or app code is invalid.')
+ return
+ }
+
+ switch (protocol) {
+ case 'saml': {
+ const samlRes = await fetchWebSAMLSSOUrl(appCode, redirectUrl)
+ router.push(samlRes.url)
+ break
+ }
+ case 'oidc': {
+ const oidcRes = await fetchWebOIDCSSOUrl(appCode, redirectUrl)
+ router.push(oidcRes.url)
+ break
+ }
+ case 'oauth2': {
+ const oauth2Res = await fetchWebOAuth2SSOUrl(appCode, redirectUrl)
+ router.push(oauth2Res.url)
+ break
+ }
+ default:
+ showErrorToast('SSO protocol is not supported.')
+ }
+ }
+
+ useEffect(() => {
+ const init = async () => {
+ const res = await fetchSystemFeatures()
+ const protocol = res.sso_enforced_for_web_protocol
+
+ if (message) {
+ showErrorToast(message)
+ return
+ }
+
+ if (!tokenFromUrl) {
+ await handleSSOLogin(protocol)
+ return
+ }
+
+ await processTokenAndRedirect()
+ }
+
+ init()
+ }, [message, tokenFromUrl]) // Added dependencies to useEffect
+
+ return (
+ <div className="flex h-full items-center justify-center">
+ <div className={cn('flex w-full grow flex-col items-center justify-center', 'px-6', 'md:px-[108px]')}>
+ <Loading type='area' />
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(WebSSOForm)
diff --git "a/app/\050shareLayout\051/workflow/\133token\135/page.tsx" "b/app/\050shareLayout\051/workflow/\133token\135/page.tsx"
new file mode 100644
index 0000000..e93bc8c
--- /dev/null
+++ "b/app/\050shareLayout\051/workflow/\133token\135/page.tsx"
@@ -0,0 +1,11 @@
+import React from 'react'
+
+import Main from '@/app/components/share/text-generation'
+
+const Workflow = () => {
+ return (
+ <Main isWorkflow />
+ )
+}
+
+export default React.memo(Workflow)
diff --git a/app/account/account-page/AvatarWithEdit.tsx b/app/account/account-page/AvatarWithEdit.tsx
new file mode 100644
index 0000000..8250789
--- /dev/null
+++ b/app/account/account-page/AvatarWithEdit.tsx
@@ -0,0 +1,122 @@
+'use client'
+
+import type { Area } from 'react-easy-crop'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { RiPencilLine } from '@remixicon/react'
+import { updateUserProfile } from '@/service/common'
+import { ToastContext } from '@/app/components/base/toast'
+import ImageInput, { type OnImageInput } from '@/app/components/base/app-icon-picker/ImageInput'
+import Modal from '@/app/components/base/modal'
+import Divider from '@/app/components/base/divider'
+import Button from '@/app/components/base/button'
+import Avatar, { type AvatarProps } from '@/app/components/base/avatar'
+import { useLocalFileUploader } from '@/app/components/base/image-uploader/hooks'
+import type { ImageFile } from '@/types/app'
+import getCroppedImg from '@/app/components/base/app-icon-picker/utils'
+import { DISABLE_UPLOAD_IMAGE_AS_ICON } from '@/config'
+
+type InputImageInfo = { file: File } | { tempUrl: string; croppedAreaPixels: Area; fileName: string }
+type AvatarWithEditProps = AvatarProps & { onSave?: () => void }
+
+const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+
+ const [inputImageInfo, setInputImageInfo] = useState<InputImageInfo>()
+ const [isShowAvatarPicker, setIsShowAvatarPicker] = useState(false)
+ const [uploading, setUploading] = useState(false)
+
+ const handleImageInput: OnImageInput = useCallback(async (isCropped: boolean, fileOrTempUrl: string | File, croppedAreaPixels?: Area, fileName?: string) => {
+ setInputImageInfo(
+ isCropped
+ ? { tempUrl: fileOrTempUrl as string, croppedAreaPixels: croppedAreaPixels!, fileName: fileName! }
+ : { file: fileOrTempUrl as File },
+ )
+ }, [setInputImageInfo])
+
+ const handleSaveAvatar = useCallback(async (uploadedFileId: string) => {
+ try {
+ await updateUserProfile({ url: 'account/avatar', body: { avatar: uploadedFileId } })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ setIsShowAvatarPicker(false)
+ onSave?.()
+ }
+ catch (e) {
+ notify({ type: 'error', message: (e as Error).message })
+ }
+ }, [notify, onSave, t])
+
+ const { handleLocalFileUpload } = useLocalFileUploader({
+ limit: 3,
+ disabled: false,
+ onUpload: (imageFile: ImageFile) => {
+ if (imageFile.progress === 100) {
+ setUploading(false)
+ setInputImageInfo(undefined)
+ handleSaveAvatar(imageFile.fileId)
+ }
+
+ // Error
+ if (imageFile.progress === -1)
+ setUploading(false)
+ },
+ })
+
+ const handleSelect = useCallback(async () => {
+ if (!inputImageInfo)
+ return
+ setUploading(true)
+ if ('file' in inputImageInfo) {
+ handleLocalFileUpload(inputImageInfo.file)
+ return
+ }
+ const blob = await getCroppedImg(inputImageInfo.tempUrl, inputImageInfo.croppedAreaPixels, inputImageInfo.fileName)
+ const file = new File([blob], inputImageInfo.fileName, { type: blob.type })
+ handleLocalFileUpload(file)
+ }, [handleLocalFileUpload, inputImageInfo])
+
+ if (DISABLE_UPLOAD_IMAGE_AS_ICON)
+ return <Avatar {...props} />
+
+ return (
+ <>
+ <div>
+ <div className="group relative">
+ <Avatar {...props} />
+ <div
+ onClick={() => { setIsShowAvatarPicker(true) }}
+ className="absolute inset-0 flex cursor-pointer items-center justify-center rounded-full bg-black bg-opacity-50 opacity-0 transition-opacity group-hover:opacity-100"
+ >
+ <span className="text-xs text-white">
+ <RiPencilLine />
+ </span>
+ </div>
+ </div>
+ </div>
+
+ <Modal
+ closable
+ className="!w-[362px] !p-0"
+ isShow={isShowAvatarPicker}
+ onClose={() => setIsShowAvatarPicker(false)}
+ >
+ <ImageInput onImageInput={handleImageInput} cropShape='round' />
+ <Divider className='m-0' />
+
+ <div className='flex w-full items-center justify-center gap-2 p-3'>
+ <Button className='w-full' onClick={() => setIsShowAvatarPicker(false)}>
+ {t('app.iconPicker.cancel')}
+ </Button>
+
+ <Button variant="primary" className='w-full' disabled={uploading || !inputImageInfo} loading={uploading} onClick={handleSelect}>
+ {t('app.iconPicker.ok')}
+ </Button>
+ </div>
+ </Modal>
+ </>
+ )
+}
+
+export default AvatarWithEdit
diff --git a/app/account/account-page/index.module.css b/app/account/account-page/index.module.css
new file mode 100644
index 0000000..949d125
--- /dev/null
+++ b/app/account/account-page/index.module.css
@@ -0,0 +1,9 @@
+.modal {
+ padding: 24px 32px !important;
+ width: 400px !important;
+}
+
+.bg {
+ background: linear-gradient(180deg, rgba(217, 45, 32, 0.05) 0%, rgba(217, 45, 32, 0.00) 24.02%), #F9FAFB;
+}
+
diff --git a/app/account/account-page/index.tsx b/app/account/account-page/index.tsx
new file mode 100644
index 0000000..72d2648
--- /dev/null
+++ b/app/account/account-page/index.tsx
@@ -0,0 +1,320 @@
+'use client'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiGraduationCapFill,
+} from '@remixicon/react'
+import { useContext } from 'use-context-selector'
+import DeleteAccount from '../delete-account'
+import s from './index.module.css'
+import AvatarWithEdit from './AvatarWithEdit'
+import Collapse from '@/app/components/header/account-setting/collapse'
+import type { IItem } from '@/app/components/header/account-setting/collapse'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import { updateUserProfile } from '@/service/common'
+import { useAppContext } from '@/context/app-context'
+import { useProviderContext } from '@/context/provider-context'
+import { ToastContext } from '@/app/components/base/toast'
+import AppIcon from '@/app/components/base/app-icon'
+import { IS_CE_EDITION } from '@/config'
+import Input from '@/app/components/base/input'
+import PremiumBadge from '@/app/components/base/premium-badge'
+
+const titleClassName = `
+ system-sm-semibold text-text-secondary
+`
+const descriptionClassName = `
+ mt-1 body-xs-regular text-text-tertiary
+`
+
+const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/
+
+export default function AccountPage() {
+ const { t } = useTranslation()
+ const { systemFeatures } = useAppContext()
+ const { mutateUserProfile, userProfile, apps } = useAppContext()
+ const { isEducationAccount } = useProviderContext()
+ const { notify } = useContext(ToastContext)
+ const [editNameModalVisible, setEditNameModalVisible] = useState(false)
+ const [editName, setEditName] = useState('')
+ const [editing, setEditing] = useState(false)
+ const [editPasswordModalVisible, setEditPasswordModalVisible] = useState(false)
+ const [currentPassword, setCurrentPassword] = useState('')
+ const [password, setPassword] = useState('')
+ const [confirmPassword, setConfirmPassword] = useState('')
+ const [showDeleteAccountModal, setShowDeleteAccountModal] = useState(false)
+ const [showCurrentPassword, setShowCurrentPassword] = useState(false)
+ const [showPassword, setShowPassword] = useState(false)
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false)
+
+ const handleEditName = () => {
+ setEditNameModalVisible(true)
+ setEditName(userProfile.name)
+ }
+ const handleSaveName = async () => {
+ try {
+ setEditing(true)
+ await updateUserProfile({ url: 'account/name', body: { name: editName } })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ mutateUserProfile()
+ setEditNameModalVisible(false)
+ setEditing(false)
+ }
+ catch (e) {
+ notify({ type: 'error', message: (e as Error).message })
+ setEditNameModalVisible(false)
+ setEditing(false)
+ }
+ }
+
+ const showErrorMessage = (message: string) => {
+ notify({
+ type: 'error',
+ message,
+ })
+ }
+ const valid = () => {
+ if (!password.trim()) {
+ showErrorMessage(t('login.error.passwordEmpty'))
+ return false
+ }
+ if (!validPassword.test(password)) {
+ showErrorMessage(t('login.error.passwordInvalid'))
+ return false
+ }
+ if (password !== confirmPassword) {
+ showErrorMessage(t('common.account.notEqual'))
+ return false
+ }
+
+ return true
+ }
+ const resetPasswordForm = () => {
+ setCurrentPassword('')
+ setPassword('')
+ setConfirmPassword('')
+ }
+ const handleSavePassword = async () => {
+ if (!valid())
+ return
+ try {
+ setEditing(true)
+ await updateUserProfile({
+ url: 'account/password',
+ body: {
+ password: currentPassword,
+ new_password: password,
+ repeat_new_password: confirmPassword,
+ },
+ })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ mutateUserProfile()
+ setEditPasswordModalVisible(false)
+ resetPasswordForm()
+ setEditing(false)
+ }
+ catch (e) {
+ notify({ type: 'error', message: (e as Error).message })
+ setEditPasswordModalVisible(false)
+ setEditing(false)
+ }
+ }
+
+ const renderAppItem = (item: IItem) => {
+ return (
+ <div className='flex px-3 py-1'>
+ <div className='mr-3'>
+ <AppIcon size='tiny' />
+ </div>
+ <div className='system-sm-medium mt-[3px] text-text-secondary'>{item.name}</div>
+ </div>
+ )
+ }
+
+ return (
+ <>
+ <div className='pb-3 pt-2'>
+ <h4 className='title-2xl-semi-bold text-text-primary'>{t('common.account.myAccount')}</h4>
+ </div>
+ <div className='mb-8 flex items-center rounded-xl bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1 p-6'>
+ <AvatarWithEdit avatar={userProfile.avatar_url} name={userProfile.name} onSave={ mutateUserProfile } size={64} />
+ <div className='ml-4'>
+ <p className='system-xl-semibold text-text-primary'>
+ {userProfile.name}
+ {isEducationAccount && (
+ <PremiumBadge size='s' color='blue' className='ml-1 !px-2'>
+ <RiGraduationCapFill className='mr-1 h-3 w-3' />
+ <span className='system-2xs-medium'>EDU</span>
+ </PremiumBadge>
+ )}
+ </p>
+ <p className='system-xs-regular text-text-tertiary'>{userProfile.email}</p>
+ </div>
+ </div>
+ <div className='mb-8'>
+ <div className={titleClassName}>{t('common.account.name')}</div>
+ <div className='mt-2 flex w-full items-center justify-between gap-2'>
+ <div className='system-sm-regular flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled '>
+ <span className='pl-1'>{userProfile.name}</span>
+ </div>
+ <div className='system-sm-medium cursor-pointer rounded-lg bg-components-button-tertiary-bg px-3 py-2 text-components-button-tertiary-text' onClick={handleEditName}>
+ {t('common.operation.edit')}
+ </div>
+ </div>
+ </div>
+ <div className='mb-8'>
+ <div className={titleClassName}>{t('common.account.email')}</div>
+ <div className='mt-2 flex w-full items-center justify-between gap-2'>
+ <div className='system-sm-regular flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled '>
+ <span className='pl-1'>{userProfile.email}</span>
+ </div>
+ </div>
+ </div>
+ {
+ systemFeatures.enable_email_password_login && (
+ <div className='mb-8 flex justify-between gap-2'>
+ <div>
+ <div className='system-sm-semibold mb-1 text-text-secondary'>{t('common.account.password')}</div>
+ <div className='body-xs-regular mb-2 text-text-tertiary'>{t('common.account.passwordTip')}</div>
+ </div>
+ <Button onClick={() => setEditPasswordModalVisible(true)}>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</Button>
+ </div>
+ )
+ }
+ <div className='mb-6 border-[1px] border-divider-subtle' />
+ <div className='mb-8'>
+ <div className={titleClassName}>{t('common.account.langGeniusAccount')}</div>
+ <div className={descriptionClassName}>{t('common.account.langGeniusAccountTip')}</div>
+ {!!apps.length && (
+ <Collapse
+ title={`${t('common.account.showAppLength', { length: apps.length })}`}
+ items={apps.map(app => ({ key: app.id, name: app.name }))}
+ renderItem={renderAppItem}
+ wrapperClassName='mt-2'
+ />
+ )}
+ {!IS_CE_EDITION && <Button className='mt-2 text-components-button-destructive-secondary-text' onClick={() => setShowDeleteAccountModal(true)}>{t('common.account.delete')}</Button>}
+ </div>
+ {
+ editNameModalVisible && (
+ <Modal
+ isShow
+ onClose={() => setEditNameModalVisible(false)}
+ className={s.modal}
+ >
+ <div className='title-2xl-semi-bold mb-6 text-text-primary'>{t('common.account.editName')}</div>
+ <div className={titleClassName}>{t('common.account.name')}</div>
+ <Input className='mt-2'
+ value={editName}
+ onChange={e => setEditName(e.target.value)}
+ />
+ <div className='mt-10 flex justify-end'>
+ <Button className='mr-2' onClick={() => setEditNameModalVisible(false)}>{t('common.operation.cancel')}</Button>
+ <Button
+ disabled={editing || !editName}
+ variant='primary'
+ onClick={handleSaveName}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ </Modal>
+ )
+ }
+ {
+ editPasswordModalVisible && (
+ <Modal
+ isShow
+ onClose={() => {
+ setEditPasswordModalVisible(false)
+ resetPasswordForm()
+ }}
+ className={s.modal}
+ >
+ <div className='title-2xl-semi-bold mb-6 text-text-primary'>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</div>
+ {userProfile.is_password_set && (
+ <>
+ <div className={titleClassName}>{t('common.account.currentPassword')}</div>
+ <div className='relative mt-2'>
+ <Input
+ type={showCurrentPassword ? 'text' : 'password'}
+ value={currentPassword}
+ onChange={e => setCurrentPassword(e.target.value)}
+ />
+
+ <div className="absolute inset-y-0 right-0 flex items-center">
+ <Button
+ type="button"
+ variant='ghost'
+ onClick={() => setShowCurrentPassword(!showCurrentPassword)}
+ >
+ {showCurrentPassword ? '馃憖' : '馃槤'}
+ </Button>
+ </div>
+ </div>
+ </>
+ )}
+ <div className='system-sm-semibold mt-8 text-text-secondary'>
+ {userProfile.is_password_set ? t('common.account.newPassword') : t('common.account.password')}
+ </div>
+ <div className='relative mt-2'>
+ <Input
+ type={showPassword ? 'text' : 'password'}
+ value={password}
+ onChange={e => setPassword(e.target.value)}
+ />
+ <div className="absolute inset-y-0 right-0 flex items-center">
+ <Button
+ type="button"
+ variant='ghost'
+ onClick={() => setShowPassword(!showPassword)}
+ >
+ {showPassword ? '馃憖' : '馃槤'}
+ </Button>
+ </div>
+ </div>
+ <div className='system-sm-semibold mt-8 text-text-secondary'>{t('common.account.confirmPassword')}</div>
+ <div className='relative mt-2'>
+ <Input
+ type={showConfirmPassword ? 'text' : 'password'}
+ value={confirmPassword}
+ onChange={e => setConfirmPassword(e.target.value)}
+ />
+ <div className="absolute inset-y-0 right-0 flex items-center">
+ <Button
+ type="button"
+ variant='ghost'
+ onClick={() => setShowConfirmPassword(!showConfirmPassword)}
+ >
+ {showConfirmPassword ? '馃憖' : '馃槤'}
+ </Button>
+ </div>
+ </div>
+ <div className='mt-10 flex justify-end'>
+ <Button className='mr-2' onClick={() => {
+ setEditPasswordModalVisible(false)
+ resetPasswordForm()
+ }}>{t('common.operation.cancel')}</Button>
+ <Button
+ disabled={editing}
+ variant='primary'
+ onClick={handleSavePassword}
+ >
+ {userProfile.is_password_set ? t('common.operation.reset') : t('common.operation.save')}
+ </Button>
+ </div>
+ </Modal>
+ )
+ }
+ {
+ showDeleteAccountModal && (
+ <DeleteAccount
+ onCancel={() => setShowDeleteAccountModal(false)}
+ onConfirm={() => setShowDeleteAccountModal(false)}
+ />
+ )
+ }
+ </>
+ )
+}
diff --git a/app/account/avatar.tsx b/app/account/avatar.tsx
new file mode 100644
index 0000000..ea897e6
--- /dev/null
+++ b/app/account/avatar.tsx
@@ -0,0 +1,109 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { Fragment } from 'react'
+import { useRouter } from 'next/navigation'
+import {
+ RiGraduationCapFill,
+} from '@remixicon/react'
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import Avatar from '@/app/components/base/avatar'
+import { logout } from '@/service/common'
+import { useAppContext } from '@/context/app-context'
+import { useProviderContext } from '@/context/provider-context'
+import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
+import PremiumBadge from '@/app/components/base/premium-badge'
+
+export type IAppSelector = {
+ isMobile: boolean
+}
+
+export default function AppSelector() {
+ const router = useRouter()
+ const { t } = useTranslation()
+ const { userProfile } = useAppContext()
+ const { isEducationAccount } = useProviderContext()
+
+ const handleLogout = async () => {
+ await logout({
+ url: '/logout',
+ params: {},
+ })
+
+ localStorage.removeItem('setup_status')
+ localStorage.removeItem('console_token')
+ localStorage.removeItem('refresh_token')
+
+ router.push('/signin')
+ }
+
+ return (
+ <Menu as="div" className="relative inline-block text-left">
+ {
+ ({ open }) => (
+ <>
+ <div>
+ <MenuButton
+ className={`
+ p-1x inline-flex
+ items-center rounded-[20px] text-sm
+ text-text-primary
+ mobile:px-1
+ ${open && 'bg-components-panel-bg-blur'}
+ `}
+ >
+ <Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={32} />
+ </MenuButton>
+ </div>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems
+ className="
+ absolute -right-2 -top-1 w-60 max-w-80
+ origin-top-right divide-y divide-divider-subtle rounded-lg bg-components-panel-bg-blur
+ shadow-lg
+ "
+ >
+ <MenuItem>
+ <div className='p-1'>
+ <div className='flex flex-nowrap items-center px-3 py-2'>
+ <div className='grow'>
+ <div className='system-md-medium break-all text-text-primary'>
+ {userProfile.name}
+ {isEducationAccount && (
+ <PremiumBadge size='s' color='blue' className='ml-1 !px-2'>
+ <RiGraduationCapFill className='mr-1 h-3 w-3' />
+ <span className='system-2xs-medium'>EDU</span>
+ </PremiumBadge>
+ )}
+ </div>
+ <div className='system-xs-regular break-all text-text-tertiary'>{userProfile.email}</div>
+ </div>
+ <Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={32} />
+ </div>
+ </div>
+ </MenuItem>
+ <MenuItem>
+ <div className='p-1' onClick={() => handleLogout()}>
+ <div
+ className='group flex h-9 cursor-pointer items-center justify-start rounded-lg px-3 hover:bg-state-base-hover'
+ >
+ <LogOut01 className='mr-1 flex h-4 w-4 text-text-tertiary' />
+ <div className='text-[14px] font-normal text-text-secondary'>{t('common.userProfile.logout')}</div>
+ </div>
+ </div>
+ </MenuItem>
+ </MenuItems>
+ </Transition>
+ </>
+ )
+ }
+ </Menu>
+ )
+}
diff --git a/app/account/delete-account/components/check-email.tsx b/app/account/delete-account/components/check-email.tsx
new file mode 100644
index 0000000..6359340
--- /dev/null
+++ b/app/account/delete-account/components/check-email.tsx
@@ -0,0 +1,48 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { useCallback, useState } from 'react'
+import Link from 'next/link'
+import { useSendDeleteAccountEmail } from '../state'
+import { useAppContext } from '@/context/app-context'
+import Input from '@/app/components/base/input'
+import Button from '@/app/components/base/button'
+
+type DeleteAccountProps = {
+ onCancel: () => void
+ onConfirm: () => void
+}
+
+export default function CheckEmail(props: DeleteAccountProps) {
+ const { t } = useTranslation()
+ const { userProfile } = useAppContext()
+ const [userInputEmail, setUserInputEmail] = useState('')
+
+ const { isPending: isSendingEmail, mutateAsync: getDeleteEmailVerifyCode } = useSendDeleteAccountEmail()
+
+ const handleConfirm = useCallback(async () => {
+ try {
+ const ret = await getDeleteEmailVerifyCode()
+ if (ret.result === 'success')
+ props.onConfirm()
+ }
+ catch (error) { console.error(error) }
+ }, [getDeleteEmailVerifyCode, props])
+
+ return <>
+ <div className='body-md-medium py-1 text-text-destructive'>
+ {t('common.account.deleteTip')}
+ </div>
+ <div className='body-md-regular pb-2 pt-1 text-text-secondary'>
+ {t('common.account.deletePrivacyLinkTip')}
+ <Link href='https://dify.ai/privacy' className='text-text-accent'>{t('common.account.deletePrivacyLink')}</Link>
+ </div>
+ <label className='system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary'>{t('common.account.deleteLabel')}</label>
+ <Input placeholder={t('common.account.deletePlaceholder') as string} onChange={(e) => {
+ setUserInputEmail(e.target.value)
+ }} />
+ <div className='mt-3 flex w-full flex-col gap-2'>
+ <Button className='w-full' disabled={userInputEmail !== userProfile.email || isSendingEmail} loading={isSendingEmail} variant='primary' onClick={handleConfirm}>{t('common.account.sendVerificationButton')}</Button>
+ <Button className='w-full' onClick={props.onCancel}>{t('common.operation.cancel')}</Button>
+ </div>
+ </>
+}
diff --git a/app/account/delete-account/components/feed-back.tsx b/app/account/delete-account/components/feed-back.tsx
new file mode 100644
index 0000000..2cd30bc
--- /dev/null
+++ b/app/account/delete-account/components/feed-back.tsx
@@ -0,0 +1,68 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { useCallback, useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { useDeleteAccountFeedback } from '../state'
+import { useAppContext } from '@/context/app-context'
+import Button from '@/app/components/base/button'
+import CustomDialog from '@/app/components/base/dialog'
+import Textarea from '@/app/components/base/textarea'
+import Toast from '@/app/components/base/toast'
+import { logout } from '@/service/common'
+
+type DeleteAccountProps = {
+ onCancel: () => void
+ onConfirm: () => void
+}
+
+export default function FeedBack(props: DeleteAccountProps) {
+ const { t } = useTranslation()
+ const { userProfile } = useAppContext()
+ const router = useRouter()
+ const [userFeedback, setUserFeedback] = useState('')
+ const { isPending, mutateAsync: sendFeedback } = useDeleteAccountFeedback()
+
+ const handleSuccess = useCallback(async () => {
+ try {
+ await logout({
+ url: '/logout',
+ params: {},
+ })
+ localStorage.removeItem('refresh_token')
+ localStorage.removeItem('console_token')
+ router.push('/signin')
+ Toast.notify({ type: 'info', message: t('common.account.deleteSuccessTip') })
+ }
+ catch (error) { console.error(error) }
+ }, [router, t])
+
+ const handleSubmit = useCallback(async () => {
+ try {
+ await sendFeedback({ feedback: userFeedback, email: userProfile.email })
+ props.onConfirm()
+ await handleSuccess()
+ }
+ catch (error) { console.error(error) }
+ }, [handleSuccess, userFeedback, sendFeedback, userProfile, props])
+
+ const handleSkip = useCallback(() => {
+ props.onCancel()
+ handleSuccess()
+ }, [handleSuccess, props])
+ return <CustomDialog
+ show={true}
+ onClose={props.onCancel}
+ title={t('common.account.feedbackTitle')}
+ className="max-w-[480px]"
+ footer={false}
+ >
+ <label className='system-sm-semibold mb-1 mt-3 flex items-center text-text-secondary'>{t('common.account.feedbackLabel')}</label>
+ <Textarea rows={6} value={userFeedback} placeholder={t('common.account.feedbackPlaceholder') as string} onChange={(e) => {
+ setUserFeedback(e.target.value)
+ }} />
+ <div className='mt-3 flex w-full flex-col gap-2'>
+ <Button className='w-full' loading={isPending} variant='primary' onClick={handleSubmit}>{t('common.operation.submit')}</Button>
+ <Button className='w-full' onClick={handleSkip}>{t('common.operation.skip')}</Button>
+ </div>
+ </CustomDialog>
+}
diff --git a/app/account/delete-account/components/verify-email.tsx b/app/account/delete-account/components/verify-email.tsx
new file mode 100644
index 0000000..7c9d097
--- /dev/null
+++ b/app/account/delete-account/components/verify-email.tsx
@@ -0,0 +1,55 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { useCallback, useEffect, useState } from 'react'
+import Link from 'next/link'
+import { useAccountDeleteStore, useConfirmDeleteAccount, useSendDeleteAccountEmail } from '../state'
+import Input from '@/app/components/base/input'
+import Button from '@/app/components/base/button'
+import Countdown from '@/app/components/signin/countdown'
+
+const CODE_EXP = /[A-Za-z\d]{6}/gi
+
+type DeleteAccountProps = {
+ onCancel: () => void
+ onConfirm: () => void
+}
+
+export default function VerifyEmail(props: DeleteAccountProps) {
+ const { t } = useTranslation()
+ const emailToken = useAccountDeleteStore(state => state.sendEmailToken)
+ const [verificationCode, setVerificationCode] = useState<string>()
+ const [shouldButtonDisabled, setShouldButtonDisabled] = useState(true)
+ const { mutate: sendEmail } = useSendDeleteAccountEmail()
+ const { isPending: isDeleting, mutateAsync: confirmDeleteAccount } = useConfirmDeleteAccount()
+
+ useEffect(() => {
+ setShouldButtonDisabled(!(verificationCode && CODE_EXP.test(verificationCode)) || isDeleting)
+ }, [verificationCode, isDeleting])
+
+ const handleConfirm = useCallback(async () => {
+ try {
+ const ret = await confirmDeleteAccount({ code: verificationCode!, token: emailToken })
+ if (ret.result === 'success')
+ props.onConfirm()
+ }
+ catch (error) { console.error(error) }
+ }, [emailToken, verificationCode, confirmDeleteAccount, props])
+ return <>
+ <div className='body-md-medium pt-1 text-text-destructive'>
+ {t('common.account.deleteTip')}
+ </div>
+ <div className='body-md-regular pb-2 pt-1 text-text-secondary'>
+ {t('common.account.deletePrivacyLinkTip')}
+ <Link href='https://dify.ai/privacy' className='text-text-accent'>{t('common.account.deletePrivacyLink')}</Link>
+ </div>
+ <label className='system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary'>{t('common.account.verificationLabel')}</label>
+ <Input minLength={6} maxLength={6} placeholder={t('common.account.verificationPlaceholder') as string} onChange={(e) => {
+ setVerificationCode(e.target.value)
+ }} />
+ <div className='mt-3 flex w-full flex-col gap-2'>
+ <Button className='w-full' disabled={shouldButtonDisabled} loading={isDeleting} variant='warning' onClick={handleConfirm}>{t('common.account.permanentlyDeleteButton')}</Button>
+ <Button className='w-full' onClick={props.onCancel}>{t('common.operation.cancel')}</Button>
+ <Countdown onResend={sendEmail} />
+ </div>
+ </>
+}
diff --git a/app/account/delete-account/index.tsx b/app/account/delete-account/index.tsx
new file mode 100644
index 0000000..5458890
--- /dev/null
+++ b/app/account/delete-account/index.tsx
@@ -0,0 +1,44 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { useCallback, useState } from 'react'
+import CheckEmail from './components/check-email'
+import VerifyEmail from './components/verify-email'
+import FeedBack from './components/feed-back'
+import CustomDialog from '@/app/components/base/dialog'
+import { COUNT_DOWN_KEY, COUNT_DOWN_TIME_MS } from '@/app/components/signin/countdown'
+
+type DeleteAccountProps = {
+ onCancel: () => void
+ onConfirm: () => void
+}
+
+export default function DeleteAccount(props: DeleteAccountProps) {
+ const { t } = useTranslation()
+
+ const [showVerifyEmail, setShowVerifyEmail] = useState(false)
+ const [showFeedbackDialog, setShowFeedbackDialog] = useState(false)
+
+ const handleEmailCheckSuccess = useCallback(async () => {
+ try {
+ setShowVerifyEmail(true)
+ localStorage.setItem(COUNT_DOWN_KEY, `${COUNT_DOWN_TIME_MS}`)
+ }
+ catch (error) { console.error(error) }
+ }, [])
+
+ if (showFeedbackDialog)
+ return <FeedBack onCancel={props.onCancel} onConfirm={props.onConfirm} />
+
+ return <CustomDialog
+ show={true}
+ onClose={props.onCancel}
+ title={t('common.account.delete')}
+ className="max-w-[480px]"
+ footer={false}
+ >
+ {!showVerifyEmail && <CheckEmail onCancel={props.onCancel} onConfirm={handleEmailCheckSuccess} />}
+ {showVerifyEmail && <VerifyEmail onCancel={props.onCancel} onConfirm={() => {
+ setShowFeedbackDialog(true)
+ }} />}
+ </CustomDialog>
+}
diff --git a/app/account/delete-account/state.tsx b/app/account/delete-account/state.tsx
new file mode 100644
index 0000000..4c43fba
--- /dev/null
+++ b/app/account/delete-account/state.tsx
@@ -0,0 +1,39 @@
+import { useMutation } from '@tanstack/react-query'
+import { create } from 'zustand'
+import { sendDeleteAccountCode, submitDeleteAccountFeedback, verifyDeleteAccountCode } from '@/service/common'
+
+type State = {
+ sendEmailToken: string
+ setSendEmailToken: (token: string) => void
+}
+
+export const useAccountDeleteStore = create<State>(set => ({
+ sendEmailToken: '',
+ setSendEmailToken: (token: string) => set({ sendEmailToken: token }),
+}))
+
+export function useSendDeleteAccountEmail() {
+ const updateEmailToken = useAccountDeleteStore(state => state.setSendEmailToken)
+ return useMutation({
+ mutationKey: ['delete-account'],
+ mutationFn: sendDeleteAccountCode,
+ onSuccess: (ret) => {
+ if (ret.result === 'success')
+ updateEmailToken(ret.data)
+ },
+ })
+}
+
+export function useConfirmDeleteAccount() {
+ return useMutation({
+ mutationKey: ['confirm-delete-account'],
+ mutationFn: verifyDeleteAccountCode,
+ })
+}
+
+export function useDeleteAccountFeedback() {
+ return useMutation({
+ mutationKey: ['delete-account-feedback'],
+ mutationFn: submitDeleteAccountFeedback,
+ })
+}
diff --git a/app/account/header.tsx b/app/account/header.tsx
new file mode 100644
index 0000000..11b6bee
--- /dev/null
+++ b/app/account/header.tsx
@@ -0,0 +1,39 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { RiArrowRightUpLine, RiRobot2Line } from '@remixicon/react'
+import { useRouter } from 'next/navigation'
+import Button from '../components/base/button'
+import Avatar from './avatar'
+import DifyLogo from '@/app/components/base/logo/dify-logo'
+import { useCallback } from 'react'
+
+const Header = () => {
+ const { t } = useTranslation()
+ const router = useRouter()
+
+ const back = useCallback(() => {
+ router.back()
+ }, [router])
+
+ return (
+ <div className='flex flex-1 items-center justify-between px-4'>
+ <div className='flex items-center gap-3'>
+ <div className='flex cursor-pointer items-center' onClick={back}>
+ <DifyLogo />
+ </div>
+ <div className='h-4 w-[1px] origin-center rotate-[11.31deg] bg-divider-regular' />
+ <p className='title-3xl-semi-bold relative mt-[-2px] text-text-primary'>{t('common.account.account')}</p>
+ </div>
+ <div className='flex shrink-0 items-center gap-3'>
+ <Button className='system-sm-medium gap-2 px-3 py-2' onClick={back}>
+ <RiRobot2Line className='h-4 w-4' />
+ <p>{t('common.account.studio')}</p>
+ <RiArrowRightUpLine className='h-4 w-4' />
+ </Button>
+ <div className='h-4 w-[1px] bg-divider-regular' />
+ <Avatar />
+ </div>
+ </div>
+ )
+}
+export default Header
diff --git a/app/account/layout.tsx b/app/account/layout.tsx
new file mode 100644
index 0000000..9ee7435
--- /dev/null
+++ b/app/account/layout.tsx
@@ -0,0 +1,40 @@
+import React from 'react'
+import type { ReactNode } from 'react'
+import Header from './header'
+import SwrInitor from '@/app/components/swr-initor'
+import { AppContextProvider } from '@/context/app-context'
+import GA, { GaType } from '@/app/components/base/ga'
+import HeaderWrapper from '@/app/components/header/header-wrapper'
+import { EventEmitterContextProvider } from '@/context/event-emitter'
+import { ProviderContextProvider } from '@/context/provider-context'
+import { ModalContextProvider } from '@/context/modal-context'
+
+const Layout = ({ children }: { children: ReactNode }) => {
+ return (
+ <>
+ <GA gaType={GaType.admin} />
+ <SwrInitor>
+ <AppContextProvider>
+ <EventEmitterContextProvider>
+ <ProviderContextProvider>
+ <ModalContextProvider>
+ <HeaderWrapper>
+ <Header />
+ </HeaderWrapper>
+ <div className='relative flex h-0 shrink-0 grow flex-col overflow-y-auto bg-components-panel-bg'>
+ {children}
+ </div>
+ </ModalContextProvider>
+ </ProviderContextProvider>
+ </EventEmitterContextProvider>
+ </AppContextProvider>
+ </SwrInitor>
+ </>
+ )
+}
+
+export const metadata = {
+ title: 'Dify',
+}
+
+export default Layout
diff --git a/app/account/page.tsx b/app/account/page.tsx
new file mode 100644
index 0000000..baf386e
--- /dev/null
+++ b/app/account/page.tsx
@@ -0,0 +1,7 @@
+import AccountPage from './account-page'
+
+export default function Account() {
+ return <div className='mx-auto w-full max-w-[640px] px-6 pt-12'>
+ <AccountPage />
+ </div>
+}
diff --git a/app/activate/activateForm.tsx b/app/activate/activateForm.tsx
new file mode 100644
index 0000000..782b24b
--- /dev/null
+++ b/app/activate/activateForm.tsx
@@ -0,0 +1,67 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import { useRouter, useSearchParams } from 'next/navigation'
+import cn from '@/utils/classnames'
+import Button from '@/app/components/base/button'
+
+import { invitationCheck } from '@/service/common'
+import Loading from '@/app/components/base/loading'
+
+const ActivateForm = () => {
+ const router = useRouter()
+ const { t } = useTranslation()
+ const searchParams = useSearchParams()
+ const workspaceID = searchParams.get('workspace_id')
+ const email = searchParams.get('email')
+ const token = searchParams.get('token')
+
+ const checkParams = {
+ url: '/activate/check',
+ params: {
+ ...workspaceID && { workspace_id: workspaceID },
+ ...email && { email },
+ token,
+ },
+ }
+ const { data: checkRes } = useSWR(checkParams, invitationCheck, {
+ revalidateOnFocus: false,
+ onSuccess(data) {
+ if (data.is_valid) {
+ const params = new URLSearchParams(searchParams)
+ const { email, workspace_id } = data.data
+ params.set('email', encodeURIComponent(email))
+ params.set('workspace_id', encodeURIComponent(workspace_id))
+ params.set('invite_token', encodeURIComponent(token as string))
+ router.replace(`/signin?${params.toString()}`)
+ }
+ },
+ })
+
+ return (
+ <div className={
+ cn(
+ 'flex w-full grow flex-col items-center justify-center',
+ 'px-6',
+ 'md:px-[108px]',
+ )
+ }>
+ {!checkRes && <Loading />}
+ {checkRes && !checkRes.is_valid && (
+ <div className="flex flex-col md:w-[400px]">
+ <div className="mx-auto w-full">
+ <div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-divider-regular bg-components-option-card-option-bg p-5 text-[40px] font-bold shadow-lg">馃し鈥嶁檪锔�</div>
+ <h2 className="text-[32px] font-bold text-text-primary">{t('login.invalid')}</h2>
+ </div>
+ <div className="mx-auto mt-6 w-full">
+ <Button variant='primary' className='w-full !text-sm'>
+ <a href="https://dify.ai">{t('login.explore')}</a>
+ </Button>
+ </div>
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default ActivateForm
diff --git a/app/activate/page.tsx b/app/activate/page.tsx
new file mode 100644
index 0000000..221559f
--- /dev/null
+++ b/app/activate/page.tsx
@@ -0,0 +1,20 @@
+import React from 'react'
+import Header from '../signin/_header'
+import ActivateForm from './activateForm'
+import cn from '@/utils/classnames'
+
+const Activate = () => {
+ return (
+ <div className={cn('flex min-h-screen w-full justify-center bg-background-default-burn p-6')}>
+ <div className={cn('flex w-full shrink-0 flex-col rounded-2xl border border-effects-highlight bg-background-default-subtle')}>
+ <Header />
+ <ActivateForm />
+ <div className='px-8 py-6 text-sm font-normal text-text-tertiary'>
+ 漏 {new Date().getFullYear()} LangGenius, Inc. All rights reserved.
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default Activate
diff --git a/app/components/app-sidebar/app-info.tsx b/app/components/app-sidebar/app-info.tsx
new file mode 100644
index 0000000..5ec0e31
--- /dev/null
+++ b/app/components/app-sidebar/app-info.tsx
@@ -0,0 +1,418 @@
+import { useTranslation } from 'react-i18next'
+import { useRouter } from 'next/navigation'
+import { useContext, useContextSelector } from 'use-context-selector'
+import React, { useCallback, useState } from 'react'
+import {
+ RiDeleteBinLine,
+ RiEditLine,
+ RiEqualizer2Line,
+ RiExchange2Line,
+ RiFileCopy2Line,
+ RiFileDownloadLine,
+ RiFileUploadLine,
+ RiMoreLine,
+} from '@remixicon/react'
+import AppIcon from '../base/app-icon'
+import SwitchAppModal from '../app/switch-app-modal'
+import cn from '@/utils/classnames'
+import Confirm from '@/app/components/base/confirm'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import { ToastContext } from '@/app/components/base/toast'
+import AppsContext, { useAppContext } from '@/context/app-context'
+import { useProviderContext } from '@/context/provider-context'
+import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps'
+import DuplicateAppModal from '@/app/components/app/duplicate-modal'
+import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal'
+import CreateAppModal from '@/app/components/explore/create-app-modal'
+import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
+import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
+import { getRedirection } from '@/utils/app-redirection'
+import UpdateDSLModal from '@/app/components/workflow/update-dsl-modal'
+import type { EnvironmentVariable } from '@/app/components/workflow/types'
+import DSLExportConfirmModal from '@/app/components/workflow/dsl-export-confirm-modal'
+import { fetchWorkflowDraft } from '@/service/workflow'
+import ContentDialog from '@/app/components/base/content-dialog'
+import Button from '@/app/components/base/button'
+import CardView from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '../base/portal-to-follow-elem'
+
+export type IAppInfoProps = {
+ expand: boolean
+}
+
+const AppInfo = ({ expand }: IAppInfoProps) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const { replace } = useRouter()
+ const { onPlanInfoChanged } = useProviderContext()
+ const appDetail = useAppStore(state => state.appDetail)
+ const setAppDetail = useAppStore(state => state.setAppDetail)
+ const [open, setOpen] = useState(false)
+ const [showEditModal, setShowEditModal] = useState(false)
+ const [showDuplicateModal, setShowDuplicateModal] = useState(false)
+ const [showConfirmDelete, setShowConfirmDelete] = useState(false)
+ const [showSwitchModal, setShowSwitchModal] = useState<boolean>(false)
+ const [showImportDSLModal, setShowImportDSLModal] = useState<boolean>(false)
+ const [secretEnvList, setSecretEnvList] = useState<EnvironmentVariable[]>([])
+
+ const mutateApps = useContextSelector(
+ AppsContext,
+ state => state.mutateApps,
+ )
+
+ const onEdit: CreateAppModalProps['onConfirm'] = useCallback(async ({
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ description,
+ use_icon_as_answer_icon,
+ }) => {
+ if (!appDetail)
+ return
+ try {
+ const app = await updateAppInfo({
+ appID: appDetail.id,
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ description,
+ use_icon_as_answer_icon,
+ })
+ setShowEditModal(false)
+ notify({
+ type: 'success',
+ message: t('app.editDone'),
+ })
+ setAppDetail(app)
+ mutateApps()
+ }
+ catch {
+ notify({ type: 'error', message: t('app.editFailed') })
+ }
+ }, [appDetail, mutateApps, notify, setAppDetail, t])
+
+ const onCopy: DuplicateAppModalProps['onConfirm'] = async ({ name, icon_type, icon, icon_background }) => {
+ if (!appDetail)
+ return
+ try {
+ const newApp = await copyApp({
+ appID: appDetail.id,
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ mode: appDetail.mode,
+ })
+ setShowDuplicateModal(false)
+ notify({
+ type: 'success',
+ message: t('app.newApp.appCreated'),
+ })
+ localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
+ mutateApps()
+ onPlanInfoChanged()
+ getRedirection(true, newApp, replace)
+ }
+ catch {
+ notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
+ }
+ }
+
+ const onExport = async (include = false) => {
+ if (!appDetail)
+ return
+ try {
+ const { data } = await exportAppConfig({
+ appID: appDetail.id,
+ include,
+ })
+ const a = document.createElement('a')
+ const file = new Blob([data], { type: 'application/yaml' })
+ a.href = URL.createObjectURL(file)
+ a.download = `${appDetail.name}.yml`
+ a.click()
+ }
+ catch {
+ notify({ type: 'error', message: t('app.exportFailed') })
+ }
+ }
+
+ const exportCheck = async () => {
+ if (!appDetail)
+ return
+ if (appDetail.mode !== 'workflow' && appDetail.mode !== 'advanced-chat') {
+ onExport()
+ return
+ }
+ try {
+ const workflowDraft = await fetchWorkflowDraft(`/apps/${appDetail.id}/workflows/draft`)
+ const list = (workflowDraft.environment_variables || []).filter(env => env.value_type === 'secret')
+ if (list.length === 0) {
+ onExport()
+ return
+ }
+ setSecretEnvList(list)
+ }
+ catch {
+ notify({ type: 'error', message: t('app.exportFailed') })
+ }
+ }
+
+ const onConfirmDelete = useCallback(async () => {
+ if (!appDetail)
+ return
+ try {
+ await deleteApp(appDetail.id)
+ notify({ type: 'success', message: t('app.appDeleted') })
+ mutateApps()
+ onPlanInfoChanged()
+ setAppDetail()
+ replace('/apps')
+ }
+ catch (e: any) {
+ notify({
+ type: 'error',
+ message: `${t('app.appDeleteFailed')}${'message' in e ? `: ${e.message}` : ''}`,
+ })
+ }
+ setShowConfirmDelete(false)
+ }, [appDetail, mutateApps, notify, onPlanInfoChanged, replace, setAppDetail, t])
+
+ const { isCurrentWorkspaceEditor } = useAppContext()
+
+ const [showMore, setShowMore] = useState(false)
+ const handleTriggerMore = useCallback(() => {
+ setShowMore(true)
+ }, [setShowMore])
+
+ if (!appDetail)
+ return null
+
+ return (
+ <div>
+ <button
+ onClick={() => {
+ if (isCurrentWorkspaceEditor)
+ setOpen(v => !v)
+ }}
+ className='block w-full'
+ >
+ <div className={cn('flex rounded-lg', expand ? 'flex-col gap-2 p-2 pb-2.5' : 'items-start justify-center gap-1 p-1', open && 'bg-state-base-hover', isCurrentWorkspaceEditor && 'cursor-pointer hover:bg-state-base-hover')}>
+ <div className={`flex items-center self-stretch ${expand ? 'justify-between' : 'flex-col gap-1'}`}>
+ <AppIcon
+ size={expand ? 'large' : 'small'}
+ iconType={appDetail.icon_type}
+ icon={appDetail.icon}
+ background={appDetail.icon_background}
+ imageUrl={appDetail.icon_url}
+ />
+ <div className='flex items-center justify-center rounded-md p-0.5'>
+ <div className='flex h-5 w-5 items-center justify-center'>
+ <RiEqualizer2Line className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ {
+ expand && (
+ <div className='flex flex-col items-start gap-1'>
+ <div className='flex w-full'>
+ <div className='system-md-semibold truncate text-text-secondary'>{appDetail.name}</div>
+ </div>
+ <div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === 'advanced-chat' ? t('app.types.advanced') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}</div>
+ </div>
+ )
+ }
+ </div>
+ </button>
+ <ContentDialog
+ show={open}
+ onClose={() => setOpen(false)}
+ className='absolute bottom-2 left-2 top-2 flex w-[420px] flex-col rounded-2xl !p-0'
+ >
+ <div className='flex shrink-0 flex-col items-start justify-center gap-3 self-stretch p-4'>
+ <div className='flex items-center gap-3 self-stretch'>
+ <AppIcon
+ size="large"
+ iconType={appDetail.icon_type}
+ icon={appDetail.icon}
+ background={appDetail.icon_background}
+ imageUrl={appDetail.icon_url}
+ />
+ <div className='flex w-full grow flex-col items-start justify-center'>
+ <div className='system-md-semibold w-full truncate text-text-secondary'>{appDetail.name}</div>
+ <div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === 'advanced-chat' ? t('app.types.advanced') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}</div>
+ </div>
+ </div>
+ {/* description */}
+ {appDetail.description && (
+ <div className='system-xs-regular text-text-tertiary'>{appDetail.description}</div>
+ )}
+ {/* operations */}
+ <div className='flex flex-wrap items-center gap-1 self-stretch'>
+ <Button
+ size={'small'}
+ variant={'secondary'}
+ className='gap-[1px]'
+ onClick={() => {
+ setOpen(false)
+ setShowEditModal(true)
+ }}
+ >
+ <RiEditLine className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <span className='system-xs-medium text-components-button-secondary-text'>{t('app.editApp')}</span>
+ </Button>
+ <Button
+ size={'small'}
+ variant={'secondary'}
+ className='gap-[1px]'
+ onClick={() => {
+ setOpen(false)
+ setShowDuplicateModal(true)
+ }}
+ >
+ <RiFileCopy2Line className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <span className='system-xs-medium text-components-button-secondary-text'>{t('app.duplicate')}</span>
+ </Button>
+ <Button
+ size={'small'}
+ variant={'secondary'}
+ className='gap-[1px]'
+ onClick={exportCheck}
+ >
+ <RiFileDownloadLine className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <span className='system-xs-medium text-components-button-secondary-text'>{t('app.export')}</span>
+ </Button>
+ {appDetail.mode !== 'agent-chat' && <PortalToFollowElem
+ open={showMore}
+ onOpenChange={setShowMore}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 4,
+ }}>
+ <PortalToFollowElemTrigger onClick={handleTriggerMore}>
+ <Button
+ size={'small'}
+ variant={'secondary'}
+ className='gap-[1px]'
+ >
+ <RiMoreLine className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <span className='system-xs-medium text-components-button-secondary-text'>{t('common.operation.more')}</span>
+ </Button>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[21]'>
+ <div className='flex w-[264px] flex-col rounded-[12px] border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-[5px]'>
+ {
+ (appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow')
+ && <div className='flex h-8 cursor-pointer items-center gap-x-1 rounded-lg p-1.5 hover:bg-state-base-hover'
+ onClick={() => {
+ setOpen(false)
+ setShowImportDSLModal(true)
+ }}>
+ <RiFileUploadLine className='h-4 w-4 text-text-tertiary' />
+ <span className='system-md-regular text-text-secondary'>{t('workflow.common.importDSL')}</span>
+ </div>
+ }
+ {
+ (appDetail.mode === 'completion' || appDetail.mode === 'chat')
+ && <div className='flex h-8 cursor-pointer items-center gap-x-1 rounded-lg p-1.5 hover:bg-state-base-hover'
+ onClick={() => {
+ setOpen(false)
+ setShowSwitchModal(true)
+ }}>
+ <RiExchange2Line className='h-4 w-4 text-text-tertiary' />
+ <span className='system-md-regular text-text-secondary'>{t('app.switch')}</span>
+ </div>
+ }
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>}
+ </div>
+ </div>
+ <div className='flex flex-1'>
+ <CardView
+ appId={appDetail.id}
+ isInPanel={true}
+ className='flex grow flex-col gap-2 overflow-auto px-2 py-1'
+ />
+ </div>
+ <div className='flex min-h-fit shrink-0 flex-col items-start justify-center gap-3 self-stretch border-t-[0.5px] border-divider-subtle p-2'>
+ <Button
+ size={'medium'}
+ variant={'ghost'}
+ className='gap-0.5'
+ onClick={() => {
+ setOpen(false)
+ setShowConfirmDelete(true)
+ }}
+ >
+ <RiDeleteBinLine className='h-4 w-4 text-text-tertiary' />
+ <span className='system-sm-medium text-text-tertiary'>{t('common.operation.deleteApp')}</span>
+ </Button>
+ </div>
+ </ContentDialog>
+ {showSwitchModal && (
+ <SwitchAppModal
+ inAppDetail
+ show={showSwitchModal}
+ appDetail={appDetail}
+ onClose={() => setShowSwitchModal(false)}
+ onSuccess={() => setShowSwitchModal(false)}
+ />
+ )}
+ {showEditModal && (
+ <CreateAppModal
+ isEditModal
+ appName={appDetail.name}
+ appIconType={appDetail.icon_type}
+ appIcon={appDetail.icon}
+ appIconBackground={appDetail.icon_background}
+ appIconUrl={appDetail.icon_url}
+ appDescription={appDetail.description}
+ appMode={appDetail.mode}
+ appUseIconAsAnswerIcon={appDetail.use_icon_as_answer_icon}
+ show={showEditModal}
+ onConfirm={onEdit}
+ onHide={() => setShowEditModal(false)}
+ />
+ )}
+ {showDuplicateModal && (
+ <DuplicateAppModal
+ appName={appDetail.name}
+ icon_type={appDetail.icon_type}
+ icon={appDetail.icon}
+ icon_background={appDetail.icon_background}
+ icon_url={appDetail.icon_url}
+ show={showDuplicateModal}
+ onConfirm={onCopy}
+ onHide={() => setShowDuplicateModal(false)}
+ />
+ )}
+ {showConfirmDelete && (
+ <Confirm
+ title={t('app.deleteAppConfirmTitle')}
+ content={t('app.deleteAppConfirmContent')}
+ isShow={showConfirmDelete}
+ onConfirm={onConfirmDelete}
+ onCancel={() => setShowConfirmDelete(false)}
+ />
+ )}
+ {showImportDSLModal && (
+ <UpdateDSLModal
+ onCancel={() => setShowImportDSLModal(false)}
+ onBackup={exportCheck}
+ />
+ )}
+ {secretEnvList.length > 0 && (
+ <DSLExportConfirmModal
+ envList={secretEnvList}
+ onConfirm={onExport}
+ onClose={() => setSecretEnvList([])}
+ />
+ )}
+ </div>
+ )
+}
+
+export default React.memo(AppInfo)
diff --git a/app/components/app-sidebar/basic.tsx b/app/components/app-sidebar/basic.tsx
new file mode 100644
index 0000000..6a7d5a1
--- /dev/null
+++ b/app/components/app-sidebar/basic.tsx
@@ -0,0 +1,99 @@
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import AppIcon from '../base/app-icon'
+import Tooltip from '@/app/components/base/tooltip'
+
+export type IAppBasicProps = {
+ iconType?: 'app' | 'api' | 'dataset' | 'webapp' | 'notion'
+ icon?: string
+ icon_background?: string | null
+ isExternal?: boolean
+ name: string
+ type: string | React.ReactNode
+ hoverTip?: string
+ textStyle?: { main?: string; extra?: string }
+ isExtraInLine?: boolean
+ mode?: string
+}
+
+const ApiSvg = <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M8.5 3.5C8.5 4.60457 9.39543 5.5 10.5 5.5C11.6046 5.5 12.5 4.60457 12.5 3.5C12.5 2.39543 11.6046 1.5 10.5 1.5C9.39543 1.5 8.5 2.39543 8.5 3.5Z" stroke="#5850EC" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+ <path d="M12.5 9C12.5 10.1046 13.3954 11 14.5 11C15.6046 11 16.5 10.1046 16.5 9C16.5 7.89543 15.6046 7 14.5 7C13.3954 7 12.5 7.89543 12.5 9Z" stroke="#5850EC" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+ <path d="M8.5 3.5H5.5L3.5 6.5" stroke="#5850EC" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+ <path d="M8.5 14.5C8.5 15.6046 9.39543 16.5 10.5 16.5C11.6046 16.5 12.5 15.6046 12.5 14.5C12.5 13.3954 11.6046 12.5 10.5 12.5C9.39543 12.5 8.5 13.3954 8.5 14.5Z" stroke="#5850EC" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+ <path d="M8.5 14.5H5.5L3.5 11.5" stroke="#5850EC" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+ <path d="M12.5 9H1.5" stroke="#5850EC" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+</svg>
+
+const DatasetSvg = <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fillRule="evenodd" clipRule="evenodd" d="M0.833497 5.13481C0.833483 4.69553 0.83347 4.31654 0.858973 4.0044C0.88589 3.67495 0.94532 3.34727 1.10598 3.03195C1.34567 2.56155 1.72812 2.17909 2.19852 1.93941C2.51384 1.77875 2.84152 1.71932 3.17097 1.6924C3.48312 1.6669 3.86209 1.66691 4.30137 1.66693L7.62238 1.66684C8.11701 1.66618 8.55199 1.66561 8.95195 1.80356C9.30227 1.92439 9.62134 2.12159 9.88607 2.38088C10.1883 2.67692 10.3823 3.06624 10.603 3.50894L11.3484 5.00008H14.3679C15.0387 5.00007 15.5924 5.00006 16.0434 5.03691C16.5118 5.07518 16.9424 5.15732 17.3468 5.36339C17.974 5.68297 18.4839 6.19291 18.8035 6.82011C19.0096 7.22456 19.0917 7.65515 19.13 8.12356C19.1668 8.57455 19.1668 9.12818 19.1668 9.79898V13.5345C19.1668 14.2053 19.1668 14.7589 19.13 15.2099C19.0917 15.6784 19.0096 16.1089 18.8035 16.5134C18.4839 17.1406 17.974 17.6505 17.3468 17.9701C16.9424 18.1762 16.5118 18.2583 16.0434 18.2966C15.5924 18.3334 15.0387 18.3334 14.3679 18.3334H5.63243C4.96163 18.3334 4.40797 18.3334 3.95698 18.2966C3.48856 18.2583 3.05798 18.1762 2.65353 17.9701C2.02632 17.6505 1.51639 17.1406 1.19681 16.5134C0.990734 16.1089 0.908597 15.6784 0.870326 15.2099C0.833478 14.7589 0.833487 14.2053 0.833497 13.5345V5.13481ZM7.51874 3.33359C8.17742 3.33359 8.30798 3.34447 8.4085 3.37914C8.52527 3.41942 8.63163 3.48515 8.71987 3.57158C8.79584 3.64598 8.86396 3.7579 9.15852 4.34704L9.48505 5.00008L2.50023 5.00008C2.50059 4.61259 2.50314 4.34771 2.5201 4.14012C2.5386 3.91374 2.57 3.82981 2.59099 3.7886C2.67089 3.6318 2.79837 3.50432 2.95517 3.42442C2.99638 3.40343 3.08031 3.37203 3.30669 3.35353C3.54281 3.33424 3.85304 3.33359 4.3335 3.33359H7.51874Z" fill="#444CE7" />
+</svg>
+
+const WebappSvg = <svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M14.375 5.45825L7.99998 8.99992M7.99998 8.99992L1.62498 5.45825M7.99998 8.99992L8 16.1249M14.75 12.0439V5.95603C14.75 5.69904 14.75 5.57055 14.7121 5.45595C14.6786 5.35457 14.6239 5.26151 14.5515 5.18299C14.4697 5.09424 14.3574 5.03184 14.1328 4.90704L8.58277 1.8237C8.37007 1.70553 8.26372 1.64645 8.15109 1.62329C8.05141 1.60278 7.9486 1.60278 7.84891 1.62329C7.73628 1.64645 7.62993 1.70553 7.41723 1.8237L1.86723 4.90704C1.64259 5.03184 1.53026 5.09424 1.44847 5.18299C1.37612 5.26151 1.32136 5.35457 1.28786 5.45595C1.25 5.57055 1.25 5.69904 1.25 5.95603V12.0439C1.25 12.3008 1.25 12.4293 1.28786 12.5439C1.32136 12.6453 1.37612 12.7384 1.44847 12.8169C1.53026 12.9056 1.64259 12.968 1.86723 13.0928L7.41723 16.1762C7.62993 16.2943 7.73628 16.3534 7.84891 16.3766C7.9486 16.3971 8.05141 16.3971 8.15109 16.3766C8.26372 16.3534 8.37007 16.2943 8.58277 16.1762L14.1328 13.0928C14.3574 12.968 14.4697 12.9056 14.5515 12.8169C14.6239 12.7384 14.6786 12.6453 14.7121 12.5439C14.75 12.4293 14.75 12.3008 14.75 12.0439Z" stroke="#155EEF" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+</svg>
+
+const NotionSvg = <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <g clipPath="url(#clip0_6294_13848)">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M4.287 21.9133L1.70748 18.6999C1.08685 17.9267 0.75 16.976 0.75 15.9974V4.36124C0.75 2.89548 1.92269 1.67923 3.43553 1.57594L15.3991 0.759137C16.2682 0.699797 17.1321 0.930818 17.8461 1.41353L22.0494 4.25543C22.8018 4.76414 23.25 5.59574 23.25 6.48319V19.7124C23.25 21.1468 22.0969 22.3345 20.6157 22.4256L7.3375 23.243C6.1555 23.3158 5.01299 22.8178 4.287 21.9133Z" fill="white" />
+ <path d="M8.43607 10.1842V10.0318C8.43607 9.64564 8.74535 9.32537 9.14397 9.29876L12.0475 9.10491L16.0628 15.0178V9.82823L15.0293 9.69046V9.6181C15.0293 9.22739 15.3456 8.90501 15.7493 8.88433L18.3912 8.74899V9.12918C18.3912 9.30765 18.2585 9.46031 18.0766 9.49108L17.4408 9.59861V18.0029L16.6429 18.2773C15.9764 18.5065 15.2343 18.2611 14.8527 17.6853L10.9545 11.803V17.4173L12.1544 17.647L12.1377 17.7583C12.0853 18.1069 11.7843 18.3705 11.4202 18.3867L8.43607 18.5195C8.39662 18.1447 8.67758 17.8093 9.06518 17.7686L9.45771 17.7273V10.2416L8.43607 10.1842Z" fill="black" />
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M15.5062 2.22521L3.5426 3.04201C2.82599 3.09094 2.27051 3.66706 2.27051 4.36136V15.9975C2.27051 16.6499 2.49507 17.2837 2.90883 17.7992L5.48835 21.0126C5.90541 21.5322 6.56174 21.8183 7.24076 21.7765L20.519 20.9591C21.1995 20.9172 21.7293 20.3716 21.7293 19.7125V6.48332C21.7293 6.07557 21.5234 5.69348 21.1777 5.45975L16.9743 2.61784C16.546 2.32822 16.0277 2.1896 15.5062 2.22521ZM4.13585 4.54287C3.96946 4.41968 4.04865 4.16303 4.25768 4.14804L15.5866 3.33545C15.9476 3.30956 16.3063 3.40896 16.5982 3.61578L18.8713 5.22622C18.9576 5.28736 18.9171 5.41935 18.8102 5.42516L6.8129 6.07764C6.44983 6.09739 6.09144 5.99073 5.80276 5.77699L4.13585 4.54287ZM6.25018 8.12315C6.25018 7.7334 6.56506 7.41145 6.9677 7.38952L19.6523 6.69871C20.0447 6.67734 20.375 6.97912 20.375 7.35898V18.8141C20.375 19.2031 20.0613 19.5247 19.6594 19.5476L7.05516 20.2648C6.61845 20.2896 6.25018 19.954 6.25018 19.5312V8.12315Z" fill="black" />
+ </g>
+ <defs>
+ <clipPath id="clip0_6294_13848">
+ <rect width="24" height="24" fill="white" />
+ </clipPath>
+ </defs>
+</svg>
+
+const ICON_MAP = {
+ app: <AppIcon className='border !border-[rgba(0,0,0,0.05)]' />,
+ api: <AppIcon innerIcon={ApiSvg} className='border !border-purple-200 !bg-purple-50' />,
+ dataset: <AppIcon innerIcon={DatasetSvg} className='!border-[0.5px] !border-indigo-100 !bg-indigo-25' />,
+ webapp: <AppIcon innerIcon={WebappSvg} className='border !border-primary-200 !bg-primary-100' />,
+ notion: <AppIcon innerIcon={NotionSvg} className='!border-[0.5px] !border-indigo-100 !bg-white' />,
+}
+
+export default function AppBasic({ icon, icon_background, name, isExternal, type, hoverTip, textStyle, isExtraInLine, mode = 'expand', iconType = 'app' }: IAppBasicProps) {
+ const { t } = useTranslation()
+
+ return (
+ <div className="flex grow items-center">
+ {icon && icon_background && iconType === 'app' && (
+ <div className='mr-3 shrink-0'>
+ <AppIcon icon={icon} background={icon_background} />
+ </div>
+ )}
+ {iconType !== 'app'
+ && <div className='mr-3 shrink-0'>
+ {ICON_MAP[iconType]}
+ </div>
+
+ }
+ {mode === 'expand' && <div className="group w-full">
+ <div className={`system-md-semibold flex flex-row items-center text-text-secondary group-hover:text-text-primary ${textStyle?.main ?? ''}`}>
+ <div className="min-w-0 overflow-hidden text-ellipsis break-normal">
+ {name}
+ </div>
+ {hoverTip
+ && <Tooltip
+ popupContent={
+ <div className='w-[240px]'>
+ {hoverTip}
+ </div>
+ }
+ popupClassName='ml-1'
+ triggerClassName='w-4 h-4 ml-1'
+ position='top'
+ />
+ }
+ </div>
+ {isExtraInLine ? (
+ <div className="system-2xs-medium-uppercase flex text-text-tertiary">{type}</div>
+ ) : (
+ <div className='system-2xs-medium-uppercase text-text-tertiary'>{isExternal ? t('dataset.externalTag') : type}</div>
+ )}
+ </div>}
+ </div>
+ )
+}
diff --git a/app/components/app-sidebar/completion.png b/app/components/app-sidebar/completion.png
new file mode 100644
index 0000000..7a3cbd5
--- /dev/null
+++ b/app/components/app-sidebar/completion.png
Binary files differ
diff --git a/app/components/app-sidebar/dataset-info.tsx b/app/components/app-sidebar/dataset-info.tsx
new file mode 100644
index 0000000..7374013
--- /dev/null
+++ b/app/components/app-sidebar/dataset-info.tsx
@@ -0,0 +1,45 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import AppIcon from '../base/app-icon'
+
+const DatasetSvg = <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fillRule="evenodd" clipRule="evenodd" d="M0.833497 5.13481C0.833483 4.69553 0.83347 4.31654 0.858973 4.0044C0.88589 3.67495 0.94532 3.34727 1.10598 3.03195C1.34567 2.56155 1.72812 2.17909 2.19852 1.93941C2.51384 1.77875 2.84152 1.71932 3.17097 1.6924C3.48312 1.6669 3.86209 1.66691 4.30137 1.66693L7.62238 1.66684C8.11701 1.66618 8.55199 1.66561 8.95195 1.80356C9.30227 1.92439 9.62134 2.12159 9.88607 2.38088C10.1883 2.67692 10.3823 3.06624 10.603 3.50894L11.3484 5.00008H14.3679C15.0387 5.00007 15.5924 5.00006 16.0434 5.03691C16.5118 5.07518 16.9424 5.15732 17.3468 5.36339C17.974 5.68297 18.4839 6.19291 18.8035 6.82011C19.0096 7.22456 19.0917 7.65515 19.13 8.12356C19.1668 8.57455 19.1668 9.12818 19.1668 9.79898V13.5345C19.1668 14.2053 19.1668 14.7589 19.13 15.2099C19.0917 15.6784 19.0096 16.1089 18.8035 16.5134C18.4839 17.1406 17.974 17.6505 17.3468 17.9701C16.9424 18.1762 16.5118 18.2583 16.0434 18.2966C15.5924 18.3334 15.0387 18.3334 14.3679 18.3334H5.63243C4.96163 18.3334 4.40797 18.3334 3.95698 18.2966C3.48856 18.2583 3.05798 18.1762 2.65353 17.9701C2.02632 17.6505 1.51639 17.1406 1.19681 16.5134C0.990734 16.1089 0.908597 15.6784 0.870326 15.2099C0.833478 14.7589 0.833487 14.2053 0.833497 13.5345V5.13481ZM7.51874 3.33359C8.17742 3.33359 8.30798 3.34447 8.4085 3.37914C8.52527 3.41942 8.63163 3.48515 8.71987 3.57158C8.79584 3.64598 8.86396 3.7579 9.15852 4.34704L9.48505 5.00008L2.50023 5.00008C2.50059 4.61259 2.50314 4.34771 2.5201 4.14012C2.5386 3.91374 2.57 3.82981 2.59099 3.7886C2.67089 3.6318 2.79837 3.50432 2.95517 3.42442C2.99638 3.40343 3.08031 3.37203 3.30669 3.35353C3.54281 3.33424 3.85304 3.33359 4.3335 3.33359H7.51874Z" fill="#444CE7" />
+</svg>
+
+type Props = {
+ isExternal?: boolean
+ name: string
+ description: string
+ expand: boolean
+ extraInfo?: React.ReactNode
+}
+
+const DatasetInfo: FC<Props> = ({
+ name,
+ description,
+ isExternal,
+ expand,
+ extraInfo,
+}) => {
+ const { t } = useTranslation()
+ return (
+ <div className='pl-1 pt-1'>
+ <div className='mr-3 shrink-0'>
+ <AppIcon innerIcon={DatasetSvg} className='!border-[0.5px] !border-indigo-100 !bg-indigo-25' />
+ </div>
+ {expand && (
+ <div className='mt-2'>
+ <div className='system-md-semibold text-text-secondary'>
+ {name}
+ </div>
+ <div className='system-2xs-medium-uppercase mt-1 text-text-tertiary'>{isExternal ? t('dataset.externalTag') : t('dataset.localDocs')}</div>
+ <div className='system-xs-regular my-3 text-text-tertiary first-letter:capitalize'>{description}</div>
+ </div>
+ )}
+ {extraInfo}
+ </div>
+ )
+}
+export default React.memo(DatasetInfo)
diff --git a/app/components/app-sidebar/expert.png b/app/components/app-sidebar/expert.png
new file mode 100644
index 0000000..ba941a5
--- /dev/null
+++ b/app/components/app-sidebar/expert.png
Binary files differ
diff --git a/app/components/app-sidebar/index.tsx b/app/components/app-sidebar/index.tsx
new file mode 100644
index 0000000..3276a1c
--- /dev/null
+++ b/app/components/app-sidebar/index.tsx
@@ -0,0 +1,126 @@
+import React, { useEffect } from 'react'
+import { useShallow } from 'zustand/react/shallow'
+import { RiLayoutLeft2Line, RiLayoutRight2Line } from '@remixicon/react'
+import NavLink from './navLink'
+import type { NavIcon } from './navLink'
+import AppBasic from './basic'
+import AppInfo from './app-info'
+import DatasetInfo from './dataset-info'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import cn from '@/utils/classnames'
+
+export type IAppDetailNavProps = {
+ iconType?: 'app' | 'dataset' | 'notion'
+ title: string
+ desc: string
+ isExternal?: boolean
+ icon: string
+ icon_background: string
+ navigation: Array<{
+ name: string
+ href: string
+ icon: NavIcon
+ selectedIcon: NavIcon
+ }>
+ extraInfo?: (modeState: string) => React.ReactNode
+}
+
+const AppDetailNav = ({ title, desc, isExternal, icon, icon_background, navigation, extraInfo, iconType = 'app' }: IAppDetailNavProps) => {
+ const { appSidebarExpand, setAppSiderbarExpand } = useAppStore(useShallow(state => ({
+ appSidebarExpand: state.appSidebarExpand,
+ setAppSiderbarExpand: state.setAppSiderbarExpand,
+ })))
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+ const expand = appSidebarExpand === 'expand'
+
+ const handleToggle = (state: string) => {
+ setAppSiderbarExpand(state === 'expand' ? 'collapse' : 'expand')
+ }
+
+ useEffect(() => {
+ if (appSidebarExpand) {
+ localStorage.setItem('app-detail-collapse-or-expand', appSidebarExpand)
+ setAppSiderbarExpand(appSidebarExpand)
+ }
+ }, [appSidebarExpand, setAppSiderbarExpand])
+
+ return (
+ <div
+ className={`
+ flex shrink-0 flex-col border-r border-divider-burn bg-background-default-subtle transition-all
+ ${expand ? 'w-[216px]' : 'w-14'}
+ `}
+ >
+ <div
+ className={`
+ shrink-0
+ ${expand ? 'p-2' : 'p-1'}
+ `}
+ >
+ {iconType === 'app' && (
+ <AppInfo expand={expand} />
+ )}
+ {iconType === 'dataset' && (
+ <DatasetInfo
+ name={title}
+ description={desc}
+ isExternal={isExternal}
+ expand={expand}
+ extraInfo={extraInfo && extraInfo(appSidebarExpand)}
+ />
+ )}
+ {!['app', 'dataset'].includes(iconType) && (
+ <AppBasic
+ mode={appSidebarExpand}
+ iconType={iconType}
+ icon={icon}
+ icon_background={icon_background}
+ name={title}
+ type={desc}
+ isExternal={isExternal}
+ />
+ )}
+ </div>
+ <div className='px-4'>
+ <div className={cn('mx-auto mt-1 h-[1px] bg-divider-subtle', !expand && 'w-6')} />
+ </div>
+ <nav
+ className={`
+ grow space-y-1
+ ${expand ? 'p-4' : 'px-2.5 py-4'}
+ `}
+ >
+ {navigation.map((item, index) => {
+ return (
+ <NavLink key={index} mode={appSidebarExpand} iconMap={{ selected: item.selectedIcon, normal: item.icon }} name={item.name} href={item.href} />
+ )
+ })}
+ </nav>
+ {
+ !isMobile && (
+ <div
+ className={`
+ shrink-0 py-3
+ ${expand ? 'px-6' : 'px-4'}
+ `}
+ >
+ <div
+ className='flex h-6 w-6 cursor-pointer items-center justify-center'
+ onClick={() => handleToggle(appSidebarExpand)}
+ >
+ {
+ expand
+ ? <RiLayoutRight2Line className='h-5 w-5 text-components-menu-item-text' />
+ : <RiLayoutLeft2Line className='h-5 w-5 text-components-menu-item-text' />
+ }
+ </div>
+ </div>
+ )
+ }
+ </div>
+ )
+}
+
+export default React.memo(AppDetailNav)
diff --git a/app/components/app-sidebar/navLink.tsx b/app/components/app-sidebar/navLink.tsx
new file mode 100644
index 0000000..295b553
--- /dev/null
+++ b/app/components/app-sidebar/navLink.tsx
@@ -0,0 +1,63 @@
+'use client'
+
+import { useSelectedLayoutSegment } from 'next/navigation'
+import Link from 'next/link'
+import classNames from '@/utils/classnames'
+import type { RemixiconComponentType } from '@remixicon/react'
+
+export type NavIcon = React.ComponentType<
+React.PropsWithoutRef<React.ComponentProps<'svg'>> & {
+ title?: string | undefined
+ titleId?: string | undefined
+}> | RemixiconComponentType
+
+export type NavLinkProps = {
+ name: string
+ href: string
+ iconMap: {
+ selected: NavIcon
+ normal: NavIcon
+ }
+ mode?: string
+}
+
+export default function NavLink({
+ name,
+ href,
+ iconMap,
+ mode = 'expand',
+}: NavLinkProps) {
+ const segment = useSelectedLayoutSegment()
+ const formattedSegment = (() => {
+ let res = segment?.toLowerCase()
+ // logs and annotations use the same nav
+ if (res === 'annotations')
+ res = 'logs'
+
+ return res
+ })()
+ const isActive = href.toLowerCase().split('/')?.pop() === formattedSegment
+ const NavIcon = isActive ? iconMap.selected : iconMap.normal
+
+ return (
+ <Link
+ key={name}
+ href={href}
+ className={classNames(
+ isActive ? 'bg-state-accent-active text-text-accent font-semibold' : 'text-components-menu-item-text hover:bg-state-base-hover hover:text-components-menu-item-text-hover',
+ 'group flex items-center h-9 rounded-md py-2 text-sm font-normal',
+ mode === 'expand' ? 'px-3' : 'px-2.5',
+ )}
+ title={mode === 'collapse' ? name : ''}
+ >
+ <NavIcon
+ className={classNames(
+ 'h-4 w-4 flex-shrink-0',
+ mode === 'expand' ? 'mr-2' : 'mr-0',
+ )}
+ aria-hidden="true"
+ />
+ {mode === 'expand' && name}
+ </Link>
+ )
+}
diff --git a/app/components/app-sidebar/style.module.css b/app/components/app-sidebar/style.module.css
new file mode 100644
index 0000000..ca0978b
--- /dev/null
+++ b/app/components/app-sidebar/style.module.css
@@ -0,0 +1,11 @@
+.sidebar {
+ border-right: 1px solid #F3F4F6;
+}
+
+.completionPic {
+background-image: url('./completion.png')
+}
+
+.expertPic {
+background-image: url('./expert.png')
+}
diff --git a/app/components/app/annotation/add-annotation-modal/edit-item/index.tsx b/app/components/app/annotation/add-annotation-modal/edit-item/index.tsx
new file mode 100644
index 0000000..4c118c6
--- /dev/null
+++ b/app/components/app/annotation/add-annotation-modal/edit-item/index.tsx
@@ -0,0 +1,45 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Textarea from '@/app/components/base/textarea'
+import { Robot, User } from '@/app/components/base/icons/src/public/avatar'
+
+export enum EditItemType {
+ Query = 'query',
+ Answer = 'answer',
+}
+type Props = {
+ type: EditItemType
+ content: string
+ onChange: (content: string) => void
+}
+
+const EditItem: FC<Props> = ({
+ type,
+ content,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const avatar = type === EditItemType.Query ? <User className='h-6 w-6' /> : <Robot className='h-6 w-6' />
+ const name = type === EditItemType.Query ? t('appAnnotation.addModal.queryName') : t('appAnnotation.addModal.answerName')
+ const placeholder = type === EditItemType.Query ? t('appAnnotation.addModal.queryPlaceholder') : t('appAnnotation.addModal.answerPlaceholder')
+
+ return (
+ <div className='flex' onClick={e => e.stopPropagation()}>
+ <div className='mr-3 shrink-0'>
+ {avatar}
+ </div>
+ <div className='grow'>
+ <div className='system-xs-semibold mb-1 text-text-primary'>{name}</div>
+ <Textarea
+ value={content}
+ onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => onChange(e.target.value)}
+ placeholder={placeholder}
+ autoFocus
+ />
+ </div>
+ </div>
+ )
+}
+export default React.memo(EditItem)
diff --git a/app/components/app/annotation/add-annotation-modal/index.tsx b/app/components/app/annotation/add-annotation-modal/index.tsx
new file mode 100644
index 0000000..274a57a
--- /dev/null
+++ b/app/components/app/annotation/add-annotation-modal/index.tsx
@@ -0,0 +1,121 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { AnnotationItemBasic } from '../type'
+import EditItem, { EditItemType } from './edit-item'
+import Checkbox from '@/app/components/base/checkbox'
+import Drawer from '@/app/components/base/drawer-plus'
+import Button from '@/app/components/base/button'
+import Toast from '@/app/components/base/toast'
+import { useProviderContext } from '@/context/provider-context'
+import AnnotationFull from '@/app/components/billing/annotation-full'
+type Props = {
+ isShow: boolean
+ onHide: () => void
+ onAdd: (payload: AnnotationItemBasic) => void
+}
+
+const AddAnnotationModal: FC<Props> = ({
+ isShow,
+ onHide,
+ onAdd,
+}) => {
+ const { t } = useTranslation()
+ const { plan, enableBilling } = useProviderContext()
+ const isAnnotationFull = (enableBilling && plan.usage.annotatedResponse >= plan.total.annotatedResponse)
+ const [question, setQuestion] = useState('')
+ const [answer, setAnswer] = useState('')
+ const [isCreateNext, setIsCreateNext] = useState(false)
+ const [isSaving, setIsSaving] = useState(false)
+
+ const isValid = (payload: AnnotationItemBasic) => {
+ if (!payload.question)
+ return t('appAnnotation.errorMessage.queryRequired')
+
+ if (!payload.answer)
+ return t('appAnnotation.errorMessage.answerRequired')
+
+ return true
+ }
+
+ const handleSave = async () => {
+ const payload = {
+ question,
+ answer,
+ }
+ if (isValid(payload) !== true) {
+ Toast.notify({
+ type: 'error',
+ message: isValid(payload) as string,
+ })
+ return
+ }
+
+ setIsSaving(true)
+ try {
+ await onAdd(payload)
+ }
+ catch {
+ }
+ setIsSaving(false)
+
+ if (isCreateNext) {
+ setQuestion('')
+ setAnswer('')
+ }
+ else {
+ onHide()
+ }
+ }
+ return (
+ <div>
+ <Drawer
+ isShow={isShow}
+ onHide={onHide}
+ maxWidthClassName='!max-w-[480px]'
+ title={t('appAnnotation.addModal.title') as string}
+ body={(
+ <div className='space-y-6 p-6 pb-4'>
+ <EditItem
+ type={EditItemType.Query}
+ content={question}
+ onChange={setQuestion}
+ />
+ <EditItem
+ type={EditItemType.Answer}
+ content={answer}
+ onChange={setAnswer}
+ />
+ </div>
+ )}
+ foot={
+ (
+ <div>
+ {isAnnotationFull && (
+ <div className='mb-4 mt-6 px-6'>
+ <AnnotationFull />
+ </div>
+ )}
+ <div className='system-sm-medium flex h-16 items-center justify-between rounded-bl-xl rounded-br-xl border-t border-divider-subtle bg-background-section-burn px-4 text-text-tertiary'>
+ <div
+ className='flex items-center space-x-2'
+ >
+ <Checkbox checked={isCreateNext} onCheck={() => setIsCreateNext(!isCreateNext)} />
+ <div>{t('appAnnotation.addModal.createNext')}</div>
+ </div>
+ <div className='mt-2 flex space-x-2'>
+ <Button className='h-7 text-xs' onClick={onHide}>{t('common.operation.cancel')}</Button>
+ <Button className='h-7 text-xs' variant='primary' onClick={handleSave} loading={isSaving} disabled={isAnnotationFull}>{t('common.operation.add')}</Button>
+ </div>
+ </div>
+ </div>
+
+ )
+ }
+ >
+ </Drawer>
+ </div>
+ )
+}
+export default React.memo(AddAnnotationModal)
diff --git a/app/components/app/annotation/batch-add-annotation-modal/csv-downloader.tsx b/app/components/app/annotation/batch-add-annotation-modal/csv-downloader.tsx
new file mode 100644
index 0000000..8fb42e1
--- /dev/null
+++ b/app/components/app/annotation/batch-add-annotation-modal/csv-downloader.tsx
@@ -0,0 +1,73 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import {
+ useCSVDownloader,
+} from 'react-papaparse'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { Download02 as DownloadIcon } from '@/app/components/base/icons/src/vender/solid/general'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+
+const CSV_TEMPLATE_QA_EN = [
+ ['question', 'answer'],
+ ['question1', 'answer1'],
+ ['question2', 'answer2'],
+]
+const CSV_TEMPLATE_QA_CN = [
+ ['闂', '绛旀'],
+ ['闂 1', '绛旀 1'],
+ ['闂 2', '绛旀 2'],
+]
+
+const CSVDownload: FC = () => {
+ const { t } = useTranslation()
+
+ const { locale } = useContext(I18n)
+ const { CSVDownloader, Type } = useCSVDownloader()
+
+ const getTemplate = () => {
+ return locale !== LanguagesSupported[1] ? CSV_TEMPLATE_QA_EN : CSV_TEMPLATE_QA_CN
+ }
+
+ return (
+ <div className='mt-6'>
+ <div className='system-sm-medium text-text-primary'>{t('share.generation.csvStructureTitle')}</div>
+ <div className='mt-2 max-h-[500px] overflow-auto'>
+ <table className='w-full table-fixed border-separate border-spacing-0 rounded-lg border border-divider-regular text-xs'>
+ <thead className='text-text-tertiary'>
+ <tr>
+ <td className='h-9 border-b border-divider-regular pl-3 pr-2'>{t('appAnnotation.batchModal.question')}</td>
+ <td className='h-9 border-b border-divider-regular pl-3 pr-2'>{t('appAnnotation.batchModal.answer')}</td>
+ </tr>
+ </thead>
+ <tbody className='text-text-secondary'>
+ <tr>
+ <td className='h-9 border-b border-divider-subtle pl-3 pr-2 text-[13px]'>{t('appAnnotation.batchModal.question')} 1</td>
+ <td className='h-9 border-b border-divider-subtle pl-3 pr-2 text-[13px]'>{t('appAnnotation.batchModal.answer')} 1</td>
+ </tr>
+ <tr>
+ <td className='h-9 pl-3 pr-2 text-[13px]'>{t('appAnnotation.batchModal.question')} 2</td>
+ <td className='h-9 pl-3 pr-2 text-[13px]'>{t('appAnnotation.batchModal.answer')} 2</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <CSVDownloader
+ className="mt-2 block cursor-pointer"
+ type={Type.Link}
+ filename={`template-${locale}`}
+ bom={true}
+ data={getTemplate()}
+ >
+ <div className='system-xs-medium flex h-[18px] items-center space-x-1 text-text-accent'>
+ <DownloadIcon className='mr-1 h-3 w-3' />
+ {t('appAnnotation.batchModal.template')}
+ </div>
+ </CSVDownloader>
+ </div>
+
+ )
+}
+export default React.memo(CSVDownload)
diff --git a/app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx b/app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx
new file mode 100644
index 0000000..dfc8d10
--- /dev/null
+++ b/app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx
@@ -0,0 +1,126 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { RiDeleteBinLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { Csv as CSVIcon } from '@/app/components/base/icons/src/public/files'
+import { ToastContext } from '@/app/components/base/toast'
+import Button from '@/app/components/base/button'
+
+export type Props = {
+ file: File | undefined
+ updateFile: (file?: File) => void
+}
+
+const CSVUploader: FC<Props> = ({
+ file,
+ updateFile,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const [dragging, setDragging] = useState(false)
+ const dropRef = useRef<HTMLDivElement>(null)
+ const dragRef = useRef<HTMLDivElement>(null)
+ const fileUploader = useRef<HTMLInputElement>(null)
+
+ const handleDragEnter = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ e.target !== dragRef.current && setDragging(true)
+ }
+ const handleDragOver = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }
+ const handleDragLeave = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ e.target === dragRef.current && setDragging(false)
+ }
+ const handleDrop = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setDragging(false)
+ if (!e.dataTransfer)
+ return
+ const files = [...e.dataTransfer.files]
+ if (files.length > 1) {
+ notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.count') })
+ return
+ }
+ updateFile(files[0])
+ }
+ const selectHandle = () => {
+ if (fileUploader.current)
+ fileUploader.current.click()
+ }
+ const removeFile = () => {
+ if (fileUploader.current)
+ fileUploader.current.value = ''
+ updateFile()
+ }
+ const fileChangeHandle = (e: React.ChangeEvent<HTMLInputElement>) => {
+ const currentFile = e.target.files?.[0]
+ updateFile(currentFile)
+ }
+
+ useEffect(() => {
+ dropRef.current?.addEventListener('dragenter', handleDragEnter)
+ dropRef.current?.addEventListener('dragover', handleDragOver)
+ dropRef.current?.addEventListener('dragleave', handleDragLeave)
+ dropRef.current?.addEventListener('drop', handleDrop)
+ return () => {
+ dropRef.current?.removeEventListener('dragenter', handleDragEnter)
+ dropRef.current?.removeEventListener('dragover', handleDragOver)
+ dropRef.current?.removeEventListener('dragleave', handleDragLeave)
+ dropRef.current?.removeEventListener('drop', handleDrop)
+ }
+ }, [])
+
+ return (
+ <div className='mt-6'>
+ <input
+ ref={fileUploader}
+ style={{ display: 'none' }}
+ type="file"
+ id="fileUploader"
+ accept='.csv'
+ onChange={fileChangeHandle}
+ />
+ <div ref={dropRef}>
+ {!file && (
+ <div className={cn('system-sm-regular flex h-20 items-center rounded-xl border border-dashed border-components-dropzone-border bg-components-dropzone-bg', dragging && 'border border-components-dropzone-border-accent bg-components-dropzone-bg-accent')}>
+ <div className='flex w-full items-center justify-center space-x-2'>
+ <CSVIcon className="shrink-0" />
+ <div className='text-text-tertiary'>
+ {t('appAnnotation.batchModal.csvUploadTitle')}
+ <span className='cursor-pointer text-text-accent' onClick={selectHandle}>{t('appAnnotation.batchModal.browse')}</span>
+ </div>
+ </div>
+ {dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />}
+ </div>
+ )}
+ {file && (
+ <div className={cn('group flex h-20 items-center rounded-xl border border-components-panel-border bg-components-panel-bg px-6 text-sm font-normal', 'hover:border-components-panel-bg-blur hover:bg-components-panel-bg-blur')}>
+ <CSVIcon className="shrink-0" />
+ <div className='ml-2 flex w-0 grow'>
+ <span className='max-w-[calc(100%_-_30px)] overflow-hidden text-ellipsis whitespace-nowrap text-text-primary'>{file.name.replace(/.csv$/, '')}</span>
+ <span className='shrink-0 text-text-tertiary'>.csv</span>
+ </div>
+ <div className='hidden items-center group-hover:flex'>
+ <Button variant='secondary' onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.change')}</Button>
+ <div className='mx-2 h-4 w-px bg-divider-regular' />
+ <div className='cursor-pointer p-2' onClick={removeFile}>
+ <RiDeleteBinLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(CSVUploader)
diff --git a/app/components/app/annotation/batch-add-annotation-modal/index.tsx b/app/components/app/annotation/batch-add-annotation-modal/index.tsx
new file mode 100644
index 0000000..8f4e907
--- /dev/null
+++ b/app/components/app/annotation/batch-add-annotation-modal/index.tsx
@@ -0,0 +1,124 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import CSVUploader from './csv-uploader'
+import CSVDownloader from './csv-downloader'
+import Button from '@/app/components/base/button'
+import Modal from '@/app/components/base/modal'
+import Toast from '@/app/components/base/toast'
+import { annotationBatchImport, checkAnnotationBatchImportProgress } from '@/service/annotation'
+import { useProviderContext } from '@/context/provider-context'
+import AnnotationFull from '@/app/components/billing/annotation-full'
+import { noop } from 'lodash-es'
+
+export enum ProcessStatus {
+ WAITING = 'waiting',
+ PROCESSING = 'processing',
+ COMPLETED = 'completed',
+ ERROR = 'error',
+}
+
+export type IBatchModalProps = {
+ appId: string
+ isShow: boolean
+ onCancel: () => void
+ onAdded: () => void
+}
+
+const BatchModal: FC<IBatchModalProps> = ({
+ appId,
+ isShow,
+ onCancel,
+ onAdded,
+}) => {
+ const { t } = useTranslation()
+ const { plan, enableBilling } = useProviderContext()
+ const isAnnotationFull = (enableBilling && plan.usage.annotatedResponse >= plan.total.annotatedResponse)
+ const [currentCSV, setCurrentCSV] = useState<File>()
+ const handleFile = (file?: File) => setCurrentCSV(file)
+
+ useEffect(() => {
+ if (!isShow)
+ setCurrentCSV(undefined)
+ }, [isShow])
+
+ const [importStatus, setImportStatus] = useState<ProcessStatus | string>()
+ const notify = Toast.notify
+ const checkProcess = async (jobID: string) => {
+ try {
+ const res = await checkAnnotationBatchImportProgress({ jobID, appId })
+ setImportStatus(res.job_status)
+ if (res.job_status === ProcessStatus.WAITING || res.job_status === ProcessStatus.PROCESSING)
+ setTimeout(() => checkProcess(res.job_id), 2500)
+ if (res.job_status === ProcessStatus.ERROR)
+ notify({ type: 'error', message: `${t('appAnnotation.batchModal.runError')}` })
+ if (res.job_status === ProcessStatus.COMPLETED) {
+ notify({ type: 'success', message: `${t('appAnnotation.batchModal.completed')}` })
+ onAdded()
+ onCancel()
+ }
+ }
+ catch (e: any) {
+ notify({ type: 'error', message: `${t('appAnnotation.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` })
+ }
+ }
+
+ const runBatch = async (csv: File) => {
+ const formData = new FormData()
+ formData.append('file', csv)
+ try {
+ const res = await annotationBatchImport({
+ url: `/apps/${appId}/annotations/batch-import`,
+ body: formData,
+ })
+ setImportStatus(res.job_status)
+ checkProcess(res.job_id)
+ }
+ catch (e: any) {
+ notify({ type: 'error', message: `${t('appAnnotation.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` })
+ }
+ }
+
+ const handleSend = () => {
+ if (!currentCSV)
+ return
+ runBatch(currentCSV)
+ }
+
+ return (
+ <Modal isShow={isShow} onClose={noop} className='!max-w-[520px] !rounded-xl px-8 py-6'>
+ <div className='system-xl-medium relative pb-1 text-text-primary'>{t('appAnnotation.batchModal.title')}</div>
+ <div className='absolute right-4 top-4 cursor-pointer p-2' onClick={onCancel}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <CSVUploader
+ file={currentCSV}
+ updateFile={handleFile}
+ />
+ <CSVDownloader />
+
+ {isAnnotationFull && (
+ <div className='mt-4'>
+ <AnnotationFull />
+ </div>
+ )}
+
+ <div className='mt-[28px] flex justify-end pt-6'>
+ <Button className='system-sm-medium mr-2 text-text-tertiary' onClick={onCancel}>
+ {t('appAnnotation.batchModal.cancel')}
+ </Button>
+ <Button
+ variant="primary"
+ onClick={handleSend}
+ disabled={isAnnotationFull || !currentCSV}
+ loading={importStatus === ProcessStatus.PROCESSING || importStatus === ProcessStatus.WAITING}
+ >
+ {t('appAnnotation.batchModal.run')}
+ </Button>
+ </div>
+ </Modal>
+ )
+}
+export default React.memo(BatchModal)
diff --git a/app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx b/app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx
new file mode 100644
index 0000000..f68ec4a
--- /dev/null
+++ b/app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx
@@ -0,0 +1,128 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiDeleteBinLine, RiEditFill, RiEditLine } from '@remixicon/react'
+import { Robot, User } from '@/app/components/base/icons/src/public/avatar'
+import Textarea from '@/app/components/base/textarea'
+import Button from '@/app/components/base/button'
+import cn from '@/utils/classnames'
+
+export enum EditItemType {
+ Query = 'query',
+ Answer = 'answer',
+}
+type Props = {
+ type: EditItemType
+ content: string
+ readonly?: boolean
+ onSave: (content: string) => void
+}
+
+export const EditTitle: FC<{ className?: string; title: string }> = ({ className, title }) => (
+ <div className={cn(className, 'system-xs-medium flex h-[18px] items-center text-text-tertiary')}>
+ <RiEditFill className='mr-1 h-3.5 w-3.5' />
+ <div>{title}</div>
+ <div
+ className='ml-2 h-[1px] grow'
+ style={{
+ background: 'linear-gradient(90deg, rgba(0, 0, 0, 0.05) -1.65%, rgba(0, 0, 0, 0.00) 100%)',
+ }}
+ ></div>
+ </div>
+)
+const EditItem: FC<Props> = ({
+ type,
+ readonly,
+ content,
+ onSave,
+}) => {
+ const { t } = useTranslation()
+ const [newContent, setNewContent] = useState('')
+ const showNewContent = newContent && newContent !== content
+ const avatar = type === EditItemType.Query ? <User className='h-6 w-6' /> : <Robot className='h-6 w-6' />
+ const name = type === EditItemType.Query ? t('appAnnotation.editModal.queryName') : t('appAnnotation.editModal.answerName')
+ const editTitle = type === EditItemType.Query ? t('appAnnotation.editModal.yourQuery') : t('appAnnotation.editModal.yourAnswer')
+ const placeholder = type === EditItemType.Query ? t('appAnnotation.editModal.queryPlaceholder') : t('appAnnotation.editModal.answerPlaceholder')
+ const [isEdit, setIsEdit] = useState(false)
+
+ const handleSave = () => {
+ onSave(newContent)
+ setIsEdit(false)
+ }
+
+ const handleCancel = () => {
+ setNewContent('')
+ setIsEdit(false)
+ }
+
+ return (
+ <div className='flex' onClick={e => e.stopPropagation()}>
+ <div className='mr-3 shrink-0'>
+ {avatar}
+ </div>
+ <div className='grow'>
+ <div className='system-xs-semibold mb-1 text-text-primary'>{name}</div>
+ <div className='system-sm-regular text-text-primary'>{content}</div>
+ {!isEdit
+ ? (
+ <div>
+ {showNewContent && (
+ <div className='mt-3'>
+ <EditTitle title={editTitle} />
+ <div className='system-sm-regular mt-1 text-text-primary'>{newContent}</div>
+ </div>
+ )}
+ <div className='mt-2 flex items-center'>
+ {!readonly && (
+ <div
+ className='system-xs-medium flex cursor-pointer items-center space-x-1 text-text-accent'
+ onClick={() => {
+ setIsEdit(true)
+ }}
+ >
+ <RiEditLine className='mr-1 h-3.5 w-3.5' />
+ <div>{t('common.operation.edit')}</div>
+ </div>
+ )}
+
+ {showNewContent && (
+ <div className='system-xs-medium ml-2 flex items-center text-text-tertiary'>
+ <div className='mr-2'>路</div>
+ <div
+ className='flex cursor-pointer items-center space-x-1'
+ onClick={() => {
+ setNewContent(content)
+ onSave(content)
+ }}
+ >
+ <div className='h-3.5 w-3.5'>
+ <RiDeleteBinLine className='h-3.5 w-3.5' />
+ </div>
+ <div>{t('common.operation.delete')}</div>
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ )
+ : (
+ <div className='mt-3'>
+ <EditTitle title={editTitle} />
+ <Textarea
+ value={newContent}
+ onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setNewContent(e.target.value)}
+ placeholder={placeholder}
+ autoFocus
+ />
+ <div className='mt-2 flex space-x-2'>
+ <Button size='small' variant='primary' onClick={handleSave}>{t('common.operation.save')}</Button>
+ <Button size='small' onClick={handleCancel}>{t('common.operation.cancel')}</Button>
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+export default React.memo(EditItem)
diff --git a/app/components/app/annotation/edit-annotation-modal/index.tsx b/app/components/app/annotation/edit-annotation-modal/index.tsx
new file mode 100644
index 0000000..2961ce3
--- /dev/null
+++ b/app/components/app/annotation/edit-annotation-modal/index.tsx
@@ -0,0 +1,146 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import EditItem, { EditItemType } from './edit-item'
+import Drawer from '@/app/components/base/drawer-plus'
+import { MessageCheckRemove } from '@/app/components/base/icons/src/vender/line/communication'
+import Confirm from '@/app/components/base/confirm'
+import { addAnnotation, editAnnotation } from '@/service/annotation'
+import Toast from '@/app/components/base/toast'
+import { useProviderContext } from '@/context/provider-context'
+import AnnotationFull from '@/app/components/billing/annotation-full'
+import useTimestamp from '@/hooks/use-timestamp'
+
+type Props = {
+ isShow: boolean
+ onHide: () => void
+ appId: string
+ messageId?: string
+ annotationId?: string
+ query: string
+ answer: string
+ onEdited: (editedQuery: string, editedAnswer: string) => void
+ onAdded: (annotationId: string, authorName: string, editedQuery: string, editedAnswer: string) => void
+ createdAt?: number
+ onRemove: () => void
+ onlyEditResponse?: boolean
+}
+
+const EditAnnotationModal: FC<Props> = ({
+ isShow,
+ onHide,
+ query,
+ answer,
+ onEdited,
+ onAdded,
+ appId,
+ messageId,
+ annotationId,
+ createdAt,
+ onRemove,
+ onlyEditResponse,
+}) => {
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+ const { plan, enableBilling } = useProviderContext()
+ const isAdd = !annotationId
+ const isAnnotationFull = (enableBilling && plan.usage.annotatedResponse >= plan.total.annotatedResponse)
+ const handleSave = async (type: EditItemType, editedContent: string) => {
+ let postQuery = query
+ let postAnswer = answer
+ if (type === EditItemType.Query)
+ postQuery = editedContent
+ else
+ postAnswer = editedContent
+ if (!isAdd) {
+ await editAnnotation(appId, annotationId, {
+ message_id: messageId,
+ question: postQuery,
+ answer: postAnswer,
+ })
+ onEdited(postQuery, postAnswer)
+ }
+ else {
+ const res: any = await addAnnotation(appId, {
+ question: postQuery,
+ answer: postAnswer,
+ message_id: messageId,
+ })
+ onAdded(res.id, res.account?.name, postQuery, postAnswer)
+ }
+
+ Toast.notify({
+ message: t('common.api.actionSuccess') as string,
+ type: 'success',
+ })
+ }
+ const [showModal, setShowModal] = useState(false)
+
+ return (
+ <div>
+ <Drawer
+ isShow={isShow}
+ onHide={onHide}
+ maxWidthClassName='!max-w-[480px]'
+ title={t('appAnnotation.editModal.title') as string}
+ body={(
+ <div>
+ <div className='space-y-6 p-6 pb-4'>
+ <EditItem
+ type={EditItemType.Query}
+ content={query}
+ readonly={(isAdd && isAnnotationFull) || onlyEditResponse}
+ onSave={editedContent => handleSave(EditItemType.Query, editedContent)}
+ />
+ <EditItem
+ type={EditItemType.Answer}
+ content={answer}
+ readonly={isAdd && isAnnotationFull}
+ onSave={editedContent => handleSave(EditItemType.Answer, editedContent)}
+ />
+ <Confirm
+ isShow={showModal}
+ onCancel={() => setShowModal(false)}
+ onConfirm={() => {
+ onRemove()
+ setShowModal(false)
+ onHide()
+ }}
+ title={t('appDebug.feature.annotation.removeConfirm')}
+ />
+ </div>
+ </div>
+ )}
+ foot={
+ <div>
+ {isAnnotationFull && (
+ <div className='mb-4 mt-6 px-6'>
+ <AnnotationFull />
+ </div>
+ )}
+
+ {
+ annotationId
+ ? (
+ <div className='system-sm-medium flex h-16 items-center justify-between rounded-bl-xl rounded-br-xl border-t border-divider-subtle bg-background-section-burn px-4 text-text-tertiary'>
+ <div
+ className='flex cursor-pointer items-center space-x-2 pl-3'
+ onClick={() => setShowModal(true)}
+ >
+ <MessageCheckRemove />
+ <div>{t('appAnnotation.editModal.removeThisCache')}</div>
+ </div>
+ {createdAt && <div>{t('appAnnotation.editModal.createdAt')} {formatTime(createdAt, t('appLog.dateTimeFormat') as string)}</div>}
+ </div>
+ )
+ : undefined
+ }
+ </div>
+ }
+ />
+ </div>
+
+ )
+}
+export default React.memo(EditAnnotationModal)
diff --git a/app/components/app/annotation/empty-element.tsx b/app/components/app/annotation/empty-element.tsx
new file mode 100644
index 0000000..a240f93
--- /dev/null
+++ b/app/components/app/annotation/empty-element.tsx
@@ -0,0 +1,26 @@
+'use client'
+import type { FC, SVGProps } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+
+const ThreeDotsIcon = ({ className }: SVGProps<SVGElement>) => {
+ return <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
+ <path d="M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103" stroke="#374151" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+}
+
+const EmptyElement: FC = () => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex h-full items-center justify-center'>
+ <div className='box-border h-fit w-[560px] rounded-2xl bg-background-section-burn px-5 py-4'>
+ <span className='system-md-semibold text-text-secondary'>{t('appAnnotation.noData.title')}<ThreeDotsIcon className='relative -left-1.5 -top-3 inline' /></span>
+ <div className='system-sm-regular mt-2 text-text-tertiary'>
+ {t('appAnnotation.noData.description')}
+ </div>
+ </div>
+ </div>
+ )
+}
+export default React.memo(EmptyElement)
diff --git a/app/components/app/annotation/filter.tsx b/app/components/app/annotation/filter.tsx
new file mode 100644
index 0000000..b494d38
--- /dev/null
+++ b/app/components/app/annotation/filter.tsx
@@ -0,0 +1,48 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import Input from '@/app/components/base/input'
+import { fetchAnnotationsCount } from '@/service/log'
+
+export type QueryParam = {
+ keyword?: string
+}
+
+type IFilterProps = {
+ appId: string
+ queryParams: QueryParam
+ setQueryParams: (v: QueryParam) => void
+ children: React.JSX.Element
+}
+
+const Filter: FC<IFilterProps> = ({
+ appId,
+ queryParams,
+ setQueryParams,
+ children,
+}) => {
+ // TODO: change fetch list api
+ const { data } = useSWR({ url: `/apps/${appId}/annotations/count` }, fetchAnnotationsCount)
+ const { t } = useTranslation()
+ if (!data)
+ return null
+ return (
+ <div className='mb-2 flex flex-row flex-wrap items-center justify-between gap-2'>
+ <Input
+ wrapperClassName='w-[200px]'
+ showLeftIcon
+ showClearIcon
+ value={queryParams.keyword}
+ placeholder={t('common.operation.search')!}
+ onChange={(e) => {
+ setQueryParams({ ...queryParams, keyword: e.target.value })
+ }}
+ onClear={() => setQueryParams({ ...queryParams, keyword: '' })}
+ />
+ {children}
+ </div>
+ )
+}
+export default React.memo(Filter)
diff --git a/app/components/app/annotation/header-opts/index.tsx b/app/components/app/annotation/header-opts/index.tsx
new file mode 100644
index 0000000..eb397db
--- /dev/null
+++ b/app/components/app/annotation/header-opts/index.tsx
@@ -0,0 +1,175 @@
+'use client'
+import type { FC } from 'react'
+import React, { Fragment, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiAddLine,
+ RiMoreFill,
+} from '@remixicon/react'
+import { useContext } from 'use-context-selector'
+import {
+ useCSVDownloader,
+} from 'react-papaparse'
+import { Menu, MenuButton, MenuItems, Transition } from '@headlessui/react'
+import Button from '../../../base/button'
+import AddAnnotationModal from '../add-annotation-modal'
+import type { AnnotationItemBasic } from '../type'
+import BatchAddModal from '../batch-add-annotation-modal'
+import cn from '@/utils/classnames'
+import CustomPopover from '@/app/components/base/popover'
+import { FileDownload02, FilePlus02 } from '@/app/components/base/icons/src/vender/line/files'
+import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows'
+
+import I18n from '@/context/i18n'
+import { fetchExportAnnotationList } from '@/service/annotation'
+import { LanguagesSupported } from '@/i18n/language'
+
+const CSV_HEADER_QA_EN = ['Question', 'Answer']
+const CSV_HEADER_QA_CN = ['闂', '绛旀']
+
+type Props = {
+ appId: string
+ onAdd: (payload: AnnotationItemBasic) => void
+ onAdded: () => void
+ controlUpdateList: number
+}
+
+const HeaderOptions: FC<Props> = ({
+ appId,
+ onAdd,
+ onAdded,
+ controlUpdateList,
+}) => {
+ const { t } = useTranslation()
+ const { locale } = useContext(I18n)
+ const { CSVDownloader, Type } = useCSVDownloader()
+ const [list, setList] = useState<AnnotationItemBasic[]>([])
+ const annotationUnavailable = list.length === 0
+
+ const listTransformer = (list: AnnotationItemBasic[]) => list.map(
+ (item: AnnotationItemBasic) => {
+ const dataString = `{"messages": [{"role": "system", "content": ""}, {"role": "user", "content": ${JSON.stringify(item.question)}}, {"role": "assistant", "content": ${JSON.stringify(item.answer)}}]}`
+ return dataString
+ },
+ )
+
+ const JSONLOutput = () => {
+ const a = document.createElement('a')
+ const content = listTransformer(list).join('\n')
+ const file = new Blob([content], { type: 'application/jsonl' })
+ a.href = URL.createObjectURL(file)
+ a.download = `annotations-${locale}.jsonl`
+ a.click()
+ }
+
+ const fetchList = async () => {
+ const { data }: any = await fetchExportAnnotationList(appId)
+ setList(data as AnnotationItemBasic[])
+ }
+
+ useEffect(() => {
+ fetchList()
+ }, [])
+ useEffect(() => {
+ if (controlUpdateList)
+ fetchList()
+ }, [controlUpdateList])
+
+ const [showBulkImportModal, setShowBulkImportModal] = useState(false)
+
+ const Operations = () => {
+ return (
+ <div className="w-full py-1">
+ <button className='mx-1 flex h-9 w-[calc(100%_-_8px)] cursor-pointer items-center space-x-2 rounded-lg px-3 py-2 hover:bg-components-panel-on-panel-item-bg-hover disabled:opacity-50' onClick={() => {
+ setShowBulkImportModal(true)
+ }}>
+ <FilePlus02 className='h-4 w-4 text-text-tertiary' />
+ <span className='system-sm-regular grow text-left text-text-secondary'>{t('appAnnotation.table.header.bulkImport')}</span>
+ </button>
+ <Menu as="div" className="relative h-full w-full">
+ <MenuButton className='mx-1 flex h-9 w-[calc(100%_-_8px)] cursor-pointer items-center space-x-2 rounded-lg px-3 py-2 hover:bg-components-panel-on-panel-item-bg-hover disabled:opacity-50'>
+ <FileDownload02 className='h-4 w-4 text-text-tertiary' />
+ <span className='system-sm-regular grow text-left text-text-secondary'>{t('appAnnotation.table.header.bulkExport')}</span>
+ <ChevronRight className='h-[14px] w-[14px] shrink-0 text-text-tertiary' />
+ </MenuButton>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems
+ className={cn(
+ 'absolute left-1 top-[1px] z-10 min-w-[100px] origin-top-right -translate-x-full rounded-xl border-[0.5px] border-components-panel-on-panel-item-bg bg-components-panel-bg py-1 shadow-xs',
+ )}
+ >
+ <CSVDownloader
+ type={Type.Link}
+ filename={`annotations-${locale}`}
+ bom={true}
+ data={[
+ locale !== LanguagesSupported[1] ? CSV_HEADER_QA_EN : CSV_HEADER_QA_CN,
+ ...list.map(item => [item.question, item.answer]),
+ ]}
+ >
+ <button disabled={annotationUnavailable} className='mx-1 flex h-9 w-[calc(100%_-_8px)] cursor-pointer items-center space-x-2 rounded-lg px-3 py-2 hover:bg-components-panel-on-panel-item-bg-hover disabled:opacity-50'>
+ <span className='system-sm-regular grow text-left text-text-secondary'>CSV</span>
+ </button>
+ </CSVDownloader>
+ <button disabled={annotationUnavailable} className={cn('mx-1 flex h-9 w-[calc(100%_-_8px)] cursor-pointer items-center space-x-2 rounded-lg px-3 py-2 hover:bg-components-panel-on-panel-item-bg-hover disabled:opacity-50', '!border-0')} onClick={JSONLOutput}>
+ <span className='system-sm-regular grow text-left text-text-secondary'>JSONL</span>
+ </button>
+ </MenuItems>
+ </Transition>
+ </Menu>
+ </div>
+ )
+ }
+
+ const [showAddModal, setShowAddModal] = React.useState(false)
+
+ return (
+ <div className='flex space-x-2'>
+ <Button variant='primary' onClick={() => setShowAddModal(true)}>
+ <RiAddLine className='mr-0.5 h-4 w-4' />
+ <div>{t('appAnnotation.table.header.addAnnotation')}</div>
+ </Button>
+ <CustomPopover
+ htmlContent={<Operations />}
+ position="br"
+ trigger="click"
+ btnElement={
+ <Button variant='secondary' className='w-8 p-0'>
+ <RiMoreFill className='h-4 w-4' />
+ </Button>
+ }
+ btnClassName='p-0 border-0'
+ className={'!z-20 h-fit !w-[155px]'}
+ popupClassName='!w-full !overflow-visible'
+ manualClose
+ />
+ {showAddModal && (
+ <AddAnnotationModal
+ isShow={showAddModal}
+ onHide={() => setShowAddModal(false)}
+ onAdd={onAdd}
+ />
+ )}
+
+ {
+ showBulkImportModal && (
+ <BatchAddModal
+ appId={appId}
+ isShow={showBulkImportModal}
+ onCancel={() => setShowBulkImportModal(false)}
+ onAdded={onAdded}
+ />
+ )
+ }
+ </div>
+ )
+}
+export default React.memo(HeaderOptions)
diff --git a/app/components/app/annotation/index.tsx b/app/components/app/annotation/index.tsx
new file mode 100644
index 0000000..f010f5f
--- /dev/null
+++ b/app/components/app/annotation/index.tsx
@@ -0,0 +1,287 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useDebounce } from 'ahooks'
+import { RiEqualizer2Line } from '@remixicon/react'
+import Toast from '../../base/toast'
+import Filter from './filter'
+import type { QueryParam } from './filter'
+import List from './list'
+import EmptyElement from './empty-element'
+import HeaderOpts from './header-opts'
+import { AnnotationEnableStatus, type AnnotationItem, type AnnotationItemBasic, JobStatus } from './type'
+import ViewAnnotationModal from './view-annotation-modal'
+import { MessageFast } from '@/app/components/base/icons/src/vender/solid/communication'
+import ActionButton from '@/app/components/base/action-button'
+import Pagination from '@/app/components/base/pagination'
+import Switch from '@/app/components/base/switch'
+import { addAnnotation, delAnnotation, fetchAnnotationConfig as doFetchAnnotationConfig, editAnnotation, fetchAnnotationList, queryAnnotationJobStatus, updateAnnotationScore, updateAnnotationStatus } from '@/service/annotation'
+import Loading from '@/app/components/base/loading'
+import { APP_PAGE_LIMIT } from '@/config'
+import ConfigParamModal from '@/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal'
+import type { AnnotationReplyConfig } from '@/models/debug'
+import { sleep } from '@/utils'
+import { useProviderContext } from '@/context/provider-context'
+import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
+import type { App } from '@/types/app'
+import cn from '@/utils/classnames'
+
+type Props = {
+ appDetail: App
+}
+
+const Annotation: FC<Props> = ({
+ appDetail,
+}) => {
+ const { t } = useTranslation()
+ const [isShowEdit, setIsShowEdit] = React.useState(false)
+ const [annotationConfig, setAnnotationConfig] = useState<AnnotationReplyConfig | null>(null)
+ const [isChatApp, setIsChatApp] = useState(false)
+
+ const fetchAnnotationConfig = async () => {
+ const res = await doFetchAnnotationConfig(appDetail.id)
+ setAnnotationConfig(res as AnnotationReplyConfig)
+ return (res as AnnotationReplyConfig).id
+ }
+ useEffect(() => {
+ const isChatApp = appDetail.mode !== 'completion'
+ setIsChatApp(isChatApp)
+ if (isChatApp)
+ fetchAnnotationConfig()
+ }, [])
+ const [controlRefreshSwitch, setControlRefreshSwitch] = useState(Date.now())
+ const { plan, enableBilling } = useProviderContext()
+ const isAnnotationFull = (enableBilling && plan.usage.annotatedResponse >= plan.total.annotatedResponse)
+ const [isShowAnnotationFullModal, setIsShowAnnotationFullModal] = useState(false)
+ const ensureJobCompleted = async (jobId: string, status: AnnotationEnableStatus) => {
+ let isCompleted = false
+ while (!isCompleted) {
+ const res: any = await queryAnnotationJobStatus(appDetail.id, status, jobId)
+ isCompleted = res.job_status === JobStatus.completed
+ if (isCompleted)
+ break
+
+ await sleep(2000)
+ }
+ }
+
+ const [queryParams, setQueryParams] = useState<QueryParam>({})
+ const [currPage, setCurrPage] = React.useState<number>(0)
+ const debouncedQueryParams = useDebounce(queryParams, { wait: 500 })
+ const [limit, setLimit] = React.useState<number>(APP_PAGE_LIMIT)
+ const query = {
+ page: currPage + 1,
+ limit,
+ keyword: debouncedQueryParams.keyword || '',
+ }
+
+ const [controlUpdateList, setControlUpdateList] = useState(Date.now())
+ const [list, setList] = useState<AnnotationItem[]>([])
+ const [total, setTotal] = useState(10)
+ const [isLoading, setIsLoading] = useState(false)
+ const fetchList = async (page = 1) => {
+ setIsLoading(true)
+ try {
+ const { data, total }: any = await fetchAnnotationList(appDetail.id, {
+ ...query,
+ page,
+ })
+ setList(data as AnnotationItem[])
+ setTotal(total)
+ }
+ catch {
+
+ }
+ setIsLoading(false)
+ }
+
+ useEffect(() => {
+ fetchList(currPage + 1)
+ }, [currPage])
+
+ useEffect(() => {
+ fetchList(1)
+ setControlUpdateList(Date.now())
+ }, [queryParams])
+
+ const handleAdd = async (payload: AnnotationItemBasic) => {
+ await addAnnotation(appDetail.id, {
+ ...payload,
+ })
+ Toast.notify({
+ message: t('common.api.actionSuccess'),
+ type: 'success',
+ })
+ fetchList()
+ setControlUpdateList(Date.now())
+ }
+
+ const handleRemove = async (id: string) => {
+ await delAnnotation(appDetail.id, id)
+ Toast.notify({
+ message: t('common.api.actionSuccess'),
+ type: 'success',
+ })
+ fetchList()
+ setControlUpdateList(Date.now())
+ }
+
+ const [currItem, setCurrItem] = useState<AnnotationItem | null>(list[0])
+ const [isShowViewModal, setIsShowViewModal] = useState(false)
+ useEffect(() => {
+ if (!isShowEdit)
+ setControlRefreshSwitch(Date.now())
+ }, [isShowEdit])
+ const handleView = (item: AnnotationItem) => {
+ setCurrItem(item)
+ setIsShowViewModal(true)
+ }
+
+ const handleSave = async (question: string, answer: string) => {
+ await editAnnotation(appDetail.id, (currItem as AnnotationItem).id, {
+ question,
+ answer,
+ })
+ Toast.notify({
+ message: t('common.api.actionSuccess'),
+ type: 'success',
+ })
+ fetchList()
+ setControlUpdateList(Date.now())
+ }
+
+ return (
+ <div className='flex h-full flex-col'>
+ <p className='system-sm-regular text-text-tertiary'>{t('appLog.description')}</p>
+ <div className='flex flex-1 flex-col py-4'>
+ <Filter appId={appDetail.id} queryParams={queryParams} setQueryParams={setQueryParams}>
+ <div className='flex items-center space-x-2'>
+ {isChatApp && (
+ <>
+ <div className={cn(!annotationConfig?.enabled && 'pr-2', 'flex h-7 items-center space-x-1 rounded-lg border border-components-panel-border bg-components-panel-bg-blur pl-2')}>
+ <MessageFast className='h-4 w-4 text-util-colors-indigo-indigo-600' />
+ <div className='system-sm-medium text-text-primary'>{t('appAnnotation.name')}</div>
+ <Switch
+ key={controlRefreshSwitch}
+ defaultValue={annotationConfig?.enabled}
+ size='md'
+ onChange={async (value) => {
+ if (value) {
+ if (isAnnotationFull) {
+ setIsShowAnnotationFullModal(true)
+ setControlRefreshSwitch(Date.now())
+ return
+ }
+ setIsShowEdit(true)
+ }
+ else {
+ const { job_id: jobId }: any = await updateAnnotationStatus(appDetail.id, AnnotationEnableStatus.disable, annotationConfig?.embedding_model, annotationConfig?.score_threshold)
+ await ensureJobCompleted(jobId, AnnotationEnableStatus.disable)
+ await fetchAnnotationConfig()
+ Toast.notify({
+ message: t('common.api.actionSuccess'),
+ type: 'success',
+ })
+ }
+ }}
+ ></Switch>
+ {annotationConfig?.enabled && (
+ <div className='flex items-center pl-1.5'>
+ <div className='mr-1 h-3.5 w-[1px] shrink-0 bg-divider-subtle'></div>
+ <ActionButton onClick={() => setIsShowEdit(true)}>
+ <RiEqualizer2Line className='h-4 w-4 text-text-tertiary' />
+ </ActionButton>
+ </div>
+ )}
+ </div>
+ <div className='mx-3 h-3.5 w-[1px] shrink-0 bg-divider-regular'></div>
+ </>
+ )}
+
+ <HeaderOpts
+ appId={appDetail.id}
+ controlUpdateList={controlUpdateList}
+ onAdd={handleAdd}
+ onAdded={() => {
+ fetchList()
+ }}
+ />
+ </div>
+ </Filter>
+ {isLoading
+ ? <Loading type='app' />
+ : total > 0
+ ? <List
+ list={list}
+ onRemove={handleRemove}
+ onView={handleView}
+ />
+ : <div className='flex h-full grow items-center justify-center'><EmptyElement /></div>
+ }
+ {/* Show Pagination only if the total is more than the limit */}
+ {(total && total > APP_PAGE_LIMIT)
+ ? <Pagination
+ current={currPage}
+ onChange={setCurrPage}
+ total={total}
+ limit={limit}
+ onLimitChange={setLimit}
+ />
+ : null}
+
+ {isShowViewModal && (
+ <ViewAnnotationModal
+ appId={appDetail.id}
+ isShow={isShowViewModal}
+ onHide={() => setIsShowViewModal(false)}
+ onRemove={async () => {
+ await handleRemove((currItem as AnnotationItem)?.id)
+ }}
+ item={currItem as AnnotationItem}
+ onSave={handleSave}
+ />
+ )}
+ {isShowEdit && (
+ <ConfigParamModal
+ appId={appDetail.id}
+ isShow
+ isInit={!annotationConfig?.enabled}
+ onHide={() => {
+ setIsShowEdit(false)
+ }}
+ onSave={async (embeddingModel, score) => {
+ if (
+ embeddingModel.embedding_model_name !== annotationConfig?.embedding_model?.embedding_model_name
+ || embeddingModel.embedding_provider_name !== annotationConfig?.embedding_model?.embedding_provider_name
+ ) {
+ const { job_id: jobId }: any = await updateAnnotationStatus(appDetail.id, AnnotationEnableStatus.enable, embeddingModel, score)
+ await ensureJobCompleted(jobId, AnnotationEnableStatus.enable)
+ }
+ const annotationId = await fetchAnnotationConfig()
+ if (score !== annotationConfig?.score_threshold)
+ await updateAnnotationScore(appDetail.id, annotationId, score)
+
+ await fetchAnnotationConfig()
+ Toast.notify({
+ message: t('common.api.actionSuccess'),
+ type: 'success',
+ })
+ setIsShowEdit(false)
+ }}
+ annotationConfig={annotationConfig!}
+ />
+ )}
+ {
+ isShowAnnotationFullModal && (
+ <AnnotationFullModal
+ show={isShowAnnotationFullModal}
+ onHide={() => setIsShowAnnotationFullModal(false)}
+ />
+ )
+ }
+ </div>
+ </div>
+ )
+}
+export default React.memo(Annotation)
diff --git a/app/components/app/annotation/list.tsx b/app/components/app/annotation/list.tsx
new file mode 100644
index 0000000..319f099
--- /dev/null
+++ b/app/components/app/annotation/list.tsx
@@ -0,0 +1,91 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiDeleteBinLine, RiEditLine } from '@remixicon/react'
+import type { AnnotationItem } from './type'
+import RemoveAnnotationConfirmModal from './remove-annotation-confirm-modal'
+import ActionButton from '@/app/components/base/action-button'
+import useTimestamp from '@/hooks/use-timestamp'
+import cn from '@/utils/classnames'
+
+type Props = {
+ list: AnnotationItem[]
+ onRemove: (id: string) => void
+ onView: (item: AnnotationItem) => void
+}
+
+const List: FC<Props> = ({
+ list,
+ onView,
+ onRemove,
+}) => {
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+ const [currId, setCurrId] = React.useState<string | null>(null)
+ const [showConfirmDelete, setShowConfirmDelete] = React.useState(false)
+ return (
+ <div className='overflow-x-auto'>
+ <table className={cn('mt-2 w-full min-w-[440px] border-collapse border-0')}>
+ <thead className='system-xs-medium-uppercase text-text-tertiary'>
+ <tr>
+ <td className='w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1'>{t('appAnnotation.table.header.question')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appAnnotation.table.header.answer')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appAnnotation.table.header.createdAt')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appAnnotation.table.header.hits')}</td>
+ <td className='w-[96px] whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3'>{t('appAnnotation.table.header.actions')}</td>
+ </tr>
+ </thead>
+ <tbody className="system-sm-regular text-text-secondary">
+ {list.map(item => (
+ <tr
+ key={item.id}
+ className='cursor-pointer border-b border-divider-subtle hover:bg-background-default-hover'
+ onClick={
+ () => {
+ onView(item)
+ }
+ }
+ >
+ <td
+ className='max-w-[250px] overflow-hidden text-ellipsis whitespace-nowrap p-3 pr-2'
+ title={item.question}
+ >{item.question}</td>
+ <td
+ className='max-w-[250px] overflow-hidden text-ellipsis whitespace-nowrap p-3 pr-2'
+ title={item.answer}
+ >{item.answer}</td>
+ <td className='p-3 pr-2'>{formatTime(item.created_at, t('appLog.dateTimeFormat') as string)}</td>
+ <td className='p-3 pr-2'>{item.hit_count}</td>
+ <td className='w-[96px] p-3 pr-2' onClick={e => e.stopPropagation()}>
+ {/* Actions */}
+ <div className='flex space-x-1 text-text-tertiary'>
+ <ActionButton onClick={() => onView(item)}>
+ <RiEditLine className='h-4 w-4' />
+ </ActionButton>
+ <ActionButton
+ onClick={() => {
+ setCurrId(item.id)
+ setShowConfirmDelete(true)
+ }}
+ >
+ <RiDeleteBinLine className='h-4 w-4' />
+ </ActionButton>
+ </div>
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ <RemoveAnnotationConfirmModal
+ isShow={showConfirmDelete}
+ onHide={() => setShowConfirmDelete(false)}
+ onRemove={() => {
+ onRemove(currId as string)
+ setShowConfirmDelete(false)
+ }}
+ />
+ </div>
+ )
+}
+export default React.memo(List)
diff --git a/app/components/app/annotation/remove-annotation-confirm-modal/index.tsx b/app/components/app/annotation/remove-annotation-confirm-modal/index.tsx
new file mode 100644
index 0000000..a6ade49
--- /dev/null
+++ b/app/components/app/annotation/remove-annotation-confirm-modal/index.tsx
@@ -0,0 +1,29 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Confirm from '@/app/components/base/confirm'
+
+type Props = {
+ isShow: boolean
+ onHide: () => void
+ onRemove: () => void
+}
+
+const RemoveAnnotationConfirmModal: FC<Props> = ({
+ isShow,
+ onHide,
+ onRemove,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <Confirm
+ isShow={isShow}
+ onCancel={onHide}
+ onConfirm={onRemove}
+ title={t('appDebug.feature.annotation.removeConfirm')}
+ />
+ )
+}
+export default React.memo(RemoveAnnotationConfirmModal)
diff --git a/app/components/app/annotation/type.ts b/app/components/app/annotation/type.ts
new file mode 100644
index 0000000..5df6f51
--- /dev/null
+++ b/app/components/app/annotation/type.ts
@@ -0,0 +1,39 @@
+export type AnnotationItemBasic = {
+ message_id?: string
+ question: string
+ answer: string
+}
+
+export type AnnotationItem = {
+ id: string
+ question: string
+ answer: string
+ created_at: number
+ hit_count: number
+}
+
+export type HitHistoryItem = {
+ id: string
+ question: string
+ match: string
+ response: string
+ source: string
+ score: number
+ created_at: number
+}
+
+export type EmbeddingModelConfig = {
+ embedding_provider_name: string
+ embedding_model_name: string
+}
+
+export enum AnnotationEnableStatus {
+ enable = 'enable',
+ disable = 'disable',
+}
+
+export enum JobStatus {
+ waiting = 'waiting',
+ processing = 'processing',
+ completed = 'completed',
+}
diff --git a/app/components/app/annotation/view-annotation-modal/hit-history-no-data.tsx b/app/components/app/annotation/view-annotation-modal/hit-history-no-data.tsx
new file mode 100644
index 0000000..ae4eb67
--- /dev/null
+++ b/app/components/app/annotation/view-annotation-modal/hit-history-no-data.tsx
@@ -0,0 +1,19 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { ClockFastForward } from '@/app/components/base/icons/src/vender/line/time'
+
+const HitHistoryNoData: FC = () => {
+ const { t } = useTranslation()
+ return (
+ <div className='mx-auto mt-20 w-[480px] space-y-2 rounded-2xl bg-background-section-burn p-5'>
+ <div className='inline-block rounded-lg border border-divider-subtle p-3'>
+ <ClockFastForward className='h-5 w-5 text-text-tertiary' />
+ </div>
+ <div className='system-sm-regular text-text-tertiary'>{t('appAnnotation.viewModal.noHitHistory')}</div>
+ </div>
+ )
+}
+
+export default React.memo(HitHistoryNoData)
diff --git a/app/components/app/annotation/view-annotation-modal/index.tsx b/app/components/app/annotation/view-annotation-modal/index.tsx
new file mode 100644
index 0000000..08904d2
--- /dev/null
+++ b/app/components/app/annotation/view-annotation-modal/index.tsx
@@ -0,0 +1,215 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import EditItem, { EditItemType } from '../edit-annotation-modal/edit-item'
+import type { AnnotationItem, HitHistoryItem } from '../type'
+import HitHistoryNoData from './hit-history-no-data'
+import Badge from '@/app/components/base/badge'
+import Drawer from '@/app/components/base/drawer-plus'
+import Pagination from '@/app/components/base/pagination'
+import { MessageCheckRemove } from '@/app/components/base/icons/src/vender/line/communication'
+import Confirm from '@/app/components/base/confirm'
+import TabSlider from '@/app/components/base/tab-slider-plain'
+import { fetchHitHistoryList } from '@/service/annotation'
+import { APP_PAGE_LIMIT } from '@/config'
+import useTimestamp from '@/hooks/use-timestamp'
+import cn from '@/utils/classnames'
+
+type Props = {
+ appId: string
+ isShow: boolean
+ onHide: () => void
+ item: AnnotationItem
+ onSave: (editedQuery: string, editedAnswer: string) => void
+ onRemove: () => void
+}
+
+enum TabType {
+ annotation = 'annotation',
+ hitHistory = 'hitHistory',
+}
+
+const ViewAnnotationModal: FC<Props> = ({
+ appId,
+ isShow,
+ onHide,
+ item,
+ onSave,
+ onRemove,
+}) => {
+ const { id, question, answer, created_at: createdAt } = item
+ const [newQuestion, setNewQuery] = useState(question)
+ const [newAnswer, setNewAnswer] = useState(answer)
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+ const [currPage, setCurrPage] = React.useState<number>(0)
+ const [total, setTotal] = useState(0)
+ const [hitHistoryList, setHitHistoryList] = useState<HitHistoryItem[]>([])
+ const fetchHitHistory = async (page = 1) => {
+ try {
+ const { data, total }: any = await fetchHitHistoryList(appId, id, {
+ page,
+ limit: 10,
+ })
+ setHitHistoryList(data as HitHistoryItem[])
+ setTotal(total)
+ }
+ catch {
+ }
+ }
+
+ useEffect(() => {
+ fetchHitHistory(currPage + 1)
+ }, [currPage])
+
+ const tabs = [
+ { value: TabType.annotation, text: t('appAnnotation.viewModal.annotatedResponse') },
+ {
+ value: TabType.hitHistory,
+ text: (
+ hitHistoryList.length > 0
+ ? (
+ <div className='flex items-center space-x-1'>
+ <div>{t('appAnnotation.viewModal.hitHistory')}</div>
+ <Badge
+ text={`${total} ${t(`appAnnotation.viewModal.hit${hitHistoryList.length > 1 ? 's' : ''}`)}`}
+ />
+ </div>
+ )
+ : t('appAnnotation.viewModal.hitHistory')
+ ),
+ },
+ ]
+ const [activeTab, setActiveTab] = useState(TabType.annotation)
+ const handleSave = (type: EditItemType, editedContent: string) => {
+ if (type === EditItemType.Query) {
+ setNewQuery(editedContent)
+ onSave(editedContent, newAnswer)
+ }
+ else {
+ setNewAnswer(editedContent)
+ onSave(newQuestion, editedContent)
+ }
+ }
+ const [showModal, setShowModal] = useState(false)
+
+ const annotationTab = (
+ <>
+ <EditItem
+ type={EditItemType.Query}
+ content={question}
+ onSave={editedContent => handleSave(EditItemType.Query, editedContent)}
+ />
+ <EditItem
+ type={EditItemType.Answer}
+ content={answer}
+ onSave={editedContent => handleSave(EditItemType.Answer, editedContent)}
+ />
+ </>
+ )
+
+ const hitHistoryTab = total === 0
+ ? (<HitHistoryNoData />)
+ : (
+ <div>
+ <table className={cn('w-full min-w-[440px] border-collapse border-0')} >
+ <thead className="system-xs-medium-uppercase text-text-tertiary">
+ <tr>
+ <td className='w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1'>{t('appAnnotation.hitHistoryTable.query')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appAnnotation.hitHistoryTable.match')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appAnnotation.hitHistoryTable.response')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appAnnotation.hitHistoryTable.source')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appAnnotation.hitHistoryTable.score')}</td>
+ <td className='w-[160px] whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3'>{t('appAnnotation.hitHistoryTable.time')}</td>
+ </tr>
+ </thead>
+ <tbody className="system-sm-regular text-text-secondary">
+ {hitHistoryList.map(item => (
+ <tr
+ key={item.id}
+ className={'cursor-pointer border-b border-divider-subtle hover:bg-background-default-hover'}
+ >
+ <td
+ className='max-w-[250px] overflow-hidden text-ellipsis whitespace-nowrap p-3 pr-2'
+ title={item.question}
+ >{item.question}</td>
+ <td
+ className='max-w-[250px] overflow-hidden text-ellipsis whitespace-nowrap p-3 pr-2'
+ title={item.match}
+ >{item.match}</td>
+ <td
+ className='max-w-[250px] overflow-hidden text-ellipsis whitespace-nowrap p-3 pr-2'
+ title={item.response}
+ >{item.response}</td>
+ <td className='p-3 pr-2'>{item.source}</td>
+ <td className='p-3 pr-2'>{item.score ? item.score.toFixed(2) : '-'}</td>
+ <td className='p-3 pr-2'>{formatTime(item.created_at, t('appLog.dateTimeFormat') as string)}</td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ {(total && total > APP_PAGE_LIMIT)
+ ? <Pagination
+ className='px-0'
+ current={currPage}
+ onChange={setCurrPage}
+ total={total}
+ />
+ : null}
+ </div>
+
+ )
+ return (
+ <div>
+ <Drawer
+ isShow={isShow}
+ onHide={onHide}
+ maxWidthClassName='!max-w-[800px]'
+ title={
+ <TabSlider
+ className='relative top-[9px] shrink-0'
+ value={activeTab}
+ onChange={v => setActiveTab(v as TabType)}
+ options={tabs}
+ noBorderBottom
+ itemClassName='!pb-3.5'
+ />
+ }
+ body={(
+ <div>
+ <div className='space-y-6 p-6 pb-4'>
+ {activeTab === TabType.annotation ? annotationTab : hitHistoryTab}
+ </div>
+ <Confirm
+ isShow={showModal}
+ onCancel={() => setShowModal(false)}
+ onConfirm={async () => {
+ await onRemove()
+ setShowModal(false)
+ onHide()
+ }}
+ title={t('appDebug.feature.annotation.removeConfirm')}
+ />
+ </div>
+ )}
+ foot={id
+ ? (
+ <div className='system-sm-medium flex h-16 items-center justify-between rounded-bl-xl rounded-br-xl border-t border-divider-subtle bg-background-section-burn px-4 text-text-tertiary'>
+ <div
+ className='flex cursor-pointer items-center space-x-2 pl-3'
+ onClick={() => setShowModal(true)}
+ >
+ <MessageCheckRemove />
+ <div>{t('appAnnotation.editModal.removeThisCache')}</div>
+ </div>
+ <div>{t('appAnnotation.editModal.createdAt')} {formatTime(createdAt, t('appLog.dateTimeFormat') as string)}</div>
+ </div>
+ )
+ : undefined}
+ />
+ </div>
+
+ )
+}
+export default React.memo(ViewAnnotationModal)
diff --git a/app/components/app/app-publisher/features-wrapper.tsx b/app/components/app/app-publisher/features-wrapper.tsx
new file mode 100644
index 0000000..dadd112
--- /dev/null
+++ b/app/components/app/app-publisher/features-wrapper.tsx
@@ -0,0 +1,86 @@
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import type { AppPublisherProps } from '@/app/components/app/app-publisher'
+import Confirm from '@/app/components/base/confirm'
+import AppPublisher from '@/app/components/app/app-publisher'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { ModelAndParameter } from '@/app/components/app/configuration/debug/types'
+import type { FileUpload } from '@/app/components/base/features/types'
+import { Resolution } from '@/types/app'
+import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+
+type Props = Omit<AppPublisherProps, 'onPublish'> & {
+ onPublish?: (modelAndParameter?: ModelAndParameter, features?: any) => Promise<any> | any
+ publishedConfig?: any
+ resetAppConfig?: () => void
+}
+
+const FeaturesWrappedAppPublisher = (props: Props) => {
+ const { t } = useTranslation()
+ const features = useFeatures(s => s.features)
+ const featuresStore = useFeaturesStore()
+ const [restoreConfirmOpen, setRestoreConfirmOpen] = useState(false)
+ const handleConfirm = useCallback(() => {
+ props.resetAppConfig?.()
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+ const newFeatures = produce(features, (draft) => {
+ draft.moreLikeThis = props.publishedConfig.modelConfig.more_like_this || { enabled: false }
+ draft.opening = {
+ enabled: !!props.publishedConfig.modelConfig.opening_statement,
+ opening_statement: props.publishedConfig.modelConfig.opening_statement || '',
+ suggested_questions: props.publishedConfig.modelConfig.suggested_questions || [],
+ }
+ draft.moderation = props.publishedConfig.modelConfig.sensitive_word_avoidance || { enabled: false }
+ draft.speech2text = props.publishedConfig.modelConfig.speech_to_text || { enabled: false }
+ draft.text2speech = props.publishedConfig.modelConfig.text_to_speech || { enabled: false }
+ draft.suggested = props.publishedConfig.modelConfig.suggested_questions_after_answer || { enabled: false }
+ draft.citation = props.publishedConfig.modelConfig.retriever_resource || { enabled: false }
+ draft.annotationReply = props.publishedConfig.modelConfig.annotation_reply || { enabled: false }
+ draft.file = {
+ image: {
+ detail: props.publishedConfig.modelConfig.file_upload?.image?.detail || Resolution.high,
+ enabled: !!props.publishedConfig.modelConfig.file_upload?.image?.enabled,
+ number_limits: props.publishedConfig.modelConfig.file_upload?.image?.number_limits || 3,
+ transfer_methods: props.publishedConfig.modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
+ },
+ enabled: !!(props.publishedConfig.modelConfig.file_upload?.enabled || props.publishedConfig.modelConfig.file_upload?.image?.enabled),
+ allowed_file_types: props.publishedConfig.modelConfig.file_upload?.allowed_file_types || [SupportUploadFileTypes.image],
+ allowed_file_extensions: props.publishedConfig.modelConfig.file_upload?.allowed_file_extensions || FILE_EXTS[SupportUploadFileTypes.image].map(ext => `.${ext}`),
+ allowed_file_upload_methods: props.publishedConfig.modelConfig.file_upload?.allowed_file_upload_methods || props.publishedConfig.modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
+ number_limits: props.publishedConfig.modelConfig.file_upload?.number_limits || props.publishedConfig.modelConfig.file_upload?.image?.number_limits || 3,
+ } as FileUpload
+ })
+ setFeatures(newFeatures)
+ setRestoreConfirmOpen(false)
+ }, [featuresStore, props])
+
+ const handlePublish = useCallback((modelAndParameter?: ModelAndParameter) => {
+ return props.onPublish?.(modelAndParameter, features)
+ }, [features, props])
+
+ return (
+ <>
+ <AppPublisher {...{
+ ...props,
+ onPublish: handlePublish,
+ onRestore: () => setRestoreConfirmOpen(true),
+ }}/>
+ {restoreConfirmOpen && (
+ <Confirm
+ title={t('appDebug.resetConfig.title')}
+ content={t('appDebug.resetConfig.message')}
+ isShow={restoreConfirmOpen}
+ onConfirm={handleConfirm}
+ onCancel={() => setRestoreConfirmOpen(false)}
+ />
+ )}
+ </>
+ )
+}
+
+export default FeaturesWrappedAppPublisher
diff --git a/app/components/app/app-publisher/index.tsx b/app/components/app/app-publisher/index.tsx
new file mode 100644
index 0000000..1214483
--- /dev/null
+++ b/app/components/app/app-publisher/index.tsx
@@ -0,0 +1,304 @@
+import {
+ memo,
+ useCallback,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import dayjs from 'dayjs'
+import {
+ RiArrowDownSLine,
+ RiPlanetLine,
+ RiPlayCircleLine,
+ RiPlayList2Line,
+ RiTerminalBoxLine,
+} from '@remixicon/react'
+import { useKeyPress } from 'ahooks'
+import Toast from '../../base/toast'
+import type { ModelAndParameter } from '../configuration/debug/types'
+import { getKeyboardKeyCodeBySystem } from '../../workflow/utils'
+import SuggestedAction from './suggested-action'
+import PublishWithMultipleModel from './publish-with-multiple-model'
+import Button from '@/app/components/base/button'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { WEB_PREFIX } from '@/config'
+import { fetchInstalledAppList } from '@/service/explore'
+import EmbeddedModal from '@/app/components/app/overview/embedded'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import { useGetLanguage } from '@/context/i18n'
+import { CodeBrowser } from '@/app/components/base/icons/src/vender/line/development'
+import WorkflowToolConfigureButton from '@/app/components/tools/workflow-tool/configure-button'
+import type { InputVar } from '@/app/components/workflow/types'
+import { appDefaultIconBackground } from '@/config'
+import type { PublishWorkflowParams } from '@/types/workflow'
+
+export type AppPublisherProps = {
+ disabled?: boolean
+ publishDisabled?: boolean
+ publishedAt?: number
+ /** only needed in workflow / chatflow mode */
+ draftUpdatedAt?: number
+ debugWithMultipleModel?: boolean
+ multipleModelConfigs?: ModelAndParameter[]
+ /** modelAndParameter is passed when debugWithMultipleModel is true */
+ onPublish?: (params?: any) => Promise<any> | any
+ onRestore?: () => Promise<any> | any
+ onToggle?: (state: boolean) => void
+ crossAxisOffset?: number
+ toolPublished?: boolean
+ inputs?: InputVar[]
+ onRefreshData?: () => void
+}
+
+const PUBLISH_SHORTCUT = ['鈱�', '鈬�', 'P']
+
+const AppPublisher = ({
+ disabled = false,
+ publishDisabled = false,
+ publishedAt,
+ draftUpdatedAt,
+ debugWithMultipleModel = false,
+ multipleModelConfigs = [],
+ onPublish,
+ onRestore,
+ onToggle,
+ crossAxisOffset = 0,
+ toolPublished,
+ inputs,
+ onRefreshData,
+}: AppPublisherProps) => {
+ const { t } = useTranslation()
+ const [published, setPublished] = useState(false)
+ const [open, setOpen] = useState(false)
+ const appDetail = useAppStore(state => state.appDetail)
+ const { app_base_url: appBaseURL = '', access_token: accessToken = '' } = appDetail?.site ?? {}
+ const appMode = (appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow') ? 'chat' : appDetail.mode
+ const appURL = `${appBaseURL}/${appMode}/${accessToken}`
+ const isChatApp = ['chat', 'agent-chat', 'completion'].includes(appDetail?.mode || '')
+
+ const language = useGetLanguage()
+ const formatTimeFromNow = useCallback((time: number) => {
+ return dayjs(time).locale(language === 'zh_Hans' ? 'zh-cn' : language.replace('_', '-')).fromNow()
+ }, [language])
+
+ const handlePublish = useCallback(async (params?: ModelAndParameter | PublishWorkflowParams) => {
+ try {
+ await onPublish?.(params)
+ setPublished(true)
+ }
+ catch {
+ setPublished(false)
+ }
+ }, [onPublish])
+
+ const handleRestore = useCallback(async () => {
+ try {
+ await onRestore?.()
+ setOpen(false)
+ }
+ catch {}
+ }, [onRestore])
+
+ const handleTrigger = useCallback(() => {
+ const state = !open
+
+ if (disabled) {
+ setOpen(false)
+ return
+ }
+
+ onToggle?.(state)
+ setOpen(state)
+
+ if (state)
+ setPublished(false)
+ }, [disabled, onToggle, open])
+
+ const handleOpenInExplore = useCallback(async () => {
+ try {
+ const { installed_apps }: any = await fetchInstalledAppList(appDetail?.id) || {}
+ if (installed_apps?.length > 0)
+ window.open(`${WEB_PREFIX}/explore/installed/${installed_apps[0].id}`, '_blank')
+ else
+ throw new Error('No app found in Explore')
+ }
+ catch (e: any) {
+ Toast.notify({ type: 'error', message: `${e.message || e}` })
+ }
+ }, [appDetail?.id])
+
+ const [embeddingModalOpen, setEmbeddingModalOpen] = useState(false)
+
+ useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.shift.p`, (e) => {
+ e.preventDefault()
+ if (publishDisabled || published)
+ return
+ handlePublish()
+ },
+ { exactMatch: true, useCapture: true })
+
+ return (
+ <>
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 4,
+ crossAxis: crossAxisOffset,
+ }}
+ >
+ <PortalToFollowElemTrigger onClick={handleTrigger}>
+ <Button
+ variant='primary'
+ className='p-2'
+ disabled={disabled}
+ >
+ {t('workflow.common.publish')}
+ <RiArrowDownSLine className='h-4 w-4 text-components-button-primary-text' />
+ </Button>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[11]'>
+ <div className='w-[320px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl shadow-shadow-shadow-5'>
+ <div className='p-4 pt-3'>
+ <div className='system-xs-medium-uppercase flex h-6 items-center text-text-tertiary'>
+ {publishedAt ? t('workflow.common.latestPublished') : t('workflow.common.currentDraftUnpublished')}
+ </div>
+ {publishedAt
+ ? (
+ <div className='flex items-center justify-between'>
+ <div className='system-sm-medium flex items-center text-text-secondary'>
+ {t('workflow.common.publishedAt')} {formatTimeFromNow(publishedAt)}
+ </div>
+ {isChatApp && <Button
+ variant='secondary-accent'
+ size='small'
+ onClick={handleRestore}
+ disabled={published}
+ >
+ {t('workflow.common.restore')}
+ </Button>}
+ </div>
+ )
+ : (
+ <div className='system-sm-medium flex items-center text-text-secondary'>
+ {t('workflow.common.autoSaved')} 路 {Boolean(draftUpdatedAt) && formatTimeFromNow(draftUpdatedAt!)}
+ </div>
+ )}
+ {debugWithMultipleModel
+ ? (
+ <PublishWithMultipleModel
+ multipleModelConfigs={multipleModelConfigs}
+ onSelect={item => handlePublish(item)}
+ // textGenerationModelList={textGenerationModelList}
+ />
+ )
+ : (
+ <Button
+ variant='primary'
+ className='mt-3 w-full'
+ onClick={() => handlePublish()}
+ disabled={publishDisabled || published}
+ >
+ {
+ published
+ ? t('workflow.common.published')
+ : (
+ <div className='flex gap-1'>
+ <span>{t('workflow.common.publishUpdate')}</span>
+ <div className='flex gap-0.5'>
+ {PUBLISH_SHORTCUT.map(key => (
+ <span key={key} className='system-kbd h-4 w-4 rounded-[4px] bg-components-kbd-bg-white text-text-primary-on-surface'>
+ {key}
+ </span>
+ ))}
+ </div>
+ </div>
+ )
+ }
+ </Button>
+ )
+ }
+ </div>
+ <div className='border-t-[0.5px] border-t-divider-regular p-4 pt-3'>
+ <SuggestedAction
+ disabled={!publishedAt}
+ link={appURL}
+ icon={<RiPlayCircleLine className='h-4 w-4' />}
+ >
+ {t('workflow.common.runApp')}
+ </SuggestedAction>
+ {appDetail?.mode === 'workflow' || appDetail?.mode === 'completion'
+ ? (
+ <SuggestedAction
+ disabled={!publishedAt}
+ link={`${appURL}${appURL.includes('?') ? '&' : '?'}mode=batch`}
+ icon={<RiPlayList2Line className='h-4 w-4' />}
+ >
+ {t('workflow.common.batchRunApp')}
+ </SuggestedAction>
+ )
+ : (
+ <SuggestedAction
+ onClick={() => {
+ setEmbeddingModalOpen(true)
+ handleTrigger()
+ }}
+ disabled={!publishedAt}
+ icon={<CodeBrowser className='h-4 w-4' />}
+ >
+ {t('workflow.common.embedIntoSite')}
+ </SuggestedAction>
+ )}
+ <SuggestedAction
+ onClick={() => {
+ publishedAt && handleOpenInExplore()
+ }}
+ disabled={!publishedAt}
+ icon={<RiPlanetLine className='h-4 w-4' />}
+ >
+ {t('workflow.common.openInExplore')}
+ </SuggestedAction>
+ <SuggestedAction
+ disabled={!publishedAt}
+ link='./develop'
+ icon={<RiTerminalBoxLine className='h-4 w-4' />}
+ >
+ {t('workflow.common.accessAPIReference')}
+ </SuggestedAction>
+ {appDetail?.mode === 'workflow' && (
+ <WorkflowToolConfigureButton
+ disabled={!publishedAt}
+ published={!!toolPublished}
+ detailNeedUpdate={!!toolPublished && published}
+ workflowAppId={appDetail?.id}
+ icon={{
+ content: (appDetail.icon_type === 'image' ? '馃' : appDetail?.icon) || '馃',
+ background: (appDetail.icon_type === 'image' ? appDefaultIconBackground : appDetail?.icon_background) || appDefaultIconBackground,
+ }}
+ name={appDetail?.name}
+ description={appDetail?.description}
+ inputs={inputs}
+ handlePublish={handlePublish}
+ onRefreshData={onRefreshData}
+ />
+ )}
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ <EmbeddedModal
+ siteInfo={appDetail?.site}
+ isShow={embeddingModalOpen}
+ onClose={() => setEmbeddingModalOpen(false)}
+ appBaseUrl={appBaseURL}
+ accessToken={accessToken}
+ />
+ </PortalToFollowElem >
+ </>
+ )
+}
+
+export default memo(AppPublisher)
diff --git a/app/components/app/app-publisher/publish-with-multiple-model.tsx b/app/components/app/app-publisher/publish-with-multiple-model.tsx
new file mode 100644
index 0000000..e376787
--- /dev/null
+++ b/app/components/app/app-publisher/publish-with-multiple-model.tsx
@@ -0,0 +1,108 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowDownSLine } from '@remixicon/react'
+import type { ModelAndParameter } from '../configuration/debug/types'
+import ModelIcon from '../../header/account-setting/model-provider-page/model-icon'
+import Button from '@/app/components/base/button'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { useProviderContext } from '@/context/provider-context'
+import type { Model, ModelItem } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
+
+type PublishWithMultipleModelProps = {
+ multipleModelConfigs: ModelAndParameter[]
+ // textGenerationModelList?: Model[]
+ onSelect: (v: ModelAndParameter) => void
+}
+const PublishWithMultipleModel: FC<PublishWithMultipleModelProps> = ({
+ multipleModelConfigs,
+ // textGenerationModelList = [],
+ onSelect,
+}) => {
+ const { t } = useTranslation()
+ const language = useLanguage()
+ const { textGenerationModelList } = useProviderContext()
+ const [open, setOpen] = useState(false)
+
+ const validModelConfigs: (ModelAndParameter & { modelItem: ModelItem; providerItem: Model })[] = []
+
+ multipleModelConfigs.forEach((item) => {
+ const provider = textGenerationModelList.find(model => model.provider === item.provider)
+
+ if (provider) {
+ const model = provider.models.find(model => model.model === item.model)
+
+ if (model) {
+ validModelConfigs.push({
+ id: item.id,
+ model: item.model,
+ provider: item.provider,
+ modelItem: model,
+ providerItem: provider,
+ parameters: item.parameters,
+ })
+ }
+ }
+ })
+
+ const handleToggle = () => {
+ if (validModelConfigs.length)
+ setOpen(v => !v)
+ }
+
+ const handleSelect = (item: ModelAndParameter) => {
+ onSelect(item)
+ setOpen(false)
+ }
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ >
+ <PortalToFollowElemTrigger className='w-full' onClick={handleToggle}>
+ <Button
+ variant='primary'
+ disabled={!validModelConfigs.length}
+ className='mt-3 w-full'
+ >
+ {t('appDebug.operation.applyConfig')}
+ <RiArrowDownSLine className='ml-0.5 h-3 w-3' />
+ </Button>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-50 mt-1 w-[288px]'>
+ <div className='rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg p-1 shadow-lg'>
+ <div className='flex h-[22px] items-center px-3 text-xs font-medium text-text-tertiary'>
+ {t('appDebug.publishAs')}
+ </div>
+ {
+ validModelConfigs.map((item, index) => (
+ <div
+ key={item.id}
+ className='flex h-8 cursor-pointer items-center rounded-lg px-3 text-sm text-text-tertiary hover:bg-state-base-hover'
+ onClick={() => handleSelect(item)}
+ >
+ <span className='min-w-[18px] italic'>#{index + 1}</span>
+ <ModelIcon modelName={item.model} provider={item.providerItem} className='ml-2' />
+ <div
+ className='ml-1 truncate text-text-secondary'
+ title={item.modelItem.label[language]}
+ >
+ {item.modelItem.label[language]}
+ </div>
+ </div>
+ ))
+ }
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default PublishWithMultipleModel
diff --git a/app/components/app/app-publisher/suggested-action.tsx b/app/components/app/app-publisher/suggested-action.tsx
new file mode 100644
index 0000000..388fb8b
--- /dev/null
+++ b/app/components/app/app-publisher/suggested-action.tsx
@@ -0,0 +1,29 @@
+import type { HTMLProps, PropsWithChildren } from 'react'
+import { RiArrowRightUpLine } from '@remixicon/react'
+import classNames from '@/utils/classnames'
+
+export type SuggestedActionProps = PropsWithChildren<HTMLProps<HTMLAnchorElement> & {
+ icon?: React.ReactNode
+ link?: string
+ disabled?: boolean
+}>
+
+const SuggestedAction = ({ icon, link, disabled, children, className, ...props }: SuggestedActionProps) => (
+ <a
+ href={disabled ? undefined : link}
+ target='_blank'
+ rel='noreferrer'
+ className={classNames(
+ 'flex justify-start items-center gap-2 py-2 px-2.5 bg-background-section-burn rounded-lg transition-colors [&:not(:first-child)]:mt-1',
+ disabled ? 'shadow-xs opacity-30 cursor-not-allowed' : 'text-text-secondary hover:bg-state-accent-hover hover:text-text-accent cursor-pointer',
+ className,
+ )}
+ {...props}
+ >
+ <div className='relative h-4 w-4'>{icon}</div>
+ <div className='system-sm-medium shrink grow basis-0'>{children}</div>
+ <RiArrowRightUpLine className='h-3.5 w-3.5' />
+ </a>
+)
+
+export default SuggestedAction
diff --git a/app/components/app/app-publisher/version-info-modal.tsx b/app/components/app/app-publisher/version-info-modal.tsx
new file mode 100644
index 0000000..4d5d370
--- /dev/null
+++ b/app/components/app/app-publisher/version-info-modal.tsx
@@ -0,0 +1,112 @@
+import React, { type FC, useCallback, useState } from 'react'
+import Modal from '@/app/components/base/modal'
+import type { VersionHistory } from '@/types/workflow'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import Input from '../../base/input'
+import Textarea from '../../base/textarea'
+import Button from '../../base/button'
+import Toast from '@/app/components/base/toast'
+
+type VersionInfoModalProps = {
+ isOpen: boolean
+ versionInfo?: VersionHistory
+ onClose: () => void
+ onPublish: (params: { title: string; releaseNotes: string; id?: string }) => void
+}
+
+const TITLE_MAX_LENGTH = 15
+const RELEASE_NOTES_MAX_LENGTH = 100
+
+const VersionInfoModal: FC<VersionInfoModalProps> = ({
+ isOpen,
+ versionInfo,
+ onClose,
+ onPublish,
+}) => {
+ const { t } = useTranslation()
+ const [title, setTitle] = useState(versionInfo?.marked_name || '')
+ const [releaseNotes, setReleaseNotes] = useState(versionInfo?.marked_comment || '')
+ const [titleError, setTitleError] = useState(false)
+ const [releaseNotesError, setReleaseNotesError] = useState(false)
+
+ const handlePublish = () => {
+ if (title.length > TITLE_MAX_LENGTH) {
+ setTitleError(true)
+ Toast.notify({
+ type: 'error',
+ message: t('workflow.versionHistory.editField.titleLengthLimit', { limit: TITLE_MAX_LENGTH }),
+ })
+ return
+ }
+ else {
+ titleError && setTitleError(false)
+ }
+
+ if (releaseNotes.length > RELEASE_NOTES_MAX_LENGTH) {
+ setReleaseNotesError(true)
+ Toast.notify({
+ type: 'error',
+ message: t('workflow.versionHistory.editField.releaseNotesLengthLimit', { limit: RELEASE_NOTES_MAX_LENGTH }),
+ })
+ return
+ }
+ else {
+ releaseNotesError && setReleaseNotesError(false)
+ }
+
+ onPublish({ title, releaseNotes, id: versionInfo?.id })
+ onClose()
+ }
+
+ const handleTitleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
+ setTitle(e.target.value)
+ }, [])
+
+ const handleDescriptionChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
+ setReleaseNotes(e.target.value)
+ }, [])
+
+ return <Modal className='p-0' isShow={isOpen} onClose={onClose}>
+ <div className='relative w-full p-6 pb-4 pr-14'>
+ <div className='title-2xl-semi-bold text-text-primary first-letter:capitalize'>
+ {versionInfo?.marked_name ? t('workflow.versionHistory.editVersionInfo') : t('workflow.versionHistory.nameThisVersion')}
+ </div>
+ <div className='absolute right-5 top-5 flex h-8 w-8 cursor-pointer items-center justify-center p-1.5' onClick={onClose}>
+ <RiCloseLine className='h-[18px] w-[18px] text-text-tertiary' />
+ </div>
+ </div>
+ <div className='flex flex-col gap-y-4 px-6 py-3'>
+ <div className='flex flex-col gap-y-1'>
+ <div className='system-sm-semibold flex h-6 items-center text-text-secondary'>
+ {t('workflow.versionHistory.editField.title')}
+ </div>
+ <Input
+ value={title}
+ placeholder={`${t('workflow.versionHistory.nameThisVersion')}${t('workflow.panel.optional')}`}
+ onChange={handleTitleChange}
+ destructive={titleError}
+ />
+ </div>
+ <div className='flex flex-col gap-y-1'>
+ <div className='system-sm-semibold flex h-6 items-center text-text-secondary'>
+ {t('workflow.versionHistory.editField.releaseNotes')}
+ </div>
+ <Textarea
+ value={releaseNotes}
+ placeholder={`${t('workflow.versionHistory.releaseNotesPlaceholder')}${t('workflow.panel.optional')}`}
+ onChange={handleDescriptionChange}
+ destructive={releaseNotesError}
+ />
+ </div>
+ </div>
+ <div className='flex justify-end p-6 pt-5'>
+ <div className='flex items-center gap-x-3'>
+ <Button onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' onClick={handlePublish}>{t('workflow.common.publish')}</Button>
+ </div>
+ </div>
+ </Modal>
+}
+
+export default VersionInfoModal
diff --git a/app/components/app/configuration/base/feature-panel/index.tsx b/app/components/app/configuration/base/feature-panel/index.tsx
new file mode 100644
index 0000000..ec5ab96
--- /dev/null
+++ b/app/components/app/configuration/base/feature-panel/index.tsx
@@ -0,0 +1,48 @@
+'use client'
+import type { FC, ReactNode } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+
+export type IFeaturePanelProps = {
+ className?: string
+ headerIcon?: ReactNode
+ title: ReactNode
+ headerRight?: ReactNode
+ hasHeaderBottomBorder?: boolean
+ noBodySpacing?: boolean
+ children?: ReactNode
+}
+
+const FeaturePanel: FC<IFeaturePanelProps> = ({
+ className,
+ headerIcon,
+ title,
+ headerRight,
+ hasHeaderBottomBorder,
+ noBodySpacing,
+ children,
+}) => {
+ return (
+ <div className={cn('rounded-xl border-l-[0.5px] border-t-[0.5px] border-effects-highlight bg-background-section-burn pb-3', noBodySpacing && 'pb-0', className)}>
+ {/* Header */}
+ <div className={cn('px-3 pt-2', hasHeaderBottomBorder && 'border-b border-divider-subtle')}>
+ <div className='flex h-8 items-center justify-between'>
+ <div className='flex shrink-0 items-center space-x-1'>
+ {headerIcon && <div className='flex h-6 w-6 items-center justify-center'>{headerIcon}</div>}
+ <div className='system-sm-semibold text-text-secondary'>{title}</div>
+ </div>
+ <div className='flex items-center gap-2'>
+ {headerRight && <div>{headerRight}</div>}
+ </div>
+ </div>
+ </div>
+ {/* Body */}
+ {children && (
+ <div className={cn(!noBodySpacing && 'mt-1 px-3')}>
+ {children}
+ </div>
+ )}
+ </div>
+ )
+}
+export default React.memo(FeaturePanel)
diff --git a/app/components/app/configuration/base/group-name/index.tsx b/app/components/app/configuration/base/group-name/index.tsx
new file mode 100644
index 0000000..d387b11
--- /dev/null
+++ b/app/components/app/configuration/base/group-name/index.tsx
@@ -0,0 +1,24 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+
+export type IGroupNameProps = {
+ name: string
+}
+
+const GroupName: FC<IGroupNameProps> = ({
+ name,
+}) => {
+ return (
+ <div className='mb-1 flex items-center'>
+ <div className='mr-3 text-xs font-semibold uppercase leading-[18px] text-text-tertiary'>{name}</div>
+ <div className='h-[1px] grow'
+ style={{
+ background: 'linear-gradient(270deg, rgba(243, 244, 246, 0) 0%, #F3F4F6 100%)',
+
+ }}
+ ></div>
+ </div>
+ )
+}
+export default React.memo(GroupName)
diff --git a/app/components/app/configuration/base/icons/citation.tsx b/app/components/app/configuration/base/icons/citation.tsx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/components/app/configuration/base/icons/citation.tsx
diff --git a/app/components/app/configuration/base/icons/more-like-this-icon.tsx b/app/components/app/configuration/base/icons/more-like-this-icon.tsx
new file mode 100644
index 0000000..74c808e
--- /dev/null
+++ b/app/components/app/configuration/base/icons/more-like-this-icon.tsx
@@ -0,0 +1,14 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+
+const MoreLikeThisIcon: FC = () => {
+ return (
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fillRule="evenodd" clipRule="evenodd" d="M5.83914 0.666748H10.1609C10.6975 0.666741 11.1404 0.666734 11.5012 0.696212C11.8759 0.726829 12.2204 0.792538 12.544 0.957399C13.0457 1.21306 13.4537 1.62101 13.7093 2.12277C13.8742 2.44633 13.9399 2.7908 13.9705 3.16553C14 3.52633 14 3.96923 14 4.50587V7.41171C14 7.62908 14 7.73776 13.9652 7.80784C13.9303 7.87806 13.8939 7.91566 13.8249 7.95288C13.756 7.99003 13.6262 7.99438 13.3665 8.00307C12.8879 8.01909 12.4204 8.14633 11.997 8.36429C10.9478 7.82388 9.62021 7.82912 8.53296 8.73228C7.15064 9.88056 6.92784 11.8645 8.0466 13.2641C8.36602 13.6637 8.91519 14.1949 9.40533 14.6492C9.49781 14.7349 9.54405 14.7777 9.5632 14.8041C9.70784 15.003 9.5994 15.2795 9.35808 15.3271C9.32614 15.3334 9.26453 15.3334 9.14129 15.3334H5.83912C5.30248 15.3334 4.85958 15.3334 4.49878 15.304C4.12405 15.2733 3.77958 15.2076 3.45603 15.0428C2.95426 14.7871 2.54631 14.3792 2.29065 13.8774C2.12579 13.5538 2.06008 13.2094 2.02946 12.8346C1.99999 12.4738 1.99999 12.0309 2 11.4943V4.50587C1.99999 3.96924 1.99999 3.52632 2.02946 3.16553C2.06008 2.7908 2.12579 2.44633 2.29065 2.12277C2.54631 1.62101 2.95426 1.21306 3.45603 0.957399C3.77958 0.792538 4.12405 0.726829 4.49878 0.696212C4.85957 0.666734 5.3025 0.666741 5.83914 0.666748ZM4.66667 5.33342C4.29848 5.33342 4 5.63189 4 6.00008C4 6.36827 4.29848 6.66675 4.66667 6.66675H8.66667C9.03486 6.66675 9.33333 6.36827 9.33333 6.00008C9.33333 5.63189 9.03486 5.33342 8.66667 5.33342H4.66667ZM4 8.66675C4 8.29856 4.29848 8.00008 4.66667 8.00008H6C6.36819 8.00008 6.66667 8.29856 6.66667 8.66675C6.66667 9.03494 6.36819 9.33342 6 9.33342H4.66667C4.29848 9.33342 4 9.03494 4 8.66675ZM4.66667 2.66675C4.29848 2.66675 4 2.96523 4 3.33342C4 3.7016 4.29848 4.00008 4.66667 4.00008H10.6667C11.0349 4.00008 11.3333 3.7016 11.3333 3.33342C11.3333 2.96523 11.0349 2.66675 10.6667 2.66675H4.66667Z" fill="#DD2590" />
+ <path d="M11.9977 10.0256C11.3313 9.26808 10.2199 9.06432 9.3849 9.75796C8.54988 10.4516 8.43232 11.6113 9.08807 12.4317C9.58479 13.0531 10.9986 14.3025 11.655 14.8719C11.7744 14.9754 11.8341 15.0272 11.9037 15.0477C11.9642 15.0654 12.0312 15.0654 12.0917 15.0477C12.1613 15.0272 12.221 14.9754 12.3404 14.8719C12.9968 14.3025 14.4106 13.0531 14.9074 12.4317C15.5631 11.6113 15.4599 10.4443 14.6105 9.75796C13.7612 9.07161 12.6642 9.26808 11.9977 10.0256Z" fill="#DD2590" />
+ </svg>
+
+ )
+}
+export default React.memo(MoreLikeThisIcon)
diff --git a/app/components/app/configuration/base/icons/remove-icon/index.tsx b/app/components/app/configuration/base/icons/remove-icon/index.tsx
new file mode 100644
index 0000000..f4b30a9
--- /dev/null
+++ b/app/components/app/configuration/base/icons/remove-icon/index.tsx
@@ -0,0 +1,31 @@
+'use client'
+import React, { useState } from 'react'
+import cn from '@/utils/classnames'
+
+type IRemoveIconProps = {
+ className?: string
+ isHoverStatus?: boolean
+ onClick: () => void
+}
+
+const RemoveIcon = ({
+ className,
+ isHoverStatus,
+ onClick,
+}: IRemoveIconProps) => {
+ const [isHovered, setIsHovered] = useState(false)
+ const computedIsHovered = isHoverStatus || isHovered
+ return (
+ <div
+ className={cn(className, computedIsHovered && 'bg-[#FEE4E2]', 'flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-[#FEE4E2]')}
+ onMouseEnter={() => setIsHovered(true)}
+ onMouseLeave={() => setIsHovered(false)}
+ onClick={onClick}
+ >
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M10 6H14M6 8H18M16.6667 8L16.1991 15.0129C16.129 16.065 16.0939 16.5911 15.8667 16.99C15.6666 17.3412 15.3648 17.6235 15.0011 17.7998C14.588 18 14.0607 18 13.0062 18H10.9938C9.93927 18 9.41202 18 8.99889 17.7998C8.63517 17.6235 8.33339 17.3412 8.13332 16.99C7.90607 16.5911 7.871 16.065 7.80086 15.0129L7.33333 8M10.6667 11V14.3333M13.3333 11V14.3333" stroke={computedIsHovered ? '#D92D20' : '#667085'} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+ </div>
+ )
+}
+export default React.memo(RemoveIcon)
diff --git a/app/components/app/configuration/base/icons/remove-icon/style.module.css b/app/components/app/configuration/base/icons/remove-icon/style.module.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/components/app/configuration/base/icons/remove-icon/style.module.css
diff --git a/app/components/app/configuration/base/icons/suggested-questions-after-answer-icon.tsx b/app/components/app/configuration/base/icons/suggested-questions-after-answer-icon.tsx
new file mode 100644
index 0000000..cabc2e4
--- /dev/null
+++ b/app/components/app/configuration/base/icons/suggested-questions-after-answer-icon.tsx
@@ -0,0 +1,12 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+
+const SuggestedQuestionsAfterAnswerIcon: FC = () => {
+ return (
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fillRule="evenodd" clipRule="evenodd" d="M10.8275 1.33325H5.17245C4.63581 1.33324 4.19289 1.33324 3.8321 1.36272C3.45737 1.39333 3.1129 1.45904 2.78934 1.6239C2.28758 1.87956 1.87963 2.28751 1.62397 2.78928C1.45911 3.11284 1.3934 3.4573 1.36278 3.83204C1.3333 4.19283 1.33331 4.63574 1.33332 5.17239L1.33328 9.42497C1.333 9.95523 1.33278 10.349 1.42418 10.6901C1.67076 11.6103 2.38955 12.3291 3.3098 12.5757C3.51478 12.6306 3.73878 12.6525 3.99998 12.6611L3.99998 13.5806C3.99995 13.7374 3.99992 13.8973 4.01182 14.0283C4.0232 14.1536 4.05333 14.3901 4.21844 14.5969C4.40843 14.8349 4.69652 14.9734 5.00106 14.973C5.26572 14.9728 5.46921 14.8486 5.57416 14.7792C5.6839 14.7066 5.80872 14.6067 5.93117 14.5087L7.53992 13.2217C7.88564 12.9451 7.98829 12.8671 8.09494 12.8126C8.20192 12.7579 8.3158 12.718 8.43349 12.6938C8.55081 12.6697 8.67974 12.6666 9.12248 12.6666H10.8275C11.3642 12.6666 11.8071 12.6666 12.1679 12.6371C12.5426 12.6065 12.8871 12.5408 13.2106 12.3759C13.7124 12.1203 14.1203 11.7123 14.376 11.2106C14.5409 10.887 14.6066 10.5425 14.6372 10.1678C14.6667 9.80701 14.6667 9.36411 14.6667 8.82747V5.17237C14.6667 4.63573 14.6667 4.19283 14.6372 3.83204C14.6066 3.4573 14.5409 3.11284 14.376 2.78928C14.1203 2.28751 13.7124 1.87956 13.2106 1.6239C12.8871 1.45904 12.5426 1.39333 12.1679 1.36272C11.8071 1.33324 11.3642 1.33324 10.8275 1.33325ZM8.99504 4.99992C8.99504 4.44763 9.44275 3.99992 9.99504 3.99992C10.5473 3.99992 10.995 4.44763 10.995 4.99992C10.995 5.5522 10.5473 5.99992 9.99504 5.99992C9.44275 5.99992 8.99504 5.5522 8.99504 4.99992ZM4.92837 7.79996C5.222 7.57974 5.63816 7.63837 5.85961 7.93051C5.90071 7.98295 5.94593 8.03229 5.99199 8.08035C6.09019 8.18282 6.23775 8.32184 6.42882 8.4608C6.81353 8.74059 7.3454 8.99996 7.99504 8.99996C8.64469 8.99996 9.17655 8.74059 9.56126 8.4608C9.75233 8.32184 9.89989 8.18282 9.99809 8.08035C10.0441 8.0323 10.0894 7.98294 10.1305 7.93051C10.3519 7.63837 10.7681 7.57974 11.0617 7.79996C11.3563 8.02087 11.416 8.43874 11.195 8.73329C11.1967 8.73112 11.1928 8.7361 11.186 8.74466C11.1697 8.7651 11.1372 8.80597 11.1261 8.81916C11.087 8.86575 11.0317 8.92884 10.9607 9.00289C10.8194 9.15043 10.6128 9.34474 10.3455 9.53912C9.81353 9.92599 9.01206 10.3333 7.99504 10.3333C6.97802 10.3333 6.17655 9.92599 5.64459 9.53912C5.37733 9.34474 5.17072 9.15043 5.02934 9.00289C4.95837 8.92884 4.90305 8.86575 4.86395 8.81916C4.84438 8.79585 4.82881 8.77659 4.81731 8.76207C4.58702 8.46455 4.61798 8.03275 4.92837 7.79996ZM5.99504 3.99992C5.44275 3.99992 4.99504 4.44763 4.99504 4.99992C4.99504 5.5522 5.44275 5.99992 5.99504 5.99992C6.54732 5.99992 6.99504 5.5522 6.99504 4.99992C6.99504 4.44763 6.54732 3.99992 5.99504 3.99992Z" fill="#06AED4" />
+ </svg>
+ )
+}
+export default React.memo(SuggestedQuestionsAfterAnswerIcon)
diff --git a/app/components/app/configuration/base/operation-btn/index.tsx b/app/components/app/configuration/base/operation-btn/index.tsx
new file mode 100644
index 0000000..aba35cd
--- /dev/null
+++ b/app/components/app/configuration/base/operation-btn/index.tsx
@@ -0,0 +1,44 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiAddLine,
+ RiEditLine,
+} from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+export type IOperationBtnProps = {
+ className?: string
+ type: 'add' | 'edit'
+ actionName?: string
+ onClick?: () => void
+}
+
+const iconMap = {
+ add: <RiAddLine className='h-3.5 w-3.5' />,
+ edit: <RiEditLine className='h-3.5 w-3.5' />,
+}
+
+const OperationBtn: FC<IOperationBtnProps> = ({
+ className,
+ type,
+ actionName,
+ onClick = noop,
+}) => {
+ const { t } = useTranslation()
+ return (
+ <div
+ className={cn('flex h-7 cursor-pointer select-none items-center space-x-1 rounded-md px-3 text-text-secondary hover:bg-state-base-hover', className)}
+ onClick={onClick}>
+ <div>
+ {iconMap[type]}
+ </div>
+ <div className='text-xs font-medium'>
+ {actionName || t(`common.operation.${type}`)}
+ </div>
+ </div>
+ )
+}
+export default React.memo(OperationBtn)
diff --git a/app/components/app/configuration/base/var-highlight/index.tsx b/app/components/app/configuration/base/var-highlight/index.tsx
new file mode 100644
index 0000000..1900dd5
--- /dev/null
+++ b/app/components/app/configuration/base/var-highlight/index.tsx
@@ -0,0 +1,37 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+
+import s from './style.module.css'
+
+export type IVarHighlightProps = {
+ name: string
+ className?: string
+}
+
+const VarHighlight: FC<IVarHighlightProps> = ({
+ name,
+ className = '',
+}) => {
+ return (
+ <div
+ key={name}
+ className={`${s.item} ${className} mb-2 flex h-5 items-center justify-center rounded-md px-1 text-xs font-medium text-primary-600`}
+ >
+ <span className='opacity-60'>{'{{'}</span>
+ <span>{name}</span>
+ <span className='opacity-60'>{'}}'}</span>
+ </div>
+ )
+}
+
+export const varHighlightHTML = ({ name, className = '' }: IVarHighlightProps) => {
+ const html = `<div class="${s.item} ${className} inline-flex mb-2 items-center justify-center px-1 rounded-md h-5 text-xs font-medium text-primary-600">
+ <span class='opacity-60'>{{</span>
+ <span>${name}</span>
+ <span class='opacity-60'>}}</span>
+</div>`
+ return html
+}
+
+export default React.memo(VarHighlight)
diff --git a/app/components/app/configuration/base/var-highlight/style.module.css b/app/components/app/configuration/base/var-highlight/style.module.css
new file mode 100644
index 0000000..2bcef0d
--- /dev/null
+++ b/app/components/app/configuration/base/var-highlight/style.module.css
@@ -0,0 +1,3 @@
+.item {
+ background-color: rgba(21, 94, 239, 0.05);
+}
diff --git a/app/components/app/configuration/base/warning-mask/cannot-query-dataset.tsx b/app/components/app/configuration/base/warning-mask/cannot-query-dataset.tsx
new file mode 100644
index 0000000..be247b0
--- /dev/null
+++ b/app/components/app/configuration/base/warning-mask/cannot-query-dataset.tsx
@@ -0,0 +1,31 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import WarningMask from '.'
+import Button from '@/app/components/base/button'
+
+export type IFormattingChangedProps = {
+ onConfirm: () => void
+}
+
+const FormattingChanged: FC<IFormattingChangedProps> = ({
+ onConfirm,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <WarningMask
+ title={t('appDebug.feature.dataSet.queryVariable.unableToQueryDataSet')}
+ description={t('appDebug.feature.dataSet.queryVariable.unableToQueryDataSetTip')}
+ footer={
+ <div className='flex space-x-2'>
+ <Button variant='primary' className='flex !w-[96px] justify-start' onClick={onConfirm}>
+ <span className='text-[13px] font-medium'>{t('appDebug.feature.dataSet.queryVariable.ok')}</span>
+ </Button>
+ </div>
+ }
+ />
+ )
+}
+export default React.memo(FormattingChanged)
diff --git a/app/components/app/configuration/base/warning-mask/formatting-changed.tsx b/app/components/app/configuration/base/warning-mask/formatting-changed.tsx
new file mode 100644
index 0000000..35c2283
--- /dev/null
+++ b/app/components/app/configuration/base/warning-mask/formatting-changed.tsx
@@ -0,0 +1,41 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import WarningMask from '.'
+import Button from '@/app/components/base/button'
+
+export type IFormattingChangedProps = {
+ onConfirm: () => void
+ onCancel: () => void
+}
+
+const icon = (
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M1.33337 6.66667C1.33337 6.66667 2.67003 4.84548 3.75593 3.75883C4.84183 2.67218 6.34244 2 8.00004 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8.00004 14C5.26465 14 2.95678 12.1695 2.23455 9.66667M1.33337 6.66667V2.66667M1.33337 6.66667H5.33337" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+)
+
+const FormattingChanged: FC<IFormattingChangedProps> = ({
+ onConfirm,
+ onCancel,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <WarningMask
+ title={t('appDebug.formattingChangedTitle')}
+ description={t('appDebug.formattingChangedText')}
+ footer={
+ <div className='flex space-x-2'>
+ <Button variant='primary' className='flex space-x-2' onClick={onConfirm}>
+ {icon}
+ <span>{t('common.operation.refresh')}</span>
+ </Button>
+ <Button onClick={onCancel}>{t('common.operation.cancel') as string}</Button>
+ </div>
+ }
+ />
+ )
+}
+export default React.memo(FormattingChanged)
diff --git a/app/components/app/configuration/base/warning-mask/has-not-set-api.tsx b/app/components/app/configuration/base/warning-mask/has-not-set-api.tsx
new file mode 100644
index 0000000..d83f9d9
--- /dev/null
+++ b/app/components/app/configuration/base/warning-mask/has-not-set-api.tsx
@@ -0,0 +1,38 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import WarningMask from '.'
+import Button from '@/app/components/base/button'
+
+export type IHasNotSetAPIProps = {
+ isTrailFinished: boolean
+ onSetting: () => void
+}
+
+const icon = (
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M14 6.00001L14 2.00001M14 2.00001H9.99999M14 2.00001L8 8M6.66667 2H5.2C4.0799 2 3.51984 2 3.09202 2.21799C2.71569 2.40973 2.40973 2.71569 2.21799 3.09202C2 3.51984 2 4.07989 2 5.2V10.8C2 11.9201 2 12.4802 2.21799 12.908C2.40973 13.2843 2.71569 13.5903 3.09202 13.782C3.51984 14 4.07989 14 5.2 14H10.8C11.9201 14 12.4802 14 12.908 13.782C13.2843 13.5903 13.5903 13.2843 13.782 12.908C14 12.4802 14 11.9201 14 10.8V9.33333" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+
+)
+
+const HasNotSetAPI: FC<IHasNotSetAPIProps> = ({
+ isTrailFinished,
+ onSetting,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <WarningMask
+ title={isTrailFinished ? t('appDebug.notSetAPIKey.trailFinished') : t('appDebug.notSetAPIKey.title')}
+ description={t('appDebug.notSetAPIKey.description')}
+ footer={
+ <Button variant='primary' className='flex space-x-2' onClick={onSetting}>
+ <span>{t('appDebug.notSetAPIKey.settingBtn')}</span>
+ {icon}
+ </Button>}
+ />
+ )
+}
+export default React.memo(HasNotSetAPI)
diff --git a/app/components/app/configuration/base/warning-mask/index.tsx b/app/components/app/configuration/base/warning-mask/index.tsx
new file mode 100644
index 0000000..fbe58be
--- /dev/null
+++ b/app/components/app/configuration/base/warning-mask/index.tsx
@@ -0,0 +1,43 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+
+import s from './style.module.css'
+
+export type IWarningMaskProps = {
+ title: string
+ description: string
+ footer: React.ReactNode
+}
+
+const warningIcon = (
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M9.99996 13.3334V10.0001M9.99996 6.66675H10.0083M18.3333 10.0001C18.3333 14.6025 14.6023 18.3334 9.99996 18.3334C5.39759 18.3334 1.66663 14.6025 1.66663 10.0001C1.66663 5.39771 5.39759 1.66675 9.99996 1.66675C14.6023 1.66675 18.3333 5.39771 18.3333 10.0001Z" stroke="#F79009" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+)
+
+const WarningMask: FC<IWarningMaskProps> = ({
+ title,
+ description,
+ footer,
+}) => {
+ return (
+ <div className={`${s.mask} absolute inset-0 z-10 pt-16`}
+ >
+ <div className='mx-auto px-10'>
+ <div className={`${s.icon} flex h-11 w-11 items-center justify-center rounded-xl bg-white`}>{warningIcon}</div>
+ <div className='mt-4 text-[24px] font-semibold leading-normal text-gray-800'>
+ {title}
+ </div>
+ <div className='mt-3 text-base text-gray-500'>
+ {description}
+ </div>
+ <div className='mt-6'>
+ {footer}
+ </div>
+ </div>
+
+ </div>
+ )
+}
+export default React.memo(WarningMask)
diff --git a/app/components/app/configuration/base/warning-mask/style.module.css b/app/components/app/configuration/base/warning-mask/style.module.css
new file mode 100644
index 0000000..87f226f
--- /dev/null
+++ b/app/components/app/configuration/base/warning-mask/style.module.css
@@ -0,0 +1,8 @@
+.mask {
+ background-color: rgba(239, 244, 255, 0.9);
+ backdrop-filter: blur(2px);
+}
+
+.icon {
+ box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);
+}
diff --git a/app/components/app/configuration/config-prompt/advanced-prompt-input.tsx b/app/components/app/configuration/config-prompt/advanced-prompt-input.tsx
new file mode 100644
index 0000000..1eec519
--- /dev/null
+++ b/app/components/app/configuration/config-prompt/advanced-prompt-input.tsx
@@ -0,0 +1,275 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import copy from 'copy-to-clipboard'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { useBoolean } from 'ahooks'
+import produce from 'immer'
+import {
+ RiDeleteBinLine,
+ RiErrorWarningFill,
+} from '@remixicon/react'
+import s from './style.module.css'
+import MessageTypeSelector from './message-type-selector'
+import ConfirmAddVar from './confirm-add-var'
+import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
+import cn from '@/utils/classnames'
+import type { PromptRole, PromptVariable } from '@/models/debug'
+import {
+ Clipboard,
+ ClipboardCheck,
+} from '@/app/components/base/icons/src/vender/line/files'
+import Button from '@/app/components/base/button'
+import Tooltip from '@/app/components/base/tooltip'
+import PromptEditor from '@/app/components/base/prompt-editor'
+import ConfigContext from '@/context/debug-configuration'
+import { getNewVar, getVars } from '@/utils/var'
+import { AppType } from '@/types/app'
+import { useModalContext } from '@/context/modal-context'
+import type { ExternalDataTool } from '@/models/common'
+import { useToastContext } from '@/app/components/base/toast'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { ADD_EXTERNAL_DATA_TOOL } from '@/app/components/app/configuration/config-var'
+import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '@/app/components/base/prompt-editor/plugins/variable-block'
+type Props = {
+ type: PromptRole
+ isChatMode: boolean
+ value: string
+ onTypeChange: (value: PromptRole) => void
+ onChange: (value: string) => void
+ canDelete: boolean
+ onDelete: () => void
+ promptVariables: PromptVariable[]
+ isContextMissing: boolean
+ onHideContextMissingTip: () => void
+ noResize?: boolean
+}
+
+const AdvancedPromptInput: FC<Props> = ({
+ type,
+ isChatMode,
+ value,
+ onChange,
+ onTypeChange,
+ canDelete,
+ onDelete,
+ promptVariables,
+ isContextMissing,
+ onHideContextMissingTip,
+ noResize,
+}) => {
+ const { t } = useTranslation()
+ const { eventEmitter } = useEventEmitterContextContext()
+
+ const {
+ mode,
+ hasSetBlockStatus,
+ modelConfig,
+ setModelConfig,
+ conversationHistoriesRole,
+ showHistoryModal,
+ dataSets,
+ showSelectDataSet,
+ externalDataToolsConfig,
+ } = useContext(ConfigContext)
+ const { notify } = useToastContext()
+ const { setShowExternalDataToolModal } = useModalContext()
+ const handleOpenExternalDataToolModal = () => {
+ setShowExternalDataToolModal({
+ payload: {},
+ onSaveCallback: (newExternalDataTool: ExternalDataTool) => {
+ eventEmitter?.emit({
+ type: ADD_EXTERNAL_DATA_TOOL,
+ payload: newExternalDataTool,
+ } as any)
+ eventEmitter?.emit({
+ type: INSERT_VARIABLE_VALUE_BLOCK_COMMAND,
+ payload: newExternalDataTool.variable,
+ } as any)
+ },
+ onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
+ for (let i = 0; i < promptVariables.length; i++) {
+ if (promptVariables[i].key === newExternalDataTool.variable) {
+ notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
+ return false
+ }
+ }
+
+ return true
+ },
+ })
+ }
+ const isChatApp = mode !== AppType.completion
+ const [isCopied, setIsCopied] = React.useState(false)
+
+ const promptVariablesObj = (() => {
+ const obj: Record<string, boolean> = {}
+ promptVariables.forEach((item) => {
+ obj[item.key] = true
+ })
+ return obj
+ })()
+ const [newPromptVariables, setNewPromptVariables] = React.useState<PromptVariable[]>(promptVariables)
+ const [isShowConfirmAddVar, { setTrue: showConfirmAddVar, setFalse: hideConfirmAddVar }] = useBoolean(false)
+ const handlePromptChange = (newValue: string) => {
+ if (value === newValue)
+ return
+ onChange(newValue)
+ }
+ const handleBlur = () => {
+ const keys = getVars(value)
+ const newPromptVariables = keys.filter(key => !(key in promptVariablesObj) && !externalDataToolsConfig.find(item => item.variable === key)).map(key => getNewVar(key, ''))
+ if (newPromptVariables.length > 0) {
+ setNewPromptVariables(newPromptVariables)
+ showConfirmAddVar()
+ }
+ }
+
+ const handleAutoAdd = (isAdd: boolean) => {
+ return () => {
+ if (isAdd) {
+ const newModelConfig = produce(modelConfig, (draft) => {
+ draft.configs.prompt_variables = [...draft.configs.prompt_variables, ...newPromptVariables]
+ })
+ setModelConfig(newModelConfig)
+ }
+ hideConfirmAddVar()
+ }
+ }
+
+ const minHeight = 102
+ const [editorHeight, setEditorHeight] = React.useState(isChatMode ? 200 : 508)
+ const contextMissing = (
+ <div
+ className='flex h-11 items-center justify-between rounded-tl-xl rounded-tr-xl pb-1 pl-4 pr-3 pt-2'
+ style={{
+ background: 'linear-gradient(180deg, #FEF0C7 0%, rgba(254, 240, 199, 0) 100%)',
+ }}
+ >
+ <div className='flex items-center pr-2' >
+ <RiErrorWarningFill className='mr-1 h-4 w-4 text-[#F79009]' />
+ <div className='text-[13px] font-medium leading-[18px] text-[#DC6803]'>{t('appDebug.promptMode.contextMissing')}</div>
+ </div>
+ <Button
+ size='small'
+ variant='secondary-accent'
+ onClick={onHideContextMissingTip}
+ >{t('common.operation.ok')}</Button>
+ </div>
+ )
+ return (
+ <div className={`rounded-xl bg-gradient-to-r from-components-input-border-active-prompt-1 to-components-input-border-active-prompt-2 p-0.5 shadow-xs ${!isContextMissing ? '' : s.warningBorder}`}>
+ <div className='rounded-xl bg-background-default'>
+ {isContextMissing
+ ? contextMissing
+ : (
+ <div className={cn(s.boxHeader, 'flex h-11 items-center justify-between rounded-tl-xl rounded-tr-xl bg-background-default pb-1 pl-4 pr-3 pt-2 hover:shadow-xs')}>
+ {isChatMode
+ ? (
+ <MessageTypeSelector value={type} onChange={onTypeChange} />
+ )
+ : (
+ <div className='flex items-center space-x-1'>
+
+ <div className='text-sm font-semibold uppercase text-indigo-800'>{t('appDebug.pageTitle.line1')}
+ </div>
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]'>
+ {t('appDebug.promptTip')}
+ </div>
+ }
+ />
+ </div>)}
+ <div className={cn(s.optionWrap, 'items-center space-x-1')}>
+ {canDelete && (
+ <RiDeleteBinLine onClick={onDelete} className='h-6 w-6 cursor-pointer p-1 text-text-tertiary' />
+ )}
+ {!isCopied
+ ? (
+ <Clipboard className='h-6 w-6 cursor-pointer p-1 text-text-tertiary' onClick={() => {
+ copy(value)
+ setIsCopied(true)
+ }} />
+ )
+ : (
+ <ClipboardCheck className='h-6 w-6 p-1 text-text-tertiary' />
+ )}
+ </div>
+ </div>
+ )}
+
+ <PromptEditorHeightResizeWrap
+ className='min-h-[102px] overflow-y-auto px-4 text-sm text-text-secondary'
+ height={editorHeight}
+ minHeight={minHeight}
+ onHeightChange={setEditorHeight}
+ footer={(
+ <div className='flex pb-2 pl-4'>
+ <div className="h-[18px] rounded-md bg-divider-regular px-1 text-xs leading-[18px] text-text-tertiary">{value.length}</div>
+ </div>
+ )}
+ hideResize={noResize}
+ >
+ <PromptEditor
+ className='min-h-[84px]'
+ value={value}
+ contextBlock={{
+ show: true,
+ selectable: !hasSetBlockStatus.context,
+ datasets: dataSets.map(item => ({
+ id: item.id,
+ name: item.name,
+ type: item.data_source_type,
+ })),
+ onAddContext: showSelectDataSet,
+ }}
+ variableBlock={{
+ show: true,
+ variables: modelConfig.configs.prompt_variables.filter(item => item.type !== 'api').map(item => ({
+ name: item.name,
+ value: item.key,
+ })),
+ }}
+ externalToolBlock={{
+ externalTools: modelConfig.configs.prompt_variables.filter(item => item.type === 'api').map(item => ({
+ name: item.name,
+ variableName: item.key,
+ icon: item.icon,
+ icon_background: item.icon_background,
+ })),
+ onAddExternalTool: handleOpenExternalDataToolModal,
+ }}
+ historyBlock={{
+ show: !isChatMode && isChatApp,
+ selectable: !hasSetBlockStatus.history,
+ history: {
+ user: conversationHistoriesRole?.user_prefix,
+ assistant: conversationHistoriesRole?.assistant_prefix,
+ },
+ onEditRole: showHistoryModal,
+ }}
+ queryBlock={{
+ show: !isChatMode && isChatApp,
+ selectable: !hasSetBlockStatus.query,
+ }}
+ onChange={handlePromptChange}
+ onBlur={handleBlur}
+ />
+ </PromptEditorHeightResizeWrap>
+
+ </div>
+
+ {isShowConfirmAddVar && (
+ <ConfirmAddVar
+ varNameArr={newPromptVariables.map(v => v.name)}
+ onConfirm={handleAutoAdd(true)}
+ onCancel={handleAutoAdd(false)}
+ onHide={hideConfirmAddVar}
+ />
+ )}
+ </div>
+ )
+}
+export default React.memo(AdvancedPromptInput)
diff --git a/app/components/app/configuration/config-prompt/confirm-add-var/index.tsx b/app/components/app/configuration/config-prompt/confirm-add-var/index.tsx
new file mode 100644
index 0000000..413f73f
--- /dev/null
+++ b/app/components/app/configuration/config-prompt/confirm-add-var/index.tsx
@@ -0,0 +1,69 @@
+'use client'
+import type { FC } from 'react'
+import React, { useRef } from 'react'
+import { useTranslation } from 'react-i18next'
+import VarHighlight from '../../base/var-highlight'
+import Button from '@/app/components/base/button'
+
+export type IConfirmAddVarProps = {
+ varNameArr: string[]
+ onConfirm: () => void
+ onCancel: () => void
+ onHide: () => void
+}
+
+const VarIcon = (
+ <svg width="16" height="14" viewBox="0 0 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M13.8683 0.704745C13.7051 0.374685 13.3053 0.239393 12.9752 0.402563C12.6452 0.565732 12.5099 0.965573 12.673 1.29563C13.5221 3.01316 13.9999 4.94957 13.9999 7.00019C13.9999 9.05081 13.5221 10.9872 12.673 12.7047C12.5099 13.0348 12.6452 13.4346 12.9752 13.5978C13.3053 13.761 13.7051 13.6257 13.8683 13.2956C14.8063 11.3983 15.3333 9.26009 15.3333 7.00019C15.3333 4.74029 14.8063 2.60209 13.8683 0.704745Z" fill="#FD853A" />
+ <path d="M3.32687 1.29563C3.49004 0.965573 3.35475 0.565732 3.02469 0.402563C2.69463 0.239393 2.29479 0.374685 2.13162 0.704745C1.19364 2.60209 0.666626 4.74029 0.666626 7.00019C0.666626 9.26009 1.19364 11.3983 2.13162 13.2956C2.29479 13.6257 2.69463 13.761 3.02469 13.5978C3.35475 13.4346 3.49004 13.0348 3.32687 12.7047C2.47779 10.9872 1.99996 9.05081 1.99996 7.00019C1.99996 4.94957 2.47779 3.01316 3.32687 1.29563Z" fill="#FD853A" />
+ <path d="M9.33238 4.8413C9.74208 4.36081 10.3411 4.08337 10.9726 4.08337H11.0324C11.4006 4.08337 11.6991 4.38185 11.6991 4.75004C11.6991 5.11823 11.4006 5.41671 11.0324 5.41671H10.9726C10.7329 5.41671 10.5042 5.52196 10.347 5.7064L8.78693 7.536L9.28085 9.27382C9.29145 9.31112 9.32388 9.33337 9.35696 9.33337H10.2864C10.6545 9.33337 10.953 9.63185 10.953 10C10.953 10.3682 10.6545 10.6667 10.2864 10.6667H9.35696C8.72382 10.6667 8.17074 10.245 7.99832 9.63834L7.74732 8.75524L6.76373 9.90878C6.35403 10.3893 5.75501 10.6667 5.1235 10.6667H5.06372C4.69553 10.6667 4.39705 10.3682 4.39705 10C4.39705 9.63185 4.69553 9.33337 5.06372 9.33337H5.1235C5.3632 9.33337 5.59189 9.22812 5.74915 9.04368L7.30926 7.21399L6.81536 5.47626C6.80476 5.43897 6.77233 5.41671 6.73925 5.41671H5.80986C5.44167 5.41671 5.14319 5.11823 5.14319 4.75004C5.14319 4.38185 5.44167 4.08337 5.80986 4.08337H6.73925C7.37239 4.08337 7.92547 4.50508 8.0979 5.11174L8.34887 5.99475L9.33238 4.8413Z" fill="#FD853A" />
+ </svg>
+)
+
+const ConfirmAddVar: FC<IConfirmAddVarProps> = ({
+ varNameArr,
+ onConfirm,
+ onCancel,
+ // onHide,
+}) => {
+ const { t } = useTranslation()
+ const mainContentRef = useRef<HTMLDivElement>(null)
+ // new prompt editor blur trigger click...
+ // useClickAway(() => {
+ // onHide()
+ // }, mainContentRef)
+ return (
+ <div className='absolute inset-0 flex items-center justify-center rounded-xl'
+ style={{
+ backgroundColor: 'rgba(35, 56, 118, 0.2)',
+ }}>
+ <div
+ ref={mainContentRef}
+ className='w-[420px] rounded-xl bg-components-panel-bg p-6'
+ style={{
+ boxShadow: '0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03)',
+ }}
+ >
+ <div className='flex items-start space-x-3'>
+ <div
+ className='flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-components-card-border bg-components-card-bg-alt shadow-lg'
+ >{VarIcon}</div>
+ <div className='grow-1'>
+ <div className='text-sm font-medium text-text-primary'>{t('appDebug.autoAddVar')}</div>
+ <div className='mt-[15px] flex max-h-[66px] flex-wrap space-x-1 overflow-y-auto px-1'>
+ {varNameArr.map(name => (
+ <VarHighlight key={name} name={name} />
+ ))}
+ </div>
+ </div>
+ </div>
+ <div className='mt-7 flex justify-end space-x-2'>
+ <Button onClick={onCancel}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' onClick={onConfirm}>{t('common.operation.add')}</Button>
+ </div>
+ </div>
+
+ </div>
+ )
+}
+export default React.memo(ConfirmAddVar)
diff --git a/app/components/app/configuration/config-prompt/conversation-history/edit-modal.tsx b/app/components/app/configuration/config-prompt/conversation-history/edit-modal.tsx
new file mode 100644
index 0000000..ff115da
--- /dev/null
+++ b/app/components/app/configuration/config-prompt/conversation-history/edit-modal.tsx
@@ -0,0 +1,58 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import Modal from '@/app/components/base/modal'
+import type { ConversationHistoriesRole } from '@/models/debug'
+import Button from '@/app/components/base/button'
+type Props = {
+ isShow: boolean
+ saveLoading: boolean
+ data: ConversationHistoriesRole
+ onClose: () => void
+ onSave: (data: any) => void
+}
+
+const EditModal: FC<Props> = ({
+ isShow,
+ saveLoading,
+ data,
+ onClose,
+ onSave,
+}) => {
+ const { t } = useTranslation()
+ const [tempData, setTempData] = useState(data)
+ return (
+ <Modal
+ title={t('appDebug.feature.conversationHistory.editModal.title')}
+ isShow={isShow}
+ onClose={onClose}
+ >
+ <div className={'mt-6 text-sm font-medium leading-[21px] text-text-primary'}>{t('appDebug.feature.conversationHistory.editModal.userPrefix')}</div>
+ <input className={'mt-2 box-border h-10 w-full rounded-lg bg-components-input-bg-normal px-3 text-sm leading-10'}
+ value={tempData.user_prefix}
+ onChange={e => setTempData({
+ ...tempData,
+ user_prefix: e.target.value,
+ })}
+ />
+
+ <div className={'mt-6 text-sm font-medium leading-[21px] text-text-primary'}>{t('appDebug.feature.conversationHistory.editModal.assistantPrefix')}</div>
+ <input className={'mt-2 box-border h-10 w-full rounded-lg bg-components-input-bg-normal px-3 text-sm leading-10'}
+ value={tempData.assistant_prefix}
+ onChange={e => setTempData({
+ ...tempData,
+ assistant_prefix: e.target.value,
+ })}
+ placeholder={t('common.chat.conversationNamePlaceholder') || ''}
+ />
+
+ <div className='mt-10 flex justify-end'>
+ <Button className='mr-2 shrink-0' onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' className='shrink-0' onClick={() => onSave(tempData)} loading={saveLoading}>{t('common.operation.save')}</Button>
+ </div>
+ </Modal>
+ )
+}
+
+export default React.memo(EditModal)
diff --git a/app/components/app/configuration/config-prompt/conversation-history/history-panel.tsx b/app/components/app/configuration/config-prompt/conversation-history/history-panel.tsx
new file mode 100644
index 0000000..592c952
--- /dev/null
+++ b/app/components/app/configuration/config-prompt/conversation-history/history-panel.tsx
@@ -0,0 +1,60 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
+import Panel from '@/app/components/app/configuration/base/feature-panel'
+import { MessageClockCircle } from '@/app/components/base/icons/src/vender/solid/general'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+
+type Props = {
+ showWarning: boolean
+ onShowEditModal: () => void
+}
+
+const HistoryPanel: FC<Props> = ({
+ showWarning,
+ onShowEditModal,
+}) => {
+ const { t } = useTranslation()
+ const { locale } = useContext(I18n)
+
+ return (
+ <Panel
+ className='mt-2'
+ title={
+ <div className='flex items-center gap-2'>
+ <div>{t('appDebug.feature.conversationHistory.title')}</div>
+ </div>
+ }
+ headerIcon={
+ <div className='rounded-md p-1 shadow-xs'>
+ <MessageClockCircle className='h-4 w-4 text-[#DD2590]' />
+ </div>}
+ headerRight={
+ <div className='flex items-center'>
+ <div className='text-xs text-text-tertiary'>{t('appDebug.feature.conversationHistory.description')}</div>
+ <div className='ml-3 h-[14px] w-[1px] bg-divider-regular'></div>
+ <OperationBtn type="edit" onClick={onShowEditModal} />
+ </div>
+ }
+ noBodySpacing
+ >
+ {showWarning && (
+ <div className='flex justify-between rounded-b-xl bg-background-section-burn px-3 py-2 text-xs text-text-secondary'>
+ <div>{t('appDebug.feature.conversationHistory.tip')}
+ <a href={`${locale === LanguagesSupported[1]
+ ? 'https://docs.dify.ai/zh-hans/learn-more/extended-reading/prompt-engineering/README'
+ : 'https://docs.dify.ai/en/features/prompt-engineering'}`}
+ target='_blank' rel='noopener noreferrer'
+ className='text-[#155EEF]'>{t('appDebug.feature.conversationHistory.learnMore')}
+ </a>
+ </div>
+ </div>
+ )}
+ </Panel>
+ )
+}
+export default React.memo(HistoryPanel)
diff --git a/app/components/app/configuration/config-prompt/index.tsx b/app/components/app/configuration/config-prompt/index.tsx
new file mode 100644
index 0000000..1caca47
--- /dev/null
+++ b/app/components/app/configuration/config-prompt/index.tsx
@@ -0,0 +1,170 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useContext } from 'use-context-selector'
+import produce from 'immer'
+import {
+ RiAddLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import SimplePromptInput from './simple-prompt-input'
+import Button from '@/app/components/base/button'
+import AdvancedMessageInput from '@/app/components/app/configuration/config-prompt/advanced-prompt-input'
+import { PromptRole } from '@/models/debug'
+import type { PromptItem, PromptVariable } from '@/models/debug'
+import { type AppType, ModelModeType } from '@/types/app'
+import ConfigContext from '@/context/debug-configuration'
+import { MAX_PROMPT_MESSAGE_LENGTH } from '@/config'
+export type IPromptProps = {
+ mode: AppType
+ promptTemplate: string
+ promptVariables: PromptVariable[]
+ readonly?: boolean
+ noTitle?: boolean
+ gradientBorder?: boolean
+ editorHeight?: number
+ noResize?: boolean
+ onChange?: (prompt: string, promptVariables: PromptVariable[]) => void
+}
+
+const Prompt: FC<IPromptProps> = ({
+ mode,
+ promptTemplate,
+ promptVariables,
+ noTitle,
+ gradientBorder,
+ readonly = false,
+ editorHeight,
+ noResize,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+
+ const {
+ isAdvancedMode,
+ currentAdvancedPrompt,
+ setCurrentAdvancedPrompt,
+ modelModeType,
+ dataSets,
+ hasSetBlockStatus,
+ } = useContext(ConfigContext)
+
+ const handleMessageTypeChange = (index: number, role: PromptRole) => {
+ const newPrompt = produce(currentAdvancedPrompt as PromptItem[], (draft) => {
+ draft[index].role = role
+ })
+ setCurrentAdvancedPrompt(newPrompt)
+ }
+
+ const handleValueChange = (value: string, index?: number) => {
+ if (modelModeType === ModelModeType.chat) {
+ const newPrompt = produce(currentAdvancedPrompt as PromptItem[], (draft) => {
+ draft[index as number].text = value
+ })
+ setCurrentAdvancedPrompt(newPrompt, true)
+ }
+ else {
+ const prompt = currentAdvancedPrompt as PromptItem
+ setCurrentAdvancedPrompt({
+ ...prompt,
+ text: value,
+ }, true)
+ }
+ }
+
+ const handleAddMessage = () => {
+ const currentAdvancedPromptList = currentAdvancedPrompt as PromptItem[]
+ if (currentAdvancedPromptList.length === 0) {
+ setCurrentAdvancedPrompt([{
+ role: PromptRole.system,
+ text: '',
+ }])
+ return
+ }
+ const lastMessageType = currentAdvancedPromptList[currentAdvancedPromptList.length - 1]?.role
+ const appendMessage = {
+ role: lastMessageType === PromptRole.user ? PromptRole.assistant : PromptRole.user,
+ text: '',
+ }
+ setCurrentAdvancedPrompt([...currentAdvancedPromptList, appendMessage])
+ }
+
+ const handlePromptDelete = (index: number) => {
+ const currentAdvancedPromptList = currentAdvancedPrompt as PromptItem[]
+ const newPrompt = produce(currentAdvancedPromptList, (draft) => {
+ draft.splice(index, 1)
+ })
+ setCurrentAdvancedPrompt(newPrompt)
+ }
+
+ const isContextMissing = dataSets.length > 0 && !hasSetBlockStatus.context
+ const [isHideContextMissTip, setIsHideContextMissTip] = React.useState(false)
+
+ if (!isAdvancedMode) {
+ return (
+ <SimplePromptInput
+ mode={mode}
+ promptTemplate={promptTemplate}
+ promptVariables={promptVariables}
+ readonly={readonly}
+ onChange={onChange}
+ noTitle={noTitle}
+ gradientBorder={gradientBorder}
+ editorHeight={editorHeight}
+ noResize={noResize}
+ />
+ )
+ }
+
+ return (
+ <div>
+ <div className='space-y-3'>
+ {modelModeType === ModelModeType.chat
+ ? (
+ (currentAdvancedPrompt as PromptItem[]).map((item, index) => (
+ <AdvancedMessageInput
+ key={index}
+ isChatMode
+ type={item.role as PromptRole}
+ value={item.text}
+ onTypeChange={type => handleMessageTypeChange(index, type)}
+ canDelete={(currentAdvancedPrompt as PromptItem[]).length > 1}
+ onDelete={() => handlePromptDelete(index)}
+ onChange={value => handleValueChange(value, index)}
+ promptVariables={promptVariables}
+ isContextMissing={isContextMissing && !isHideContextMissTip}
+ onHideContextMissingTip={() => setIsHideContextMissTip(true)}
+ noResize={noResize}
+ />
+ ))
+ )
+ : (
+ <AdvancedMessageInput
+ type={(currentAdvancedPrompt as PromptItem).role as PromptRole}
+ isChatMode={false}
+ value={(currentAdvancedPrompt as PromptItem).text}
+ onTypeChange={type => handleMessageTypeChange(0, type)}
+ canDelete={false}
+ onDelete={() => handlePromptDelete(0)}
+ onChange={value => handleValueChange(value)}
+ promptVariables={promptVariables}
+ isContextMissing={isContextMissing && !isHideContextMissTip}
+ onHideContextMissingTip={() => setIsHideContextMissTip(true)}
+ noResize={noResize}
+ />
+ )
+ }
+ </div>
+ {(modelModeType === ModelModeType.chat && (currentAdvancedPrompt as PromptItem[]).length < MAX_PROMPT_MESSAGE_LENGTH) && (
+ <Button
+ onClick={handleAddMessage}
+ className='mt-3 w-full'>
+ <RiAddLine className='mr-2 h-4 w-4' />
+ <div>{t('appDebug.promptMode.operation.addMessage')}</div>
+ </Button>
+ )}
+ </div>
+ )
+}
+
+export default React.memo(Prompt)
diff --git a/app/components/app/configuration/config-prompt/message-type-selector.tsx b/app/components/app/configuration/config-prompt/message-type-selector.tsx
new file mode 100644
index 0000000..17b3ecb
--- /dev/null
+++ b/app/components/app/configuration/config-prompt/message-type-selector.tsx
@@ -0,0 +1,50 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useBoolean, useClickAway } from 'ahooks'
+import cn from '@/utils/classnames'
+import { PromptRole } from '@/models/debug'
+import { ChevronSelectorVertical } from '@/app/components/base/icons/src/vender/line/arrows'
+type Props = {
+ value: PromptRole
+ onChange: (value: PromptRole) => void
+}
+
+const allTypes = [PromptRole.system, PromptRole.user, PromptRole.assistant]
+const MessageTypeSelector: FC<Props> = ({
+ value,
+ onChange,
+}) => {
+ const [showOption, { setFalse: setHide, toggle: toggleShow }] = useBoolean(false)
+ const ref = React.useRef(null)
+ useClickAway(() => {
+ setHide()
+ }, ref)
+ return (
+ <div className='relative left-[-8px]' ref={ref}>
+ <div
+ onClick={toggleShow}
+ className={cn(showOption && 'bg-indigo-100', 'flex h-7 cursor-pointer items-center space-x-0.5 rounded-lg pl-1.5 pr-1 text-indigo-800')}>
+ <div className='text-sm font-semibold uppercase'>{value}</div>
+ <ChevronSelectorVertical className='h-3 w-3 ' />
+ </div>
+ {showOption && (
+ <div className='absolute top-[30px] z-10 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg'>
+ {allTypes.map(type => (
+ <div
+ key={type}
+ onClick={() => {
+ setHide()
+ onChange(type)
+ }}
+ className='flex h-9 min-w-[44px] cursor-pointer items-center rounded-lg px-3 text-sm font-medium uppercase text-text-secondary hover:bg-state-base-hover'
+ >{type}</div>
+ ))
+ }
+ </div>
+ )
+ }
+ </div>
+ )
+}
+export default React.memo(MessageTypeSelector)
diff --git a/app/components/app/configuration/config-prompt/prompt-editor-height-resize-wrap.tsx b/app/components/app/configuration/config-prompt/prompt-editor-height-resize-wrap.tsx
new file mode 100644
index 0000000..1457a29
--- /dev/null
+++ b/app/components/app/configuration/config-prompt/prompt-editor-height-resize-wrap.tsx
@@ -0,0 +1,96 @@
+'use client'
+import React, { useCallback, useEffect, useState } from 'react'
+import type { FC } from 'react'
+import { useDebounceFn } from 'ahooks'
+import cn from '@/utils/classnames'
+
+type Props = {
+ className?: string
+ height: number
+ minHeight: number
+ onHeightChange: (height: number) => void
+ children: React.JSX.Element
+ footer?: React.JSX.Element
+ hideResize?: boolean
+}
+
+const PromptEditorHeightResizeWrap: FC<Props> = ({
+ className,
+ height,
+ minHeight,
+ onHeightChange,
+ children,
+ footer,
+ hideResize,
+}) => {
+ const [clientY, setClientY] = useState(0)
+ const [isResizing, setIsResizing] = useState(false)
+ const [prevUserSelectStyle, setPrevUserSelectStyle] = useState(getComputedStyle(document.body).userSelect)
+ const [oldHeight, setOldHeight] = useState(height)
+
+ const handleStartResize = useCallback((e: React.MouseEvent<HTMLElement>) => {
+ setClientY(e.clientY)
+ setIsResizing(true)
+ setOldHeight(height)
+ setPrevUserSelectStyle(getComputedStyle(document.body).userSelect)
+ document.body.style.userSelect = 'none'
+ }, [height])
+
+ const handleStopResize = useCallback(() => {
+ setIsResizing(false)
+ document.body.style.userSelect = prevUserSelectStyle
+ }, [prevUserSelectStyle])
+
+ const { run: didHandleResize } = useDebounceFn((e) => {
+ if (!isResizing)
+ return
+
+ const offset = e.clientY - clientY
+ let newHeight = oldHeight + offset
+ if (newHeight < minHeight)
+ newHeight = minHeight
+ onHeightChange(newHeight)
+ }, {
+ wait: 0,
+ })
+
+ const handleResize = useCallback(didHandleResize, [isResizing, height, minHeight, clientY])
+
+ useEffect(() => {
+ document.addEventListener('mousemove', handleResize)
+ return () => {
+ document.removeEventListener('mousemove', handleResize)
+ }
+ }, [handleResize])
+
+ useEffect(() => {
+ document.addEventListener('mouseup', handleStopResize)
+ return () => {
+ document.removeEventListener('mouseup', handleStopResize)
+ }
+ }, [handleStopResize])
+
+ return (
+ <div
+ className='relative'
+ >
+ <div className={cn(className, 'overflow-y-auto')}
+ style={{
+ height,
+ }}
+ >
+ {children}
+ </div>
+ {/* resize handler */}
+ {footer}
+ {!hideResize && (
+ <div
+ className='absolute bottom-0 left-0 flex h-2 w-full cursor-row-resize justify-center'
+ onMouseDown={handleStartResize}>
+ <div className='h-[3px] w-5 rounded-sm bg-gray-300'></div>
+ </div>
+ )}
+ </div>
+ )
+}
+export default React.memo(PromptEditorHeightResizeWrap)
diff --git a/app/components/app/configuration/config-prompt/simple-prompt-input.tsx b/app/components/app/configuration/config-prompt/simple-prompt-input.tsx
new file mode 100644
index 0000000..3268c1d
--- /dev/null
+++ b/app/components/app/configuration/config-prompt/simple-prompt-input.tsx
@@ -0,0 +1,284 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import produce from 'immer'
+import { useContext } from 'use-context-selector'
+import ConfirmAddVar from './confirm-add-var'
+import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
+import cn from '@/utils/classnames'
+import type { PromptVariable } from '@/models/debug'
+import Tooltip from '@/app/components/base/tooltip'
+import type { CompletionParams } from '@/types/app'
+import { AppType } from '@/types/app'
+import { getNewVar, getVars } from '@/utils/var'
+import AutomaticBtn from '@/app/components/app/configuration/config/automatic/automatic-btn'
+import type { AutomaticRes } from '@/service/debug'
+import GetAutomaticResModal from '@/app/components/app/configuration/config/automatic/get-automatic-res'
+import PromptEditor from '@/app/components/base/prompt-editor'
+import ConfigContext from '@/context/debug-configuration'
+import { useModalContext } from '@/context/modal-context'
+import type { ExternalDataTool } from '@/models/common'
+import { useToastContext } from '@/app/components/base/toast'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { ADD_EXTERNAL_DATA_TOOL } from '@/app/components/app/configuration/config-var'
+import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '@/app/components/base/prompt-editor/plugins/variable-block'
+import { PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER } from '@/app/components/base/prompt-editor/plugins/update-block'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import { useFeaturesStore } from '@/app/components/base/features/hooks'
+import { noop } from 'lodash-es'
+
+export type ISimplePromptInput = {
+ mode: AppType
+ promptTemplate: string
+ promptVariables: PromptVariable[]
+ readonly?: boolean
+ onChange?: (prompt: string, promptVariables: PromptVariable[]) => void
+ noTitle?: boolean
+ gradientBorder?: boolean
+ editorHeight?: number
+ noResize?: boolean
+}
+
+const Prompt: FC<ISimplePromptInput> = ({
+ mode,
+ promptTemplate,
+ promptVariables,
+ readonly = false,
+ onChange,
+ noTitle,
+ editorHeight: initEditorHeight,
+ noResize,
+}) => {
+ const { t } = useTranslation()
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+ const featuresStore = useFeaturesStore()
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const { eventEmitter } = useEventEmitterContextContext()
+ const {
+ modelConfig,
+ completionParams,
+ dataSets,
+ setModelConfig,
+ setPrevPromptConfig,
+ setIntroduction,
+ hasSetBlockStatus,
+ showSelectDataSet,
+ externalDataToolsConfig,
+ } = useContext(ConfigContext)
+ const { notify } = useToastContext()
+ const { setShowExternalDataToolModal } = useModalContext()
+ const handleOpenExternalDataToolModal = () => {
+ setShowExternalDataToolModal({
+ payload: {},
+ onSaveCallback: (newExternalDataTool: ExternalDataTool) => {
+ eventEmitter?.emit({
+ type: ADD_EXTERNAL_DATA_TOOL,
+ payload: newExternalDataTool,
+ } as any)
+ eventEmitter?.emit({
+ type: INSERT_VARIABLE_VALUE_BLOCK_COMMAND,
+ payload: newExternalDataTool.variable,
+ } as any)
+ },
+ onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
+ for (let i = 0; i < promptVariables.length; i++) {
+ if (promptVariables[i].key === newExternalDataTool.variable) {
+ notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
+ return false
+ }
+ }
+
+ return true
+ },
+ })
+ }
+ const promptVariablesObj = (() => {
+ const obj: Record<string, boolean> = {}
+ promptVariables.forEach((item) => {
+ obj[item.key] = true
+ })
+ return obj
+ })()
+
+ const [newPromptVariables, setNewPromptVariables] = React.useState<PromptVariable[]>(promptVariables)
+ const [newTemplates, setNewTemplates] = React.useState('')
+ const [isShowConfirmAddVar, { setTrue: showConfirmAddVar, setFalse: hideConfirmAddVar }] = useBoolean(false)
+
+ const handleChange = (newTemplates: string, keys: string[]) => {
+ const newPromptVariables = keys.filter(key => !(key in promptVariablesObj) && !externalDataToolsConfig.find(item => item.variable === key)).map(key => getNewVar(key, ''))
+ if (newPromptVariables.length > 0) {
+ setNewPromptVariables(newPromptVariables)
+ setNewTemplates(newTemplates)
+ showConfirmAddVar()
+ return
+ }
+ onChange?.(newTemplates, [])
+ }
+
+ const handleAutoAdd = (isAdd: boolean) => {
+ return () => {
+ onChange?.(newTemplates, isAdd ? newPromptVariables : [])
+ hideConfirmAddVar()
+ }
+ }
+
+ const [showAutomatic, { setTrue: showAutomaticTrue, setFalse: showAutomaticFalse }] = useBoolean(false)
+ const handleAutomaticRes = (res: AutomaticRes) => {
+ // put eventEmitter in first place to prevent overwrite the configs.prompt_variables.But another problem is that prompt won't hight the prompt_variables.
+ eventEmitter?.emit({
+ type: PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER,
+ payload: res.prompt,
+ } as any)
+ const newModelConfig = produce(modelConfig, (draft) => {
+ draft.configs.prompt_template = res.prompt
+ draft.configs.prompt_variables = res.variables.map(key => ({ key, name: key, type: 'string', required: true }))
+ })
+ setModelConfig(newModelConfig)
+ setPrevPromptConfig(modelConfig.configs)
+
+ if (mode !== AppType.completion) {
+ setIntroduction(res.opening_statement)
+ const newFeatures = produce(features, (draft) => {
+ draft.opening = {
+ ...draft.opening,
+ enabled: !!res.opening_statement,
+ opening_statement: res.opening_statement,
+ }
+ })
+ setFeatures(newFeatures)
+ }
+ showAutomaticFalse()
+ }
+ const minHeight = initEditorHeight || 228
+ const [editorHeight, setEditorHeight] = useState(minHeight)
+
+ return (
+ <div className={cn('relative rounded-xl bg-gradient-to-r from-components-input-border-active-prompt-1 to-components-input-border-active-prompt-2 p-0.5 shadow-xs')}>
+ <div className='rounded-xl bg-background-section-burn'>
+ {!noTitle && (
+ <div className="flex h-11 items-center justify-between pl-3 pr-2.5">
+ <div className="flex items-center space-x-1">
+ <div className='h2 system-sm-semibold-uppercase text-text-secondary'>{mode !== AppType.completion ? t('appDebug.chatSubTitle') : t('appDebug.completionSubTitle')}</div>
+ {!readonly && (
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]'>
+ {t('appDebug.promptTip')}
+ </div>
+ }
+ />
+ )}
+ </div>
+ <div className='flex items-center'>
+ {!readonly && !isMobile && (
+ <AutomaticBtn onClick={showAutomaticTrue} />
+ )}
+ </div>
+ </div>
+ )}
+
+ <PromptEditorHeightResizeWrap
+ className='min-h-[228px] rounded-t-xl bg-background-default px-4 pt-2 text-sm text-text-secondary'
+ height={editorHeight}
+ minHeight={minHeight}
+ onHeightChange={setEditorHeight}
+ hideResize={noResize}
+ footer={(
+ <div className='flex rounded-b-xl bg-background-default pb-2 pl-4'>
+ <div className="h-[18px] rounded-md bg-components-badge-bg-gray-soft px-1 text-xs leading-[18px] text-text-tertiary">{promptTemplate.length}</div>
+ </div>
+ )}
+ >
+ <PromptEditor
+ className='min-h-[210px]'
+ compact
+ value={promptTemplate}
+ contextBlock={{
+ show: false,
+ selectable: !hasSetBlockStatus.context,
+ datasets: dataSets.map(item => ({
+ id: item.id,
+ name: item.name,
+ type: item.data_source_type,
+ })),
+ onAddContext: showSelectDataSet,
+ }}
+ variableBlock={{
+ show: true,
+ variables: modelConfig.configs.prompt_variables.filter(item => item.type !== 'api').map(item => ({
+ name: item.name,
+ value: item.key,
+ })),
+ }}
+ externalToolBlock={{
+ show: true,
+ externalTools: modelConfig.configs.prompt_variables.filter(item => item.type === 'api').map(item => ({
+ name: item.name,
+ variableName: item.key,
+ icon: item.icon,
+ icon_background: item.icon_background,
+ })),
+ onAddExternalTool: handleOpenExternalDataToolModal,
+ }}
+ historyBlock={{
+ show: false,
+ selectable: false,
+ history: {
+ user: '',
+ assistant: '',
+ },
+ onEditRole: noop,
+ }}
+ queryBlock={{
+ show: false,
+ selectable: !hasSetBlockStatus.query,
+ }}
+ onChange={(value) => {
+ if (handleChange)
+ handleChange(value, [])
+ }}
+ onBlur={() => {
+ handleChange(promptTemplate, getVars(promptTemplate))
+ }}
+ editable={!readonly}
+ />
+ </PromptEditorHeightResizeWrap>
+ </div>
+
+ {isShowConfirmAddVar && (
+ <ConfirmAddVar
+ varNameArr={newPromptVariables.map(v => v.name)}
+ onConfirm={handleAutoAdd(true)}
+ onCancel={handleAutoAdd(false)}
+ onHide={hideConfirmAddVar}
+ />
+ )}
+
+ {showAutomatic && (
+ <GetAutomaticResModal
+ mode={mode as AppType}
+ model={
+ {
+ provider: modelConfig.provider,
+ name: modelConfig.model_id,
+ mode: modelConfig.mode,
+ completion_params: completionParams as CompletionParams,
+ }
+ }
+ isShow={showAutomatic}
+ onClose={showAutomaticFalse}
+ onFinished={handleAutomaticRes}
+ />
+ )}
+ </div>
+ )
+}
+
+export default React.memo(Prompt)
diff --git a/app/components/app/configuration/config-prompt/style.module.css b/app/components/app/configuration/config-prompt/style.module.css
new file mode 100644
index 0000000..224d59d
--- /dev/null
+++ b/app/components/app/configuration/config-prompt/style.module.css
@@ -0,0 +1,28 @@
+.gradientBorder {
+ background: radial-gradient(circle at 100% 100%, #fcfcfd 0, #fcfcfd 10px, transparent 10px) 0% 0%/12px 12px no-repeat,
+ radial-gradient(circle at 0 100%, #fcfcfd 0, #fcfcfd 10px, transparent 10px) 100% 0%/12px 12px no-repeat,
+ radial-gradient(circle at 100% 0, #fcfcfd 0, #fcfcfd 10px, transparent 10px) 0% 100%/12px 12px no-repeat,
+ radial-gradient(circle at 0 0, #fcfcfd 0, #fcfcfd 10px, transparent 10px) 100% 100%/12px 12px no-repeat,
+ linear-gradient(#fcfcfd, #fcfcfd) 50% 50%/calc(100% - 4px) calc(100% - 24px) no-repeat,
+ linear-gradient(#fcfcfd, #fcfcfd) 50% 50%/calc(100% - 24px) calc(100% - 4px) no-repeat,
+ radial-gradient(at 100% 100%, rgba(45,13,238,0.8) 0%, transparent 70%),
+ radial-gradient(at 100% 0%, rgba(45,13,238,0.8) 0%, transparent 70%),
+ radial-gradient(at 0% 0%, rgba(42,135,245,0.8) 0%, transparent 70%),
+ radial-gradient(at 0% 100%, rgba(42,135,245,0.8) 0%, transparent 70%);
+ border-radius: 12px;
+ padding: 2px;
+ box-sizing: border-box;
+}
+
+.warningBorder {
+ border: 2px solid #F79009;
+ border-radius: 12px;
+}
+
+.optionWrap {
+ display: none;
+}
+
+.boxHeader:hover .optionWrap {
+ display: flex;
+}
diff --git a/app/components/app/configuration/config-var/config-modal/field.tsx b/app/components/app/configuration/config-var/config-modal/field.tsx
new file mode 100644
index 0000000..78bd2d9
--- /dev/null
+++ b/app/components/app/configuration/config-var/config-modal/field.tsx
@@ -0,0 +1,24 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+
+type Props = {
+ className?: string
+ title: string
+ children: React.JSX.Element
+}
+
+const Field: FC<Props> = ({
+ className,
+ title,
+ children,
+}) => {
+ return (
+ <div className={cn(className)}>
+ <div className='system-sm-semibold leading-8 text-text-secondary'>{title}</div>
+ <div>{children}</div>
+ </div>
+ )
+}
+export default React.memo(Field)
diff --git a/app/components/app/configuration/config-var/config-modal/index.tsx b/app/components/app/configuration/config-var/config-modal/index.tsx
new file mode 100644
index 0000000..4b6bfda
--- /dev/null
+++ b/app/components/app/configuration/config-var/config-modal/index.tsx
@@ -0,0 +1,249 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import produce from 'immer'
+import ModalFoot from '../modal-foot'
+import ConfigSelect from '../config-select'
+import ConfigString from '../config-string'
+import SelectTypeItem from '../select-type-item'
+import Field from './field'
+import Input from '@/app/components/base/input'
+import Toast from '@/app/components/base/toast'
+import { checkKeys, getNewVarInWorkflow } from '@/utils/var'
+import ConfigContext from '@/context/debug-configuration'
+import type { InputVar, MoreInfo, UploadFileSetting } from '@/app/components/workflow/types'
+import Modal from '@/app/components/base/modal'
+import { ChangeType, InputVarType, SupportUploadFileTypes } from '@/app/components/workflow/types'
+import FileUploadSetting from '@/app/components/workflow/nodes/_base/components/file-upload-setting'
+import Checkbox from '@/app/components/base/checkbox'
+import { DEFAULT_FILE_UPLOAD_SETTING } from '@/app/components/workflow/constants'
+import { DEFAULT_VALUE_MAX_LEN } from '@/config'
+
+const TEXT_MAX_LENGTH = 256
+
+export type IConfigModalProps = {
+ isCreate?: boolean
+ payload?: InputVar
+ isShow: boolean
+ varKeys?: string[]
+ onClose: () => void
+ onConfirm: (newValue: InputVar, moreInfo?: MoreInfo) => void
+ supportFile?: boolean
+}
+
+const ConfigModal: FC<IConfigModalProps> = ({
+ isCreate,
+ payload,
+ isShow,
+ onClose,
+ onConfirm,
+ supportFile,
+}) => {
+ const { modelConfig } = useContext(ConfigContext)
+ const { t } = useTranslation()
+ const [tempPayload, setTempPayload] = useState<InputVar>(payload || getNewVarInWorkflow('') as any)
+ const { type, label, variable, options, max_length } = tempPayload
+ const modalRef = useRef<HTMLDivElement>(null)
+ useEffect(() => {
+ // To fix the first input element auto focus, then directly close modal will raise error
+ if (isShow)
+ modalRef.current?.focus()
+ }, [isShow])
+
+ const isStringInput = type === InputVarType.textInput || type === InputVarType.paragraph
+ const checkVariableName = useCallback((value: string, canBeEmpty?: boolean) => {
+ const { isValid, errorMessageKey } = checkKeys([value], canBeEmpty)
+ if (!isValid) {
+ Toast.notify({
+ type: 'error',
+ message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: t('appDebug.variableConfig.varName') }),
+ })
+ return false
+ }
+ return true
+ }, [t])
+ const handlePayloadChange = useCallback((key: string) => {
+ return (value: any) => {
+ setTempPayload((prev) => {
+ const newPayload = {
+ ...prev,
+ [key]: value,
+ }
+
+ return newPayload
+ })
+ }
+ }, [])
+
+ const handleTypeChange = useCallback((type: InputVarType) => {
+ return () => {
+ const newPayload = produce(tempPayload, (draft) => {
+ draft.type = type
+ if ([InputVarType.singleFile, InputVarType.multiFiles].includes(type)) {
+ (Object.keys(DEFAULT_FILE_UPLOAD_SETTING)).forEach((key) => {
+ if (key !== 'max_length')
+ (draft as any)[key] = (DEFAULT_FILE_UPLOAD_SETTING as any)[key]
+ })
+ if (type === InputVarType.multiFiles)
+ draft.max_length = DEFAULT_FILE_UPLOAD_SETTING.max_length
+ }
+ if (type === InputVarType.paragraph)
+ draft.max_length = DEFAULT_VALUE_MAX_LEN
+ })
+ setTempPayload(newPayload)
+ }
+ }, [tempPayload])
+
+ const handleVarKeyBlur = useCallback((e: any) => {
+ const varName = e.target.value
+ if (!checkVariableName(varName, true) || tempPayload.label)
+ return
+
+ setTempPayload((prev) => {
+ return {
+ ...prev,
+ label: varName,
+ }
+ })
+ }, [checkVariableName, tempPayload.label])
+
+ const handleConfirm = () => {
+ const moreInfo = tempPayload.variable === payload?.variable
+ ? undefined
+ : {
+ type: ChangeType.changeVarName,
+ payload: { beforeKey: payload?.variable || '', afterKey: tempPayload.variable },
+ }
+
+ const isVariableNameValid = checkVariableName(tempPayload.variable)
+ if (!isVariableNameValid)
+ return
+
+ // TODO: check if key already exists. should the consider the edit case
+ // if (varKeys.map(key => key?.trim()).includes(tempPayload.variable.trim())) {
+ // Toast.notify({
+ // type: 'error',
+ // message: t('appDebug.varKeyError.keyAlreadyExists', { key: tempPayload.variable }),
+ // })
+ // return
+ // }
+
+ if (!tempPayload.label) {
+ Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.labelNameRequired') })
+ return
+ }
+ if (isStringInput || type === InputVarType.number) {
+ onConfirm(tempPayload, moreInfo)
+ }
+ else if (type === InputVarType.select) {
+ if (options?.length === 0) {
+ Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.atLeastOneOption') })
+ return
+ }
+ const obj: Record<string, boolean> = {}
+ let hasRepeatedItem = false
+ options?.forEach((o) => {
+ if (obj[o]) {
+ hasRepeatedItem = true
+ return
+ }
+ obj[o] = true
+ })
+ if (hasRepeatedItem) {
+ Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.optionRepeat') })
+ return
+ }
+ onConfirm(tempPayload, moreInfo)
+ }
+ else if ([InputVarType.singleFile, InputVarType.multiFiles].includes(type)) {
+ if (tempPayload.allowed_file_types?.length === 0) {
+ const errorMessages = t('workflow.errorMsg.fieldRequired', { field: t('appDebug.variableConfig.file.supportFileTypes') })
+ Toast.notify({ type: 'error', message: errorMessages })
+ return
+ }
+ if (tempPayload.allowed_file_types?.includes(SupportUploadFileTypes.custom) && !tempPayload.allowed_file_extensions?.length) {
+ const errorMessages = t('workflow.errorMsg.fieldRequired', { field: t('appDebug.variableConfig.file.custom.name') })
+ Toast.notify({ type: 'error', message: errorMessages })
+ return
+ }
+ onConfirm(tempPayload, moreInfo)
+ }
+ else {
+ onConfirm(tempPayload, moreInfo)
+ }
+ }
+
+ return (
+ <Modal
+ title={t(`appDebug.variableConfig.${isCreate ? 'addModalTitle' : 'editModalTitle'}`)}
+ isShow={isShow}
+ onClose={onClose}
+ >
+ <div className='mb-8' ref={modalRef} tabIndex={-1}>
+ <div className='space-y-2'>
+
+ <Field title={t('appDebug.variableConfig.fieldType')}>
+ <div className='grid grid-cols-3 gap-2'>
+ <SelectTypeItem type={InputVarType.textInput} selected={type === InputVarType.textInput} onClick={handleTypeChange(InputVarType.textInput)} />
+ <SelectTypeItem type={InputVarType.paragraph} selected={type === InputVarType.paragraph} onClick={handleTypeChange(InputVarType.paragraph)} />
+ <SelectTypeItem type={InputVarType.select} selected={type === InputVarType.select} onClick={handleTypeChange(InputVarType.select)} />
+ <SelectTypeItem type={InputVarType.number} selected={type === InputVarType.number} onClick={handleTypeChange(InputVarType.number)} />
+ {supportFile && <>
+ <SelectTypeItem type={InputVarType.singleFile} selected={type === InputVarType.singleFile} onClick={handleTypeChange(InputVarType.singleFile)} />
+ <SelectTypeItem type={InputVarType.multiFiles} selected={type === InputVarType.multiFiles} onClick={handleTypeChange(InputVarType.multiFiles)} />
+ </>}
+ </div>
+ </Field>
+
+ <Field title={t('appDebug.variableConfig.varName')}>
+ <Input
+ value={variable}
+ onChange={e => handlePayloadChange('variable')(e.target.value)}
+ onBlur={handleVarKeyBlur}
+ placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
+ />
+ </Field>
+ <Field title={t('appDebug.variableConfig.labelName')}>
+ <Input
+ value={label as string}
+ onChange={e => handlePayloadChange('label')(e.target.value)}
+ placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
+ />
+ </Field>
+
+ {isStringInput && (
+ <Field title={t('appDebug.variableConfig.maxLength')}>
+ <ConfigString maxLength={type === InputVarType.textInput ? TEXT_MAX_LENGTH : Infinity} modelId={modelConfig.model_id} value={max_length} onChange={handlePayloadChange('max_length')} />
+ </Field>
+
+ )}
+ {type === InputVarType.select && (
+ <Field title={t('appDebug.variableConfig.options')}>
+ <ConfigSelect options={options || []} onChange={handlePayloadChange('options')} />
+ </Field>
+ )}
+
+ {[InputVarType.singleFile, InputVarType.multiFiles].includes(type) && (
+ <FileUploadSetting
+ payload={tempPayload as UploadFileSetting}
+ onChange={(p: UploadFileSetting) => setTempPayload(p as InputVar)}
+ isMultiple={type === InputVarType.multiFiles}
+ />
+ )}
+
+ <div className='!mt-5 flex h-6 items-center space-x-2'>
+ <Checkbox checked={tempPayload.required} onCheck={() => handlePayloadChange('required')(!tempPayload.required)} />
+ <span className='system-sm-semibold text-text-secondary'>{t('appDebug.variableConfig.required')}</span>
+ </div>
+ </div>
+ </div>
+ <ModalFoot
+ onConfirm={handleConfirm}
+ onCancel={onClose}
+ />
+ </Modal>
+ )
+}
+export default React.memo(ConfigModal)
diff --git a/app/components/app/configuration/config-var/config-select/index.spec.tsx b/app/components/app/configuration/config-var/config-select/index.spec.tsx
new file mode 100644
index 0000000..18df318
--- /dev/null
+++ b/app/components/app/configuration/config-var/config-select/index.spec.tsx
@@ -0,0 +1,82 @@
+import { fireEvent, render, screen } from '@testing-library/react'
+import ConfigSelect from './index'
+
+jest.mock('react-sortablejs', () => ({
+ ReactSortable: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
+}))
+
+jest.mock('react-i18next', () => ({
+ useTranslation: () => ({
+ t: (key: string) => key,
+ }),
+}))
+
+describe('ConfigSelect Component', () => {
+ const defaultProps = {
+ options: ['Option 1', 'Option 2'],
+ onChange: jest.fn(),
+ }
+
+ afterEach(() => {
+ jest.clearAllMocks()
+ })
+
+ it('renders all options', () => {
+ render(<ConfigSelect {...defaultProps} />)
+
+ defaultProps.options.forEach((option) => {
+ expect(screen.getByDisplayValue(option)).toBeInTheDocument()
+ })
+ })
+
+ it('renders add button', () => {
+ render(<ConfigSelect {...defaultProps} />)
+
+ expect(screen.getByText('appDebug.variableConfig.addOption')).toBeInTheDocument()
+ })
+
+ it('handles option deletion', () => {
+ render(<ConfigSelect {...defaultProps} />)
+ const optionContainer = screen.getByDisplayValue('Option 1').closest('div')
+ const deleteButton = optionContainer?.querySelector('div[role="button"]')
+
+ if (!deleteButton) return
+ fireEvent.click(deleteButton)
+ expect(defaultProps.onChange).toHaveBeenCalledWith(['Option 2'])
+ })
+
+ it('handles adding new option', () => {
+ render(<ConfigSelect {...defaultProps} />)
+ const addButton = screen.getByText('appDebug.variableConfig.addOption')
+
+ fireEvent.click(addButton)
+
+ expect(defaultProps.onChange).toHaveBeenCalledWith([...defaultProps.options, ''])
+ })
+
+ it('applies focus styles on input focus', () => {
+ render(<ConfigSelect {...defaultProps} />)
+ const firstInput = screen.getByDisplayValue('Option 1')
+
+ fireEvent.focus(firstInput)
+
+ expect(firstInput.closest('div')).toHaveClass('border-components-input-border-active')
+ })
+
+ it('applies delete hover styles', () => {
+ render(<ConfigSelect {...defaultProps} />)
+ const optionContainer = screen.getByDisplayValue('Option 1').closest('div')
+ const deleteButton = optionContainer?.querySelector('div[role="button"]')
+
+ if (!deleteButton) return
+ fireEvent.mouseEnter(deleteButton)
+ expect(optionContainer).toHaveClass('border-components-input-border-destructive')
+ })
+
+ it('renders empty state correctly', () => {
+ render(<ConfigSelect options={[]} onChange={defaultProps.onChange} />)
+
+ expect(screen.queryByRole('textbox')).not.toBeInTheDocument()
+ expect(screen.getByText('appDebug.variableConfig.addOption')).toBeInTheDocument()
+ })
+})
diff --git a/app/components/app/configuration/config-var/config-select/index.tsx b/app/components/app/configuration/config-var/config-select/index.tsx
new file mode 100644
index 0000000..40ddaef
--- /dev/null
+++ b/app/components/app/configuration/config-var/config-select/index.tsx
@@ -0,0 +1,96 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { RiAddLine, RiDeleteBinLine, RiDraggable } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { ReactSortable } from 'react-sortablejs'
+import cn from '@/utils/classnames'
+
+export type Options = string[]
+export type IConfigSelectProps = {
+ options: Options
+ onChange: (options: Options) => void
+}
+
+const ConfigSelect: FC<IConfigSelectProps> = ({
+ options,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const [focusID, setFocusID] = useState<number | null>(null)
+ const [deletingID, setDeletingID] = useState<number | null>(null)
+
+ const optionList = options.map((content, index) => {
+ return ({
+ id: index,
+ name: content,
+ })
+ })
+
+ return (
+ <div>
+ {options.length > 0 && (
+ <div className='mb-1'>
+ <ReactSortable
+ className="space-y-1"
+ list={optionList}
+ setList={list => onChange(list.map(item => item.name))}
+ handle='.handle'
+ ghostClass="opacity-50"
+ animation={150}
+ >
+ {options.map((o, index) => (
+ <div
+ className={cn(
+ 'group relative flex items-center rounded-lg border border-components-panel-border-subtle bg-components-panel-on-panel-item-bg pl-2.5 hover:bg-components-panel-on-panel-item-bg-hover',
+ focusID === index && 'border-components-input-border-active bg-components-input-bg-active hover:border-components-input-border-active hover:bg-components-input-bg-active',
+ deletingID === index && 'border-components-input-border-destructive bg-state-destructive-hover hover:border-components-input-border-destructive hover:bg-state-destructive-hover',
+ )}
+ key={index}
+ >
+ <RiDraggable className='handle h-4 w-4 cursor-grab text-text-quaternary' />
+ <input
+ key={index}
+ type='input'
+ value={o || ''}
+ onChange={(e) => {
+ const value = e.target.value
+ onChange(options.map((item, i) => {
+ if (index === i)
+ return value
+
+ return item
+ }))
+ }}
+ className={'h-9 w-full grow cursor-pointer overflow-x-auto rounded-lg border-0 bg-transparent pl-1.5 pr-8 text-sm leading-9 text-text-secondary focus:outline-none'}
+ onFocus={() => setFocusID(index)}
+ onBlur={() => setFocusID(null)}
+ />
+ <div
+ role='button'
+ className='absolute right-1.5 top-1/2 block translate-y-[-50%] cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive'
+ onClick={() => {
+ onChange(options.filter((_, i) => index !== i))
+ }}
+ onMouseEnter={() => setDeletingID(index)}
+ onMouseLeave={() => setDeletingID(null)}
+ >
+ <RiDeleteBinLine className='h-3.5 w-3.5' />
+ </div>
+ </div>
+ ))}
+ </ReactSortable>
+ </div>
+ )}
+
+ <div
+ onClick={() => { onChange([...options, '']) }}
+ className='mt-1 flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-components-button-tertiary-bg px-3 text-components-button-tertiary-text hover:bg-components-button-tertiary-bg-hover'>
+ <RiAddLine className='h-4 w-4' />
+ <div className='system-sm-medium text-[13px]'>{t('appDebug.variableConfig.addOption')}</div>
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(ConfigSelect)
diff --git a/app/components/app/configuration/config-var/config-string/index.tsx b/app/components/app/configuration/config-var/config-string/index.tsx
new file mode 100644
index 0000000..78f185b
--- /dev/null
+++ b/app/components/app/configuration/config-var/config-string/index.tsx
@@ -0,0 +1,45 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect } from 'react'
+import Input from '@/app/components/base/input'
+
+export type IConfigStringProps = {
+ value: number | undefined
+ maxLength: number
+ modelId: string
+ onChange: (value: number | undefined) => void
+}
+
+const ConfigString: FC<IConfigStringProps> = ({
+ value,
+ onChange,
+ maxLength,
+}) => {
+ useEffect(() => {
+ if (value && value > maxLength)
+ onChange(maxLength)
+ }, [value, maxLength, onChange])
+
+ return (
+ <div>
+ <Input
+ type="number"
+ max={maxLength}
+ min={1}
+ value={value || ''}
+ onChange={(e) => {
+ let value = Number.parseInt(e.target.value, 10)
+ if (value > maxLength)
+ value = maxLength
+
+ else if (value < 1)
+ value = 1
+
+ onChange(value)
+ }}
+ />
+ </div>
+ )
+}
+
+export default React.memo(ConfigString)
diff --git a/app/components/app/configuration/config-var/index.tsx b/app/components/app/configuration/config-var/index.tsx
new file mode 100644
index 0000000..612d476
--- /dev/null
+++ b/app/components/app/configuration/config-var/index.tsx
@@ -0,0 +1,271 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import { useContext } from 'use-context-selector'
+import produce from 'immer'
+import Panel from '../base/feature-panel'
+import EditModal from './config-modal'
+import VarItem from './var-item'
+import SelectVarType from './select-var-type'
+import Tooltip from '@/app/components/base/tooltip'
+import type { PromptVariable } from '@/models/debug'
+import { DEFAULT_VALUE_MAX_LEN } from '@/config'
+import { getNewVar } from '@/utils/var'
+import Toast from '@/app/components/base/toast'
+import Confirm from '@/app/components/base/confirm'
+import ConfigContext from '@/context/debug-configuration'
+import { AppType } from '@/types/app'
+import type { ExternalDataTool } from '@/models/common'
+import { useModalContext } from '@/context/modal-context'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import type { InputVar } from '@/app/components/workflow/types'
+import { InputVarType } from '@/app/components/workflow/types'
+
+export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL'
+
+type ExternalDataToolParams = {
+ key: string
+ type: string
+ index: number
+ name: string
+ config?: Record<string, any>
+ icon?: string
+ icon_background?: string
+}
+
+export type IConfigVarProps = {
+ promptVariables: PromptVariable[]
+ readonly?: boolean
+ onPromptVariablesChange?: (promptVariables: PromptVariable[]) => void
+}
+
+const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVariablesChange }) => {
+ const { t } = useTranslation()
+ const {
+ mode,
+ dataSets,
+ } = useContext(ConfigContext)
+ const { eventEmitter } = useEventEmitterContextContext()
+
+ const hasVar = promptVariables.length > 0
+ const [currIndex, setCurrIndex] = useState<number>(-1)
+ const currItem = currIndex !== -1 ? promptVariables[currIndex] : null
+ const currItemToEdit: InputVar | null = (() => {
+ if (!currItem)
+ return null
+
+ return {
+ ...currItem,
+ label: currItem.name,
+ variable: currItem.key,
+ type: currItem.type === 'string' ? InputVarType.textInput : currItem.type,
+ } as InputVar
+ })()
+ const updatePromptVariableItem = (payload: InputVar) => {
+ const newPromptVariables = produce(promptVariables, (draft) => {
+ const { variable, label, type, ...rest } = payload
+ draft[currIndex] = {
+ ...rest,
+ type: type === InputVarType.textInput ? 'string' : type,
+ key: variable,
+ name: label as string,
+ }
+
+ if (payload.type === InputVarType.textInput)
+ draft[currIndex].max_length = draft[currIndex].max_length || DEFAULT_VALUE_MAX_LEN
+
+ if (payload.type !== InputVarType.select)
+ delete draft[currIndex].options
+ })
+
+ onPromptVariablesChange?.(newPromptVariables)
+ }
+
+ const { setShowExternalDataToolModal } = useModalContext()
+
+ const handleOpenExternalDataToolModal = (
+ { key, type, index, name, config, icon, icon_background }: ExternalDataToolParams,
+ oldPromptVariables: PromptVariable[],
+ ) => {
+ setShowExternalDataToolModal({
+ payload: {
+ type,
+ variable: key,
+ label: name,
+ config,
+ icon,
+ icon_background,
+ },
+ onSaveCallback: (newExternalDataTool: ExternalDataTool) => {
+ const newPromptVariables = oldPromptVariables.map((item, i) => {
+ if (i === index) {
+ return {
+ key: newExternalDataTool.variable as string,
+ name: newExternalDataTool.label as string,
+ enabled: newExternalDataTool.enabled,
+ type: newExternalDataTool.type as string,
+ config: newExternalDataTool.config,
+ required: item.required,
+ icon: newExternalDataTool.icon,
+ icon_background: newExternalDataTool.icon_background,
+ }
+ }
+ return item
+ })
+ onPromptVariablesChange?.(newPromptVariables)
+ },
+ onCancelCallback: () => {
+ if (!key)
+ onPromptVariablesChange?.(promptVariables.filter((_, i) => i !== index))
+ },
+ onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
+ for (let i = 0; i < promptVariables.length; i++) {
+ if (promptVariables[i].key === newExternalDataTool.variable && i !== index) {
+ Toast.notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
+ return false
+ }
+ }
+
+ return true
+ },
+ })
+ }
+
+ const handleAddVar = (type: string) => {
+ const newVar = getNewVar('', type)
+ const newPromptVariables = [...promptVariables, newVar]
+ onPromptVariablesChange?.(newPromptVariables)
+
+ if (type === 'api') {
+ handleOpenExternalDataToolModal({
+ type,
+ key: newVar.key,
+ name: newVar.name,
+ index: promptVariables.length,
+ }, newPromptVariables)
+ }
+ }
+
+ eventEmitter?.useSubscription((v: any) => {
+ if (v.type === ADD_EXTERNAL_DATA_TOOL) {
+ const payload = v.payload
+ onPromptVariablesChange?.([
+ ...promptVariables,
+ {
+ key: payload.variable as string,
+ name: payload.label as string,
+ enabled: payload.enabled,
+ type: payload.type as string,
+ config: payload.config,
+ required: true,
+ icon: payload.icon,
+ icon_background: payload.icon_background,
+ },
+ ])
+ }
+ })
+
+ const [isShowDeleteContextVarModal, { setTrue: showDeleteContextVarModal, setFalse: hideDeleteContextVarModal }] = useBoolean(false)
+ const [removeIndex, setRemoveIndex] = useState<number | null>(null)
+ const didRemoveVar = (index: number) => {
+ onPromptVariablesChange?.(promptVariables.filter((_, i) => i !== index))
+ }
+
+ const handleRemoveVar = (index: number) => {
+ const removeVar = promptVariables[index]
+
+ if (mode === AppType.completion && dataSets.length > 0 && removeVar.is_context_var) {
+ showDeleteContextVarModal()
+ setRemoveIndex(index)
+ return
+ }
+ didRemoveVar(index)
+ }
+
+ // const [currKey, setCurrKey] = useState<string | null>(null)
+ const [isShowEditModal, { setTrue: showEditModal, setFalse: hideEditModal }] = useBoolean(false)
+
+ const handleConfig = ({ key, type, index, name, config, icon, icon_background }: ExternalDataToolParams) => {
+ // setCurrKey(key)
+ setCurrIndex(index)
+ if (type !== 'string' && type !== 'paragraph' && type !== 'select' && type !== 'number') {
+ handleOpenExternalDataToolModal({ key, type, index, name, config, icon, icon_background }, promptVariables)
+ return
+ }
+
+ showEditModal()
+ }
+ return (
+ <Panel
+ className="mt-2"
+ title={
+ <div className='flex items-center'>
+ <div className='mr-1'>{t('appDebug.variableTitle')}</div>
+ {!readonly && (
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]'>
+ {t('appDebug.variableTip')}
+ </div>
+ }
+ />
+ )}
+ </div>
+ }
+ headerRight={!readonly ? <SelectVarType onChange={handleAddVar} /> : null}
+ noBodySpacing
+ >
+ {!hasVar && (
+ <div className='mt-1 px-3 pb-3'>
+ <div className='pb-1 pt-2 text-xs text-text-tertiary'>{t('appDebug.notSetVar')}</div>
+ </div>
+ )}
+ {hasVar && (
+ <div className='mt-1 px-3 pb-3'>
+ {promptVariables.map(({ key, name, type, required, config, icon, icon_background }, index) => (
+ <VarItem
+ key={index}
+ readonly={readonly}
+ name={key}
+ label={name}
+ required={!!required}
+ type={type}
+ onEdit={() => handleConfig({ type, key, index, name, config, icon, icon_background })}
+ onRemove={() => handleRemoveVar(index)}
+ />
+ ))}
+ </div>
+ )}
+
+ {isShowEditModal && (
+ <EditModal
+ payload={currItemToEdit!}
+ isShow={isShowEditModal}
+ onClose={hideEditModal}
+ onConfirm={(item) => {
+ updatePromptVariableItem(item)
+ hideEditModal()
+ }}
+ varKeys={promptVariables.map(v => v.key)}
+ />
+ )}
+
+ {isShowDeleteContextVarModal && (
+ <Confirm
+ isShow={isShowDeleteContextVarModal}
+ title={t('appDebug.feature.dataSet.queryVariable.deleteContextVarTitle', { varName: promptVariables[removeIndex as number]?.name })}
+ content={t('appDebug.feature.dataSet.queryVariable.deleteContextVarTip')}
+ onConfirm={() => {
+ didRemoveVar(removeIndex as number)
+ hideDeleteContextVarModal()
+ }}
+ onCancel={hideDeleteContextVarModal}
+ />
+ )}
+
+ </Panel>
+ )
+}
+export default React.memo(ConfigVar)
diff --git a/app/components/app/configuration/config-var/input-type-icon.tsx b/app/components/app/configuration/config-var/input-type-icon.tsx
new file mode 100644
index 0000000..edd2dc6
--- /dev/null
+++ b/app/components/app/configuration/config-var/input-type-icon.tsx
@@ -0,0 +1,44 @@
+'use client'
+import React from 'react'
+import type { FC } from 'react'
+import { ApiConnection } from '@/app/components/base/icons/src/vender/solid/development'
+import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
+import { InputVarType } from '@/app/components/workflow/types'
+
+export type IInputTypeIconProps = {
+ type: 'string' | 'select'
+ className: string
+}
+
+const IconMap = (type: IInputTypeIconProps['type'], className: string) => {
+ const classNames = `w-3.5 h-3.5 ${className}`
+ const icons = {
+ string: (
+ <InputVarTypeIcon type={InputVarType.textInput} className={classNames} />
+ ),
+ paragraph: (
+ <InputVarTypeIcon type={InputVarType.paragraph} className={classNames} />
+ ),
+ select: (
+ <InputVarTypeIcon type={InputVarType.select} className={classNames} />
+ ),
+ number: (
+ <InputVarTypeIcon type={InputVarType.number} className={classNames} />
+ ),
+ api: (
+ <ApiConnection className={classNames} />
+ ),
+ }
+
+ return icons[type]
+}
+
+const InputTypeIcon: FC<IInputTypeIconProps> = ({
+ type,
+ className,
+}) => {
+ const Icon = IconMap(type, className)
+ return Icon
+}
+
+export default React.memo(InputTypeIcon)
diff --git a/app/components/app/configuration/config-var/modal-foot.tsx b/app/components/app/configuration/config-var/modal-foot.tsx
new file mode 100644
index 0000000..a73ebe4
--- /dev/null
+++ b/app/components/app/configuration/config-var/modal-foot.tsx
@@ -0,0 +1,24 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Button from '@/app/components/base/button'
+
+export type IModalFootProps = {
+ onConfirm: () => void
+ onCancel: () => void
+}
+
+const ModalFoot: FC<IModalFootProps> = ({
+ onConfirm,
+ onCancel,
+}) => {
+ const { t } = useTranslation()
+ return (
+ <div className='flex justify-end gap-2'>
+ <Button onClick={onCancel}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' onClick={onConfirm}>{t('common.operation.save')}</Button>
+ </div>
+ )
+}
+export default React.memo(ModalFoot)
diff --git a/app/components/app/configuration/config-var/select-type-item/index.tsx b/app/components/app/configuration/config-var/select-type-item/index.tsx
new file mode 100644
index 0000000..a952bcf
--- /dev/null
+++ b/app/components/app/configuration/config-var/select-type-item/index.tsx
@@ -0,0 +1,41 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+import type { InputVarType } from '@/app/components/workflow/types'
+import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
+export type ISelectTypeItemProps = {
+ type: InputVarType
+ selected: boolean
+ onClick: () => void
+}
+
+const i18nFileTypeMap: Record<string, string> = {
+ 'file': 'single-file',
+ 'file-list': 'multi-files',
+}
+
+const SelectTypeItem: FC<ISelectTypeItemProps> = ({
+ type,
+ selected,
+ onClick,
+}) => {
+ const { t } = useTranslation()
+ const typeName = t(`appDebug.variableConfig.${i18nFileTypeMap[type] || type}`)
+
+ return (
+ <div
+ className={cn(
+ 'flex h-[58px] flex-col items-center justify-center space-y-1 rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary',
+ selected ? 'system-xs-medium border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg shadow-xs' : ' system-xs-regular cursor-pointer hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover hover:shadow-xs')}
+ onClick={onClick}
+ >
+ <div className='shrink-0'>
+ <InputVarTypeIcon type={type} className='h-5 w-5' />
+ </div>
+ <span>{typeName}</span>
+ </div>
+ )
+}
+export default React.memo(SelectTypeItem)
diff --git a/app/components/app/configuration/config-var/select-var-type.tsx b/app/components/app/configuration/config-var/select-var-type.tsx
new file mode 100644
index 0000000..f82e931
--- /dev/null
+++ b/app/components/app/configuration/config-var/select-var-type.tsx
@@ -0,0 +1,79 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { ApiConnection } from '@/app/components/base/icons/src/vender/solid/development'
+import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
+import { InputVarType } from '@/app/components/workflow/types'
+
+type Props = {
+ onChange: (value: string) => void
+}
+
+type ItemProps = {
+ text: string
+ value: string
+ Icon?: any
+ type?: InputVarType
+ onClick: (value: string) => void
+}
+
+const SelectItem: FC<ItemProps> = ({ text, type, value, Icon, onClick }) => {
+ return (
+ <div
+ className='flex h-8 cursor-pointer items-center rounded-lg px-3 hover:bg-gray-50'
+ onClick={() => onClick(value)}
+ >
+ {Icon ? <Icon className='h-4 w-4 text-gray-500' /> : <InputVarTypeIcon type={type!} className='h-4 w-4 text-gray-500' />}
+ <div className='ml-2 truncate text-xs text-gray-600'>{text}</div>
+ </div>
+ )
+}
+
+const SelectVarType: FC<Props> = ({
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const handleChange = (value: string) => {
+ onChange(value)
+ setOpen(false)
+ }
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 8,
+ crossAxis: -2,
+ }}
+ >
+ <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
+ <OperationBtn type='add' className={cn(open && 'bg-gray-200')} />
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 1000 }}>
+ <div className='min-w-[192px] rounded-lg border border-gray-200 bg-white shadow-lg'>
+ <div className='p-1'>
+ <SelectItem type={InputVarType.textInput} value='string' text={t('appDebug.variableConfig.string')} onClick={handleChange}></SelectItem>
+ <SelectItem type={InputVarType.paragraph} value='paragraph' text={t('appDebug.variableConfig.paragraph')} onClick={handleChange}></SelectItem>
+ <SelectItem type={InputVarType.select} value='select' text={t('appDebug.variableConfig.select')} onClick={handleChange}></SelectItem>
+ <SelectItem type={InputVarType.number} value='number' text={t('appDebug.variableConfig.number')} onClick={handleChange}></SelectItem>
+ </div>
+ <div className='h-[1px] bg-gray-100'></div>
+ <div className='p-1'>
+ <SelectItem Icon={ApiConnection} value='api' text={t('appDebug.variableConfig.apiBasedVar')} onClick={handleChange}></SelectItem>
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(SelectVarType)
diff --git a/app/components/app/configuration/config-var/var-item.tsx b/app/components/app/configuration/config-var/var-item.tsx
new file mode 100644
index 0000000..78ed4b1
--- /dev/null
+++ b/app/components/app/configuration/config-var/var-item.tsx
@@ -0,0 +1,72 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import {
+ RiDeleteBinLine,
+ RiEditLine,
+} from '@remixicon/react'
+import type { IInputTypeIconProps } from './input-type-icon'
+import IconTypeIcon from './input-type-icon'
+import { BracketsX as VarIcon } from '@/app/components/base/icons/src/vender/line/development'
+import Badge from '@/app/components/base/badge'
+import cn from '@/utils/classnames'
+
+type ItemProps = {
+ readonly?: boolean
+ name: string
+ label: string
+ required: boolean
+ type: string
+ onEdit: () => void
+ onRemove: () => void
+}
+
+const VarItem: FC<ItemProps> = ({
+ readonly,
+ name,
+ label,
+ required,
+ type,
+ onEdit,
+ onRemove,
+}) => {
+ const [isDeleting, setIsDeleting] = useState(false)
+
+ return (
+ <div className={cn('group relative mb-1 flex h-[34px] w-full items-center rounded-lg border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg pl-2.5 pr-3 shadow-xs last-of-type:mb-0 hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-sm', isDeleting && 'border-state-destructive-border hover:bg-state-destructive-hover', readonly && 'cursor-not-allowed opacity-30')}>
+ <VarIcon className='mr-1 h-4 w-4 shrink-0 text-text-accent' />
+ <div className='flex w-0 grow items-center'>
+ <div className='truncate' title={`${name} 路 ${label}`}>
+ <span className='system-sm-medium text-text-secondary'>{name}</span>
+ <span className='system-xs-regular px-1 text-text-quaternary'>路</span>
+ <span className='system-xs-medium text-text-tertiary'>{label}</span>
+ </div>
+ </div>
+ <div className='shrink-0'>
+ <div className={cn('flex items-center', !readonly && 'group-hover:hidden')}>
+ {required && <Badge text='required' />}
+ <span className='system-xs-regular pl-2 pr-1 text-text-tertiary'>{type}</span>
+ <IconTypeIcon type={type as IInputTypeIconProps['type']} className='text-text-tertiary' />
+ </div>
+ <div className={cn('hidden items-center justify-end rounded-lg', !readonly && 'group-hover:flex')}>
+ <div
+ className='mr-1 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-black/5'
+ onClick={onEdit}
+ >
+ <RiEditLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div
+ className='flex h-6 w-6 cursor-pointer items-center justify-center text-text-tertiary hover:text-text-destructive'
+ onClick={onRemove}
+ onMouseOver={() => setIsDeleting(true)}
+ onMouseLeave={() => setIsDeleting(false)}
+ >
+ <RiDeleteBinLine className='h-4 w-4' />
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default VarItem
diff --git a/app/components/app/configuration/config-vision/index.tsx b/app/components/app/configuration/config-vision/index.tsx
new file mode 100644
index 0000000..f719822
--- /dev/null
+++ b/app/components/app/configuration/config-vision/index.tsx
@@ -0,0 +1,112 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { useContext } from 'use-context-selector'
+import ParamConfig from './param-config'
+import { Vision } from '@/app/components/base/icons/src/vender/features'
+import Tooltip from '@/app/components/base/tooltip'
+// import OptionCard from '@/app/components/workflow/nodes/_base/components/option-card'
+import ConfigContext from '@/context/debug-configuration'
+// import { Resolution } from '@/types/app'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import Switch from '@/app/components/base/switch'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+
+const ConfigVision: FC = () => {
+ const { t } = useTranslation()
+ const { isShowVisionConfig, isAllowVideoUpload } = useContext(ConfigContext)
+ const file = useFeatures(s => s.features.file)
+ const featuresStore = useFeaturesStore()
+
+ const isImageEnabled = file?.allowed_file_types?.includes(SupportUploadFileTypes.image) ?? false
+
+ const handleChange = useCallback((value: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ if (value) {
+ draft.file!.allowed_file_types = Array.from(new Set([
+ ...(draft.file?.allowed_file_types || []),
+ SupportUploadFileTypes.image,
+ ...(isAllowVideoUpload ? [SupportUploadFileTypes.video] : []),
+ ]))
+ }
+ else {
+ draft.file!.allowed_file_types = draft.file!.allowed_file_types?.filter(
+ type => type !== SupportUploadFileTypes.image && (isAllowVideoUpload ? type !== SupportUploadFileTypes.video : true),
+ )
+ }
+
+ if (draft.file) {
+ draft.file.enabled = (draft.file.allowed_file_types?.length ?? 0) > 0
+ draft.file.image = {
+ ...(draft.file.image || {}),
+ enabled: value,
+ }
+ }
+ })
+ setFeatures(newFeatures)
+ }, [featuresStore, isAllowVideoUpload])
+
+ if (!isShowVisionConfig)
+ return null
+
+ return (
+ <div className='mt-2 flex items-center gap-2 rounded-xl border-l-[0.5px] border-t-[0.5px] border-effects-highlight bg-background-section-burn p-2'>
+ <div className='shrink-0 p-1'>
+ <div className='rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
+ <Vision className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ </div>
+ <div className='flex grow items-center'>
+ <div className='system-sm-semibold mr-1 text-text-secondary'>{t('appDebug.vision.name')}</div>
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]' >
+ {t('appDebug.vision.description')}
+ </div>
+ }
+ />
+ </div>
+ <div className='flex shrink-0 items-center'>
+ {/* <div className='mr-2 flex items-center gap-0.5'>
+ <div className='text-text-tertiary system-xs-medium-uppercase'>{t('appDebug.vision.visionSettings.resolution')}</div>
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]' >
+ {t('appDebug.vision.visionSettings.resolutionTooltip').split('\n').map(item => (
+ <div key={item}>{item}</div>
+ ))}
+ </div>
+ }
+ />
+ </div> */}
+ {/* <div className='flex items-center gap-1'>
+ <OptionCard
+ title={t('appDebug.vision.visionSettings.high')}
+ selected={file?.image?.detail === Resolution.high}
+ onSelect={() => handleChange(Resolution.high)}
+ />
+ <OptionCard
+ title={t('appDebug.vision.visionSettings.low')}
+ selected={file?.image?.detail === Resolution.low}
+ onSelect={() => handleChange(Resolution.low)}
+ />
+ </div> */}
+ <ParamConfig />
+ <div className='ml-1 mr-3 h-3.5 w-[1px] bg-divider-regular'></div>
+ <Switch
+ defaultValue={isImageEnabled}
+ onChange={handleChange}
+ size='md'
+ />
+ </div>
+ </div>
+ )
+}
+export default React.memo(ConfigVision)
diff --git a/app/components/app/configuration/config-vision/param-config-content.tsx b/app/components/app/configuration/config-vision/param-config-content.tsx
new file mode 100644
index 0000000..f0d8122
--- /dev/null
+++ b/app/components/app/configuration/config-vision/param-config-content.tsx
@@ -0,0 +1,142 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import OptionCard from '@/app/components/workflow/nodes/_base/components/option-card'
+import { Resolution, TransferMethod } from '@/types/app'
+import ParamItem from '@/app/components/base/param-item'
+import Tooltip from '@/app/components/base/tooltip'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { FileUpload } from '@/app/components/base/features/types'
+
+const MIN = 1
+const MAX = 6
+const ParamConfigContent: FC = () => {
+ const { t } = useTranslation()
+ const file = useFeatures(s => s.features.file)
+ const featuresStore = useFeaturesStore()
+
+ const handleChange = useCallback((data: FileUpload) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft.file = {
+ ...draft.file,
+ allowed_file_upload_methods: data.allowed_file_upload_methods,
+ number_limits: data.number_limits,
+ image: {
+ enabled: data.enabled,
+ detail: data.image?.detail,
+ transfer_methods: data.allowed_file_upload_methods,
+ number_limits: data.number_limits,
+ },
+ }
+ })
+ setFeatures(newFeatures)
+ }, [featuresStore])
+
+ return (
+ <div>
+ <div className='text-base font-semibold leading-6 text-text-primary'>{t('appDebug.vision.visionSettings.title')}</div>
+ <div className='space-y-6 pt-3'>
+ <div>
+ <div className='mb-2 flex items-center space-x-1'>
+ <div className='text-[13px] font-semibold leading-[18px] text-text-secondary'>{t('appDebug.vision.visionSettings.resolution')}</div>
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]' >
+ {t('appDebug.vision.visionSettings.resolutionTooltip').split('\n').map(item => (
+ <div key={item}>{item}</div>
+ ))}
+ </div>
+ }
+ />
+ </div>
+ <div className='flex items-center gap-1'>
+ <OptionCard
+ className='grow'
+ title={t('appDebug.vision.visionSettings.high')}
+ selected={file?.image?.detail === Resolution.high}
+ onSelect={() => handleChange({
+ ...file,
+ image: { detail: Resolution.high },
+ })}
+ />
+ <OptionCard
+ className='grow'
+ title={t('appDebug.vision.visionSettings.low')}
+ selected={file?.image?.detail === Resolution.low}
+ onSelect={() => handleChange({
+ ...file,
+ image: { detail: Resolution.low },
+ })}
+ />
+ </div>
+ </div>
+ <div>
+ <div className='mb-2 text-[13px] font-semibold leading-[18px] text-text-secondary'>{t('appDebug.vision.visionSettings.uploadMethod')}</div>
+ <div className='flex items-center gap-1'>
+ <OptionCard
+ className='grow'
+ title={t('appDebug.vision.visionSettings.both')}
+ selected={!!file?.allowed_file_upload_methods?.includes(TransferMethod.local_file) && !!file?.allowed_file_upload_methods?.includes(TransferMethod.remote_url)}
+ onSelect={() => handleChange({
+ ...file,
+ allowed_file_upload_methods: [TransferMethod.local_file, TransferMethod.remote_url],
+ })}
+ />
+ <OptionCard
+ className='grow'
+ title={t('appDebug.vision.visionSettings.localUpload')}
+ selected={!!file?.allowed_file_upload_methods?.includes(TransferMethod.local_file) && file?.allowed_file_upload_methods?.length === 1}
+ onSelect={() => handleChange({
+ ...file,
+ allowed_file_upload_methods: [TransferMethod.local_file],
+ })}
+ />
+ <OptionCard
+ className='grow'
+ title={t('appDebug.vision.visionSettings.url')}
+ selected={!!file?.allowed_file_upload_methods?.includes(TransferMethod.remote_url) && file?.allowed_file_upload_methods?.length === 1}
+ onSelect={() => handleChange({
+ ...file,
+ allowed_file_upload_methods: [TransferMethod.remote_url],
+ })}
+ />
+ </div>
+ </div>
+ <div>
+ <ParamItem
+ id='upload_limit'
+ className=''
+ name={t('appDebug.vision.visionSettings.uploadLimit')}
+ noTooltip
+ {...{
+ default: 2,
+ step: 1,
+ min: MIN,
+ max: MAX,
+ }}
+ value={file?.number_limits || 3}
+ enable={true}
+ onChange={(_key: string, value: number) => {
+ if (!value)
+ return
+
+ handleChange({
+ ...file,
+ number_limits: value,
+ })
+ }}
+ />
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(ParamConfigContent)
diff --git a/app/components/app/configuration/config-vision/param-config.tsx b/app/components/app/configuration/config-vision/param-config.tsx
new file mode 100644
index 0000000..5e4aac6
--- /dev/null
+++ b/app/components/app/configuration/config-vision/param-config.tsx
@@ -0,0 +1,42 @@
+'use client'
+import type { FC } from 'react'
+import { memo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiSettings2Line } from '@remixicon/react'
+import ParamConfigContent from './param-config-content'
+import Button from '@/app/components/base/button'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import cn from '@/utils/classnames'
+
+const ParamsConfig: FC = () => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 4,
+ }}
+ >
+ <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
+ <Button variant='ghost' size='small' className={cn('')}>
+ <RiSettings2Line className='h-3.5 w-3.5' />
+ <div className='ml-1'>{t('appDebug.voice.settings')}</div>
+ </Button>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 50 }}>
+ <div className='w-80 space-y-3 rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-lg sm:w-[412px]'>
+ <ParamConfigContent />
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default memo(ParamsConfig)
diff --git a/app/components/app/configuration/config/agent-setting-button.tsx b/app/components/app/configuration/config/agent-setting-button.tsx
new file mode 100644
index 0000000..b0a93d5
--- /dev/null
+++ b/app/components/app/configuration/config/agent-setting-button.tsx
@@ -0,0 +1,47 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiSettings2Line } from '@remixicon/react'
+import AgentSetting from './agent/agent-setting'
+import Button from '@/app/components/base/button'
+import type { AgentConfig } from '@/models/debug'
+
+type Props = {
+ isFunctionCall: boolean
+ isChatModel: boolean
+ agentConfig?: AgentConfig
+ onAgentSettingChange: (payload: AgentConfig) => void
+}
+
+const AgentSettingButton: FC<Props> = ({
+ onAgentSettingChange,
+ isFunctionCall,
+ isChatModel,
+ agentConfig,
+}) => {
+ const { t } = useTranslation()
+ const [isShowAgentSetting, setIsShowAgentSetting] = useState(false)
+
+ return (
+ <>
+ <Button onClick={() => setIsShowAgentSetting(true)} className='mr-2 shrink-0'>
+ <RiSettings2Line className='mr-1 h-4 w-4 text-text-tertiary' />
+ {t('appDebug.agent.setting.name')}
+ </Button>
+ {isShowAgentSetting && (
+ <AgentSetting
+ isFunctionCall={isFunctionCall}
+ payload={agentConfig as AgentConfig}
+ isChatModel={isChatModel}
+ onSave={(payloadNew) => {
+ onAgentSettingChange(payloadNew)
+ setIsShowAgentSetting(false)
+ }}
+ onCancel={() => setIsShowAgentSetting(false)}
+ />
+ )}
+ </>
+ )
+}
+export default React.memo(AgentSettingButton)
diff --git a/app/components/app/configuration/config/agent/agent-setting/index.tsx b/app/components/app/configuration/config/agent/agent-setting/index.tsx
new file mode 100644
index 0000000..26a1242
--- /dev/null
+++ b/app/components/app/configuration/config/agent/agent-setting/index.tsx
@@ -0,0 +1,165 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import { useClickAway } from 'ahooks'
+import ItemPanel from './item-panel'
+import Button from '@/app/components/base/button'
+import { CuteRobot } from '@/app/components/base/icons/src/vender/solid/communication'
+import { Unblur } from '@/app/components/base/icons/src/vender/solid/education'
+import Slider from '@/app/components/base/slider'
+import type { AgentConfig } from '@/models/debug'
+import { DEFAULT_AGENT_PROMPT, MAX_ITERATIONS_NUM } from '@/config'
+
+type Props = {
+ isChatModel: boolean
+ payload: AgentConfig
+ isFunctionCall: boolean
+ onCancel: () => void
+ onSave: (payload: any) => void
+}
+
+const maxIterationsMin = 1
+
+const AgentSetting: FC<Props> = ({
+ isChatModel,
+ payload,
+ isFunctionCall,
+ onCancel,
+ onSave,
+}) => {
+ const { t } = useTranslation()
+ const [tempPayload, setTempPayload] = useState(payload)
+ const ref = useRef(null)
+ const [mounted, setMounted] = useState(false)
+
+ useClickAway(() => {
+ if (mounted)
+ onCancel()
+ }, ref)
+
+ useEffect(() => {
+ setMounted(true)
+ }, [])
+
+ const handleSave = () => {
+ onSave(tempPayload)
+ }
+
+ return (
+ <div className='fixed inset-0 z-[100] flex justify-end overflow-hidden p-2'
+ style={{
+ backgroundColor: 'rgba(16, 24, 40, 0.20)',
+ }}
+ >
+ <div
+ ref={ref}
+ className='flex h-full w-[640px] flex-col overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl'
+ >
+ <div className='flex h-14 shrink-0 items-center justify-between border-b border-divider-regular pl-6 pr-5'>
+ <div className='flex flex-col text-base font-semibold text-text-primary'>
+ <div className='leading-6'>{t('appDebug.agent.setting.name')}</div>
+ </div>
+ <div className='flex items-center'>
+ <div
+ onClick={onCancel}
+ className='flex h-6 w-6 cursor-pointer items-center justify-center'
+ >
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ {/* Body */}
+ <div className='grow overflow-y-auto border-b p-6 pb-[68px] pt-5' style={{
+ borderBottom: 'rgba(0, 0, 0, 0.05)',
+ }}>
+ {/* Agent Mode */}
+ <ItemPanel
+ className='mb-4'
+ icon={
+ <CuteRobot className='h-4 w-4 text-indigo-600' />
+ }
+ name={t('appDebug.agent.agentMode')}
+ description={t('appDebug.agent.agentModeDes')}
+ >
+ <div className='text-[13px] font-medium leading-[18px] text-text-primary'>{isFunctionCall ? t('appDebug.agent.agentModeType.functionCall') : t('appDebug.agent.agentModeType.ReACT')}</div>
+ </ItemPanel>
+
+ <ItemPanel
+ className='mb-4'
+ icon={
+ <Unblur className='h-4 w-4 text-[#FB6514]' />
+ }
+ name={t('appDebug.agent.setting.maximumIterations.name')}
+ description={t('appDebug.agent.setting.maximumIterations.description')}
+ >
+ <div className='flex items-center'>
+ <Slider
+ className='mr-3 w-[156px]'
+ min={maxIterationsMin}
+ max={MAX_ITERATIONS_NUM}
+ value={tempPayload.max_iteration}
+ onChange={(value) => {
+ setTempPayload({
+ ...tempPayload,
+ max_iteration: value,
+ })
+ }}
+ />
+
+ <input
+ type="number"
+ min={maxIterationsMin}
+ max={MAX_ITERATIONS_NUM} step={1}
+ className="block h-7 w-11 rounded-lg border-0 bg-components-input-bg-normal px-1.5 pl-1 leading-7 text-text-primary placeholder:text-text-tertiary focus:ring-1 focus:ring-inset focus:ring-primary-600"
+ value={tempPayload.max_iteration}
+ onChange={(e) => {
+ let value = Number.parseInt(e.target.value, 10)
+ if (value < maxIterationsMin)
+ value = maxIterationsMin
+
+ if (value > MAX_ITERATIONS_NUM)
+ value = MAX_ITERATIONS_NUM
+ setTempPayload({
+ ...tempPayload,
+ max_iteration: value,
+ })
+ }} />
+ </div>
+ </ItemPanel>
+
+ {!isFunctionCall && (
+ <div className='rounded-xl bg-background-section-burn py-2 shadow-xs'>
+ <div className='flex h-8 items-center px-4 text-sm font-semibold leading-6 text-text-secondary'>{t('tools.builtInPromptTitle')}</div>
+ <div className='h-[396px] overflow-y-auto whitespace-pre-line px-4 text-sm font-normal leading-5 text-text-secondary'>
+ {isChatModel ? DEFAULT_AGENT_PROMPT.chat : DEFAULT_AGENT_PROMPT.completion}
+ </div>
+ <div className='px-4'>
+ <div className='inline-flex h-5 items-center rounded-md bg-components-input-bg-normal px-1 text-xs font-medium leading-[18px] text-text-tertiary'>{(isChatModel ? DEFAULT_AGENT_PROMPT.chat : DEFAULT_AGENT_PROMPT.completion).length}</div>
+ </div>
+ </div>
+ )}
+
+ </div>
+ <div
+ className='sticky bottom-0 z-[5] flex w-full justify-end border-t border-divider-regular bg-background-section-burn px-6 py-4'
+ >
+ <Button
+ onClick={onCancel}
+ className='mr-2'
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ onClick={handleSave}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ </div>
+ </div>
+ )
+}
+export default React.memo(AgentSetting)
diff --git a/app/components/app/configuration/config/agent/agent-setting/item-panel.tsx b/app/components/app/configuration/config/agent/agent-setting/item-panel.tsx
new file mode 100644
index 0000000..6512e11
--- /dev/null
+++ b/app/components/app/configuration/config/agent/agent-setting/item-panel.tsx
@@ -0,0 +1,41 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import Tooltip from '@/app/components/base/tooltip'
+type Props = {
+ className?: string
+ icon: React.JSX.Element
+ name: string
+ description: string
+ children: React.JSX.Element
+}
+
+const ItemPanel: FC<Props> = ({
+ className,
+ icon,
+ name,
+ description,
+ children,
+}) => {
+ return (
+ <div className={cn(className, 'flex h-12 items-center justify-between rounded-lg bg-background-section-burn px-3')}>
+ <div className='flex items-center'>
+ {icon}
+ <div className='ml-3 mr-1 text-sm font-semibold leading-6 text-text-secondary'>{name}</div>
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]'>
+ {description}
+ </div>
+ }
+ >
+ </Tooltip>
+ </div>
+ <div>
+ {children}
+ </div>
+ </div>
+ )
+}
+export default React.memo(ItemPanel)
diff --git a/app/components/app/configuration/config/agent/agent-tools/index.tsx b/app/components/app/configuration/config/agent/agent-tools/index.tsx
new file mode 100644
index 0000000..4b773c0
--- /dev/null
+++ b/app/components/app/configuration/config/agent/agent-tools/index.tsx
@@ -0,0 +1,302 @@
+'use client'
+import type { FC } from 'react'
+import React, { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import copy from 'copy-to-clipboard'
+import produce from 'immer'
+import {
+ RiDeleteBinLine,
+ RiEqualizer2Line,
+ RiInformation2Line,
+} from '@remixicon/react'
+import { useFormattingChangedDispatcher } from '../../../debug/hooks'
+import SettingBuiltInTool from './setting-built-in-tool'
+import Panel from '@/app/components/app/configuration/base/feature-panel'
+import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
+import AppIcon from '@/app/components/base/app-icon'
+import Button from '@/app/components/base/button'
+import Indicator from '@/app/components/header/indicator'
+import Switch from '@/app/components/base/switch'
+import Toast from '@/app/components/base/toast'
+import ConfigContext from '@/context/debug-configuration'
+import type { AgentTool } from '@/types/app'
+import { type Collection, CollectionType } from '@/app/components/tools/types'
+import { MAX_TOOLS_NUM } from '@/config'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
+import Tooltip from '@/app/components/base/tooltip'
+import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other'
+import 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'
+import { canFindTool } from '@/utils'
+
+type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null
+const AgentTools: FC = () => {
+ const { t } = useTranslation()
+ const [isShowChooseTool, setIsShowChooseTool] = useState(false)
+ const { modelConfig, setModelConfig, collectionList } = useContext(ConfigContext)
+ const formattingChangedDispatcher = useFormattingChangedDispatcher()
+
+ const [currentTool, setCurrentTool] = useState<AgentToolWithMoreInfo>(null)
+ const currentCollection = useMemo(() => {
+ if (!currentTool) return null
+ const collection = collectionList.find(collection => canFindTool(collection.id, currentTool?.provider_id) && collection.type === currentTool?.provider_type)
+ return collection
+ }, [currentTool, collectionList])
+ const [isShowSettingTool, setIsShowSettingTool] = useState(false)
+ const [isShowSettingAuth, setShowSettingAuth] = useState(false)
+ const tools = (modelConfig?.agentConfig?.tools as AgentTool[] || []).map((item) => {
+ const collection = collectionList.find(
+ collection =>
+ canFindTool(collection.id, item.provider_id)
+ && collection.type === item.provider_type,
+ )
+ const icon = collection?.icon
+ return {
+ ...item,
+ icon,
+ collection,
+ }
+ })
+
+ const handleToolSettingChange = (value: Record<string, any>) => {
+ const newModelConfig = produce(modelConfig, (draft) => {
+ const tool = (draft.agentConfig.tools).find((item: any) => item.provider_id === currentTool?.collection?.id && item.tool_name === currentTool?.tool_name)
+ if (tool)
+ (tool as AgentTool).tool_parameters = value
+ })
+ setModelConfig(newModelConfig)
+ setIsShowSettingTool(false)
+ formattingChangedDispatcher()
+ }
+
+ const handleToolAuthSetting = (value: AgentToolWithMoreInfo) => {
+ const newModelConfig = produce(modelConfig, (draft) => {
+ const tool = (draft.agentConfig.tools).find((item: any) => item.provider_id === value?.collection?.id && item.tool_name === value?.tool_name)
+ if (tool)
+ (tool as AgentTool).notAuthor = false
+ })
+ setModelConfig(newModelConfig)
+ setIsShowSettingTool(false)
+ formattingChangedDispatcher()
+ }
+
+ const [isDeleting, setIsDeleting] = useState<number>(-1)
+
+ const handleSelectTool = (tool: ToolDefaultValue) => {
+ const newModelConfig = produce(modelConfig, (draft) => {
+ draft.agentConfig.tools.push({
+ provider_id: tool.provider_id,
+ provider_type: tool.provider_type as CollectionType,
+ provider_name: tool.provider_name,
+ tool_name: tool.tool_name,
+ tool_label: tool.tool_label,
+ tool_parameters: tool.params,
+ notAuthor: !tool.is_team_authorization,
+ enabled: true,
+ })
+ })
+ setModelConfig(newModelConfig)
+ }
+
+ return (
+ <>
+ <Panel
+ className={cn('mt-2', tools.length === 0 && 'pb-2')}
+ noBodySpacing={tools.length === 0}
+ title={
+ <div className='flex items-center'>
+ <div className='mr-1'>{t('appDebug.agent.tools.name')}</div>
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]'>
+ {t('appDebug.agent.tools.description')}
+ </div>
+ }
+ />
+ </div>
+ }
+ headerRight={
+ <div className='flex items-center'>
+ <div className='text-xs font-normal leading-[18px] text-text-tertiary'>{tools.filter(item => !!item.enabled).length}/{tools.length} {t('appDebug.agent.tools.enabled')}</div>
+ {tools.length < MAX_TOOLS_NUM && (
+ <>
+ <div className='ml-3 mr-1 h-3.5 w-px bg-divider-regular'></div>
+ <ToolPicker
+ trigger={<OperationBtn type="add" />}
+ isShow={isShowChooseTool}
+ onShowChange={setIsShowChooseTool}
+ disabled={false}
+ supportAddCustomTool
+ onSelect={handleSelectTool}
+ selectedTools={tools}
+ />
+ </>
+ )}
+ </div>
+ }
+ >
+ <div className='grid grid-cols-1 flex-wrap items-center justify-between gap-1 2xl:grid-cols-2'>
+ {tools.map((item: AgentTool & { icon: any; collection?: Collection }, index) => (
+ <div key={index}
+ className={cn(
+ 'cursor group relative flex w-full items-center justify-between rounded-lg border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg p-1.5 pr-2 shadow-xs last-of-type:mb-0 hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-sm',
+ isDeleting === index && 'border-state-destructive-border hover:bg-state-destructive-hover',
+ )}
+ >
+ <div className='flex w-0 grow items-center'>
+ {item.isDeleted && <DefaultToolIcon className='h-5 w-5' />}
+ {!item.isDeleted && (
+ <div className={cn((item.notAuthor || !item.enabled) && 'opacity-50')}>
+ {typeof item.icon === 'string' && <div className='h-5 w-5 rounded-md bg-cover bg-center' style={{ backgroundImage: `url(${item.icon})` }} />}
+ {typeof item.icon !== 'string' && <AppIcon className='rounded-md' size='xs' icon={item.icon?.content} background={item.icon?.background} />}
+ </div>
+ )}
+ <div
+ className={cn(
+ 'system-xs-regular ml-1.5 flex w-0 grow items-center truncate',
+ (item.isDeleted || item.notAuthor || !item.enabled) ? 'opacity-50' : '',
+ )}
+ >
+ <span className='system-xs-medium pr-1.5 text-text-secondary'>{item.provider_type === CollectionType.builtIn ? item.provider_name.split('/').pop() : item.tool_label}</span>
+ <span className='text-text-tertiary'>{item.tool_label}</span>
+ {!item.isDeleted && (
+ <Tooltip
+ needsDelay
+ popupContent={
+ <div className='w-[180px]'>
+ <div className='mb-1.5 text-text-secondary'>{item.tool_name}</div>
+ <div className='mb-1.5 text-text-tertiary'>{t('tools.toolNameUsageTip')}</div>
+ <div className='cursor-pointer text-text-accent' onClick={() => copy(item.tool_name)}>{t('tools.copyToolName')}</div>
+ </div>
+ }
+ >
+ <div className='h-4 w-4'>
+ <div className='ml-0.5 hidden group-hover:inline-block'>
+ <RiInformation2Line className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </Tooltip>
+ )}
+ </div>
+ </div>
+ <div className='ml-1 flex shrink-0 items-center'>
+ {item.isDeleted && (
+ <div className='mr-2 flex items-center'>
+ <Tooltip
+ popupContent={t('tools.toolRemoved')}
+ needsDelay
+ >
+ <div className='mr-1 cursor-pointer rounded-md p-1 hover:bg-black/5'>
+ <AlertTriangle className='h-4 w-4 text-[#F79009]' />
+ </div>
+ </Tooltip>
+ <div
+ className='cursor-pointer rounded-md p-1 text-text-tertiary hover:text-text-destructive'
+ onClick={() => {
+ const newModelConfig = produce(modelConfig, (draft) => {
+ draft.agentConfig.tools.splice(index, 1)
+ })
+ setModelConfig(newModelConfig)
+ formattingChangedDispatcher()
+ }}
+ onMouseOver={() => setIsDeleting(index)}
+ onMouseLeave={() => setIsDeleting(-1)}
+ >
+ <RiDeleteBinLine className='h-4 w-4' />
+ </div>
+ </div>
+ )}
+ {!item.isDeleted && (
+ <div className='mr-2 hidden items-center gap-1 group-hover:flex'>
+ {!item.notAuthor && (
+ <Tooltip
+ popupContent={t('tools.setBuiltInTools.infoAndSetting')}
+ needsDelay
+ >
+ <div className='cursor-pointer rounded-md p-1 hover:bg-black/5' onClick={() => {
+ setCurrentTool(item)
+ setIsShowSettingTool(true)
+ }}>
+ <RiEqualizer2Line className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </Tooltip>
+ )}
+ <div
+ className='cursor-pointer rounded-md p-1 text-text-tertiary hover:text-text-destructive'
+ onClick={() => {
+ const newModelConfig = produce(modelConfig, (draft) => {
+ draft.agentConfig.tools.splice(index, 1)
+ })
+ setModelConfig(newModelConfig)
+ formattingChangedDispatcher()
+ }}
+ onMouseOver={() => setIsDeleting(index)}
+ onMouseLeave={() => setIsDeleting(-1)}
+ >
+ <RiDeleteBinLine className='h-4 w-4' />
+ </div>
+ </div>
+ )}
+ <div className={cn(item.isDeleted && 'opacity-50')}>
+ {!item.notAuthor && (
+ <Switch
+ defaultValue={item.isDeleted ? false : item.enabled}
+ disabled={item.isDeleted}
+ size='md'
+ onChange={(enabled) => {
+ const newModelConfig = produce(modelConfig, (draft) => {
+ (draft.agentConfig.tools[index] as any).enabled = enabled
+ })
+ setModelConfig(newModelConfig)
+ formattingChangedDispatcher()
+ }} />
+ )}
+ {item.notAuthor && (
+ <Button variant='secondary' size='small' onClick={() => {
+ setCurrentTool(item)
+ setShowSettingAuth(true)
+ }}>
+ {t('tools.notAuthorized')}
+ <Indicator className='ml-2' color='orange' />
+ </Button>
+ )}
+ </div>
+ </div>
+ </div>
+ ))}
+ </div >
+ </Panel >
+ {isShowSettingTool && (
+ <SettingBuiltInTool
+ toolName={currentTool?.tool_name as string}
+ setting={currentTool?.tool_parameters}
+ collection={currentTool?.collection as Collection}
+ isBuiltIn={currentTool?.collection?.type === CollectionType.builtIn}
+ isModel={currentTool?.collection?.type === CollectionType.model}
+ onSave={handleToolSettingChange}
+ onHide={() => setIsShowSettingTool(false)}
+ />
+ )}
+ {isShowSettingAuth && (
+ <ConfigCredential
+ collection={currentCollection as any}
+ onCancel={() => setShowSettingAuth(false)}
+ onSaved={async (value) => {
+ await updateBuiltInToolCredential((currentCollection as any).name, value)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.actionSuccess'),
+ })
+ handleToolAuthSetting(currentTool)
+ setShowSettingAuth(false)
+ }}
+ />
+ )}
+ </>
+ )
+}
+export default React.memo(AgentTools)
diff --git a/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx b/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx
new file mode 100644
index 0000000..952ad66
--- /dev/null
+++ b/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool.tsx
@@ -0,0 +1,238 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import {
+ RiArrowLeftLine,
+ RiCloseLine,
+} from '@remixicon/react'
+import Drawer from '@/app/components/base/drawer'
+import Loading from '@/app/components/base/loading'
+import ActionButton from '@/app/components/base/action-button'
+import Icon from '@/app/components/plugins/card/base/card-icon'
+import OrgInfo from '@/app/components/plugins/card/base/org-info'
+import Description from '@/app/components/plugins/card/base/description'
+import TabSlider from '@/app/components/base/tab-slider-plain'
+
+import Button from '@/app/components/base/button'
+import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
+import { addDefaultValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
+import type { Collection, Tool } from '@/app/components/tools/types'
+import { CollectionType } from '@/app/components/tools/types'
+import { fetchBuiltInToolList, fetchCustomToolList, fetchModelToolList, fetchWorkflowToolList } from '@/service/tools'
+import I18n from '@/context/i18n'
+import { getLanguage } from '@/i18n/language'
+import cn from '@/utils/classnames'
+
+type Props = {
+ showBackButton?: boolean
+ collection: Collection
+ isBuiltIn?: boolean
+ isModel?: boolean
+ toolName: string
+ setting?: Record<string, any>
+ readonly?: boolean
+ onHide: () => void
+ onSave?: (value: Record<string, any>) => void
+}
+
+const SettingBuiltInTool: FC<Props> = ({
+ showBackButton = false,
+ collection,
+ isBuiltIn = true,
+ isModel = true,
+ toolName,
+ setting = {},
+ readonly,
+ onHide,
+ onSave,
+}) => {
+ const { locale } = useContext(I18n)
+ const language = getLanguage(locale)
+ const { t } = useTranslation()
+
+ const [isLoading, setIsLoading] = useState(true)
+ const [tools, setTools] = useState<Tool[]>([])
+ const currTool = tools.find(tool => tool.name === toolName)
+ const formSchemas = currTool ? toolParametersToFormSchemas(currTool.parameters) : []
+ const infoSchemas = formSchemas.filter(item => item.form === 'llm')
+ const settingSchemas = formSchemas.filter(item => item.form !== 'llm')
+ const hasSetting = settingSchemas.length > 0
+ const [tempSetting, setTempSetting] = useState(setting)
+ const [currType, setCurrType] = useState('info')
+ const isInfoActive = currType === 'info'
+ useEffect(() => {
+ if (!collection)
+ return
+
+ (async () => {
+ setIsLoading(true)
+ try {
+ const list = await new Promise<Tool[]>((resolve) => {
+ (async function () {
+ if (isModel)
+ resolve(await fetchModelToolList(collection.name))
+ else if (isBuiltIn)
+ resolve(await fetchBuiltInToolList(collection.name))
+ else if (collection.type === CollectionType.workflow)
+ resolve(await fetchWorkflowToolList(collection.id))
+ else
+ resolve(await fetchCustomToolList(collection.name))
+ }())
+ })
+ setTools(list)
+ const currTool = list.find(tool => tool.name === toolName)
+ if (currTool) {
+ const formSchemas = toolParametersToFormSchemas(currTool.parameters)
+ setTempSetting(addDefaultValue(setting, formSchemas))
+ }
+ }
+ catch { }
+ setIsLoading(false)
+ })()
+ }, [collection?.name, collection?.id, collection?.type])
+
+ useEffect(() => {
+ setCurrType((!readonly && hasSetting) ? 'setting' : 'info')
+ }, [hasSetting])
+
+ const isValid = (() => {
+ let valid = true
+ settingSchemas.forEach((item) => {
+ if (item.required && !tempSetting[item.name])
+ valid = false
+ })
+ return valid
+ })()
+
+ const getType = (type: string) => {
+ if (type === 'number-input')
+ return t('tools.setBuiltInTools.number')
+ if (type === 'text-input')
+ return t('tools.setBuiltInTools.string')
+ if (type === 'file')
+ return t('tools.setBuiltInTools.file')
+ return type
+ }
+
+ const infoUI = (
+ <div className=''>
+ {infoSchemas.length > 0 && (
+ <div className='space-y-1 py-2'>
+ {infoSchemas.map((item, index) => (
+ <div key={index} className='py-1'>
+ <div className='flex items-center gap-2'>
+ <div className='code-sm-semibold text-text-secondary'>{item.label[language]}</div>
+ <div className='system-xs-regular text-text-tertiary'>
+ {getType(item.type)}
+ </div>
+ {item.required && (
+ <div className='system-xs-medium text-text-warning-secondary'>{t('tools.setBuiltInTools.required')}</div>
+ )}
+ </div>
+ {item.human_description && (
+ <div className='system-xs-regular mt-0.5 text-text-tertiary'>
+ {item.human_description?.[language]}
+ </div>
+ )}
+ </div>
+ ))}
+ </div>
+ )}
+ </div>
+ )
+
+ const settingUI = (
+ <Form
+ value={tempSetting}
+ onChange={setTempSetting}
+ formSchemas={settingSchemas}
+ isEditMode={false}
+ showOnVariableMap={{}}
+ validating={false}
+ readonly={readonly}
+ />
+ )
+
+ return (
+ <Drawer
+ isOpen
+ clickOutsideNotOpen={false}
+ onClose={onHide}
+ footer={null}
+ mask={false}
+ positionCenter={false}
+ panelClassName={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')}
+ >
+ <>
+ {isLoading && <Loading type='app' />}
+ {!isLoading && (
+ <>
+ {/* header */}
+ <div className='relative border-b border-divider-subtle p-4 pb-3'>
+ <div className='absolute right-3 top-3'>
+ <ActionButton onClick={onHide}>
+ <RiCloseLine className='h-4 w-4' />
+ </ActionButton>
+ </div>
+ {showBackButton && (
+ <div
+ className='system-xs-semibold-uppercase mb-2 flex cursor-pointer items-center gap-1 text-text-accent-secondary'
+ onClick={onHide}
+ >
+ <RiArrowLeftLine className='h-4 w-4' />
+ BACK
+ </div>
+ )}
+ <div className='flex items-center gap-1'>
+ <Icon size='tiny' className='h-6 w-6' src={collection.icon} />
+ <OrgInfo
+ packageNameClassName='w-auto'
+ orgName={collection.author}
+ packageName={collection.name.split('/').pop() || ''}
+ />
+ </div>
+ <div className='system-md-semibold mt-1 text-text-primary'>{currTool?.label[language]}</div>
+ {!!currTool?.description[language] && (
+ <Description className='mt-3' text={currTool.description[language]} descriptionLineRows={2}></Description>
+ )}
+ </div>
+ {/* form */}
+ <div className='h-full'>
+ <div className='flex h-full flex-col'>
+ {(hasSetting && !readonly) ? (
+ <TabSlider
+ className='mt-1 shrink-0 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='system-sm-semibold-uppercase p-4 pb-1 text-text-primary'>{t('tools.setBuiltInTools.parameters')}</div>
+ )}
+ <div className='h-0 grow overflow-y-auto px-4'>
+ {isInfoActive ? infoUI : settingUI}
+ </div>
+ {!readonly && !isInfoActive && (
+ <div className='mt-2 flex shrink-0 justify-end space-x-2 rounded-b-[10px] border-t border-divider-regular bg-components-panel-bg px-6 py-4'>
+ <Button className='flex h-8 items-center !px-3 !text-[13px] font-medium ' onClick={onHide}>{t('common.operation.cancel')}</Button>
+ <Button className='flex h-8 items-center !px-3 !text-[13px] font-medium' variant='primary' disabled={!isValid} onClick={() => onSave?.(addDefaultValue(tempSetting, formSchemas))}>{t('common.operation.save')}</Button>
+ </div>
+ )}
+ </div>
+ </div>
+ </>
+ )}
+ </>
+ </Drawer>
+ )
+}
+export default React.memo(SettingBuiltInTool)
diff --git a/app/components/app/configuration/config/agent/prompt-editor.tsx b/app/components/app/configuration/config/agent/prompt-editor.tsx
new file mode 100644
index 0000000..7f7f140
--- /dev/null
+++ b/app/components/app/configuration/config/agent/prompt-editor.tsx
@@ -0,0 +1,149 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import copy from 'copy-to-clipboard'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+import {
+ Clipboard,
+ ClipboardCheck,
+} from '@/app/components/base/icons/src/vender/line/files'
+import PromptEditor from '@/app/components/base/prompt-editor'
+import type { ExternalDataTool } from '@/models/common'
+import ConfigContext from '@/context/debug-configuration'
+import { useModalContext } from '@/context/modal-context'
+import { useToastContext } from '@/app/components/base/toast'
+import s from '@/app/components/app/configuration/config-prompt/style.module.css'
+import { noop } from 'lodash-es'
+
+type Props = {
+ className?: string
+ type: 'first-prompt' | 'next-iteration'
+ value: string
+ onChange: (value: string) => void
+}
+
+const Editor: FC<Props> = ({
+ className,
+ type,
+ value,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+
+ const { notify } = useToastContext()
+
+ const [isCopied, setIsCopied] = React.useState(false)
+ const {
+ modelConfig,
+ hasSetBlockStatus,
+ dataSets,
+ showSelectDataSet,
+ externalDataToolsConfig,
+ setExternalDataToolsConfig,
+ } = useContext(ConfigContext)
+ const promptVariables = modelConfig.configs.prompt_variables
+ const { setShowExternalDataToolModal } = useModalContext()
+ const isFirstPrompt = type === 'first-prompt'
+ const editorHeight = isFirstPrompt ? 'h-[336px]' : 'h-[52px]'
+
+ const handleOpenExternalDataToolModal = () => {
+ setShowExternalDataToolModal({
+ payload: {},
+ onSaveCallback: (newExternalDataTool: ExternalDataTool) => {
+ setExternalDataToolsConfig([...externalDataToolsConfig, newExternalDataTool])
+ },
+ onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
+ for (let i = 0; i < promptVariables.length; i++) {
+ if (promptVariables[i].key === newExternalDataTool.variable) {
+ notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
+ return false
+ }
+ }
+
+ for (let i = 0; i < externalDataToolsConfig.length; i++) {
+ if (externalDataToolsConfig[i].variable === newExternalDataTool.variable) {
+ notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: externalDataToolsConfig[i].variable }) })
+ return false
+ }
+ }
+
+ return true
+ },
+ })
+ }
+ return (
+ <div className={cn(className, s.gradientBorder, 'relative')}>
+ <div className='rounded-xl bg-white'>
+ <div className={cn(s.boxHeader, 'flex h-11 items-center justify-between rounded-tl-xl rounded-tr-xl bg-white pb-1 pl-4 pr-3 pt-2 hover:shadow-xs')}>
+ <div className='text-sm font-semibold uppercase text-indigo-800'>{t(`appDebug.agent.${isFirstPrompt ? 'firstPrompt' : 'nextIteration'}`)}</div>
+ <div className={cn(s.optionWrap, 'items-center space-x-1')}>
+ {!isCopied
+ ? (
+ <Clipboard className='h-6 w-6 cursor-pointer p-1 text-gray-500' onClick={() => {
+ copy(value)
+ setIsCopied(true)
+ }} />
+ )
+ : (
+ <ClipboardCheck className='h-6 w-6 p-1 text-gray-500' />
+ )}
+ </div>
+ </div>
+ <div className={cn(editorHeight, ' min-h-[102px] overflow-y-auto px-4 text-sm text-gray-700')}>
+ <PromptEditor
+ className={editorHeight}
+ value={value}
+ contextBlock={{
+ show: true,
+ selectable: !hasSetBlockStatus.context,
+ datasets: dataSets.map(item => ({
+ id: item.id,
+ name: item.name,
+ type: item.data_source_type,
+ })),
+ onAddContext: showSelectDataSet,
+ }}
+ variableBlock={{
+ show: true,
+ variables: modelConfig.configs.prompt_variables.map(item => ({
+ name: item.name,
+ value: item.key,
+ })),
+ }}
+ externalToolBlock={{
+ show: true,
+ externalTools: externalDataToolsConfig.map(item => ({
+ name: item.label!,
+ variableName: item.variable!,
+ icon: item.icon,
+ icon_background: item.icon_background,
+ })),
+ onAddExternalTool: handleOpenExternalDataToolModal,
+ }}
+ historyBlock={{
+ show: false,
+ selectable: false,
+ history: {
+ user: '',
+ assistant: '',
+ },
+ onEditRole: noop,
+ }}
+ queryBlock={{
+ show: false,
+ selectable: false,
+ }}
+ onChange={onChange}
+ onBlur={noop}
+ />
+ </div>
+ <div className='flex pb-2 pl-4'>
+ <div className="h-[18px] rounded-md bg-gray-100 px-1 text-xs leading-[18px] text-gray-500">{value.length}</div>
+ </div>
+ </div>
+ </div>
+ )
+}
+export default React.memo(Editor)
diff --git a/app/components/app/configuration/config/assistant-type-picker/index.tsx b/app/components/app/configuration/config/assistant-type-picker/index.tsx
new file mode 100644
index 0000000..874c6bc
--- /dev/null
+++ b/app/components/app/configuration/config/assistant-type-picker/index.tsx
@@ -0,0 +1,165 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowDownSLine } from '@remixicon/react'
+import AgentSetting from '../agent/agent-setting'
+import cn from '@/utils/classnames'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { BubbleText } from '@/app/components/base/icons/src/vender/solid/education'
+import Radio from '@/app/components/base/radio/ui'
+import { CuteRobot } from '@/app/components/base/icons/src/vender/solid/communication'
+import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
+import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows'
+import type { AgentConfig } from '@/models/debug'
+
+type Props = {
+ value: string
+ disabled: boolean
+ onChange: (value: string) => void
+ isFunctionCall: boolean
+ isChatModel: boolean
+ agentConfig?: AgentConfig
+ onAgentSettingChange: (payload: AgentConfig) => void
+}
+
+type ItemProps = {
+ text: string
+ disabled: boolean
+ value: string
+ isChecked: boolean
+ description: string
+ Icon: any
+ onClick: (value: string) => void
+}
+
+const SelectItem: FC<ItemProps> = ({ text, value, Icon, isChecked, description, onClick, disabled }) => {
+ return (
+ <div
+ className={cn(disabled ? 'opacity-50' : 'cursor-pointer', isChecked ? 'border-[2px] border-indigo-600 shadow-sm' : 'border border-gray-100', 'mb-2 rounded-xl bg-gray-25 p-3 pr-4 hover:bg-gray-50')}
+ onClick={() => !disabled && onClick(value)}
+ >
+ <div className='flex items-center justify-between'>
+ <div className='flex items-center '>
+ <div className='mr-3 rounded-lg bg-indigo-50 p-1'>
+ <Icon className='h-4 w-4 text-indigo-600' />
+ </div>
+ <div className='text-sm font-medium leading-5 text-gray-900'>{text}</div>
+ </div>
+ <Radio isChecked={isChecked} />
+ </div>
+ <div className='ml-9 text-xs font-normal leading-[18px] text-gray-500'>{description}</div>
+ </div>
+ )
+}
+
+const AssistantTypePicker: FC<Props> = ({
+ value,
+ disabled,
+ onChange,
+ onAgentSettingChange,
+ isFunctionCall,
+ isChatModel,
+ agentConfig,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const handleChange = (chosenValue: string) => {
+ if (value === chosenValue)
+ return
+
+ onChange(chosenValue)
+ if (chosenValue !== 'agent')
+ setOpen(false)
+ }
+ const isAgent = value === 'agent'
+ const [isShowAgentSetting, setIsShowAgentSetting] = useState(false)
+
+ const agentConfigUI = (
+ <>
+ <div className='my-4 h-[1px] bg-gray-100'></div>
+ <div
+ className={cn(isAgent ? 'group cursor-pointer hover:bg-primary-50' : 'opacity-30', 'rounded-xl bg-gray-50 p-3 pr-4 ')}
+ onClick={() => {
+ if (isAgent) {
+ setOpen(false)
+ setIsShowAgentSetting(true)
+ }
+ }}
+ >
+ <div className='flex items-center justify-between'>
+ <div className='flex items-center '>
+ <div className='mr-3 rounded-lg bg-gray-200 p-1 group-hover:bg-white'>
+ <Settings04 className='h-4 w-4 text-gray-600 group-hover:text-[#155EEF]' />
+ </div>
+ <div className='text-sm font-medium leading-5 text-gray-900 group-hover:text-[#155EEF]'>{t('appDebug.agent.setting.name')}</div>
+ </div>
+ <ArrowUpRight className='h-4 w-4 text-gray-500 group-hover:text-[#155EEF]' />
+ </div>
+ <div className='ml-9 text-xs font-normal leading-[18px] text-gray-500'>{t('appDebug.agent.setting.description')}</div>
+ </div>
+ </>
+ )
+ return (
+ <>
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 8,
+ crossAxis: -2,
+ }}
+ >
+ <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
+ <div className={cn(open && 'bg-gray-50', 'flex h-8 cursor-pointer select-none items-center space-x-1 rounded-lg border border-black/5 px-3 text-indigo-600')}>
+ {isAgent ? <BubbleText className='h-3 w-3' /> : <CuteRobot className='h-3 w-3' />}
+ <div className='text-xs font-medium'>{t(`appDebug.assistantType.${isAgent ? 'agentAssistant' : 'chatAssistant'}.name`)}</div>
+ <RiArrowDownSLine className='h-3 w-3' />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 1000 }}>
+ <div className='relative left-0.5 w-[480px] rounded-xl border border-black/8 bg-white p-6 shadow-lg'>
+ <div className='mb-2 text-sm font-semibold leading-5 text-gray-900'>{t('appDebug.assistantType.name')}</div>
+ <SelectItem
+ Icon={BubbleText}
+ value='chat'
+ disabled={disabled}
+ text={t('appDebug.assistantType.chatAssistant.name')}
+ description={t('appDebug.assistantType.chatAssistant.description')}
+ isChecked={!isAgent}
+ onClick={handleChange}
+ />
+ <SelectItem
+ Icon={CuteRobot}
+ value='agent'
+ disabled={disabled}
+ text={t('appDebug.assistantType.agentAssistant.name')}
+ description={t('appDebug.assistantType.agentAssistant.description')}
+ isChecked={isAgent}
+ onClick={handleChange}
+ />
+ {!disabled && agentConfigUI}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ {isShowAgentSetting && (
+ <AgentSetting
+ isFunctionCall={isFunctionCall}
+ payload={agentConfig as AgentConfig}
+ isChatModel={isChatModel}
+ onSave={(payloadNew) => {
+ onAgentSettingChange(payloadNew)
+ setIsShowAgentSetting(false)
+ }}
+ onCancel={() => setIsShowAgentSetting(false)}
+ />
+ )}
+ </>
+ )
+}
+export default React.memo(AssistantTypePicker)
diff --git a/app/components/app/configuration/config/automatic/automatic-btn.tsx b/app/components/app/configuration/config/automatic/automatic-btn.tsx
new file mode 100644
index 0000000..b2d4e30
--- /dev/null
+++ b/app/components/app/configuration/config/automatic/automatic-btn.tsx
@@ -0,0 +1,25 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiSparklingFill,
+} from '@remixicon/react'
+import Button from '@/app/components/base/button'
+
+export type IAutomaticBtnProps = {
+ onClick: () => void
+}
+const AutomaticBtn: FC<IAutomaticBtnProps> = ({
+ onClick,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <Button variant='secondary-accent' size='small' onClick={onClick}>
+ <RiSparklingFill className='mr-1 h-3.5 w-3.5' />
+ <span className=''>{t('appDebug.operation.automatic')}</span>
+ </Button>
+ )
+}
+export default React.memo(AutomaticBtn)
diff --git a/app/components/app/configuration/config/automatic/get-automatic-res.tsx b/app/components/app/configuration/config/automatic/get-automatic-res.tsx
new file mode 100644
index 0000000..e4b333d
--- /dev/null
+++ b/app/components/app/configuration/config/automatic/get-automatic-res.tsx
@@ -0,0 +1,330 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import {
+ RiDatabase2Line,
+ RiFileExcel2Line,
+ RiGitCommitLine,
+ RiNewspaperLine,
+ RiPresentationLine,
+ RiRoadMapLine,
+ RiTerminalBoxLine,
+ RiTranslate,
+ RiUser2Line,
+} from '@remixicon/react'
+import cn from 'classnames'
+import s from './style.module.css'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import Textarea from '@/app/components/base/textarea'
+import Toast from '@/app/components/base/toast'
+import { generateRule } from '@/service/debug'
+import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
+import type { Model } from '@/types/app'
+import { AppType } from '@/types/app'
+import ConfigVar from '@/app/components/app/configuration/config-var'
+import GroupName from '@/app/components/app/configuration/base/group-name'
+import Loading from '@/app/components/base/loading'
+import Confirm from '@/app/components/base/confirm'
+import { LoveMessage } from '@/app/components/base/icons/src/vender/features'
+
+// type
+import type { AutomaticRes } from '@/service/debug'
+import { Generator } from '@/app/components/base/icons/src/vender/other'
+import ModelIcon from '@/app/components/header/account-setting/model-provider-page/model-icon'
+import ModelName from '@/app/components/header/account-setting/model-provider-page/model-name'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+
+export type IGetAutomaticResProps = {
+ mode: AppType
+ model: Model
+ isShow: boolean
+ onClose: () => void
+ onFinished: (res: AutomaticRes) => void
+ isInLLMNode?: boolean
+}
+
+const TryLabel: FC<{
+ Icon: any
+ text: string
+ onClick: () => void
+}> = ({ Icon, text, onClick }) => {
+ return (
+ <div
+ className='mr-1 mt-2 flex h-7 shrink-0 cursor-pointer items-center rounded-lg bg-components-button-secondary-bg px-2'
+ onClick={onClick}
+ >
+ <Icon className='h-4 w-4 text-text-tertiary'></Icon>
+ <div className='ml-1 text-xs font-medium text-text-secondary'>{text}</div>
+ </div>
+ )
+}
+
+const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
+ mode,
+ model,
+ isShow,
+ onClose,
+ isInLLMNode,
+ onFinished,
+}) => {
+ const { t } = useTranslation()
+ const {
+ currentProvider,
+ currentModel,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.textGeneration)
+ const tryList = [
+ {
+ icon: RiTerminalBoxLine,
+ key: 'pythonDebugger',
+ },
+ {
+ icon: RiTranslate,
+ key: 'translation',
+ },
+ {
+ icon: RiPresentationLine,
+ key: 'meetingTakeaways',
+ },
+ {
+ icon: RiNewspaperLine,
+ key: 'writingsPolisher',
+ },
+ {
+ icon: RiUser2Line,
+ key: 'professionalAnalyst',
+ },
+ {
+ icon: RiFileExcel2Line,
+ key: 'excelFormulaExpert',
+ },
+ {
+ icon: RiRoadMapLine,
+ key: 'travelPlanning',
+ },
+ {
+ icon: RiDatabase2Line,
+ key: 'SQLSorcerer',
+ },
+ {
+ icon: RiGitCommitLine,
+ key: 'GitGud',
+ },
+ ]
+
+ const [instruction, setInstruction] = React.useState<string>('')
+ const handleChooseTemplate = useCallback((key: string) => {
+ return () => {
+ const template = t(`appDebug.generate.template.${key}.instruction`)
+ setInstruction(template)
+ }
+ }, [t])
+ const isValid = () => {
+ if (instruction.trim() === '') {
+ Toast.notify({
+ type: 'error',
+ message: t('common.errorMsg.fieldRequired', {
+ field: t('appDebug.generate.instruction'),
+ }),
+ })
+ return false
+ }
+ return true
+ }
+ const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false)
+ const [res, setRes] = React.useState<AutomaticRes | null>(null)
+
+ const renderLoading = (
+ <div className='flex h-full w-0 grow flex-col items-center justify-center space-y-3'>
+ <Loading />
+ <div className='text-[13px] text-text-tertiary'>{t('appDebug.generate.loading')}</div>
+ </div>
+ )
+
+ const renderNoData = (
+ <div className='flex h-full w-0 grow flex-col items-center justify-center space-y-3 px-8'>
+ <Generator className='h-14 w-14 text-text-tertiary' />
+ <div className='text-center text-[13px] font-normal leading-5 text-text-tertiary'>
+ <div>{t('appDebug.generate.noDataLine1')}</div>
+ <div>{t('appDebug.generate.noDataLine2')}</div>
+ </div>
+ </div>
+ )
+
+ const onGenerate = async () => {
+ if (!isValid())
+ return
+ if (isLoading)
+ return
+ setLoadingTrue()
+ try {
+ const { error, ...res } = await generateRule({
+ instruction,
+ model_config: model,
+ no_variable: !!isInLLMNode,
+ })
+ setRes(res)
+ if (error) {
+ Toast.notify({
+ type: 'error',
+ message: error,
+ })
+ }
+ }
+ finally {
+ setLoadingFalse()
+ }
+ }
+
+ const [showConfirmOverwrite, setShowConfirmOverwrite] = React.useState(false)
+
+ const isShowAutoPromptResPlaceholder = () => {
+ return !isLoading && !res
+ }
+
+ return (
+ <Modal
+ isShow={isShow}
+ onClose={onClose}
+ className='min-w-[1140px] !p-0'
+ closable
+ >
+ <div className='flex h-[680px] flex-wrap'>
+ <div className='h-full w-[570px] shrink-0 overflow-y-auto border-r border-divider-regular p-6'>
+ <div className='mb-8'>
+ <div className={`text-lg font-bold leading-[28px] ${s.textGradient}`}>{t('appDebug.generate.title')}</div>
+ <div className='mt-1 text-[13px] font-normal text-text-tertiary'>{t('appDebug.generate.description')}</div>
+ </div>
+ <div className='mb-8 flex items-center'>
+ <ModelIcon
+ className='mr-1.5 shrink-0 '
+ provider={currentProvider}
+ modelName={currentModel?.model}
+ />
+ <ModelName
+ className='grow'
+ modelItem={currentModel!}
+ showMode
+ showFeatures
+ />
+ </div>
+ <div >
+ <div className='flex items-center'>
+ <div className='mr-3 shrink-0 text-xs font-semibold uppercase leading-[18px] text-text-tertiary'>{t('appDebug.generate.tryIt')}</div>
+ <div className='h-px grow' style={{
+ background: 'linear-gradient(to right, rgba(243, 244, 246, 1), rgba(243, 244, 246, 0))',
+ }}></div>
+ </div>
+ <div className='flex flex-wrap'>
+ {tryList.map(item => (
+ <TryLabel
+ key={item.key}
+ Icon={item.icon}
+ text={t(`appDebug.generate.template.${item.key}.name`)}
+ onClick={handleChooseTemplate(item.key)}
+ />
+ ))}
+ </div>
+ </div>
+ {/* inputs */}
+ <div className='mt-6'>
+ <div className='text-[0px]'>
+ <div className='mb-2 text-sm font-medium leading-5 text-text-primary'>{t('appDebug.generate.instruction')}</div>
+ <Textarea
+ className="h-[200px] resize-none"
+ placeholder={t('appDebug.generate.instructionPlaceHolder') as string}
+ value={instruction}
+ onChange={e => setInstruction(e.target.value)} />
+ </div>
+
+ <div className='mt-5 flex justify-end'>
+ <Button
+ className='flex space-x-1'
+ variant='primary'
+ onClick={onGenerate}
+ disabled={isLoading}
+ >
+ <Generator className='h-4 w-4 text-white' />
+ <span className='text-xs font-semibold text-white'>{t('appDebug.generate.generate')}</span>
+ </Button>
+ </div>
+ </div>
+ </div>
+
+ {(!isLoading && res) && (
+ <div className='h-full w-0 grow p-6 pb-0'>
+ <div className='mb-3 shrink-0 text-base font-semibold leading-[160%] text-text-secondary'>{t('appDebug.generate.resTitle')}</div>
+ <div className={cn('max-h-[555px] overflow-y-auto', !isInLLMNode && 'pb-2')}>
+ <ConfigPrompt
+ mode={mode}
+ promptTemplate={res?.prompt || ''}
+ promptVariables={[]}
+ readonly
+ noTitle={isInLLMNode}
+ gradientBorder
+ editorHeight={isInLLMNode ? 524 : 0}
+ noResize={isInLLMNode}
+ />
+ {!isInLLMNode && (
+ <>
+ {(res?.variables?.length && res?.variables?.length > 0)
+ ? (
+ <ConfigVar
+ promptVariables={res?.variables.map(key => ({ key, name: key, type: 'string', required: true })) || []}
+ readonly
+ />
+ )
+ : ''}
+
+ {(mode !== AppType.completion && res?.opening_statement) && (
+ <div className='mt-7'>
+ <GroupName name={t('appDebug.feature.groupChat.title')} />
+ <div
+ className='mb-1 rounded-xl border-l-[0.5px] border-t-[0.5px] border-effects-highlight bg-background-section-burn p-3'
+ >
+ <div className='mb-2 flex items-center gap-2'>
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
+ <LoveMessage className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ <div className='system-sm-semibold flex grow items-center text-text-secondary'>
+ {t('appDebug.feature.conversationOpener.title')}
+ </div>
+ </div>
+ <div className='system-xs-regular min-h-8 text-text-tertiary'>{res.opening_statement}</div>
+ </div>
+ </div>
+ )}
+ </>
+ )}
+ </div>
+
+ <div className='flex justify-end bg-background-default py-4'>
+ <Button onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' className='ml-2' onClick={() => {
+ setShowConfirmOverwrite(true)
+ }}>{t('appDebug.generate.apply')}</Button>
+ </div>
+ </div>
+ )}
+ {isLoading && renderLoading}
+ {isShowAutoPromptResPlaceholder() && renderNoData}
+ {showConfirmOverwrite && (
+ <Confirm
+ title={t('appDebug.generate.overwriteTitle')}
+ content={t('appDebug.generate.overwriteMessage')}
+ isShow={showConfirmOverwrite}
+ onConfirm={() => {
+ setShowConfirmOverwrite(false)
+ onFinished(res!)
+ }}
+ onCancel={() => setShowConfirmOverwrite(false)}
+ />
+ )}
+ </div>
+ </Modal>
+ )
+}
+export default React.memo(GetAutomaticRes)
diff --git a/app/components/app/configuration/config/automatic/style.module.css b/app/components/app/configuration/config/automatic/style.module.css
new file mode 100644
index 0000000..15bedd8
--- /dev/null
+++ b/app/components/app/configuration/config/automatic/style.module.css
@@ -0,0 +1,7 @@
+.textGradient {
+ background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ text-fill-color: transparent;
+}
diff --git a/app/components/app/configuration/config/code-generator/get-code-generator-res.tsx b/app/components/app/configuration/config/code-generator/get-code-generator-res.tsx
new file mode 100644
index 0000000..ddae2f5
--- /dev/null
+++ b/app/components/app/configuration/config/code-generator/get-code-generator-res.tsx
@@ -0,0 +1,230 @@
+import type { FC } from 'react'
+import React from 'react'
+import cn from 'classnames'
+import useBoolean from 'ahooks/lib/useBoolean'
+import { useTranslation } from 'react-i18next'
+import ConfigPrompt from '../../config-prompt'
+import { languageMap } from '../../../../workflow/nodes/_base/components/editor/code-editor/index'
+import { generateRuleCode } from '@/service/debug'
+import type { CodeGenRes } from '@/service/debug'
+import { type AppType, type Model, ModelModeType } from '@/types/app'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import { Generator } from '@/app/components/base/icons/src/vender/other'
+import Toast from '@/app/components/base/toast'
+import Loading from '@/app/components/base/loading'
+import Confirm from '@/app/components/base/confirm'
+import type { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
+import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import ModelIcon from '@/app/components/header/account-setting/model-provider-page/model-icon'
+import ModelName from '@/app/components/header/account-setting/model-provider-page/model-name'
+export type IGetCodeGeneratorResProps = {
+ mode: AppType
+ isShow: boolean
+ codeLanguages: CodeLanguage
+ onClose: () => void
+ onFinished: (res: CodeGenRes) => void
+}
+
+export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
+ {
+ mode,
+ isShow,
+ codeLanguages,
+ onClose,
+ onFinished,
+ },
+) => {
+ const {
+ currentProvider,
+ currentModel,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.textGeneration)
+ const { t } = useTranslation()
+ const [instruction, setInstruction] = React.useState<string>('')
+ const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false)
+ const [res, setRes] = React.useState<CodeGenRes | null>(null)
+ const isValid = () => {
+ if (instruction.trim() === '') {
+ Toast.notify({
+ type: 'error',
+ message: t('common.errorMsg.fieldRequired', {
+ field: t('appDebug.code.instruction'),
+ }),
+ })
+ return false
+ }
+ return true
+ }
+ const model: Model = {
+ provider: currentProvider?.provider || '',
+ name: currentModel?.model || '',
+ mode: ModelModeType.chat,
+ // This is a fixed parameter
+ completion_params: {
+ temperature: 0.7,
+ max_tokens: 0,
+ top_p: 0,
+ echo: false,
+ stop: [],
+ presence_penalty: 0,
+ frequency_penalty: 0,
+ },
+ }
+ const isInLLMNode = true
+ const onGenerate = async () => {
+ if (!isValid())
+ return
+ if (isLoading)
+ return
+ setLoadingTrue()
+ try {
+ const { error, ...res } = await generateRuleCode({
+ instruction,
+ model_config: model,
+ no_variable: !!isInLLMNode,
+ code_language: languageMap[codeLanguages] || 'javascript',
+ })
+ setRes(res)
+ if (error) {
+ Toast.notify({
+ type: 'error',
+ message: error,
+ })
+ }
+ }
+ finally {
+ setLoadingFalse()
+ }
+ }
+ const [showConfirmOverwrite, setShowConfirmOverwrite] = React.useState(false)
+
+ const renderLoading = (
+ <div className='flex h-full w-0 grow flex-col items-center justify-center space-y-3'>
+ <Loading />
+ <div className='text-[13px] text-gray-400'>{t('appDebug.codegen.loading')}</div>
+ </div>
+ )
+ const renderNoData = (
+ <div className='flex h-full w-0 grow flex-col items-center justify-center space-y-3 px-8'>
+ <Generator className='h-14 w-14 text-gray-300' />
+ <div className='text-center text-[13px] font-normal leading-5 text-gray-400'>
+ <div>{t('appDebug.codegen.noDataLine1')}</div>
+ <div>{t('appDebug.codegen.noDataLine2')}</div>
+ </div>
+ </div>
+ )
+
+ return (
+ <Modal
+ isShow={isShow}
+ onClose={onClose}
+ className='min-w-[1140px] !p-0'
+ closable
+ >
+ <div className='relative flex h-[680px] flex-wrap'>
+ <div className='h-full w-[570px] shrink-0 overflow-y-auto border-r border-gray-100 p-8'>
+ <div className='mb-8'>
+ <div className={'text-lg font-bold leading-[28px]'}>{t('appDebug.codegen.title')}</div>
+ <div className='mt-1 text-[13px] font-normal text-gray-500'>{t('appDebug.codegen.description')}</div>
+ </div>
+ <div className='flex items-center'>
+ <ModelIcon
+ className='mr-1.5 shrink-0'
+ provider={currentProvider}
+ modelName={currentModel?.model}
+ />
+ <ModelName
+ className='grow'
+ modelItem={currentModel!}
+ showMode
+ showFeatures
+ />
+ </div>
+ <div className='mt-6'>
+ <div className='text-[0px]'>
+ <div className='mb-2 text-sm font-medium leading-5 text-gray-900'>{t('appDebug.codegen.instruction')}</div>
+ <textarea
+ className="h-[200px] w-full overflow-y-auto rounded-lg bg-gray-50 px-3 py-2 text-sm"
+ placeholder={t('appDebug.codegen.instructionPlaceholder') || ''}
+ value={instruction}
+ onChange={e => setInstruction(e.target.value)}
+ />
+ </div>
+
+ <div className='mt-5 flex justify-end'>
+ <Button
+ className='flex space-x-1'
+ variant='primary'
+ onClick={onGenerate}
+ disabled={isLoading}
+ >
+ <Generator className='h-4 w-4 text-white' />
+ <span className='text-xs font-semibold text-white'>{t('appDebug.codegen.generate')}</span>
+ </Button>
+ </div>
+ </div>
+ </div>
+ {isLoading && renderLoading}
+ {!isLoading && !res && renderNoData}
+ {(!isLoading && res) && (
+ <div className='h-full w-0 grow p-6 pb-0'>
+ <div className='mb-3 shrink-0 text-base font-semibold leading-[160%] text-gray-800'>{t('appDebug.codegen.resTitle')}</div>
+ <div className={cn('max-h-[555px] overflow-y-auto', !isInLLMNode && 'pb-2')}>
+ <ConfigPrompt
+ mode={mode}
+ promptTemplate={res?.code || ''}
+ promptVariables={[]}
+ readonly
+ noTitle={isInLLMNode}
+ gradientBorder
+ editorHeight={isInLLMNode ? 524 : 0}
+ noResize={isInLLMNode}
+ />
+ {!isInLLMNode && (
+ <>
+ {res?.code && (
+ <div className='mt-4'>
+ <h3 className='mb-2 text-sm font-medium text-gray-900'>{t('appDebug.codegen.generatedCode')}</h3>
+ <pre className='overflow-x-auto rounded-lg bg-gray-50 p-4'>
+ <code className={`language-${res.language}`}>
+ {res.code}
+ </code>
+ </pre>
+ </div>
+ )}
+ {res?.error && (
+ <div className='mt-4 rounded-lg bg-red-50 p-4'>
+ <p className='text-sm text-red-600'>{res.error}</p>
+ </div>
+ )}
+ </>
+ )}
+ </div>
+
+ <div className='flex justify-end bg-white py-4'>
+ <Button onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' className='ml-2' onClick={() => {
+ setShowConfirmOverwrite(true)
+ }}>{t('appDebug.codegen.apply')}</Button>
+ </div>
+ </div>
+ )}
+ </div>
+ {showConfirmOverwrite && (
+ <Confirm
+ title={t('appDebug.codegen.overwriteConfirmTitle')}
+ content={t('appDebug.codegen.overwriteConfirmMessage')}
+ isShow={showConfirmOverwrite}
+ onConfirm={() => {
+ setShowConfirmOverwrite(false)
+ onFinished(res!)
+ }}
+ onCancel={() => setShowConfirmOverwrite(false)}
+ />
+ )}
+ </Modal>
+ )
+}
+
+export default React.memo(GetCodeGeneratorResModal)
diff --git a/app/components/app/configuration/config/config-document.tsx b/app/components/app/configuration/config/config-document.tsx
new file mode 100644
index 0000000..9300bbc
--- /dev/null
+++ b/app/components/app/configuration/config/config-document.tsx
@@ -0,0 +1,78 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { useContext } from 'use-context-selector'
+
+import { Document } from '@/app/components/base/icons/src/vender/features'
+import Tooltip from '@/app/components/base/tooltip'
+import ConfigContext from '@/context/debug-configuration'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import Switch from '@/app/components/base/switch'
+
+const ConfigDocument: FC = () => {
+ const { t } = useTranslation()
+ const file = useFeatures(s => s.features.file)
+ const featuresStore = useFeaturesStore()
+ const { isShowDocumentConfig } = useContext(ConfigContext)
+
+ const isDocumentEnabled = file?.allowed_file_types?.includes(SupportUploadFileTypes.document) ?? false
+
+ const handleChange = useCallback((value: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ if (value) {
+ draft.file!.allowed_file_types = Array.from(new Set([
+ ...(draft.file?.allowed_file_types || []),
+ SupportUploadFileTypes.document,
+ ]))
+ }
+ else {
+ draft.file!.allowed_file_types = draft.file!.allowed_file_types?.filter(
+ type => type !== SupportUploadFileTypes.document,
+ )
+ }
+ if (draft.file)
+ draft.file.enabled = (draft.file.allowed_file_types?.length ?? 0) > 0
+ })
+ setFeatures(newFeatures)
+ }, [featuresStore])
+
+ if (!isShowDocumentConfig)
+ return null
+
+ return (
+ <div className='mt-2 flex items-center gap-2 rounded-xl border-l-[0.5px] border-t-[0.5px] bg-background-section-burn p-2'>
+ <div className='shrink-0 p-1'>
+ <div className='rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
+ <Document className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ </div>
+ <div className='flex grow items-center'>
+ <div className='system-sm-semibold mr-1 text-text-secondary'>{t('appDebug.feature.documentUpload.title')}</div>
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]' >
+ {t('appDebug.feature.documentUpload.description')}
+ </div>
+ }
+ />
+ </div>
+ <div className='flex shrink-0 items-center'>
+ <div className='ml-1 mr-3 h-3.5 w-[1px] bg-divider-subtle'></div>
+ <Switch
+ defaultValue={isDocumentEnabled}
+ onChange={handleChange}
+ size='md'
+ />
+ </div>
+ </div>
+ )
+}
+export default React.memo(ConfigDocument)
diff --git a/app/components/app/configuration/config/feature/use-feature.tsx b/app/components/app/configuration/config/feature/use-feature.tsx
new file mode 100644
index 0000000..acc08dd
--- /dev/null
+++ b/app/components/app/configuration/config/feature/use-feature.tsx
@@ -0,0 +1,96 @@
+import React, { useEffect } from 'react'
+
+function useFeature({
+ introduction,
+ setIntroduction,
+ moreLikeThis,
+ setMoreLikeThis,
+ suggestedQuestionsAfterAnswer,
+ setSuggestedQuestionsAfterAnswer,
+ speechToText,
+ setSpeechToText,
+ textToSpeech,
+ setTextToSpeech,
+ citation,
+ setCitation,
+ annotation,
+ setAnnotation,
+ moderation,
+ setModeration,
+}: {
+ introduction: string
+ setIntroduction: (introduction: string) => void
+ moreLikeThis: boolean
+ setMoreLikeThis: (moreLikeThis: boolean) => void
+ suggestedQuestionsAfterAnswer: boolean
+ setSuggestedQuestionsAfterAnswer: (suggestedQuestionsAfterAnswer: boolean) => void
+ speechToText: boolean
+ setSpeechToText: (speechToText: boolean) => void
+ textToSpeech: boolean
+ setTextToSpeech: (textToSpeech: boolean) => void
+ citation: boolean
+ setCitation: (citation: boolean) => void
+ annotation: boolean
+ setAnnotation: (annotation: boolean) => void
+ moderation: boolean
+ setModeration: (moderation: boolean) => void
+}) {
+ const [tempShowOpeningStatement, setTempShowOpeningStatement] = React.useState(!!introduction)
+ useEffect(() => {
+ // wait to api data back
+ if (introduction)
+ setTempShowOpeningStatement(true)
+ }, [introduction])
+
+ // const [tempMoreLikeThis, setTempMoreLikeThis] = React.useState(moreLikeThis)
+ // useEffect(() => {
+ // setTempMoreLikeThis(moreLikeThis)
+ // }, [moreLikeThis])
+
+ const featureConfig = {
+ openingStatement: tempShowOpeningStatement,
+ moreLikeThis,
+ suggestedQuestionsAfterAnswer,
+ speechToText,
+ textToSpeech,
+ citation,
+ annotation,
+ moderation,
+ }
+ const handleFeatureChange = (key: string, value: boolean) => {
+ switch (key) {
+ case 'openingStatement':
+ if (!value)
+ setIntroduction('')
+
+ setTempShowOpeningStatement(value)
+ break
+ case 'moreLikeThis':
+ setMoreLikeThis(value)
+ break
+ case 'suggestedQuestionsAfterAnswer':
+ setSuggestedQuestionsAfterAnswer(value)
+ break
+ case 'speechToText':
+ setSpeechToText(value)
+ break
+ case 'textToSpeech':
+ setTextToSpeech(value)
+ break
+ case 'citation':
+ setCitation(value)
+ break
+ case 'annotation':
+ setAnnotation(value)
+ break
+ case 'moderation':
+ setModeration(value)
+ }
+ }
+ return {
+ featureConfig,
+ handleFeatureChange,
+ }
+}
+
+export default useFeature
diff --git a/app/components/app/configuration/config/index.tsx b/app/components/app/configuration/config/index.tsx
new file mode 100644
index 0000000..dc20955
--- /dev/null
+++ b/app/components/app/configuration/config/index.tsx
@@ -0,0 +1,99 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useContext } from 'use-context-selector'
+import produce from 'immer'
+import { useFormattingChangedDispatcher } from '../debug/hooks'
+import DatasetConfig from '../dataset-config'
+import HistoryPanel from '../config-prompt/conversation-history/history-panel'
+import ConfigVision from '../config-vision'
+import ConfigDocument from './config-document'
+import AgentTools from './agent/agent-tools'
+import ConfigContext from '@/context/debug-configuration'
+import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
+import ConfigVar from '@/app/components/app/configuration/config-var'
+import type { ModelConfig, PromptVariable } from '@/models/debug'
+import type { AppType } from '@/types/app'
+import { ModelModeType } from '@/types/app'
+
+const Config: FC = () => {
+ const {
+ mode,
+ isAdvancedMode,
+ modelModeType,
+ isAgent,
+ hasSetBlockStatus,
+ showHistoryModal,
+ modelConfig,
+ setModelConfig,
+ setPrevPromptConfig,
+ } = useContext(ConfigContext)
+ const isChatApp = ['advanced-chat', 'agent-chat', 'chat'].includes(mode)
+ const formattingChangedDispatcher = useFormattingChangedDispatcher()
+
+ const promptTemplate = modelConfig.configs.prompt_template
+ const promptVariables = modelConfig.configs.prompt_variables
+ // simple mode
+ const handlePromptChange = (newTemplate: string, newVariables: PromptVariable[]) => {
+ const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
+ draft.configs.prompt_template = newTemplate
+ draft.configs.prompt_variables = [...draft.configs.prompt_variables, ...newVariables]
+ })
+ if (modelConfig.configs.prompt_template !== newTemplate)
+ formattingChangedDispatcher()
+
+ setPrevPromptConfig(modelConfig.configs)
+ setModelConfig(newModelConfig)
+ }
+
+ const handlePromptVariablesNameChange = (newVariables: PromptVariable[]) => {
+ setPrevPromptConfig(modelConfig.configs)
+ const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
+ draft.configs.prompt_variables = newVariables
+ })
+ setModelConfig(newModelConfig)
+ }
+
+ return (
+ <>
+ <div
+ className="relative h-0 grow overflow-y-auto px-6 pb-[50px]"
+ >
+ {/* Template */}
+ <ConfigPrompt
+ mode={mode as AppType}
+ promptTemplate={promptTemplate}
+ promptVariables={promptVariables}
+ onChange={handlePromptChange}
+ />
+
+ {/* Variables */}
+ <ConfigVar
+ promptVariables={promptVariables}
+ onPromptVariablesChange={handlePromptVariablesNameChange}
+ />
+
+ {/* Dataset */}
+ <DatasetConfig />
+
+ {/* Tools */}
+ {isAgent && (
+ <AgentTools />
+ )}
+
+ <ConfigVision />
+
+ <ConfigDocument />
+
+ {/* Chat History */}
+ {isAdvancedMode && isChatApp && modelModeType === ModelModeType.completion && (
+ <HistoryPanel
+ showWarning={!hasSetBlockStatus.history}
+ onShowEditModal={showHistoryModal}
+ />
+ )}
+ </div>
+ </>
+ )
+}
+export default React.memo(Config)
diff --git a/app/components/app/configuration/ctrl-btn-group/index.tsx b/app/components/app/configuration/ctrl-btn-group/index.tsx
new file mode 100644
index 0000000..e126e12
--- /dev/null
+++ b/app/components/app/configuration/ctrl-btn-group/index.tsx
@@ -0,0 +1,24 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import s from './style.module.css'
+import Button from '@/app/components/base/button'
+
+export type IContrlBtnGroupProps = {
+ onSave: () => void
+ onReset: () => void
+}
+
+const ContrlBtnGroup: FC<IContrlBtnGroupProps> = ({ onSave, onReset }) => {
+ const { t } = useTranslation()
+ return (
+ <div className="fixed bottom-0 left-[224px] h-[64px] w-[519px]">
+ <div className={`${s.ctrlBtn} flex h-full items-center gap-2 bg-white pl-4`}>
+ <Button variant='primary' onClick={onSave}>{t('appDebug.operation.applyConfig')}</Button>
+ <Button onClick={onReset}>{t('appDebug.operation.resetConfig')}</Button>
+ </div>
+ </div>
+ )
+}
+export default React.memo(ContrlBtnGroup)
diff --git a/app/components/app/configuration/ctrl-btn-group/style.module.css b/app/components/app/configuration/ctrl-btn-group/style.module.css
new file mode 100644
index 0000000..3e87486
--- /dev/null
+++ b/app/components/app/configuration/ctrl-btn-group/style.module.css
@@ -0,0 +1,6 @@
+.ctrlBtn {
+ left: -16px;
+ right: -16px;
+ bottom: -16px;
+ border-top: 1px solid #F3F4F6;
+}
diff --git a/app/components/app/configuration/dataset-config/card-item/index.tsx b/app/components/app/configuration/dataset-config/card-item/index.tsx
new file mode 100644
index 0000000..1220c75
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/card-item/index.tsx
@@ -0,0 +1,58 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import TypeIcon from '../type-icon'
+import RemoveIcon from '../../base/icons/remove-icon'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import type { DataSet } from '@/models/datasets'
+import { formatNumber } from '@/utils/format'
+import Tooltip from '@/app/components/base/tooltip'
+
+export type ICardItemProps = {
+ className?: string
+ config: DataSet
+ onRemove: (id: string) => void
+ readonly?: boolean
+}
+const CardItem: FC<ICardItemProps> = ({
+ className,
+ config,
+ onRemove,
+ readonly,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div
+ className={
+ cn(className, s.card,
+ 'relative flex cursor-pointer items-center rounded-xl border border-gray-200 bg-white px-3 py-2.5')
+ }>
+ <div className='flex items-center space-x-2'>
+ <div className={cn(!config.embedding_available && 'opacity-50')}>
+ <TypeIcon type="upload_file" />
+ </div>
+ <div>
+ <div className='mr-1 flex w-[160px] items-center'>
+ <div className={cn('overflow-hidden text-ellipsis whitespace-nowrap text-[13px] font-medium leading-[18px] text-gray-800', !config.embedding_available && 'opacity-50')}>{config.name}</div>
+ {!config.embedding_available && (
+ <Tooltip
+ popupContent={t('dataset.unavailableTip')}
+ >
+ <span className='inline-flex shrink-0 whitespace-nowrap rounded-md border border-gray-200 px-1 text-xs font-normal leading-[18px] text-gray-500'>{t('dataset.unavailable')}</span>
+ </Tooltip>
+ )}
+ </div>
+ <div className={cn('flex max-w-[150px] text-xs text-gray-500', !config.embedding_available && 'opacity-50')}>
+ {formatNumber(config.word_count)} {t('appDebug.feature.dataSet.words')} 路 {formatNumber(config.document_count)} {t('appDebug.feature.dataSet.textBlocks')}
+ </div>
+ </div>
+ </div>
+
+ {!readonly && <RemoveIcon className={`${s.deleteBtn} absolute right-1 top-1/2 translate-y-[-50%]`} onClick={() => onRemove(config.id)} />}
+ </div>
+ )
+}
+export default React.memo(CardItem)
diff --git a/app/components/app/configuration/dataset-config/card-item/item.tsx b/app/components/app/configuration/dataset-config/card-item/item.tsx
new file mode 100644
index 0000000..4feba8b
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/card-item/item.tsx
@@ -0,0 +1,122 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import {
+ RiDeleteBinLine,
+ RiEditLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import SettingsModal from '../settings-modal'
+import type { DataSet } from '@/models/datasets'
+import { DataSourceType } from '@/models/datasets'
+import FileIcon from '@/app/components/base/file-icon'
+import { Folder } from '@/app/components/base/icons/src/vender/solid/files'
+import { Globe06 } from '@/app/components/base/icons/src/vender/solid/mapsAndTravel'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+import Drawer from '@/app/components/base/drawer'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import Badge from '@/app/components/base/badge'
+import { useKnowledge } from '@/hooks/use-knowledge'
+import cn from '@/utils/classnames'
+
+type ItemProps = {
+ className?: string
+ config: DataSet
+ onRemove: (id: string) => void
+ readonly?: boolean
+ onSave: (newDataset: DataSet) => void
+ editable?: boolean
+}
+
+const Item: FC<ItemProps> = ({
+ config,
+ onSave,
+ onRemove,
+ editable = true,
+}) => {
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+ const [showSettingsModal, setShowSettingsModal] = useState(false)
+ const { formatIndexingTechniqueAndMethod } = useKnowledge()
+ const { t } = useTranslation()
+
+ const handleSave = (newDataset: DataSet) => {
+ onSave(newDataset)
+ setShowSettingsModal(false)
+ }
+
+ const [isDeleting, setIsDeleting] = useState(false)
+
+ return (
+ <div className={cn(
+ 'group relative mb-1 flex h-10 w-full cursor-pointer items-center justify-between rounded-lg border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg px-2 last-of-type:mb-0 hover:bg-components-panel-on-panel-item-bg-hover',
+ isDeleting && 'border-state-destructive-border hover:bg-state-destructive-hover',
+ )}>
+ <div className='flex w-0 grow items-center space-x-1.5'>
+ {
+ config.data_source_type === DataSourceType.FILE && (
+ <div className='mr-2 flex h-6 w-6 shrink-0 items-center justify-center rounded-md border-[0.5px] border-[#E0EAFF] bg-[#F5F8FF]'>
+ <Folder className='h-4 w-4 text-[#444CE7]' />
+ </div>
+ )
+ }
+ {
+ config.data_source_type === DataSourceType.NOTION && (
+ <div className='mr-2 flex h-6 w-6 shrink-0 items-center justify-center rounded-md border-[0.5px] border-[#EAECF5]'>
+ <FileIcon type='notion' className='h-4 w-4' />
+ </div>
+ )
+ }
+ {
+ config.data_source_type === DataSourceType.WEB && (
+ <div className='mr-2 flex h-6 w-6 shrink-0 items-center justify-center rounded-md border-[0.5px] border-blue-100 bg-[#F5FAFF]'>
+ <Globe06 className='h-4 w-4 text-blue-600' />
+ </div>
+ )
+ }
+ <div className='system-sm-medium w-0 grow truncate text-text-secondary' title={config.name}>{config.name}</div>
+ </div>
+ <div className='ml-2 hidden shrink-0 items-center space-x-1 group-hover:flex'>
+ {
+ editable && <ActionButton
+ onClick={(e) => {
+ e.stopPropagation()
+ setShowSettingsModal(true)
+ }}
+ >
+ <RiEditLine className='h-4 w-4 shrink-0 text-text-tertiary' />
+ </ActionButton>
+ }
+ <ActionButton
+ onClick={() => onRemove(config.id)}
+ state={isDeleting ? ActionButtonState.Destructive : ActionButtonState.Default}
+ onMouseEnter={() => setIsDeleting(true)}
+ onMouseLeave={() => setIsDeleting(false)}
+ >
+ <RiDeleteBinLine className={cn('h-4 w-4 shrink-0 text-text-tertiary', isDeleting && 'text-text-destructive')} />
+ </ActionButton>
+ </div>
+ {
+ config.indexing_technique && <Badge
+ className='shrink-0 group-hover:hidden'
+ text={formatIndexingTechniqueAndMethod(config.indexing_technique, config.retrieval_model_dict?.search_method)}
+ />
+ }
+ {
+ config.provider === 'external' && <Badge
+ className='shrink-0 group-hover:hidden'
+ text={t('dataset.externalTag') as string}
+ />
+ }
+ <Drawer isOpen={showSettingsModal} onClose={() => setShowSettingsModal(false)} footer={null} mask={isMobile} panelClassName='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'>
+ <SettingsModal
+ currentDataset={config}
+ onCancel={() => setShowSettingsModal(false)}
+ onSave={handleSave}
+ />
+ </Drawer>
+ </div >
+ )
+}
+
+export default Item
diff --git a/app/components/app/configuration/dataset-config/card-item/style.module.css b/app/components/app/configuration/dataset-config/card-item/style.module.css
new file mode 100644
index 0000000..da07056
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/card-item/style.module.css
@@ -0,0 +1,22 @@
+.card {
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+ width: 100%;
+}
+
+.card:hover {
+ box-shadow: 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06);
+}
+
+.btnWrap {
+ padding-left: 64px;
+ visibility: hidden;
+ background: linear-gradient(270deg, #FFF 49.99%, rgba(255, 255, 255, 0.00) 98.1%);
+}
+
+.card:hover .btnWrap {
+ visibility: visible;
+}
+
+.settingBtn:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+}
diff --git a/app/components/app/configuration/dataset-config/context-var/index.tsx b/app/components/app/configuration/dataset-config/context-var/index.tsx
new file mode 100644
index 0000000..ebba9c5
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/context-var/index.tsx
@@ -0,0 +1,37 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import type { Props } from './var-picker'
+import VarPicker from './var-picker'
+import cn from '@/utils/classnames'
+import { BracketsX } from '@/app/components/base/icons/src/vender/line/development'
+import Tooltip from '@/app/components/base/tooltip'
+
+const ContextVar: FC<Props> = (props) => {
+ const { t } = useTranslation()
+ const { value, options } = props
+ const currItem = options.find(item => item.value === value)
+ const notSetVar = !currItem
+ return (
+ <div className={cn(notSetVar ? 'rounded-bl-xl rounded-br-xl border-[#FEF0C7] bg-[#FEF0C7]' : 'border-components-panel-border-subtle', 'flex h-12 items-center justify-between border-t px-3 ')}>
+ <div className='flex shrink-0 items-center space-x-1'>
+ <div className='p-1'>
+ <BracketsX className='h-4 w-4 text-text-accent' />
+ </div>
+ <div className='mr-1 text-sm font-medium text-text-secondary'>{t('appDebug.feature.dataSet.queryVariable.title')}</div>
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]'>
+ {t('appDebug.feature.dataSet.queryVariable.tip')}
+ </div>
+ }
+ />
+ </div>
+
+ <VarPicker {...props} />
+ </div>
+ )
+}
+
+export default React.memo(ContextVar)
diff --git a/app/components/app/configuration/dataset-config/context-var/var-picker.tsx b/app/components/app/configuration/dataset-config/context-var/var-picker.tsx
new file mode 100644
index 0000000..c443ea0
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/context-var/var-picker.tsx
@@ -0,0 +1,104 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { ChevronDownIcon } from '@heroicons/react/24/outline'
+import cn from '@/utils/classnames'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import type { IInputTypeIconProps } from '@/app/components/app/configuration/config-var/input-type-icon'
+import IconTypeIcon from '@/app/components/app/configuration/config-var/input-type-icon'
+
+type Option = { name: string; value: string; type: string }
+export type Props = {
+ triggerClassName?: string
+ className?: string
+ value: string | undefined
+ options: Option[]
+ onChange: (value: string) => void
+ notSelectedVarTip?: string | null
+}
+
+const VarItem: FC<{ item: Option }> = ({ item }) => (
+ <div className='flex h-[18px] items-center space-x-1 rounded bg-[#EFF8FF] px-1'>
+ <IconTypeIcon type={item.type as IInputTypeIconProps['type']} className='text-[#1570EF]' />
+ <div className='flex text-xs font-medium text-[#1570EF]'>
+ <span className='opacity-60'>{'{{'}</span>
+ <span className='max-w-[150px] truncate'>{item.value}</span>
+ <span className='opacity-60'>{'}}'}</span>
+ </div>
+ </div>
+)
+const VarPicker: FC<Props> = ({
+ triggerClassName,
+ className,
+ value,
+ options,
+ onChange,
+ notSelectedVarTip,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const currItem = options.find(item => item.value === value)
+ const notSetVar = !currItem
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 8,
+ }}
+ >
+ <PortalToFollowElemTrigger className={cn(triggerClassName)} onClick={() => setOpen(v => !v)}>
+ <div className={cn(
+ className,
+ notSetVar ? 'border-[#FEDF89] bg-[#FFFCF5] text-[#DC6803]' : ' border-components-button-secondary-border text-text-accent hover:bg-components-button-secondary-bg',
+ open ? 'bg-components-button-secondary-bg' : 'bg-transparent',
+ `
+ flex h-8 cursor-pointer items-center justify-center space-x-1 rounded-lg border px-2 text-[13px]
+ font-medium shadow-xs
+ `)}>
+ <div>
+ {value
+ ? (
+ <VarItem item={currItem as Option} />
+ )
+ : (<div>
+ {notSelectedVarTip || t('appDebug.feature.dataSet.queryVariable.choosePlaceholder')}
+ </div>)}
+ </div>
+ <ChevronDownIcon className={cn(open && 'rotate-180 text-text-tertiary', 'h-3.5 w-3.5')} />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 1000 }}>
+ {options.length > 0
+ ? (<div className='max-h-[50vh] w-[240px] overflow-y-auto rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg'>
+ {options.map(({ name, value, type }, index) => (
+ <div
+ key={index}
+ className='flex cursor-pointer rounded-lg px-3 py-1 hover:bg-state-base-hover'
+ onClick={() => {
+ onChange(value)
+ setOpen(false)
+ }}
+ >
+ <VarItem item={{ name, value, type }} />
+ </div>
+ ))}
+ </div>)
+ : (
+ <div className='w-[240px] rounded-lg border border-components-panel-border bg-components-panel-bg p-6 shadow-lg'>
+ <div className='mb-1 text-sm font-medium text-text-secondary'>{t('appDebug.feature.dataSet.queryVariable.noVar')}</div>
+ <div className='text-xs leading-normal text-text-tertiary'>{t('appDebug.feature.dataSet.queryVariable.noVarTip')}</div>
+ </div>
+ )}
+
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(VarPicker)
diff --git a/app/components/app/configuration/dataset-config/index.tsx b/app/components/app/configuration/dataset-config/index.tsx
new file mode 100644
index 0000000..6165cfd
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/index.tsx
@@ -0,0 +1,288 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import { intersectionBy } from 'lodash-es'
+import { useContext } from 'use-context-selector'
+import produce from 'immer'
+import { v4 as uuid4 } from 'uuid'
+import { useFormattingChangedDispatcher } from '../debug/hooks'
+import FeaturePanel from '../base/feature-panel'
+import OperationBtn from '../base/operation-btn'
+import CardItem from './card-item/item'
+import ParamsConfig from './params-config'
+import ContextVar from './context-var'
+import ConfigContext from '@/context/debug-configuration'
+import { AppType } from '@/types/app'
+import type { DataSet } from '@/models/datasets'
+import {
+ getMultipleRetrievalConfig,
+ getSelectedDatasetsMode,
+} from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
+import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { useSelector as useAppContextSelector } from '@/context/app-context'
+import { hasEditPermissionForDataset } from '@/utils/permission'
+import MetadataFilter from '@/app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-filter'
+import type {
+ HandleAddCondition,
+ HandleRemoveCondition,
+ HandleToggleConditionLogicalOperator,
+ HandleUpdateCondition,
+ MetadataFilteringModeEnum,
+} from '@/app/components/workflow/nodes/knowledge-retrieval/types'
+import {
+ ComparisonOperator,
+ LogicalOperator,
+ MetadataFilteringVariableType,
+} from '@/app/components/workflow/nodes/knowledge-retrieval/types'
+
+const DatasetConfig: FC = () => {
+ const { t } = useTranslation()
+ const userProfile = useAppContextSelector(s => s.userProfile)
+ const {
+ mode,
+ dataSets: dataSet,
+ setDataSets: setDataSet,
+ modelConfig,
+ setModelConfig,
+ showSelectDataSet,
+ isAgent,
+ datasetConfigs,
+ datasetConfigsRef,
+ setDatasetConfigs,
+ setRerankSettingModalOpen,
+ } = useContext(ConfigContext)
+ const formattingChangedDispatcher = useFormattingChangedDispatcher()
+
+ const hasData = dataSet.length > 0
+
+ const {
+ currentModel: currentRerankModel,
+ currentProvider: currentRerankProvider,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
+
+ const onRemove = (id: string) => {
+ const filteredDataSets = dataSet.filter(item => item.id !== id)
+ setDataSet(filteredDataSets)
+ const retrievalConfig = getMultipleRetrievalConfig(datasetConfigs as any, filteredDataSets, dataSet, {
+ provider: currentRerankProvider?.provider,
+ model: currentRerankModel?.model,
+ })
+ setDatasetConfigs({
+ ...(datasetConfigs as any),
+ ...retrievalConfig,
+ })
+ const {
+ allExternal,
+ allInternal,
+ mixtureInternalAndExternal,
+ mixtureHighQualityAndEconomic,
+ inconsistentEmbeddingModel,
+ } = getSelectedDatasetsMode(filteredDataSets)
+
+ if (
+ (allInternal && (mixtureHighQualityAndEconomic || inconsistentEmbeddingModel))
+ || mixtureInternalAndExternal
+ || allExternal
+ )
+ setRerankSettingModalOpen(true)
+ formattingChangedDispatcher()
+ }
+
+ const handleSave = (newDataset: DataSet) => {
+ const index = dataSet.findIndex(item => item.id === newDataset.id)
+
+ const newDatasets = [...dataSet.slice(0, index), newDataset, ...dataSet.slice(index + 1)]
+ setDataSet(newDatasets)
+ formattingChangedDispatcher()
+ }
+
+ const promptVariables = modelConfig.configs.prompt_variables
+ const promptVariablesToSelect = promptVariables.map(item => ({
+ name: item.name,
+ type: item.type,
+ value: item.key,
+ }))
+ const selectedContextVar = promptVariables?.find(item => item.is_context_var)
+ const handleSelectContextVar = (selectedValue: string) => {
+ const newModelConfig = produce(modelConfig, (draft) => {
+ draft.configs.prompt_variables = modelConfig.configs.prompt_variables.map((item) => {
+ return ({
+ ...item,
+ is_context_var: item.key === selectedValue,
+ })
+ })
+ })
+ setModelConfig(newModelConfig)
+ }
+
+ const formattedDataset = useMemo(() => {
+ return dataSet.map((item) => {
+ const datasetConfig = {
+ createdBy: item.created_by,
+ partialMemberList: item.partial_member_list || [],
+ permission: item.permission,
+ }
+ return {
+ ...item,
+ editable: hasEditPermissionForDataset(userProfile?.id || '', datasetConfig),
+ }
+ })
+ }, [dataSet, userProfile?.id])
+
+ const metadataList = useMemo(() => {
+ return intersectionBy(...formattedDataset.filter((dataset) => {
+ return !!dataset.doc_metadata
+ }).map((dataset) => {
+ return dataset.doc_metadata!
+ }), 'name')
+ }, [formattedDataset])
+
+ const handleMetadataFilterModeChange = useCallback((newMode: MetadataFilteringModeEnum) => {
+ setDatasetConfigs(produce(datasetConfigsRef.current!, (draft) => {
+ draft.metadata_filtering_mode = newMode
+ }))
+ }, [setDatasetConfigs, datasetConfigsRef])
+
+ const handleAddCondition = useCallback<HandleAddCondition>(({ name, type }) => {
+ let operator: ComparisonOperator = ComparisonOperator.is
+
+ if (type === MetadataFilteringVariableType.number)
+ operator = ComparisonOperator.equal
+
+ const newCondition = {
+ id: uuid4(),
+ name,
+ comparison_operator: operator,
+ }
+
+ const newInputs = produce(datasetConfigsRef.current!, (draft) => {
+ if (draft.metadata_filtering_conditions) {
+ draft.metadata_filtering_conditions.conditions.push(newCondition)
+ }
+ else {
+ draft.metadata_filtering_conditions = {
+ logical_operator: LogicalOperator.and,
+ conditions: [newCondition],
+ }
+ }
+ })
+ setDatasetConfigs(newInputs)
+ }, [setDatasetConfigs, datasetConfigsRef])
+
+ const handleRemoveCondition = useCallback<HandleRemoveCondition>((id) => {
+ const conditions = datasetConfigsRef.current!.metadata_filtering_conditions?.conditions || []
+ const index = conditions.findIndex(c => c.id === id)
+ const newInputs = produce(datasetConfigsRef.current!, (draft) => {
+ if (index > -1)
+ draft.metadata_filtering_conditions?.conditions.splice(index, 1)
+ })
+ setDatasetConfigs(newInputs)
+ }, [setDatasetConfigs, datasetConfigsRef])
+
+ const handleUpdateCondition = useCallback<HandleUpdateCondition>((id, newCondition) => {
+ const conditions = datasetConfigsRef.current!.metadata_filtering_conditions?.conditions || []
+ const index = conditions.findIndex(c => c.id === id)
+ const newInputs = produce(datasetConfigsRef.current!, (draft) => {
+ if (index > -1)
+ draft.metadata_filtering_conditions!.conditions[index] = newCondition
+ })
+ setDatasetConfigs(newInputs)
+ }, [setDatasetConfigs, datasetConfigsRef])
+
+ const handleToggleConditionLogicalOperator = useCallback<HandleToggleConditionLogicalOperator>(() => {
+ const oldLogicalOperator = datasetConfigsRef.current!.metadata_filtering_conditions?.logical_operator
+ const newLogicalOperator = oldLogicalOperator === LogicalOperator.and ? LogicalOperator.or : LogicalOperator.and
+ const newInputs = produce(datasetConfigsRef.current!, (draft) => {
+ draft.metadata_filtering_conditions!.logical_operator = newLogicalOperator
+ })
+ setDatasetConfigs(newInputs)
+ }, [setDatasetConfigs, datasetConfigsRef])
+
+ const handleMetadataModelChange = useCallback((model: { provider: string; modelId: string; mode?: string }) => {
+ const newInputs = produce(datasetConfigsRef.current!, (draft) => {
+ draft.metadata_model_config = {
+ provider: model.provider,
+ name: model.modelId,
+ mode: model.mode || 'chat',
+ completion_params: draft.metadata_model_config?.completion_params || { temperature: 0.7 },
+ }
+ })
+ setDatasetConfigs(newInputs)
+ }, [setDatasetConfigs, datasetConfigsRef])
+
+ const handleMetadataCompletionParamsChange = useCallback((newParams: Record<string, any>) => {
+ const newInputs = produce(datasetConfigsRef.current!, (draft) => {
+ draft.metadata_model_config = {
+ ...draft.metadata_model_config!,
+ completion_params: newParams,
+ }
+ })
+ setDatasetConfigs(newInputs)
+ }, [setDatasetConfigs, datasetConfigsRef])
+
+ return (
+ <FeaturePanel
+ className='mt-2'
+ title={t('appDebug.feature.dataSet.title')}
+ headerRight={
+ <div className='flex items-center gap-1'>
+ {!isAgent && <ParamsConfig disabled={!hasData} selectedDatasets={dataSet} />}
+ <OperationBtn type="add" onClick={showSelectDataSet} />
+ </div>
+ }
+ hasHeaderBottomBorder={!hasData}
+ noBodySpacing
+ >
+ {hasData
+ ? (
+ <div className='mt-1 flex flex-wrap justify-between px-3 pb-3'>
+ {formattedDataset.map(item => (
+ <CardItem
+ key={item.id}
+ config={item}
+ onRemove={onRemove}
+ onSave={handleSave}
+ editable={item.editable}
+ />
+ ))}
+ </div>
+ )
+ : (
+ <div className='mt-1 px-3 pb-3'>
+ <div className='pb-1 pt-2 text-xs text-text-tertiary'>{t('appDebug.feature.dataSet.noData')}</div>
+ </div>
+ )}
+
+ <div className='border-t border-t-divider-subtle py-2'>
+ <MetadataFilter
+ metadataList={metadataList}
+ selectedDatasetsLoaded
+ metadataFilterMode={datasetConfigs.metadata_filtering_mode}
+ metadataFilteringConditions={datasetConfigs.metadata_filtering_conditions}
+ handleAddCondition={handleAddCondition}
+ handleMetadataFilterModeChange={handleMetadataFilterModeChange}
+ handleRemoveCondition={handleRemoveCondition}
+ handleToggleConditionLogicalOperator={handleToggleConditionLogicalOperator}
+ handleUpdateCondition={handleUpdateCondition}
+ metadataModelConfig={datasetConfigs.metadata_model_config}
+ handleMetadataModelChange={handleMetadataModelChange}
+ handleMetadataCompletionParamsChange={handleMetadataCompletionParamsChange}
+ isCommonVariable
+ availableCommonStringVars={promptVariablesToSelect.filter(item => item.type === MetadataFilteringVariableType.string || item.type === MetadataFilteringVariableType.select)}
+ availableCommonNumberVars={promptVariablesToSelect.filter(item => item.type === MetadataFilteringVariableType.number)}
+ />
+ </div>
+
+ {mode === AppType.completion && dataSet.length > 0 && (
+ <ContextVar
+ value={selectedContextVar?.key}
+ options={promptVariablesToSelect}
+ onChange={handleSelectContextVar}
+ />
+ )}
+ </FeaturePanel>
+ )
+}
+export default React.memo(DatasetConfig)
diff --git a/app/components/app/configuration/dataset-config/params-config/config-content.tsx b/app/components/app/configuration/dataset-config/params-config/config-content.tsx
new file mode 100644
index 0000000..86025f6
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/params-config/config-content.tsx
@@ -0,0 +1,382 @@
+'use client'
+
+import { memo, useCallback, useEffect, useMemo } from 'react'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import WeightedScore from './weighted-score'
+import TopKItem from '@/app/components/base/param-item/top-k-item'
+import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item'
+import { RETRIEVE_TYPE } from '@/types/app'
+import type {
+ DatasetConfigs,
+} from '@/models/debug'
+import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
+import { useCurrentProviderAndModel, useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import type { ModelConfig } from '@/app/components/workflow/types'
+import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
+import Tooltip from '@/app/components/base/tooltip'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import type {
+ DataSet,
+} from '@/models/datasets'
+import { RerankingModeEnum } from '@/models/datasets'
+import cn from '@/utils/classnames'
+import { useSelectedDatasetsMode } from '@/app/components/workflow/nodes/knowledge-retrieval/hooks'
+import Switch from '@/app/components/base/switch'
+import Toast from '@/app/components/base/toast'
+import Divider from '@/app/components/base/divider'
+import { noop } from 'lodash-es'
+
+type Props = {
+ datasetConfigs: DatasetConfigs
+ onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void
+ isInWorkflow?: boolean
+ singleRetrievalModelConfig?: ModelConfig
+ onSingleRetrievalModelChange?: (config: ModelConfig) => void
+ onSingleRetrievalModelParamsChange?: (config: ModelConfig) => void
+ selectedDatasets?: DataSet[]
+}
+
+const ConfigContent: FC<Props> = ({
+ datasetConfigs,
+ onChange,
+ isInWorkflow,
+ singleRetrievalModelConfig: singleRetrievalConfig = {} as ModelConfig,
+ onSingleRetrievalModelChange = noop,
+ onSingleRetrievalModelParamsChange = noop,
+ selectedDatasets = [],
+}) => {
+ const { t } = useTranslation()
+ const selectedDatasetsMode = useSelectedDatasetsMode(selectedDatasets)
+ const type = datasetConfigs.retrieval_model
+
+ useEffect(() => {
+ if (type === RETRIEVE_TYPE.oneWay) {
+ onChange({
+ ...datasetConfigs,
+ retrieval_model: RETRIEVE_TYPE.multiWay,
+ }, isInWorkflow)
+ }
+ }, [type, datasetConfigs, isInWorkflow, onChange])
+
+ const {
+ modelList: rerankModelList,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
+
+ const {
+ currentModel: currentRerankModel,
+ } = useCurrentProviderAndModel(
+ rerankModelList,
+ {
+ provider: datasetConfigs.reranking_model?.reranking_provider_name,
+ model: datasetConfigs.reranking_model?.reranking_model_name,
+ },
+ )
+
+ const rerankModel = useMemo(() => {
+ return {
+ provider_name: datasetConfigs?.reranking_model?.reranking_provider_name ?? '',
+ model_name: datasetConfigs?.reranking_model?.reranking_model_name ?? '',
+ }
+ }, [datasetConfigs.reranking_model])
+
+ const handleParamChange = (key: string, value: number) => {
+ if (key === 'top_k') {
+ onChange({
+ ...datasetConfigs,
+ top_k: value,
+ })
+ }
+ else if (key === 'score_threshold') {
+ onChange({
+ ...datasetConfigs,
+ score_threshold: value,
+ })
+ }
+ }
+
+ const handleSwitch = (key: string, enable: boolean) => {
+ if (key === 'top_k')
+ return
+
+ onChange({
+ ...datasetConfigs,
+ score_threshold_enabled: enable,
+ })
+ }
+
+ const handleWeightedScoreChange = (value: { value: number[] }) => {
+ const configs = {
+ ...datasetConfigs,
+ weights: {
+ ...datasetConfigs.weights!,
+ vector_setting: {
+ ...datasetConfigs.weights!.vector_setting!,
+ vector_weight: value.value[0],
+ },
+ keyword_setting: {
+ keyword_weight: value.value[1],
+ },
+ },
+ }
+ onChange(configs)
+ }
+
+ const handleRerankModeChange = (mode: RerankingModeEnum) => {
+ if (mode === datasetConfigs.reranking_mode)
+ return
+
+ if (mode === RerankingModeEnum.RerankingModel && !currentRerankModel)
+ Toast.notify({ type: 'error', message: t('workflow.errorMsg.rerankModelRequired') })
+
+ onChange({
+ ...datasetConfigs,
+ reranking_mode: mode,
+ })
+ }
+
+ const model = singleRetrievalConfig
+
+ const rerankingModeOptions = [
+ {
+ value: RerankingModeEnum.WeightedScore,
+ label: t('dataset.weightedScore.title'),
+ tips: t('dataset.weightedScore.description'),
+ },
+ {
+ value: RerankingModeEnum.RerankingModel,
+ label: t('common.modelProvider.rerankModel.key'),
+ tips: t('common.modelProvider.rerankModel.tip'),
+ },
+ ]
+
+ const showWeightedScore = selectedDatasetsMode.allHighQuality
+ && !selectedDatasetsMode.inconsistentEmbeddingModel
+
+ const showWeightedScorePanel = showWeightedScore && datasetConfigs.reranking_mode === RerankingModeEnum.WeightedScore && datasetConfigs.weights
+ const selectedRerankMode = datasetConfigs.reranking_mode || RerankingModeEnum.RerankingModel
+
+ const canManuallyToggleRerank = useMemo(() => {
+ return (selectedDatasetsMode.allInternal && selectedDatasetsMode.allEconomic)
+ || selectedDatasetsMode.allExternal
+ }, [selectedDatasetsMode.allEconomic, selectedDatasetsMode.allExternal, selectedDatasetsMode.allInternal])
+
+ const showRerankModel = useMemo(() => {
+ if (!canManuallyToggleRerank)
+ return true
+
+ return datasetConfigs.reranking_enable
+ }, [datasetConfigs.reranking_enable, canManuallyToggleRerank])
+
+ const handleDisabledSwitchClick = useCallback((enable: boolean) => {
+ if (!currentRerankModel && enable)
+ Toast.notify({ type: 'error', message: t('workflow.errorMsg.rerankModelRequired') })
+ onChange({
+ ...datasetConfigs,
+ reranking_enable: enable,
+ })
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [currentRerankModel, datasetConfigs, onChange])
+
+ return (
+ <div>
+ <div className='system-xl-semibold text-text-primary'>{t('dataset.retrievalSettings')}</div>
+ <div className='system-xs-regular text-text-tertiary'>
+ {t('dataset.defaultRetrievalTip')}
+ </div>
+ {type === RETRIEVE_TYPE.multiWay && (
+ <>
+ <div className='my-2 flex h-6 items-center py-1'>
+ <div className='system-xs-semibold-uppercase mr-2 shrink-0 text-text-secondary'>
+ {t('dataset.rerankSettings')}
+ </div>
+ <Divider bgStyle='gradient' className='mx-0 !h-px' />
+ </div>
+ {
+ selectedDatasetsMode.inconsistentEmbeddingModel
+ && (
+ <div className='system-xs-medium mt-4 text-text-warning'>
+ {t('dataset.inconsistentEmbeddingModelTip')}
+ </div>
+ )
+ }
+ {
+ selectedDatasetsMode.mixtureInternalAndExternal && (
+ <div className='system-xs-medium mt-4 text-text-warning'>
+ {t('dataset.mixtureInternalAndExternalTip')}
+ </div>
+ )
+ }
+ {
+ selectedDatasetsMode.allExternal && (
+ <div className='system-xs-medium mt-4 text-text-warning'>
+ {t('dataset.allExternalTip')}
+ </div>
+ )
+ }
+ {
+ selectedDatasetsMode.mixtureHighQualityAndEconomic
+ && (
+ <div className='system-xs-medium mt-4 text-text-warning'>
+ {t('dataset.mixtureHighQualityAndEconomicTip')}
+ </div>
+ )
+ }
+ {
+ showWeightedScore && (
+ <div className='flex items-center justify-between'>
+ {
+ rerankingModeOptions.map(option => (
+ <div
+ key={option.value}
+ className={cn(
+ 'system-sm-medium flex h-8 w-[calc((100%-8px)/2)] cursor-pointer items-center justify-center rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary',
+ selectedRerankMode === option.value && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary',
+ )}
+ onClick={() => handleRerankModeChange(option.value)}
+ >
+ <div className='truncate'>{option.label}</div>
+ <Tooltip
+ popupContent={
+ <div className='w-[200px]'>
+ {option.tips}
+ </div>
+ }
+ popupClassName='ml-0.5'
+ triggerClassName='ml-0.5 w-3.5 h-3.5'
+ />
+ </div>
+ ))
+ }
+ </div>
+ )
+ }
+ {
+ !showWeightedScorePanel && (
+ <div className='mt-2'>
+ <div className='flex items-center'>
+ {
+ selectedDatasetsMode.allEconomic && !selectedDatasetsMode.mixtureInternalAndExternal && (
+ <Switch
+ size='md'
+ defaultValue={showRerankModel}
+ disabled={!canManuallyToggleRerank}
+ onChange={handleDisabledSwitchClick}
+ />
+ )
+ }
+ <div className='system-sm-semibold ml-1 leading-[32px] text-text-secondary'>{t('common.modelProvider.rerankModel.key')}</div>
+ <Tooltip
+ popupContent={
+ <div className="w-[200px]">
+ {t('common.modelProvider.rerankModel.tip')}
+ </div>
+ }
+ popupClassName='ml-1'
+ triggerClassName='ml-1 w-4 h-4'
+ />
+ </div>
+ {
+ showRerankModel && (
+ <div>
+ <ModelSelector
+ defaultModel={rerankModel && { provider: rerankModel?.provider_name, model: rerankModel?.model_name }}
+ onSelect={(v) => {
+ onChange({
+ ...datasetConfigs,
+ reranking_model: {
+ reranking_provider_name: v.provider,
+ reranking_model_name: v.model,
+ },
+ })
+ }}
+ modelList={rerankModelList}
+ />
+ </div>
+ )}
+ </div>
+ )
+ }
+ {
+ showWeightedScorePanel
+ && (
+ <div className='mt-2 space-y-4'>
+ <WeightedScore
+ value={{
+ value: [
+ datasetConfigs.weights!.vector_setting.vector_weight,
+ datasetConfigs.weights!.keyword_setting.keyword_weight,
+ ],
+ }}
+ onChange={handleWeightedScoreChange}
+ />
+ <TopKItem
+ value={datasetConfigs.top_k}
+ onChange={handleParamChange}
+ enable={true}
+ />
+ <ScoreThresholdItem
+ value={datasetConfigs.score_threshold as number}
+ onChange={handleParamChange}
+ enable={datasetConfigs.score_threshold_enabled}
+ hasSwitch={true}
+ onSwitchChange={handleSwitch}
+ />
+ </div>
+ )
+ }
+ {
+ !showWeightedScorePanel
+ && (
+ <div className='mt-4 space-y-4'>
+ <TopKItem
+ value={datasetConfigs.top_k}
+ onChange={handleParamChange}
+ enable={true}
+ />
+ {
+ showRerankModel && (
+ <ScoreThresholdItem
+ value={datasetConfigs.score_threshold as number}
+ onChange={handleParamChange}
+ enable={datasetConfigs.score_threshold_enabled}
+ hasSwitch={true}
+ onSwitchChange={handleSwitch}
+ />
+ )
+ }
+ </div>
+ )
+ }
+ </>
+ )}
+
+ {isInWorkflow && type === RETRIEVE_TYPE.oneWay && (
+ <div className='mt-4'>
+ <div className='flex items-center space-x-0.5'>
+ <div className='text-[13px] font-medium leading-[32px] text-text-primary'>{t('common.modelProvider.systemReasoningModel.key')}</div>
+ <Tooltip
+ popupContent={t('common.modelProvider.systemReasoningModel.tip')}
+ />
+ </div>
+ <ModelParameterModal
+ isInWorkflow={isInWorkflow}
+ popupClassName='!w-[387px]'
+ portalToFollowElemContentClassName='!z-[1002]'
+ isAdvancedMode={true}
+ mode={model?.mode}
+ provider={model?.provider}
+ completionParams={model?.completion_params}
+ modelId={model?.name}
+ setModel={onSingleRetrievalModelChange}
+ onCompletionParamsChange={onSingleRetrievalModelParamsChange}
+ hideDebugWithMultipleModel
+ debugWithMultipleModel={false}
+ />
+ </div>
+ )
+ }
+ </div >
+ )
+}
+export default memo(ConfigContent)
diff --git a/app/components/app/configuration/dataset-config/params-config/index.tsx b/app/components/app/configuration/dataset-config/params-config/index.tsx
new file mode 100644
index 0000000..df2b429
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/params-config/index.tsx
@@ -0,0 +1,156 @@
+'use client'
+import { memo, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { RiEqualizer2Line } from '@remixicon/react'
+import ConfigContent from './config-content'
+import cn from '@/utils/classnames'
+import ConfigContext from '@/context/debug-configuration'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import { RETRIEVE_TYPE } from '@/types/app'
+import Toast from '@/app/components/base/toast'
+import { useCurrentProviderAndModel, useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { RerankingModeEnum } from '@/models/datasets'
+import type { DataSet } from '@/models/datasets'
+import type { DatasetConfigs } from '@/models/debug'
+import {
+ getMultipleRetrievalConfig,
+} from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
+
+type ParamsConfigProps = {
+ disabled?: boolean
+ selectedDatasets: DataSet[]
+}
+const ParamsConfig = ({
+ disabled,
+ selectedDatasets,
+}: ParamsConfigProps) => {
+ const { t } = useTranslation()
+ const {
+ datasetConfigs,
+ setDatasetConfigs,
+ rerankSettingModalOpen,
+ setRerankSettingModalOpen,
+ } = useContext(ConfigContext)
+ const [tempDataSetConfigs, setTempDataSetConfigs] = useState(datasetConfigs)
+
+ useEffect(() => {
+ setTempDataSetConfigs(datasetConfigs)
+ }, [datasetConfigs])
+
+ const {
+ modelList: rerankModelList,
+ currentModel: rerankDefaultModel,
+ currentProvider: rerankDefaultProvider,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
+
+ const {
+ currentModel: isCurrentRerankModelValid,
+ } = useCurrentProviderAndModel(
+ rerankModelList,
+ {
+ provider: tempDataSetConfigs.reranking_model?.reranking_provider_name ?? '',
+ model: tempDataSetConfigs.reranking_model?.reranking_model_name ?? '',
+ },
+ )
+
+ const isValid = () => {
+ let errMsg = ''
+ if (tempDataSetConfigs.retrieval_model === RETRIEVE_TYPE.multiWay) {
+ if (tempDataSetConfigs.reranking_enable
+ && tempDataSetConfigs.reranking_mode === RerankingModeEnum.RerankingModel
+ && !isCurrentRerankModelValid
+ )
+ errMsg = t('appDebug.datasetConfig.rerankModelRequired')
+ }
+ if (errMsg) {
+ Toast.notify({
+ type: 'error',
+ message: errMsg,
+ })
+ }
+ return !errMsg
+ }
+ const handleSave = () => {
+ if (!isValid())
+ return
+ setDatasetConfigs(tempDataSetConfigs)
+ setRerankSettingModalOpen(false)
+ }
+
+ const handleSetTempDataSetConfigs = (newDatasetConfigs: DatasetConfigs) => {
+ const { datasets, retrieval_model, score_threshold_enabled, ...restConfigs } = newDatasetConfigs
+
+ const retrievalConfig = getMultipleRetrievalConfig({
+ top_k: restConfigs.top_k,
+ score_threshold: restConfigs.score_threshold,
+ reranking_model: restConfigs.reranking_model && {
+ provider: restConfigs.reranking_model.reranking_provider_name,
+ model: restConfigs.reranking_model.reranking_model_name,
+ },
+ reranking_mode: restConfigs.reranking_mode,
+ weights: restConfigs.weights,
+ reranking_enable: restConfigs.reranking_enable,
+ }, selectedDatasets, selectedDatasets, {
+ provider: rerankDefaultProvider?.provider,
+ model: rerankDefaultModel?.model,
+ })
+
+ setTempDataSetConfigs({
+ ...retrievalConfig,
+ reranking_model: {
+ reranking_provider_name: retrievalConfig.reranking_model?.provider || '',
+ reranking_model_name: retrievalConfig.reranking_model?.model || '',
+ },
+ retrieval_model,
+ score_threshold_enabled,
+ datasets,
+ })
+ }
+
+ return (
+ <div>
+ <Button
+ variant='ghost'
+ size='small'
+ className={cn('h-7', rerankSettingModalOpen && 'bg-components-button-ghost-bg-hover')}
+ onClick={() => {
+ setRerankSettingModalOpen(true)
+ }}
+ disabled={disabled}
+ >
+ <RiEqualizer2Line className='mr-1 h-3.5 w-3.5' />
+ {t('dataset.retrievalSettings')}
+ </Button>
+ {
+ rerankSettingModalOpen && (
+ <Modal
+ isShow={rerankSettingModalOpen}
+ onClose={() => {
+ setRerankSettingModalOpen(false)
+ }}
+ className='sm:min-w-[528px]'
+ >
+ <ConfigContent
+ datasetConfigs={tempDataSetConfigs}
+ onChange={handleSetTempDataSetConfigs}
+ selectedDatasets={selectedDatasets}
+ />
+
+ <div className='mt-6 flex justify-end'>
+ <Button className='mr-2 shrink-0' onClick={() => {
+ setTempDataSetConfigs(datasetConfigs)
+ setRerankSettingModalOpen(false)
+ }}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' className='shrink-0' onClick={handleSave} >{t('common.operation.save')}</Button>
+ </div>
+ </Modal>
+ )
+ }
+
+ </div>
+ )
+}
+export default memo(ParamsConfig)
diff --git a/app/components/app/configuration/dataset-config/params-config/weighted-score.css b/app/components/app/configuration/dataset-config/params-config/weighted-score.css
new file mode 100644
index 0000000..ef93506
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/params-config/weighted-score.css
@@ -0,0 +1,7 @@
+.weightedScoreSliderTrack {
+ background: var(--color-util-colors-blue-light-blue-light-500) !important;
+}
+
+.weightedScoreSliderTrack-1 {
+ background: transparent !important;
+}
diff --git a/app/components/app/configuration/dataset-config/params-config/weighted-score.tsx b/app/components/app/configuration/dataset-config/params-config/weighted-score.tsx
new file mode 100644
index 0000000..5f0ad94
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/params-config/weighted-score.tsx
@@ -0,0 +1,62 @@
+import { memo } from 'react'
+import { useTranslation } from 'react-i18next'
+import './weighted-score.css'
+import Slider from '@/app/components/base/slider'
+import cn from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+const formatNumber = (value: number) => {
+ if (value > 0 && value < 1)
+ return `0.${value * 10}`
+ else if (value === 1)
+ return '1.0'
+
+ return value
+}
+
+type Value = {
+ value: number[]
+}
+
+type WeightedScoreProps = {
+ value: Value
+ onChange: (value: Value) => void
+}
+const WeightedScore = ({
+ value,
+ onChange = noop,
+}: WeightedScoreProps) => {
+ const { t } = useTranslation()
+
+ return (
+ <div>
+ <div className='space-x-3 rounded-lg border border-components-panel-border px-3 pb-2 pt-5'>
+ <Slider
+ className={cn('h-0.5 grow rounded-full !bg-util-colors-teal-teal-500')}
+ max={1.0}
+ min={0}
+ step={0.1}
+ value={value.value[0]}
+ onChange={v => onChange({ value: [v, (10 - v * 10) / 10] })}
+ trackClassName='weightedScoreSliderTrack'
+ />
+ <div className='mt-3 flex justify-between'>
+ <div className='system-xs-semibold-uppercase flex w-[90px] shrink-0 items-center text-util-colors-blue-light-blue-light-500'>
+ <div className='mr-1 truncate uppercase' title={t('dataset.weightedScore.semantic') || ''}>
+ {t('dataset.weightedScore.semantic')}
+ </div>
+ {formatNumber(value.value[0])}
+ </div>
+ <div className='system-xs-semibold-uppercase flex w-[90px] shrink-0 items-center justify-end text-util-colors-teal-teal-500'>
+ {formatNumber(value.value[1])}
+ <div className='ml-1 truncate uppercase' title={t('dataset.weightedScore.keyword') || ''}>
+ {t('dataset.weightedScore.keyword')}
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default memo(WeightedScore)
diff --git a/app/components/app/configuration/dataset-config/select-dataset/index.tsx b/app/components/app/configuration/dataset-config/select-dataset/index.tsx
new file mode 100644
index 0000000..70f5e1e
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/select-dataset/index.tsx
@@ -0,0 +1,176 @@
+'use client'
+import type { FC } from 'react'
+import React, { useRef, useState } from 'react'
+import { useGetState, useInfiniteScroll } from 'ahooks'
+import { useTranslation } from 'react-i18next'
+import Link from 'next/link'
+import produce from 'immer'
+import TypeIcon from '../type-icon'
+import Modal from '@/app/components/base/modal'
+import type { DataSet } from '@/models/datasets'
+import Button from '@/app/components/base/button'
+import { fetchDatasets } from '@/service/datasets'
+import Loading from '@/app/components/base/loading'
+import Badge from '@/app/components/base/badge'
+import { useKnowledge } from '@/hooks/use-knowledge'
+import cn from '@/utils/classnames'
+
+export type ISelectDataSetProps = {
+ isShow: boolean
+ onClose: () => void
+ selectedIds: string[]
+ onSelect: (dataSet: DataSet[]) => void
+}
+
+const SelectDataSet: FC<ISelectDataSetProps> = ({
+ isShow,
+ onClose,
+ selectedIds,
+ onSelect,
+}) => {
+ const { t } = useTranslation()
+ const [selected, setSelected] = React.useState<DataSet[]>(selectedIds.map(id => ({ id }) as any))
+ const [loaded, setLoaded] = React.useState(false)
+ const [datasets, setDataSets] = React.useState<DataSet[] | null>(null)
+ const hasNoData = !datasets || datasets?.length === 0
+ const canSelectMulti = true
+
+ const listRef = useRef<HTMLDivElement>(null)
+ const [page, setPage, getPage] = useGetState(1)
+ const [isNoMore, setIsNoMore] = useState(false)
+ const { formatIndexingTechniqueAndMethod } = useKnowledge()
+
+ useInfiniteScroll(
+ async () => {
+ if (!isNoMore) {
+ const { data, has_more } = await fetchDatasets({ url: '/datasets', params: { page } })
+ setPage(getPage() + 1)
+ setIsNoMore(!has_more)
+ const newList = [...(datasets || []), ...data.filter(item => item.indexing_technique || item.provider === 'external')]
+ setDataSets(newList)
+ setLoaded(true)
+ if (!selected.find(item => !item.name))
+ return { list: [] }
+
+ const newSelected = produce(selected, (draft) => {
+ selected.forEach((item, index) => {
+ if (!item.name) { // not fetched database
+ const newItem = newList.find(i => i.id === item.id)
+ if (newItem)
+ draft[index] = newItem
+ }
+ })
+ })
+ setSelected(newSelected)
+ }
+ return { list: [] }
+ },
+ {
+ target: listRef,
+ isNoMore: () => {
+ return isNoMore
+ },
+ reloadDeps: [isNoMore],
+ },
+ )
+
+ const toggleSelect = (dataSet: DataSet) => {
+ const isSelected = selected.some(item => item.id === dataSet.id)
+ if (isSelected) {
+ setSelected(selected.filter(item => item.id !== dataSet.id))
+ }
+ else {
+ if (canSelectMulti)
+ setSelected([...selected, dataSet])
+ else
+ setSelected([dataSet])
+ }
+ }
+
+ const handleSelect = () => {
+ onSelect(selected)
+ }
+ return (
+ <Modal
+ isShow={isShow}
+ onClose={onClose}
+ className='w-[400px]'
+ title={t('appDebug.feature.dataSet.selectTitle')}
+ >
+ {!loaded && (
+ <div className='flex h-[200px]'>
+ <Loading type='area' />
+ </div>
+ )}
+
+ {(loaded && hasNoData) && (
+ <div className='mt-6 flex h-[128px] items-center justify-center space-x-1 rounded-lg border text-[13px]'
+ style={{
+ background: 'rgba(0, 0, 0, 0.02)',
+ borderColor: 'rgba(0, 0, 0, 0.02',
+ }}
+ >
+ <span className='text-text-tertiary'>{t('appDebug.feature.dataSet.noDataSet')}</span>
+ <Link href={'/datasets/create'} className='font-normal text-text-accent'>{t('appDebug.feature.dataSet.toCreate')}</Link>
+ </div>
+ )}
+
+ {datasets && datasets?.length > 0 && (
+ <>
+ <div ref={listRef} className='mt-7 max-h-[286px] space-y-1 overflow-y-auto'>
+ {datasets.map(item => (
+ <div
+ key={item.id}
+ className={cn(
+ 'flex h-10 cursor-pointer items-center justify-between rounded-lg border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg px-2 shadow-xs hover:border-components-panel-border hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-sm',
+ selected.some(i => i.id === item.id) && 'border-[1.5px] border-components-option-card-option-selected-border bg-state-accent-hover shadow-xs hover:border-components-option-card-option-selected-border hover:bg-state-accent-hover hover:shadow-xs',
+ !item.embedding_available && 'hover:border-components-panel-border-subtle hover:bg-components-panel-on-panel-item-bg hover:shadow-xs',
+ )}
+ onClick={() => {
+ if (!item.embedding_available)
+ return
+ toggleSelect(item)
+ }}
+ >
+ <div className='mr-1 flex items-center overflow-hidden'>
+ <div className={cn('mr-2', !item.embedding_available && 'opacity-30')}>
+ <TypeIcon type="upload_file" size='md' />
+ </div>
+ <div className={cn('max-w-[200px] truncate text-[13px] font-medium text-text-secondary', !item.embedding_available && '!max-w-[120px] opacity-30')}>{item.name}</div>
+ {!item.embedding_available && (
+ <span className='ml-1 shrink-0 rounded-md border border-divider-deep px-1 text-xs font-normal leading-[18px] text-text-tertiary'>{t('dataset.unavailable')}</span>
+ )}
+ </div>
+ {
+ item.indexing_technique && (
+ <Badge
+ className='shrink-0'
+ text={formatIndexingTechniqueAndMethod(item.indexing_technique, item.retrieval_model_dict?.search_method)}
+ />
+ )
+ }
+ {
+ item.provider === 'external' && (
+ <Badge className='shrink-0' text={t('dataset.externalTag')} />
+ )
+ }
+ </div>
+ ))}
+ </div>
+ </>
+ )}
+ {loaded && (
+ <div className='mt-8 flex items-center justify-between'>
+ <div className='text-sm font-medium text-text-secondary'>
+ {selected.length > 0 && `${selected.length} ${t('appDebug.feature.dataSet.selected')}`}
+ </div>
+ <div className='flex space-x-2'>
+ <Button onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' onClick={handleSelect} disabled={hasNoData}>{t('common.operation.add')}</Button>
+ </div>
+ </div>
+ )}
+ </Modal>
+ )
+}
+export default React.memo(SelectDataSet)
diff --git a/app/components/app/configuration/dataset-config/settings-modal/index.tsx b/app/components/app/configuration/dataset-config/settings-modal/index.tsx
new file mode 100644
index 0000000..3170d33
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/settings-modal/index.tsx
@@ -0,0 +1,390 @@
+import type { FC } from 'react'
+import { useRef, useState } from 'react'
+import { useMount } from 'ahooks'
+import { useTranslation } from 'react-i18next'
+import { isEqual } from 'lodash-es'
+import { RiCloseLine } from '@remixicon/react'
+import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
+import cn from '@/utils/classnames'
+import IndexMethodRadio from '@/app/components/datasets/settings/index-method-radio'
+import Divider from '@/app/components/base/divider'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import { type DataSet, DatasetPermission } from '@/models/datasets'
+import { useToastContext } from '@/app/components/base/toast'
+import { updateDatasetSetting } from '@/service/datasets'
+import { useAppContext } from '@/context/app-context'
+import { useModalContext } from '@/context/modal-context'
+import type { RetrievalConfig } from '@/types/app'
+import RetrievalSettings from '@/app/components/datasets/external-knowledge-base/create/RetrievalSettings'
+import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
+import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
+import { isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
+import PermissionSelector from '@/app/components/datasets/settings/permission-selector'
+import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
+import {
+ useModelList,
+ useModelListAndDefaultModelAndCurrentProviderAndModel,
+} from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { fetchMembers } from '@/service/common'
+import type { Member } from '@/models/common'
+
+type SettingsModalProps = {
+ currentDataset: DataSet
+ onCancel: () => void
+ onSave: (newDataset: DataSet) => void
+}
+
+const rowClass = `
+ flex justify-between py-4 flex-wrap gap-y-2
+`
+
+const labelClass = `
+ flex w-[168px] shrink-0
+`
+
+const SettingsModal: FC<SettingsModalProps> = ({
+ currentDataset,
+ onCancel,
+ onSave,
+}) => {
+ const { data: embeddingsModelList } = useModelList(ModelTypeEnum.textEmbedding)
+ const {
+ modelList: rerankModelList,
+ defaultModel: rerankDefaultModel,
+ currentModel: isRerankDefaultModelValid,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const ref = useRef(null)
+ const isExternal = currentDataset.provider === 'external'
+ const { setShowAccountSettingModal } = useModalContext()
+ const [loading, setLoading] = useState(false)
+ const { isCurrentWorkspaceDatasetOperator } = useAppContext()
+ const [localeCurrentDataset, setLocaleCurrentDataset] = useState({ ...currentDataset })
+ const [topK, setTopK] = useState(localeCurrentDataset?.external_retrieval_model.top_k ?? 2)
+ const [scoreThreshold, setScoreThreshold] = useState(localeCurrentDataset?.external_retrieval_model.score_threshold ?? 0.5)
+ const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(localeCurrentDataset?.external_retrieval_model.score_threshold_enabled ?? false)
+ const [selectedMemberIDs, setSelectedMemberIDs] = useState<string[]>(currentDataset.partial_member_list || [])
+ const [memberList, setMemberList] = useState<Member[]>([])
+
+ const [indexMethod, setIndexMethod] = useState(currentDataset.indexing_technique)
+ const [retrievalConfig, setRetrievalConfig] = useState(localeCurrentDataset?.retrieval_model_dict as RetrievalConfig)
+
+ const handleValueChange = (type: string, value: string) => {
+ setLocaleCurrentDataset({ ...localeCurrentDataset, [type]: value })
+ }
+ const [isHideChangedTip, setIsHideChangedTip] = useState(false)
+ const isRetrievalChanged = !isEqual(retrievalConfig, localeCurrentDataset?.retrieval_model_dict) || indexMethod !== localeCurrentDataset?.indexing_technique
+
+ const handleSettingsChange = (data: { top_k?: number; score_threshold?: number; score_threshold_enabled?: boolean }) => {
+ if (data.top_k !== undefined)
+ setTopK(data.top_k)
+ if (data.score_threshold !== undefined)
+ setScoreThreshold(data.score_threshold)
+ if (data.score_threshold_enabled !== undefined)
+ setScoreThresholdEnabled(data.score_threshold_enabled)
+
+ setLocaleCurrentDataset({
+ ...localeCurrentDataset,
+ external_retrieval_model: {
+ ...localeCurrentDataset?.external_retrieval_model,
+ ...data,
+ },
+ })
+ }
+
+ const handleSave = async () => {
+ if (loading)
+ return
+ if (!localeCurrentDataset.name?.trim()) {
+ notify({ type: 'error', message: t('datasetSettings.form.nameError') })
+ return
+ }
+ if (
+ !isReRankModelSelected({
+ rerankModelList,
+ retrievalConfig,
+ indexMethod,
+ })
+ ) {
+ notify({ type: 'error', message: t('appDebug.datasetConfig.rerankModelRequired') })
+ return
+ }
+ try {
+ setLoading(true)
+ const { id, name, description, permission } = localeCurrentDataset
+ const requestParams = {
+ datasetId: id,
+ body: {
+ name,
+ description,
+ permission,
+ indexing_technique: indexMethod,
+ retrieval_model: {
+ ...retrievalConfig,
+ score_threshold: retrievalConfig.score_threshold_enabled ? retrievalConfig.score_threshold : 0,
+ },
+ embedding_model: localeCurrentDataset.embedding_model,
+ embedding_model_provider: localeCurrentDataset.embedding_model_provider,
+ ...(isExternal && {
+ external_knowledge_id: currentDataset!.external_knowledge_info.external_knowledge_id,
+ external_knowledge_api_id: currentDataset!.external_knowledge_info.external_knowledge_api_id,
+ external_retrieval_model: {
+ top_k: topK,
+ score_threshold: scoreThreshold,
+ score_threshold_enabled: scoreThresholdEnabled,
+ },
+ }),
+ },
+ } as any
+ if (permission === DatasetPermission.partialMembers) {
+ requestParams.body.partial_member_list = selectedMemberIDs.map((id) => {
+ return {
+ user_id: id,
+ role: memberList.find(member => member.id === id)?.role,
+ }
+ })
+ }
+ await updateDatasetSetting(requestParams)
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ onSave({
+ ...localeCurrentDataset,
+ indexing_technique: indexMethod,
+ retrieval_model_dict: retrievalConfig,
+ })
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ const getMembers = async () => {
+ const { accounts } = await fetchMembers({ url: '/workspaces/current/members', params: {} })
+ if (!accounts)
+ setMemberList([])
+ else
+ setMemberList(accounts)
+ }
+
+ useMount(() => {
+ getMembers()
+ })
+
+ return (
+ <div
+ className='flex w-full flex-col overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl'
+ style={{
+ height: 'calc(100vh - 72px)',
+ }}
+ ref={ref}
+ >
+ <div className='flex h-14 shrink-0 items-center justify-between border-b border-divider-regular pl-6 pr-5'>
+ <div className='flex flex-col text-base font-semibold text-text-primary'>
+ <div className='leading-6'>{t('datasetSettings.title')}</div>
+ </div>
+ <div className='flex items-center'>
+ <div
+ onClick={onCancel}
+ className='flex h-6 w-6 cursor-pointer items-center justify-center'
+ >
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ {/* Body */}
+ <div className='overflow-y-auto border-b border-divider-regular p-6 pb-[68px] pt-5'>
+ <div className={cn(rowClass, 'items-center')}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.name')}</div>
+ </div>
+ <Input
+ value={localeCurrentDataset.name}
+ onChange={e => handleValueChange('name', e.target.value)}
+ className='block h-9'
+ placeholder={t('datasetSettings.form.namePlaceholder') || ''}
+ />
+ </div>
+ <div className={cn(rowClass)}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.desc')}</div>
+ </div>
+ <div className='w-full'>
+ <Textarea
+ value={localeCurrentDataset.description || ''}
+ onChange={e => handleValueChange('description', e.target.value)}
+ className='resize-none'
+ placeholder={t('datasetSettings.form.descPlaceholder') || ''}
+ />
+ </div>
+ </div>
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.permissions')}</div>
+ </div>
+ <div className='w-full'>
+ <PermissionSelector
+ disabled={!localeCurrentDataset?.embedding_available || isCurrentWorkspaceDatasetOperator}
+ permission={localeCurrentDataset.permission}
+ value={selectedMemberIDs}
+ onChange={v => handleValueChange('permission', v!)}
+ onMemberSelect={setSelectedMemberIDs}
+ memberList={memberList}
+ />
+ </div>
+ </div>
+ {currentDataset && currentDataset.indexing_technique && (
+ <div className={cn(rowClass)}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.indexMethod')}</div>
+ </div>
+ <div className='grow'>
+ <IndexMethodRadio
+ disable={!localeCurrentDataset?.embedding_available}
+ value={indexMethod}
+ onChange={v => setIndexMethod(v!)}
+ docForm={currentDataset.doc_form}
+ currentValue={currentDataset.indexing_technique}
+ />
+ </div>
+ </div>
+ )}
+ {indexMethod === 'high_quality' && (
+ <div className={cn(rowClass)}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.embeddingModel')}</div>
+ </div>
+ <div className='w-full'>
+ <div className='h-8 w-full rounded-lg bg-components-input-bg-normal opacity-60'>
+ <ModelSelector
+ readonly
+ defaultModel={{
+ provider: localeCurrentDataset.embedding_model_provider,
+ model: localeCurrentDataset.embedding_model,
+ }}
+ modelList={embeddingsModelList}
+ />
+ </div>
+ <div className='mt-2 w-full text-xs leading-6 text-text-tertiary'>
+ {t('datasetSettings.form.embeddingModelTip')}
+ <span className='cursor-pointer text-text-accent' onClick={() => setShowAccountSettingModal({ payload: 'provider' })}>{t('datasetSettings.form.embeddingModelTipLink')}</span>
+ </div>
+ </div>
+ </div>
+ )}
+
+ {/* Retrieval Method Config */}
+ {currentDataset?.provider === 'external'
+ ? <>
+ <div className={rowClass}><Divider /></div>
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
+ </div>
+ <RetrievalSettings
+ topK={topK}
+ scoreThreshold={scoreThreshold}
+ scoreThresholdEnabled={scoreThresholdEnabled}
+ onChange={handleSettingsChange}
+ isInRetrievalSetting={true}
+ />
+ </div>
+ <div className={rowClass}><Divider /></div>
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.externalKnowledgeAPI')}</div>
+ </div>
+ <div className='w-full max-w-[480px]'>
+ <div className='flex h-full items-center gap-1 rounded-lg bg-components-input-bg-normal px-3 py-2'>
+ <ApiConnectionMod className='h-4 w-4 text-text-secondary' />
+ <div className='system-sm-medium overflow-hidden text-ellipsis text-text-secondary'>
+ {currentDataset?.external_knowledge_info.external_knowledge_api_name}
+ </div>
+ <div className='system-xs-regular text-text-tertiary'>路</div>
+ <div className='system-xs-regular text-text-tertiary'>{currentDataset?.external_knowledge_info.external_knowledge_api_endpoint}</div>
+ </div>
+ </div>
+ </div>
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.externalKnowledgeID')}</div>
+ </div>
+ <div className='w-full max-w-[480px]'>
+ <div className='flex h-full items-center gap-1 rounded-lg bg-components-input-bg-normal px-3 py-2'>
+ <div className='system-xs-regular text-text-tertiary'>{currentDataset?.external_knowledge_info.external_knowledge_id}</div>
+ </div>
+ </div>
+ </div>
+ <div className={rowClass}><Divider /></div>
+ </>
+ : <div className={rowClass}>
+ <div className={cn(labelClass, 'w-auto min-w-[168px]')}>
+ <div>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
+ <div className='text-xs font-normal leading-[18px] text-text-tertiary'>
+ <a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
+ {t('datasetSettings.form.retrievalSetting.description')}
+ </div>
+ </div>
+ </div>
+ <div>
+ {indexMethod === 'high_quality'
+ ? (
+ <RetrievalMethodConfig
+ value={retrievalConfig}
+ onChange={setRetrievalConfig}
+ />
+ )
+ : (
+ <EconomicalRetrievalMethodConfig
+ value={retrievalConfig}
+ onChange={setRetrievalConfig}
+ />
+ )}
+ </div>
+ </div>}
+ </div>
+ {isRetrievalChanged && !isHideChangedTip && (
+ <div className='absolute bottom-[76px] left-[30px] right-[30px] z-10 flex h-10 items-center justify-between rounded-lg border border-[#FEF0C7] bg-[#FFFAEB] px-3 shadow-lg'>
+ <div className='flex items-center'>
+ <AlertTriangle className='mr-1 h-3 w-3 text-[#F79009]' />
+ <div className='text-xs font-medium leading-[18px] text-gray-700'>{t('appDebug.datasetConfig.retrieveChangeTip')}</div>
+ </div>
+ <div className='cursor-pointer p-1' onClick={(e) => {
+ setIsHideChangedTip(true)
+ e.stopPropagation()
+ e.nativeEvent.stopImmediatePropagation()
+ }}>
+ <RiCloseLine className='h-4 w-4 text-gray-500' />
+ </div>
+ </div>
+ )}
+
+ <div
+ className='sticky bottom-0 z-[5] flex w-full justify-end border-t border-divider-regular bg-background-section px-6 py-4'
+ >
+ <Button
+ onClick={onCancel}
+ className='mr-2'
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ disabled={loading}
+ onClick={handleSave}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ </div>
+ )
+}
+
+export default SettingsModal
diff --git a/app/components/app/configuration/dataset-config/type-icon/index.tsx b/app/components/app/configuration/dataset-config/type-icon/index.tsx
new file mode 100644
index 0000000..65951f6
--- /dev/null
+++ b/app/components/app/configuration/dataset-config/type-icon/index.tsx
@@ -0,0 +1,33 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+
+export type ITypeIconProps = {
+ type: 'upload_file'
+ size?: 'md' | 'lg'
+}
+
+// data_source_type: current only support upload_file
+const Icon = ({ type, size = 'lg' }: ITypeIconProps) => {
+ const len = size === 'lg' ? 32 : 24
+ const iconMap = {
+ upload_file: (
+ <svg width={len} height={len} viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <rect x="0.25" y="0.25" width="31.5" height="31.5" rx="7.75" fill="#F5F8FF" />
+ <path fillRule="evenodd" clipRule="evenodd" d="M8.66669 12.1078C8.66668 11.7564 8.66667 11.4532 8.68707 11.2035C8.7086 10.9399 8.75615 10.6778 8.88468 10.4255C9.07642 10.0492 9.38238 9.74322 9.75871 9.55147C10.011 9.42294 10.2731 9.3754 10.5367 9.35387C10.7864 9.33346 11.0896 9.33347 11.441 9.33349L14.0978 9.33341C14.4935 9.33289 14.8415 9.33243 15.1615 9.4428C15.4417 9.53946 15.697 9.69722 15.9087 9.90465C16.1506 10.1415 16.3058 10.4529 16.4823 10.8071L17.0786 12H19.4942C20.0309 12 20.4738 12 20.8346 12.0295C21.2093 12.0601 21.5538 12.1258 21.8773 12.2907C22.3791 12.5463 22.787 12.9543 23.0427 13.456C23.2076 13.7796 23.2733 14.1241 23.3039 14.4988C23.3334 14.8596 23.3334 15.3025 23.3334 15.8391V18.8276C23.3334 19.3642 23.3334 19.8071 23.3039 20.1679C23.2733 20.5426 23.2076 20.8871 23.0427 21.2107C22.787 21.7124 22.3791 22.1204 21.8773 22.376C21.5538 22.5409 21.2093 22.6066 20.8346 22.6372C20.4738 22.6667 20.0309 22.6667 19.4942 22.6667H12.5058C11.9692 22.6667 11.5263 22.6667 11.1655 22.6372C10.7907 22.6066 10.4463 22.5409 10.1227 22.376C9.62095 22.1204 9.213 21.7124 8.95734 21.2107C8.79248 20.8871 8.72677 20.5426 8.69615 20.1679C8.66667 19.8071 8.66668 19.3642 8.66669 18.8276V12.1078ZM14.0149 10.6668C14.5418 10.6668 14.6463 10.6755 14.7267 10.7033C14.8201 10.7355 14.9052 10.7881 14.9758 10.8572C15.0366 10.9167 15.0911 11.0063 15.3267 11.4776L15.5879 12L10.0001 12C10.0004 11.69 10.0024 11.4781 10.016 11.312C10.0308 11.1309 10.0559 11.0638 10.0727 11.0308C10.1366 10.9054 10.2386 10.8034 10.364 10.7395C10.397 10.7227 10.4641 10.6976 10.6452 10.6828C10.8341 10.6673 11.0823 10.6668 11.4667 10.6668H14.0149Z" fill="#444CE7" />
+ <rect x="0.25" y="0.25" width="31.5" height="31.5" rx="7.75" stroke="#E0EAFF" strokeWidth="0.5" />
+ </svg>
+ ),
+ }
+ return iconMap[type]
+}
+
+const TypeIcon: FC<ITypeIconProps> = ({
+ type,
+ size = 'lg',
+}) => {
+ return (
+ <Icon type={type} size={size} ></Icon>
+ )
+}
+export default React.memo(TypeIcon)
diff --git a/app/components/app/configuration/debug/chat-user-input.tsx b/app/components/app/configuration/debug/chat-user-input.tsx
new file mode 100644
index 0000000..fb4ac31
--- /dev/null
+++ b/app/components/app/configuration/debug/chat-user-input.tsx
@@ -0,0 +1,108 @@
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import ConfigContext from '@/context/debug-configuration'
+import Input from '@/app/components/base/input'
+import Select from '@/app/components/base/select'
+import Textarea from '@/app/components/base/textarea'
+import { DEFAULT_VALUE_MAX_LEN } from '@/config'
+import type { Inputs } from '@/models/debug'
+import cn from '@/utils/classnames'
+
+type Props = {
+ inputs: Inputs
+}
+
+const ChatUserInput = ({
+ inputs,
+}: Props) => {
+ const { t } = useTranslation()
+ const { modelConfig, setInputs } = useContext(ConfigContext)
+
+ const promptVariables = modelConfig.configs.prompt_variables.filter(({ key, name }) => {
+ return key && key?.trim() && name && name?.trim()
+ })
+
+ const promptVariableObj = (() => {
+ const obj: Record<string, boolean> = {}
+ promptVariables.forEach((input) => {
+ obj[input.key] = true
+ })
+ return obj
+ })()
+
+ const handleInputValueChange = (key: string, value: string) => {
+ if (!(key in promptVariableObj))
+ return
+
+ const newInputs = { ...inputs }
+ promptVariables.forEach((input) => {
+ if (input.key === key)
+ newInputs[key] = value
+ })
+ setInputs(newInputs)
+ }
+
+ if (!promptVariables.length)
+ return null
+
+ return (
+ <div className={cn('z-[1] rounded-xl border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg shadow-xs')}>
+ <div className='px-4 pb-4 pt-3'>
+ {promptVariables.map(({ key, name, type, options, max_length, required }, index) => (
+ <div
+ key={key}
+ className='mb-4 last-of-type:mb-0'
+ >
+ <div>
+ <div className='system-sm-semibold mb-1 flex h-6 items-center gap-1 text-text-secondary'>
+ <div className='truncate'>{name || key}</div>
+ {!required && <span className='system-xs-regular text-text-tertiary'>{t('workflow.panel.optional')}</span>}
+ </div>
+ <div className='grow'>
+ {type === 'string' && (
+ <Input
+ value={inputs[key] ? `${inputs[key]}` : ''}
+ onChange={(e) => { handleInputValueChange(key, e.target.value) }}
+ placeholder={name}
+ autoFocus={index === 0}
+ maxLength={max_length || DEFAULT_VALUE_MAX_LEN}
+ />
+ )}
+ {type === 'paragraph' && (
+ <Textarea
+ className='h-[120px] grow'
+ placeholder={name}
+ value={inputs[key] ? `${inputs[key]}` : ''}
+ onChange={(e) => { handleInputValueChange(key, e.target.value) }}
+ />
+ )}
+ {type === 'select' && (
+ <Select
+ className='w-full'
+ defaultValue={inputs[key] as string}
+ onSelect={(i) => { handleInputValueChange(key, i.value as string) }}
+ items={(options || []).map(i => ({ name: i, value: i }))}
+ allowSearch={false}
+ />
+ )}
+ {type === 'number' && (
+ <Input
+ type='number'
+ value={inputs[key] ? `${inputs[key]}` : ''}
+ onChange={(e) => { handleInputValueChange(key, e.target.value) }}
+ placeholder={name}
+ autoFocus={index === 0}
+ maxLength={max_length || DEFAULT_VALUE_MAX_LEN}
+ />
+ )}
+ </div>
+ </div>
+ </div>
+ ))}
+ </div>
+ </div>
+ )
+}
+
+export default ChatUserInput
diff --git a/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsx b/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsx
new file mode 100644
index 0000000..ad4c06b
--- /dev/null
+++ b/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsx
@@ -0,0 +1,160 @@
+import type { FC } from 'react'
+import {
+ memo,
+ useCallback,
+ useMemo,
+} from 'react'
+import type { ModelAndParameter } from '../types'
+import {
+ APP_CHAT_WITH_MULTIPLE_MODEL,
+ APP_CHAT_WITH_MULTIPLE_MODEL_RESTART,
+} from '../types'
+import {
+ useConfigFromDebugContext,
+ useFormattingChangedSubscription,
+} from '../hooks'
+import Chat from '@/app/components/base/chat/chat'
+import { useChat } from '@/app/components/base/chat/chat/hooks'
+import { useDebugConfigurationContext } from '@/context/debug-configuration'
+import type { ChatConfig, OnSend } from '@/app/components/base/chat/types'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { useProviderContext } from '@/context/provider-context'
+import {
+ fetchConversationMessages,
+ fetchSuggestedQuestions,
+ stopChatMessageResponding,
+} from '@/service/debug'
+import Avatar from '@/app/components/base/avatar'
+import { useAppContext } from '@/context/app-context'
+import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { useFeatures } from '@/app/components/base/features/hooks'
+import type { InputForm } from '@/app/components/base/chat/chat/type'
+import { getLastAnswer } from '@/app/components/base/chat/utils'
+import { canFindTool } from '@/utils'
+
+type ChatItemProps = {
+ modelAndParameter: ModelAndParameter
+}
+const ChatItem: FC<ChatItemProps> = ({
+ modelAndParameter,
+}) => {
+ const { userProfile } = useAppContext()
+ const {
+ modelConfig,
+ appId,
+ inputs,
+ collectionList,
+ } = useDebugConfigurationContext()
+ const { textGenerationModelList } = useProviderContext()
+ const features = useFeatures(s => s.features)
+ const configTemplate = useConfigFromDebugContext()
+ const config = useMemo(() => {
+ return {
+ ...configTemplate,
+ more_like_this: features.moreLikeThis,
+ opening_statement: features.opening?.enabled ? (features.opening?.opening_statement || '') : '',
+ suggested_questions: features.opening?.enabled ? (features.opening?.suggested_questions || []) : [],
+ sensitive_word_avoidance: features.moderation,
+ speech_to_text: features.speech2text,
+ text_to_speech: features.text2speech,
+ file_upload: features.file,
+ suggested_questions_after_answer: features.suggested,
+ retriever_resource: features.citation,
+ annotation_reply: features.annotationReply,
+ } as ChatConfig
+ }, [configTemplate, features])
+ const inputsForm = useMemo(() => {
+ return modelConfig.configs.prompt_variables.filter(item => item.type !== 'api').map(item => ({ ...item, label: item.name, variable: item.key })) as InputForm[]
+ }, [modelConfig.configs.prompt_variables])
+ const {
+ chatList,
+ isResponding,
+ handleSend,
+ suggestedQuestions,
+ handleRestart,
+ } = useChat(
+ config,
+ {
+ inputs,
+ inputsForm,
+ },
+ [],
+ taskId => stopChatMessageResponding(appId, taskId),
+ )
+ useFormattingChangedSubscription(chatList)
+
+ const doSend: OnSend = useCallback((message, files) => {
+ const currentProvider = textGenerationModelList.find(item => item.provider === modelAndParameter.provider)
+ const currentModel = currentProvider?.models.find(model => model.model === modelAndParameter.model)
+ const supportVision = currentModel?.features?.includes(ModelFeatureEnum.vision)
+
+ const configData = {
+ ...config,
+ model: {
+ provider: modelAndParameter.provider,
+ name: modelAndParameter.model,
+ mode: currentModel?.model_properties.mode,
+ completion_params: modelAndParameter.parameters,
+ },
+ }
+
+ const data: any = {
+ query: message,
+ inputs,
+ model_config: configData,
+ parent_message_id: getLastAnswer(chatList)?.id || null,
+ }
+
+ if ((config.file_upload as any).enabled && files?.length && supportVision)
+ data.files = files
+
+ handleSend(
+ `apps/${appId}/chat-messages`,
+ data,
+ {
+ onGetConversationMessages: (conversationId, getAbortController) => fetchConversationMessages(appId, conversationId, getAbortController),
+ onGetSuggestedQuestions: (responseItemId, getAbortController) => fetchSuggestedQuestions(appId, responseItemId, getAbortController),
+ },
+ )
+ }, [appId, chatList, config, handleSend, inputs, modelAndParameter.model, modelAndParameter.parameters, modelAndParameter.provider, textGenerationModelList])
+
+ const { eventEmitter } = useEventEmitterContextContext()
+ eventEmitter?.useSubscription((v: any) => {
+ if (v.type === APP_CHAT_WITH_MULTIPLE_MODEL)
+ doSend(v.payload.message, v.payload.files)
+ if (v.type === APP_CHAT_WITH_MULTIPLE_MODEL_RESTART)
+ handleRestart()
+ })
+
+ const allToolIcons = useMemo(() => {
+ const icons: Record<string, any> = {}
+ modelConfig.agentConfig.tools?.forEach((item: any) => {
+ icons[item.tool_name] = collectionList.find((collection: any) => canFindTool(collection.id, item.provider_id))?.icon
+ })
+ return icons
+ }, [collectionList, modelConfig.agentConfig.tools])
+
+ if (!chatList.length)
+ return null
+
+ return (
+ <Chat
+ config={config}
+ chatList={chatList}
+ isResponding={isResponding}
+ noChatInput
+ noStopResponding
+ chatContainerClassName='p-4'
+ chatFooterClassName='p-4 pb-0'
+ suggestedQuestions={suggestedQuestions}
+ onSend={doSend}
+ showPromptLog
+ questionIcon={<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={40} />}
+ allToolIcons={allToolIcons}
+ hideLogModal
+ noSpacing
+ />
+ )
+}
+
+export default memo(ChatItem)
diff --git a/app/components/app/configuration/debug/debug-with-multiple-model/context.tsx b/app/components/app/configuration/debug/debug-with-multiple-model/context.tsx
new file mode 100644
index 0000000..1fcd878
--- /dev/null
+++ b/app/components/app/configuration/debug/debug-with-multiple-model/context.tsx
@@ -0,0 +1,43 @@
+'use client'
+
+import { createContext, useContext } from 'use-context-selector'
+import type { ModelAndParameter } from '../types'
+import { noop } from 'lodash-es'
+
+export type DebugWithMultipleModelContextType = {
+ multipleModelConfigs: ModelAndParameter[]
+ onMultipleModelConfigsChange: (multiple: boolean, modelConfigs: ModelAndParameter[]) => void
+ onDebugWithMultipleModelChange: (singleModelConfig: ModelAndParameter) => void
+ checkCanSend?: () => boolean
+}
+const DebugWithMultipleModelContext = createContext<DebugWithMultipleModelContextType>({
+ multipleModelConfigs: [],
+ onMultipleModelConfigsChange: noop,
+ onDebugWithMultipleModelChange: noop,
+})
+
+export const useDebugWithMultipleModelContext = () => useContext(DebugWithMultipleModelContext)
+
+type DebugWithMultipleModelContextProviderProps = {
+ children: React.ReactNode
+} & DebugWithMultipleModelContextType
+export const DebugWithMultipleModelContextProvider = ({
+ children,
+ onMultipleModelConfigsChange,
+ multipleModelConfigs,
+ onDebugWithMultipleModelChange,
+ checkCanSend,
+}: DebugWithMultipleModelContextProviderProps) => {
+ return (
+ <DebugWithMultipleModelContext.Provider value={{
+ onMultipleModelConfigsChange,
+ multipleModelConfigs,
+ onDebugWithMultipleModelChange,
+ checkCanSend,
+ }}>
+ {children}
+ </DebugWithMultipleModelContext.Provider>
+ )
+}
+
+export default DebugWithMultipleModelContext
diff --git a/app/components/app/configuration/debug/debug-with-multiple-model/debug-item.tsx b/app/components/app/configuration/debug/debug-with-multiple-model/debug-item.tsx
new file mode 100644
index 0000000..95c43f5
--- /dev/null
+++ b/app/components/app/configuration/debug/debug-with-multiple-model/debug-item.tsx
@@ -0,0 +1,129 @@
+import type { CSSProperties, FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { memo } from 'react'
+import type { ModelAndParameter } from '../types'
+import ModelParameterTrigger from './model-parameter-trigger'
+import ChatItem from './chat-item'
+import TextGenerationItem from './text-generation-item'
+import { useDebugWithMultipleModelContext } from './context'
+import { useDebugConfigurationContext } from '@/context/debug-configuration'
+import Dropdown from '@/app/components/base/dropdown'
+import type { Item } from '@/app/components/base/dropdown'
+import { useProviderContext } from '@/context/provider-context'
+import { ModelStatusEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+
+type DebugItemProps = {
+ modelAndParameter: ModelAndParameter
+ className?: string
+ style?: CSSProperties
+}
+const DebugItem: FC<DebugItemProps> = ({
+ modelAndParameter,
+ className,
+ style,
+}) => {
+ const { t } = useTranslation()
+ const { mode } = useDebugConfigurationContext()
+ const {
+ multipleModelConfigs,
+ onMultipleModelConfigsChange,
+ onDebugWithMultipleModelChange,
+ } = useDebugWithMultipleModelContext()
+ const { textGenerationModelList } = useProviderContext()
+
+ const index = multipleModelConfigs.findIndex(v => v.id === modelAndParameter.id)
+ const currentProvider = textGenerationModelList.find(item => item.provider === modelAndParameter.provider)
+ const currentModel = currentProvider?.models.find(item => item.model === modelAndParameter.model)
+
+ const handleSelect = (item: Item) => {
+ if (item.value === 'duplicate') {
+ if (multipleModelConfigs.length >= 4)
+ return
+
+ onMultipleModelConfigsChange(
+ true,
+ [
+ ...multipleModelConfigs.slice(0, index + 1),
+ {
+ ...modelAndParameter,
+ id: `${Date.now()}`,
+ },
+ ...multipleModelConfigs.slice(index + 1),
+ ],
+ )
+ }
+ if (item.value === 'debug-as-single-model')
+ onDebugWithMultipleModelChange(modelAndParameter)
+ if (item.value === 'remove') {
+ onMultipleModelConfigsChange(
+ true,
+ multipleModelConfigs.filter(item => item.id !== modelAndParameter.id),
+ )
+ }
+ }
+
+ return (
+ <div
+ className={`flex min-w-[320px] flex-col rounded-xl bg-background-section-burn ${className}`}
+ style={style}
+ >
+ <div className='flex h-10 shrink-0 items-center justify-between border-b-[0.5px] border-divider-regular px-3'>
+ <div className='flex h-5 w-6 items-center justify-center font-medium italic text-text-tertiary'>
+ #{index + 1}
+ </div>
+ <ModelParameterTrigger
+ modelAndParameter={modelAndParameter}
+ />
+ <Dropdown
+ onSelect={handleSelect}
+ items={[
+ ...(
+ multipleModelConfigs.length <= 3
+ ? [
+ {
+ value: 'duplicate',
+ text: t('appDebug.duplicateModel'),
+ },
+ ]
+ : []
+ ),
+ ...(
+ (modelAndParameter.provider && modelAndParameter.model)
+ ? [
+ {
+ value: 'debug-as-single-model',
+ text: t('appDebug.debugAsSingleModel'),
+ },
+ ]
+ : []
+ ),
+ ]}
+ secondItems={
+ multipleModelConfigs.length > 2
+ ? [
+ {
+ value: 'remove',
+ text: t('common.operation.remove') as string,
+ },
+ ]
+ : undefined
+ }
+ />
+ </div>
+ <div style={{ height: 'calc(100% - 40px)' }}>
+ {
+ (mode === 'chat' || mode === 'agent-chat') && currentProvider && currentModel && currentModel.status === ModelStatusEnum.active && (
+ <ChatItem modelAndParameter={modelAndParameter} />
+ )
+ }
+ {
+ mode === 'completion' && currentProvider && currentModel && currentModel.status === ModelStatusEnum.active && (
+ <TextGenerationItem modelAndParameter={modelAndParameter}/>
+ )
+ }
+ </div>
+ </div>
+ )
+}
+
+export default memo(DebugItem)
diff --git a/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx b/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx
new file mode 100644
index 0000000..75ba836
--- /dev/null
+++ b/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx
@@ -0,0 +1,171 @@
+import type { FC } from 'react'
+import {
+ memo,
+ useCallback,
+ useMemo,
+} from 'react'
+import { APP_CHAT_WITH_MULTIPLE_MODEL } from '../types'
+import DebugItem from './debug-item'
+import {
+ DebugWithMultipleModelContextProvider,
+ useDebugWithMultipleModelContext,
+} from './context'
+import type { DebugWithMultipleModelContextType } from './context'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import ChatInputArea from '@/app/components/base/chat/chat/chat-input-area'
+import { useDebugConfigurationContext } from '@/context/debug-configuration'
+import { useFeatures } from '@/app/components/base/features/hooks'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import type { FileEntity } from '@/app/components/base/file-uploader/types'
+import type { InputForm } from '@/app/components/base/chat/chat/type'
+
+const DebugWithMultipleModel = () => {
+ const {
+ mode,
+ inputs,
+ modelConfig,
+ } = useDebugConfigurationContext()
+ const speech2text = useFeatures(s => s.features.speech2text)
+ const file = useFeatures(s => s.features.file)
+ const {
+ multipleModelConfigs,
+ checkCanSend,
+ } = useDebugWithMultipleModelContext()
+
+ const { eventEmitter } = useEventEmitterContextContext()
+ const isChatMode = mode === 'chat' || mode === 'agent-chat'
+
+ const handleSend = useCallback((message: string, files?: FileEntity[]) => {
+ if (checkCanSend && !checkCanSend())
+ return
+
+ eventEmitter?.emit({
+ type: APP_CHAT_WITH_MULTIPLE_MODEL,
+ payload: {
+ message,
+ files,
+ },
+ } as any)
+ }, [eventEmitter, checkCanSend])
+
+ const twoLine = multipleModelConfigs.length === 2
+ const threeLine = multipleModelConfigs.length === 3
+ const fourLine = multipleModelConfigs.length === 4
+
+ const size = useMemo(() => {
+ let width = ''
+ let height = ''
+ if (twoLine) {
+ width = 'calc(50% - 4px - 24px)'
+ height = '100%'
+ }
+ if (threeLine) {
+ width = 'calc(33.3% - 5.33px - 16px)'
+ height = '100%'
+ }
+ if (fourLine) {
+ width = 'calc(50% - 4px - 24px)'
+ height = 'calc(50% - 4px)'
+ }
+
+ return {
+ width,
+ height,
+ }
+ }, [twoLine, threeLine, fourLine])
+ const position = useCallback((idx: number) => {
+ let translateX = '0'
+ let translateY = '0'
+
+ if (twoLine && idx === 1)
+ translateX = 'calc(100% + 8px)'
+ if (threeLine && idx === 1)
+ translateX = 'calc(100% + 8px)'
+ if (threeLine && idx === 2)
+ translateX = 'calc(200% + 16px)'
+ if (fourLine && idx === 1)
+ translateX = 'calc(100% + 8px)'
+ if (fourLine && idx === 2)
+ translateY = 'calc(100% + 8px)'
+ if (fourLine && idx === 3) {
+ translateX = 'calc(100% + 8px)'
+ translateY = 'calc(100% + 8px)'
+ }
+
+ return {
+ translateX,
+ translateY,
+ }
+ }, [twoLine, threeLine, fourLine])
+
+ const setShowAppConfigureFeaturesModal = useAppStore(s => s.setShowAppConfigureFeaturesModal)
+ const inputsForm = modelConfig.configs.prompt_variables.filter(item => item.type !== 'api').map(item => ({ ...item, label: item.name, variable: item.key })) as InputForm[]
+
+ return (
+ <div className='flex h-full flex-col'>
+ <div
+ className={`
+ relative mb-3 grow overflow-auto px-6
+ `}
+ style={{ height: isChatMode ? 'calc(100% - 60px)' : '100%' }}
+ >
+ {
+ multipleModelConfigs.map((modelConfig, index) => (
+ <DebugItem
+ key={modelConfig.id}
+ modelAndParameter={modelConfig}
+ className={`
+ absolute left-6 top-0 min-h-[200px]
+ ${twoLine && index === 0 && 'mr-2'}
+ ${threeLine && (index === 0 || index === 1) && 'mr-2'}
+ ${fourLine && (index === 0 || index === 2) && 'mr-2'}
+ ${fourLine && (index === 0 || index === 1) && 'mb-2'}
+ `}
+ style={{
+ width: size.width,
+ height: size.height,
+ transform: `translateX(${position(index).translateX}) translateY(${position(index).translateY})`,
+ }}
+ />
+ ))
+ }
+ </div>
+ {isChatMode && (
+ <div className='shrink-0 px-6 pb-0'>
+ <ChatInputArea
+ showFeatureBar
+ showFileUpload={false}
+ onFeatureBarClick={setShowAppConfigureFeaturesModal}
+ onSend={handleSend}
+ speechToTextConfig={speech2text as any}
+ visionConfig={file}
+ inputs={inputs}
+ inputsForm={inputsForm}
+ />
+ </div>
+ )}
+ </div>
+ )
+}
+
+const DebugWithMultipleModelMemoed = memo(DebugWithMultipleModel)
+
+const DebugWithMultipleModelWrapper: FC<DebugWithMultipleModelContextType> = ({
+ onMultipleModelConfigsChange,
+ multipleModelConfigs,
+ onDebugWithMultipleModelChange,
+ checkCanSend,
+}) => {
+ return (
+ <DebugWithMultipleModelContextProvider
+ onMultipleModelConfigsChange={onMultipleModelConfigsChange}
+ multipleModelConfigs={multipleModelConfigs}
+ onDebugWithMultipleModelChange={onDebugWithMultipleModelChange}
+ checkCanSend={checkCanSend}
+ >
+ <DebugWithMultipleModelMemoed />
+ </DebugWithMultipleModelContextProvider>
+ )
+}
+
+export default memo(DebugWithMultipleModelWrapper)
diff --git a/app/components/app/configuration/debug/debug-with-multiple-model/model-parameter-trigger.tsx b/app/components/app/configuration/debug/debug-with-multiple-model/model-parameter-trigger.tsx
new file mode 100644
index 0000000..17d04ac
--- /dev/null
+++ b/app/components/app/configuration/debug/debug-with-multiple-model/model-parameter-trigger.tsx
@@ -0,0 +1,126 @@
+import type { FC } from 'react'
+import { memo } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowDownSLine } from '@remixicon/react'
+import type { ModelAndParameter } from '../types'
+import { useDebugWithMultipleModelContext } from './context'
+import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
+import ModelIcon from '@/app/components/header/account-setting/model-provider-page/model-icon'
+import ModelName from '@/app/components/header/account-setting/model-provider-page/model-name'
+import {
+ type FormValue,
+ MODEL_STATUS_TEXT,
+ ModelStatusEnum,
+} from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { useDebugConfigurationContext } from '@/context/debug-configuration'
+import { CubeOutline } from '@/app/components/base/icons/src/vender/line/shapes'
+import Tooltip from '@/app/components/base/tooltip'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
+import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
+
+type ModelParameterTriggerProps = {
+ modelAndParameter: ModelAndParameter
+}
+const ModelParameterTrigger: FC<ModelParameterTriggerProps> = ({
+ modelAndParameter,
+}) => {
+ const { t } = useTranslation()
+ const {
+ mode,
+ isAdvancedMode,
+ } = useDebugConfigurationContext()
+ const {
+ multipleModelConfigs,
+ onMultipleModelConfigsChange,
+ onDebugWithMultipleModelChange,
+ } = useDebugWithMultipleModelContext()
+ const language = useLanguage()
+ const index = multipleModelConfigs.findIndex(v => v.id === modelAndParameter.id)
+
+ const handleSelectModel = ({ modelId, provider }: { modelId: string; provider: string }) => {
+ const newModelConfigs = [...multipleModelConfigs]
+ newModelConfigs[index] = {
+ ...newModelConfigs[index],
+ model: modelId,
+ provider,
+ }
+ onMultipleModelConfigsChange(true, newModelConfigs)
+ }
+ const handleParamsChange = (params: FormValue) => {
+ const newModelConfigs = [...multipleModelConfigs]
+ newModelConfigs[index] = {
+ ...newModelConfigs[index],
+ parameters: params,
+ }
+ onMultipleModelConfigsChange(true, newModelConfigs)
+ }
+
+ return (
+ <ModelParameterModal
+ mode={mode}
+ isAdvancedMode={isAdvancedMode}
+ provider={modelAndParameter.provider}
+ modelId={modelAndParameter.model}
+ completionParams={modelAndParameter.parameters}
+ onCompletionParamsChange={handleParamsChange}
+ setModel={handleSelectModel}
+ debugWithMultipleModel
+ onDebugWithMultipleModelChange={() => onDebugWithMultipleModelChange(modelAndParameter)}
+ renderTrigger={({
+ open,
+ currentProvider,
+ currentModel,
+ }) => (
+ <div
+ className={`
+ flex h-8 max-w-[200px] cursor-pointer items-center rounded-lg px-2
+ ${open && 'bg-state-base-hover'}
+ ${currentModel && currentModel.status !== ModelStatusEnum.active && '!bg-[#FFFAEB]'}
+ `}
+ >
+ {
+ currentProvider && (
+ <ModelIcon
+ className='mr-1 !h-4 !w-4'
+ provider={currentProvider}
+ modelName={currentModel?.model}
+ />
+ )
+ }
+ {
+ !currentProvider && (
+ <div className='mr-1 flex h-4 w-4 items-center justify-center rounded'>
+ <CubeOutline className='h-4 w-4 text-text-accent' />
+ </div>
+ )
+ }
+ {
+ currentModel && (
+ <ModelName
+ className='mr-0.5 text-text-secondary'
+ modelItem={currentModel}
+ />
+ )
+ }
+ {
+ !currentModel && (
+ <div className='mr-0.5 truncate text-[13px] font-medium text-text-accent'>
+ {t('common.modelProvider.selectModel')}
+ </div>
+ )
+ }
+ <RiArrowDownSLine className={`h-3 w-3 ${(currentModel && currentProvider) ? 'text-text-tertiary' : 'text-text-accent'}`} />
+ {
+ currentModel && currentModel.status !== ModelStatusEnum.active && (
+ <Tooltip popupContent={MODEL_STATUS_TEXT[currentModel.status][language]}>
+ <AlertTriangle className='h-4 w-4 text-[#F79009]' />
+ </Tooltip>
+ )
+ }
+ </div>
+ )}
+ />
+ )
+}
+
+export default memo(ModelParameterTrigger)
diff --git a/app/components/app/configuration/debug/debug-with-multiple-model/text-generation-item.tsx b/app/components/app/configuration/debug/debug-with-multiple-model/text-generation-item.tsx
new file mode 100644
index 0000000..8f8555e
--- /dev/null
+++ b/app/components/app/configuration/debug/debug-with-multiple-model/text-generation-item.tsx
@@ -0,0 +1,144 @@
+import type { FC } from 'react'
+import { memo } from 'react'
+import type { ModelAndParameter } from '../types'
+import { APP_CHAT_WITH_MULTIPLE_MODEL } from '../types'
+import type {
+ OnSend,
+ TextGenerationConfig,
+} from '@/app/components/base/text-generation/types'
+import { useTextGeneration } from '@/app/components/base/text-generation/hooks'
+import TextGeneration from '@/app/components/app/text-generate/item'
+import { useDebugConfigurationContext } from '@/context/debug-configuration'
+import { promptVariablesToUserInputsForm } from '@/utils/model-config'
+import { TransferMethod } from '@/app/components/base/chat/types'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { useProviderContext } from '@/context/provider-context'
+import { useFeatures } from '@/app/components/base/features/hooks'
+import { noop } from 'lodash-es'
+
+type TextGenerationItemProps = {
+ modelAndParameter: ModelAndParameter
+}
+const TextGenerationItem: FC<TextGenerationItemProps> = ({
+ modelAndParameter,
+}) => {
+ const {
+ isAdvancedMode,
+ modelConfig,
+ appId,
+ inputs,
+ promptMode,
+ speechToTextConfig,
+ introduction,
+ suggestedQuestionsAfterAnswerConfig,
+ citationConfig,
+ externalDataToolsConfig,
+ chatPromptConfig,
+ completionPromptConfig,
+ dataSets,
+ datasetConfigs,
+ } = useDebugConfigurationContext()
+ const { textGenerationModelList } = useProviderContext()
+ const features = useFeatures(s => s.features)
+ const postDatasets = dataSets.map(({ id }) => ({
+ dataset: {
+ enabled: true,
+ id,
+ },
+ }))
+ const contextVar = modelConfig.configs.prompt_variables.find(item => item.is_context_var)?.key
+ const config: TextGenerationConfig = {
+ pre_prompt: !isAdvancedMode ? modelConfig.configs.prompt_template : '',
+ prompt_type: promptMode,
+ chat_prompt_config: isAdvancedMode ? chatPromptConfig : {},
+ completion_prompt_config: isAdvancedMode ? completionPromptConfig : {},
+ user_input_form: promptVariablesToUserInputsForm(modelConfig.configs.prompt_variables),
+ dataset_query_variable: contextVar || '',
+ // features
+ more_like_this: features.moreLikeThis as any,
+ sensitive_word_avoidance: features.moderation as any,
+ text_to_speech: features.text2speech as any,
+ file_upload: features.file as any,
+ opening_statement: introduction,
+ speech_to_text: speechToTextConfig,
+ suggested_questions_after_answer: suggestedQuestionsAfterAnswerConfig,
+ retriever_resource: citationConfig,
+ external_data_tools: externalDataToolsConfig,
+ agent_mode: {
+ enabled: false,
+ tools: [],
+ },
+ dataset_configs: {
+ ...datasetConfigs,
+ datasets: {
+ datasets: [...postDatasets],
+ } as any,
+ },
+ }
+ const {
+ completion,
+ handleSend,
+ isResponding,
+ messageId,
+ } = useTextGeneration()
+
+ const doSend: OnSend = (message, files) => {
+ const currentProvider = textGenerationModelList.find(item => item.provider === modelAndParameter.provider)
+ const currentModel = currentProvider?.models.find(model => model.model === modelAndParameter.model)
+
+ const configData = {
+ ...config,
+ model: {
+ provider: modelAndParameter.provider,
+ name: modelAndParameter.model,
+ mode: currentModel?.model_properties.mode,
+ completion_params: modelAndParameter.parameters,
+ },
+ }
+
+ const data: any = {
+ inputs,
+ model_config: configData,
+ }
+
+ if ((config.file_upload as any).enabled && files && files?.length > 0) {
+ data.files = files.map((item) => {
+ if (item.transfer_method === TransferMethod.local_file) {
+ return {
+ ...item,
+ url: '',
+ }
+ }
+ return item
+ })
+ }
+
+ handleSend(
+ `apps/${appId}/completion-messages`,
+ data,
+ )
+ }
+
+ const { eventEmitter } = useEventEmitterContextContext()
+ eventEmitter?.useSubscription((v: any) => {
+ if (v.type === APP_CHAT_WITH_MULTIPLE_MODEL)
+ doSend(v.payload.message, v.payload.files)
+ })
+
+ return (
+ <TextGeneration
+ className='flex h-full flex-col overflow-y-auto border-none'
+ content={completion}
+ isLoading={!completion && isResponding}
+ isResponding={isResponding}
+ isInstalledApp={false}
+ siteInfo={null}
+ messageId={messageId}
+ isError={false}
+ onRetry={noop}
+ inSidePanel
+ />
+ )
+}
+
+export default memo(TextGenerationItem)
diff --git a/app/components/app/configuration/debug/debug-with-single-model/index.tsx b/app/components/app/configuration/debug/debug-with-single-model/index.tsx
new file mode 100644
index 0000000..d439b00
--- /dev/null
+++ b/app/components/app/configuration/debug/debug-with-single-model/index.tsx
@@ -0,0 +1,185 @@
+import { memo, useCallback, useImperativeHandle, useMemo } from 'react'
+import {
+ useConfigFromDebugContext,
+ useFormattingChangedSubscription,
+} from '../hooks'
+import Chat from '@/app/components/base/chat/chat'
+import { useChat } from '@/app/components/base/chat/chat/hooks'
+import { useDebugConfigurationContext } from '@/context/debug-configuration'
+import type { ChatConfig, ChatItem, ChatItemInTree, OnSend } from '@/app/components/base/chat/types'
+import { useProviderContext } from '@/context/provider-context'
+import {
+ fetchConversationMessages,
+ fetchSuggestedQuestions,
+ stopChatMessageResponding,
+} from '@/service/debug'
+import Avatar from '@/app/components/base/avatar'
+import { useAppContext } from '@/context/app-context'
+import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import { useFeatures } from '@/app/components/base/features/hooks'
+import { getLastAnswer, isValidGeneratedAnswer } from '@/app/components/base/chat/utils'
+import type { InputForm } from '@/app/components/base/chat/chat/type'
+import { canFindTool } from '@/utils'
+import type { FileEntity } from '@/app/components/base/file-uploader/types'
+
+type DebugWithSingleModelProps = {
+ checkCanSend?: () => boolean
+}
+export type DebugWithSingleModelRefType = {
+ handleRestart: () => void
+}
+const DebugWithSingleModel = (
+ {
+ ref,
+ checkCanSend,
+ }: DebugWithSingleModelProps & {
+ ref: React.RefObject<DebugWithSingleModelRefType>;
+ },
+) => {
+ const { userProfile } = useAppContext()
+ const {
+ modelConfig,
+ appId,
+ inputs,
+ collectionList,
+ completionParams,
+ // isShowVisionConfig,
+ } = useDebugConfigurationContext()
+ const { textGenerationModelList } = useProviderContext()
+ const features = useFeatures(s => s.features)
+ const configTemplate = useConfigFromDebugContext()
+ const config = useMemo(() => {
+ return {
+ ...configTemplate,
+ more_like_this: features.moreLikeThis,
+ opening_statement: features.opening?.enabled ? (features.opening?.opening_statement || '') : '',
+ suggested_questions: features.opening?.enabled ? (features.opening?.suggested_questions || []) : [],
+ sensitive_word_avoidance: features.moderation,
+ speech_to_text: features.speech2text,
+ text_to_speech: features.text2speech,
+ file_upload: features.file,
+ suggested_questions_after_answer: features.suggested,
+ retriever_resource: features.citation,
+ annotation_reply: features.annotationReply,
+ } as ChatConfig
+ }, [configTemplate, features])
+ const inputsForm = useMemo(() => {
+ return modelConfig.configs.prompt_variables.filter(item => item.type !== 'api').map(item => ({ ...item, label: item.name, variable: item.key })) as InputForm[]
+ }, [modelConfig.configs.prompt_variables])
+ const {
+ chatList,
+ setTargetMessageId,
+ isResponding,
+ handleSend,
+ suggestedQuestions,
+ handleStop,
+ handleRestart,
+ handleAnnotationAdded,
+ handleAnnotationEdited,
+ handleAnnotationRemoved,
+ } = useChat(
+ config,
+ {
+ inputs,
+ inputsForm,
+ },
+ [],
+ taskId => stopChatMessageResponding(appId, taskId),
+ )
+ useFormattingChangedSubscription(chatList)
+
+ const doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => {
+ if (checkCanSend && !checkCanSend())
+ return
+ const currentProvider = textGenerationModelList.find(item => item.provider === modelConfig.provider)
+ const currentModel = currentProvider?.models.find(model => model.model === modelConfig.model_id)
+ const supportVision = currentModel?.features?.includes(ModelFeatureEnum.vision)
+
+ const configData = {
+ ...config,
+ model: {
+ provider: modelConfig.provider,
+ name: modelConfig.model_id,
+ mode: modelConfig.mode,
+ completion_params: completionParams,
+ },
+ }
+
+ const data: any = {
+ query: message,
+ inputs,
+ model_config: configData,
+ parent_message_id: (isRegenerate ? parentAnswer?.id : getLastAnswer(chatList)?.id) || null,
+ }
+
+ if ((config.file_upload as any)?.enabled && files?.length && supportVision)
+ data.files = files
+
+ handleSend(
+ `apps/${appId}/chat-messages`,
+ data,
+ {
+ onGetConversationMessages: (conversationId, getAbortController) => fetchConversationMessages(appId, conversationId, getAbortController),
+ onGetSuggestedQuestions: (responseItemId, getAbortController) => fetchSuggestedQuestions(appId, responseItemId, getAbortController),
+ },
+ )
+ }, [appId, chatList, checkCanSend, completionParams, config, handleSend, inputs, modelConfig.mode, modelConfig.model_id, modelConfig.provider, textGenerationModelList])
+
+ const doRegenerate = useCallback((chatItem: ChatItemInTree, editedQuestion?: { message: string, files?: FileEntity[] }) => {
+ const question = editedQuestion ? chatItem : chatList.find(item => item.id === chatItem.parentMessageId)!
+ const parentAnswer = chatList.find(item => item.id === question.parentMessageId)
+ doSend(editedQuestion ? editedQuestion.message : question.content,
+ editedQuestion ? editedQuestion.files : question.message_files,
+ true,
+ isValidGeneratedAnswer(parentAnswer) ? parentAnswer : null,
+ )
+ }, [chatList, doSend])
+
+ const allToolIcons = useMemo(() => {
+ const icons: Record<string, any> = {}
+ modelConfig.agentConfig.tools?.forEach((item: any) => {
+ icons[item.tool_name] = collectionList.find((collection: any) => canFindTool(collection.id, item.provider_id))?.icon
+ })
+ return icons
+ }, [collectionList, modelConfig.agentConfig.tools])
+
+ useImperativeHandle(ref, () => {
+ return {
+ handleRestart,
+ }
+ }, [handleRestart])
+
+ const setShowAppConfigureFeaturesModal = useAppStore(s => s.setShowAppConfigureFeaturesModal)
+
+ return (
+ <Chat
+ config={config}
+ chatList={chatList}
+ isResponding={isResponding}
+ chatContainerClassName='px-3 pt-6'
+ chatFooterClassName='px-3 pt-10 pb-0'
+ showFeatureBar
+ showFileUpload={false}
+ onFeatureBarClick={setShowAppConfigureFeaturesModal}
+ suggestedQuestions={suggestedQuestions}
+ onSend={doSend}
+ inputs={inputs}
+ inputsForm={inputsForm}
+ onRegenerate={doRegenerate}
+ switchSibling={siblingMessageId => setTargetMessageId(siblingMessageId)}
+ onStopResponding={handleStop}
+ showPromptLog
+ questionIcon={<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={40} />}
+ allToolIcons={allToolIcons}
+ onAnnotationEdited={handleAnnotationEdited}
+ onAnnotationAdded={handleAnnotationAdded}
+ onAnnotationRemoved={handleAnnotationRemoved}
+ noSpacing
+ />
+ )
+}
+
+DebugWithSingleModel.displayName = 'DebugWithSingleModel'
+
+export default memo(DebugWithSingleModel)
diff --git a/app/components/app/configuration/debug/hooks.tsx b/app/components/app/configuration/debug/hooks.tsx
new file mode 100644
index 0000000..12022e7
--- /dev/null
+++ b/app/components/app/configuration/debug/hooks.tsx
@@ -0,0 +1,158 @@
+import {
+ useCallback,
+ useRef,
+ useState,
+} from 'react'
+import type {
+ DebugWithSingleOrMultipleModelConfigs,
+ ModelAndParameter,
+} from './types'
+import { ORCHESTRATE_CHANGED } from './types'
+import type {
+ ChatConfig,
+ ChatItem,
+} from '@/app/components/base/chat/types'
+import {
+ AgentStrategy,
+} from '@/types/app'
+import { promptVariablesToUserInputsForm } from '@/utils/model-config'
+import { useDebugConfigurationContext } from '@/context/debug-configuration'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+
+export const useDebugWithSingleOrMultipleModel = (appId: string) => {
+ const localeDebugWithSingleOrMultipleModelConfigs = localStorage.getItem('app-debug-with-single-or-multiple-models')
+
+ const debugWithSingleOrMultipleModelConfigs = useRef<DebugWithSingleOrMultipleModelConfigs>({})
+
+ if (localeDebugWithSingleOrMultipleModelConfigs) {
+ try {
+ debugWithSingleOrMultipleModelConfigs.current = JSON.parse(localeDebugWithSingleOrMultipleModelConfigs) || {}
+ }
+ catch (e) {
+ console.error(e)
+ }
+ }
+
+ const [
+ debugWithMultipleModel,
+ setDebugWithMultipleModel,
+ ] = useState(debugWithSingleOrMultipleModelConfigs.current[appId]?.multiple || false)
+
+ const [
+ multipleModelConfigs,
+ setMultipleModelConfigs,
+ ] = useState(debugWithSingleOrMultipleModelConfigs.current[appId]?.configs || [])
+
+ const handleMultipleModelConfigsChange = useCallback((
+ multiple: boolean,
+ modelConfigs: ModelAndParameter[],
+ ) => {
+ const value = {
+ multiple,
+ configs: modelConfigs,
+ }
+ debugWithSingleOrMultipleModelConfigs.current[appId] = value
+ localStorage.setItem('app-debug-with-single-or-multiple-models', JSON.stringify(debugWithSingleOrMultipleModelConfigs.current))
+ setDebugWithMultipleModel(value.multiple)
+ setMultipleModelConfigs(value.configs)
+ }, [appId])
+
+ return {
+ debugWithMultipleModel,
+ multipleModelConfigs,
+ handleMultipleModelConfigsChange,
+ }
+}
+
+export const useConfigFromDebugContext = () => {
+ const {
+ isAdvancedMode,
+ modelConfig,
+ appId,
+ promptMode,
+ speechToTextConfig,
+ introduction,
+ suggestedQuestions: openingSuggestedQuestions,
+ suggestedQuestionsAfterAnswerConfig,
+ citationConfig,
+ moderationConfig,
+ chatPromptConfig,
+ completionPromptConfig,
+ dataSets,
+ datasetConfigs,
+ visionConfig,
+ annotationConfig,
+ textToSpeechConfig,
+ isFunctionCall,
+ } = useDebugConfigurationContext()
+ const postDatasets = dataSets.map(({ id }) => ({
+ dataset: {
+ enabled: true,
+ id,
+ },
+ }))
+ const contextVar = modelConfig.configs.prompt_variables.find(item => item.is_context_var)?.key
+ const config: ChatConfig = {
+ pre_prompt: !isAdvancedMode ? modelConfig.configs.prompt_template : '',
+ prompt_type: promptMode,
+ chat_prompt_config: isAdvancedMode ? chatPromptConfig : {},
+ completion_prompt_config: isAdvancedMode ? completionPromptConfig : {},
+ user_input_form: promptVariablesToUserInputsForm(modelConfig.configs.prompt_variables),
+ dataset_query_variable: contextVar || '',
+ opening_statement: introduction,
+ more_like_this: {
+ enabled: false,
+ },
+ suggested_questions: openingSuggestedQuestions,
+ suggested_questions_after_answer: suggestedQuestionsAfterAnswerConfig,
+ text_to_speech: textToSpeechConfig,
+ speech_to_text: speechToTextConfig,
+ retriever_resource: citationConfig,
+ sensitive_word_avoidance: moderationConfig,
+ agent_mode: {
+ ...modelConfig.agentConfig,
+ strategy: isFunctionCall ? AgentStrategy.functionCall : AgentStrategy.react,
+ },
+ dataset_configs: {
+ ...datasetConfigs,
+ datasets: {
+ datasets: [...postDatasets],
+ } as any,
+ },
+ file_upload: {
+ image: visionConfig,
+ },
+ annotation_reply: annotationConfig,
+
+ supportAnnotation: true,
+ appId,
+ supportCitationHitInfo: true,
+ }
+
+ return config
+}
+
+export const useFormattingChangedDispatcher = () => {
+ const { eventEmitter } = useEventEmitterContextContext()
+
+ const dispatcher = useCallback(() => {
+ eventEmitter?.emit({
+ type: ORCHESTRATE_CHANGED,
+ } as any)
+ }, [eventEmitter])
+
+ return dispatcher
+}
+export const useFormattingChangedSubscription = (chatList: ChatItem[]) => {
+ const {
+ formattingChanged,
+ setFormattingChanged,
+ } = useDebugConfigurationContext()
+ const { eventEmitter } = useEventEmitterContextContext()
+ eventEmitter?.useSubscription((v: any) => {
+ if (v.type === ORCHESTRATE_CHANGED) {
+ if (chatList.some(item => item.isAnswer) && !formattingChanged)
+ setFormattingChanged(true)
+ }
+ })
+}
diff --git a/app/components/app/configuration/debug/index.tsx b/app/components/app/configuration/debug/index.tsx
new file mode 100644
index 0000000..477328d
--- /dev/null
+++ b/app/components/app/configuration/debug/index.tsx
@@ -0,0 +1,561 @@
+'use client'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import produce, { setAutoFreeze } from 'immer'
+import { useBoolean } from 'ahooks'
+import {
+ RiAddLine,
+ RiEqualizer2Line,
+ RiSparklingFill,
+} from '@remixicon/react'
+import { useContext } from 'use-context-selector'
+import { useShallow } from 'zustand/react/shallow'
+import HasNotSetAPIKEY from '../base/warning-mask/has-not-set-api'
+import FormattingChanged from '../base/warning-mask/formatting-changed'
+import GroupName from '../base/group-name'
+import CannotQueryDataset from '../base/warning-mask/cannot-query-dataset'
+import DebugWithMultipleModel from './debug-with-multiple-model'
+import DebugWithSingleModel from './debug-with-single-model'
+import type { DebugWithSingleModelRefType } from './debug-with-single-model'
+import type { ModelAndParameter } from './types'
+import {
+ APP_CHAT_WITH_MULTIPLE_MODEL,
+ APP_CHAT_WITH_MULTIPLE_MODEL_RESTART,
+} from './types'
+import { AppType, ModelModeType, TransferMethod } from '@/types/app'
+import ChatUserInput from '@/app/components/app/configuration/debug/chat-user-input'
+import PromptValuePanel from '@/app/components/app/configuration/prompt-value-panel'
+import ConfigContext from '@/context/debug-configuration'
+import { ToastContext } from '@/app/components/base/toast'
+import { sendCompletionMessage } from '@/service/debug'
+import Button from '@/app/components/base/button'
+import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows'
+import TooltipPlus from '@/app/components/base/tooltip'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+import type { ModelConfig as BackendModelConfig, VisionFile, VisionSettings } from '@/types/app'
+import { promptVariablesToUserInputsForm } from '@/utils/model-config'
+import TextGeneration from '@/app/components/app/text-generate/item'
+import { IS_CE_EDITION } from '@/config'
+import type { Inputs } from '@/models/debug'
+import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelFeatureEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import type { ModelParameterModalProps } from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { useProviderContext } from '@/context/provider-context'
+import AgentLogModal from '@/app/components/base/agent-log-modal'
+import PromptLogModal from '@/app/components/base/prompt-log-modal'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import { noop } from 'lodash-es'
+
+type IDebug = {
+ isAPIKeySet: boolean
+ onSetting: () => void
+ inputs: Inputs
+ modelParameterParams: Pick<ModelParameterModalProps, 'setModel' | 'onCompletionParamsChange'>
+ debugWithMultipleModel: boolean
+ multipleModelConfigs: ModelAndParameter[]
+ onMultipleModelConfigsChange: (multiple: boolean, modelConfigs: ModelAndParameter[]) => void
+}
+
+const Debug: FC<IDebug> = ({
+ isAPIKeySet = true,
+ onSetting,
+ inputs,
+ modelParameterParams,
+ debugWithMultipleModel,
+ multipleModelConfigs,
+ onMultipleModelConfigsChange,
+}) => {
+ const { t } = useTranslation()
+ const {
+ appId,
+ mode,
+ modelModeType,
+ hasSetBlockStatus,
+ isAdvancedMode,
+ promptMode,
+ chatPromptConfig,
+ completionPromptConfig,
+ introduction,
+ suggestedQuestionsAfterAnswerConfig,
+ speechToTextConfig,
+ textToSpeechConfig,
+ citationConfig,
+ formattingChanged,
+ setFormattingChanged,
+ dataSets,
+ modelConfig,
+ completionParams,
+ hasSetContextVar,
+ datasetConfigs,
+ } = useContext(ConfigContext)
+ const { eventEmitter } = useEventEmitterContextContext()
+ const { data: text2speechDefaultModel } = useDefaultModel(ModelTypeEnum.textEmbedding)
+ useEffect(() => {
+ setAutoFreeze(false)
+ return () => {
+ setAutoFreeze(true)
+ }
+ }, [])
+
+ const [isResponding, { setTrue: setRespondingTrue, setFalse: setRespondingFalse }] = useBoolean(false)
+ const [isShowFormattingChangeConfirm, setIsShowFormattingChangeConfirm] = useState(false)
+ const [isShowCannotQueryDataset, setShowCannotQueryDataset] = useState(false)
+
+ useEffect(() => {
+ if (formattingChanged)
+ setIsShowFormattingChangeConfirm(true)
+ }, [formattingChanged])
+
+ const debugWithSingleModelRef = React.useRef<DebugWithSingleModelRefType | null>(null)
+ const handleClearConversation = () => {
+ debugWithSingleModelRef.current?.handleRestart()
+ }
+ const clearConversation = async () => {
+ if (debugWithMultipleModel) {
+ eventEmitter?.emit({
+ type: APP_CHAT_WITH_MULTIPLE_MODEL_RESTART,
+ } as any)
+ return
+ }
+
+ handleClearConversation()
+ }
+
+ const handleConfirm = () => {
+ clearConversation()
+ setIsShowFormattingChangeConfirm(false)
+ setFormattingChanged(false)
+ }
+
+ const handleCancel = () => {
+ setIsShowFormattingChangeConfirm(false)
+ setFormattingChanged(false)
+ }
+
+ const { notify } = useContext(ToastContext)
+ const logError = useCallback((message: string) => {
+ notify({ type: 'error', message })
+ }, [notify])
+ const [completionFiles, setCompletionFiles] = useState<VisionFile[]>([])
+
+ const checkCanSend = useCallback(() => {
+ if (isAdvancedMode && mode !== AppType.completion) {
+ if (modelModeType === ModelModeType.completion) {
+ if (!hasSetBlockStatus.history) {
+ notify({ type: 'error', message: t('appDebug.otherError.historyNoBeEmpty') })
+ return false
+ }
+ if (!hasSetBlockStatus.query) {
+ notify({ type: 'error', message: t('appDebug.otherError.queryNoBeEmpty') })
+ return false
+ }
+ }
+ }
+ let hasEmptyInput = ''
+ const requiredVars = modelConfig.configs.prompt_variables.filter(({ key, name, required, type }) => {
+ if (type !== 'string' && type !== 'paragraph' && type !== 'select')
+ return false
+ const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null)
+ return res
+ }) // compatible with old version
+ // debugger
+ requiredVars.forEach(({ key, name }) => {
+ if (hasEmptyInput)
+ return
+
+ if (!inputs[key])
+ hasEmptyInput = name
+ })
+
+ if (hasEmptyInput) {
+ logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }))
+ return false
+ }
+
+ if (completionFiles.find(item => item.transfer_method === TransferMethod.local_file && !item.upload_file_id)) {
+ notify({ type: 'info', message: t('appDebug.errorMessage.waitForFileUpload') })
+ return false
+ }
+ return !hasEmptyInput
+ }, [
+ completionFiles,
+ hasSetBlockStatus.history,
+ hasSetBlockStatus.query,
+ inputs,
+ isAdvancedMode,
+ mode,
+ modelConfig.configs.prompt_variables,
+ t,
+ logError,
+ notify,
+ modelModeType,
+ ])
+
+ const [completionRes, setCompletionRes] = useState('')
+ const [messageId, setMessageId] = useState<string | null>(null)
+ const features = useFeatures(s => s.features)
+ const featuresStore = useFeaturesStore()
+
+ const sendTextCompletion = async () => {
+ if (isResponding) {
+ notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
+ return false
+ }
+
+ if (dataSets.length > 0 && !hasSetContextVar) {
+ setShowCannotQueryDataset(true)
+ return true
+ }
+
+ if (!checkCanSend())
+ return
+
+ const postDatasets = dataSets.map(({ id }) => ({
+ dataset: {
+ enabled: true,
+ id,
+ },
+ }))
+ const contextVar = modelConfig.configs.prompt_variables.find(item => item.is_context_var)?.key
+
+ const postModelConfig: BackendModelConfig = {
+ pre_prompt: !isAdvancedMode ? modelConfig.configs.prompt_template : '',
+ prompt_type: promptMode,
+ chat_prompt_config: {},
+ completion_prompt_config: {},
+ user_input_form: promptVariablesToUserInputsForm(modelConfig.configs.prompt_variables),
+ dataset_query_variable: contextVar || '',
+ dataset_configs: {
+ ...datasetConfigs,
+ datasets: {
+ datasets: [...postDatasets],
+ } as any,
+ },
+ agent_mode: {
+ enabled: false,
+ tools: [],
+ },
+ model: {
+ provider: modelConfig.provider,
+ name: modelConfig.model_id,
+ mode: modelConfig.mode,
+ completion_params: completionParams as any,
+ },
+ more_like_this: features.moreLikeThis as any,
+ sensitive_word_avoidance: features.moderation as any,
+ text_to_speech: features.text2speech as any,
+ file_upload: features.file as any,
+ opening_statement: introduction,
+ suggested_questions_after_answer: suggestedQuestionsAfterAnswerConfig,
+ speech_to_text: speechToTextConfig,
+ retriever_resource: citationConfig,
+ }
+
+ if (isAdvancedMode) {
+ postModelConfig.chat_prompt_config = chatPromptConfig
+ postModelConfig.completion_prompt_config = completionPromptConfig
+ }
+
+ const data: Record<string, any> = {
+ inputs,
+ model_config: postModelConfig,
+ }
+
+ if ((features.file as any).enabled && completionFiles && completionFiles?.length > 0) {
+ data.files = completionFiles.map((item) => {
+ if (item.transfer_method === TransferMethod.local_file) {
+ return {
+ ...item,
+ url: '',
+ }
+ }
+ return item
+ })
+ }
+
+ setCompletionRes('')
+ setMessageId('')
+ let res: string[] = []
+
+ setRespondingTrue()
+ sendCompletionMessage(appId, data, {
+ onData: (data: string, _isFirstMessage: boolean, { messageId }) => {
+ res.push(data)
+ setCompletionRes(res.join(''))
+ setMessageId(messageId)
+ },
+ onMessageReplace: (messageReplace) => {
+ res = [messageReplace.answer]
+ setCompletionRes(res.join(''))
+ },
+ onCompleted() {
+ setRespondingFalse()
+ },
+ onError() {
+ setRespondingFalse()
+ },
+ })
+ }
+
+ const handleSendTextCompletion = () => {
+ if (debugWithMultipleModel) {
+ eventEmitter?.emit({
+ type: APP_CHAT_WITH_MULTIPLE_MODEL,
+ payload: {
+ message: '',
+ files: completionFiles,
+ },
+ } as any)
+ return
+ }
+
+ sendTextCompletion()
+ }
+
+ const varList = modelConfig.configs.prompt_variables.map((item: any) => {
+ return {
+ label: item.key,
+ value: inputs[item.key],
+ }
+ })
+
+ const { textGenerationModelList } = useProviderContext()
+ const handleChangeToSingleModel = (item: ModelAndParameter) => {
+ const currentProvider = textGenerationModelList.find(modelItem => modelItem.provider === item.provider)
+ const currentModel = currentProvider?.models.find(model => model.model === item.model)
+
+ modelParameterParams.setModel({
+ modelId: item.model,
+ provider: item.provider,
+ mode: currentModel?.model_properties.mode as string,
+ features: currentModel?.features,
+ })
+ modelParameterParams.onCompletionParamsChange(item.parameters)
+ onMultipleModelConfigsChange(
+ false,
+ [],
+ )
+ }
+
+ const handleVisionConfigInMultipleModel = useCallback(() => {
+ if (debugWithMultipleModel && mode) {
+ const supportedVision = multipleModelConfigs.some((modelConfig) => {
+ const currentProvider = textGenerationModelList.find(modelItem => modelItem.provider === modelConfig.provider)
+ const currentModel = currentProvider?.models.find(model => model.model === modelConfig.model)
+
+ return currentModel?.features?.includes(ModelFeatureEnum.vision)
+ })
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft.file = {
+ ...draft.file,
+ enabled: supportedVision,
+ }
+ })
+ setFeatures(newFeatures)
+ }
+ }, [debugWithMultipleModel, featuresStore, mode, multipleModelConfigs, textGenerationModelList])
+
+ useEffect(() => {
+ handleVisionConfigInMultipleModel()
+ }, [multipleModelConfigs, mode, handleVisionConfigInMultipleModel])
+
+ const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({
+ currentLogItem: state.currentLogItem,
+ setCurrentLogItem: state.setCurrentLogItem,
+ showPromptLogModal: state.showPromptLogModal,
+ setShowPromptLogModal: state.setShowPromptLogModal,
+ showAgentLogModal: state.showAgentLogModal,
+ setShowAgentLogModal: state.setShowAgentLogModal,
+ })))
+ const [width, setWidth] = useState(0)
+ const ref = useRef<HTMLDivElement>(null)
+
+ const adjustModalWidth = () => {
+ if (ref.current)
+ setWidth(document.body.clientWidth - (ref.current?.clientWidth + 16) - 8)
+ }
+
+ useEffect(() => {
+ adjustModalWidth()
+ }, [])
+
+ const [expanded, setExpanded] = useState(true)
+
+ return (
+ <>
+ <div className="shrink-0">
+ <div className='flex items-center justify-between px-4 pb-2 pt-3'>
+ <div className='system-xl-semibold text-text-primary'>{t('appDebug.inputs.title')}</div>
+ <div className='flex items-center'>
+ {
+ debugWithMultipleModel
+ ? (
+ <>
+ <Button
+ variant='ghost-accent'
+ onClick={() => onMultipleModelConfigsChange(true, [...multipleModelConfigs, { id: `${Date.now()}`, model: '', provider: '', parameters: {} }])}
+ disabled={multipleModelConfigs.length >= 4}
+ >
+ <RiAddLine className='mr-1 h-3.5 w-3.5' />
+ {t('common.modelProvider.addModel')}({multipleModelConfigs.length}/4)
+ </Button>
+ <div className='mx-2 h-[14px] w-[1px] bg-divider-regular' />
+ </>
+ )
+ : null
+ }
+ {mode !== AppType.completion && (
+ <>
+ <TooltipPlus
+ popupContent={t('common.operation.refresh')}
+ >
+ <ActionButton onClick={clearConversation}>
+ <RefreshCcw01 className='h-4 w-4' />
+ </ActionButton>
+ </TooltipPlus>
+ {varList.length > 0 && (
+ <div className='relative ml-1 mr-2'>
+ <TooltipPlus
+ popupContent={t('workflow.panel.userInputField')}
+ >
+ <ActionButton state={expanded ? ActionButtonState.Active : undefined} onClick={() => setExpanded(!expanded)}>
+ <RiEqualizer2Line className='h-4 w-4' />
+ </ActionButton>
+ </TooltipPlus>
+ {expanded && <div className='absolute bottom-[-14px] right-[5px] z-10 h-3 w-3 rotate-45 border-l-[0.5px] border-t-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg' />}
+ </div>
+ )}
+ </>
+ )}
+ </div>
+ </div>
+ {mode !== AppType.completion && expanded && (
+ <div className='mx-3'>
+ <ChatUserInput inputs={inputs} />
+ </div>
+ )}
+ {mode === AppType.completion && (
+ <PromptValuePanel
+ appType={mode as AppType}
+ onSend={handleSendTextCompletion}
+ inputs={inputs}
+ visionConfig={{
+ ...features.file! as VisionSettings,
+ transfer_methods: features.file!.allowed_file_upload_methods || [],
+ image_file_size_limit: features.file?.fileUploadConfig?.image_file_size_limit,
+ }}
+ onVisionFilesChange={setCompletionFiles}
+ />
+ )}
+ </div>
+ {
+ debugWithMultipleModel && (
+ <div className='mt-3 grow overflow-hidden' ref={ref}>
+ <DebugWithMultipleModel
+ multipleModelConfigs={multipleModelConfigs}
+ onMultipleModelConfigsChange={onMultipleModelConfigsChange}
+ onDebugWithMultipleModelChange={handleChangeToSingleModel}
+ checkCanSend={checkCanSend}
+ />
+ {showPromptLogModal && (
+ <PromptLogModal
+ width={width}
+ currentLogItem={currentLogItem}
+ onCancel={() => {
+ setCurrentLogItem()
+ setShowPromptLogModal(false)
+ }}
+ />
+ )}
+ {showAgentLogModal && (
+ <AgentLogModal
+ width={width}
+ currentLogItem={currentLogItem}
+ onCancel={() => {
+ setCurrentLogItem()
+ setShowAgentLogModal(false)
+ }}
+ />
+ )}
+ </div>
+ )
+ }
+ {
+ !debugWithMultipleModel && (
+ <div className="flex grow flex-col" ref={ref}>
+ {/* Chat */}
+ {mode !== AppType.completion && (
+ <div className='h-0 grow overflow-hidden'>
+ <DebugWithSingleModel
+ ref={debugWithSingleModelRef}
+ checkCanSend={checkCanSend}
+ />
+ </div>
+ )}
+ {/* Text Generation */}
+ {mode === AppType.completion && (
+ <>
+ {(completionRes || isResponding) && (
+ <>
+ <div className='mx-4 mt-3'><GroupName name={t('appDebug.result')} /></div>
+ <div className='mx-3 mb-8'>
+ <TextGeneration
+ className="mt-2"
+ content={completionRes}
+ isLoading={!completionRes && isResponding}
+ isShowTextToSpeech={textToSpeechConfig.enabled && !!text2speechDefaultModel}
+ isResponding={isResponding}
+ isInstalledApp={false}
+ messageId={messageId}
+ isError={false}
+ onRetry={noop}
+ siteInfo={null}
+ />
+ </div>
+ </>
+ )}
+ {!completionRes && !isResponding && (
+ <div className='flex grow flex-col items-center justify-center gap-2'>
+ <RiSparklingFill className='h-12 w-12 text-text-empty-state-icon' />
+ <div className='system-sm-regular text-text-quaternary'>{t('appDebug.noResult')}</div>
+ </div>
+ )}
+ </>
+ )}
+ {mode === AppType.completion && showPromptLogModal && (
+ <PromptLogModal
+ width={width}
+ currentLogItem={currentLogItem}
+ onCancel={() => {
+ setCurrentLogItem()
+ setShowPromptLogModal(false)
+ }}
+ />
+ )}
+ {isShowCannotQueryDataset && (
+ <CannotQueryDataset
+ onConfirm={() => setShowCannotQueryDataset(false)}
+ />
+ )}
+ </div>
+ )
+ }
+ {isShowFormattingChangeConfirm && (
+ <FormattingChanged
+ onConfirm={handleConfirm}
+ onCancel={handleCancel}
+ />
+ )}
+ {!isAPIKeySet && (<HasNotSetAPIKEY isTrailFinished={!IS_CE_EDITION} onSetting={onSetting} />)}
+ </>
+ )
+}
+export default React.memo(Debug)
diff --git a/app/components/app/configuration/debug/types.ts b/app/components/app/configuration/debug/types.ts
new file mode 100644
index 0000000..ada665a
--- /dev/null
+++ b/app/components/app/configuration/debug/types.ts
@@ -0,0 +1,18 @@
+export type ModelAndParameter = {
+ id: string
+ model: string
+ provider: string
+ parameters: Record<string, any>
+}
+
+export type MultipleAndConfigs = {
+ multiple: boolean
+ configs: ModelAndParameter[]
+}
+
+export type DebugWithSingleOrMultipleModelConfigs = {
+ [k: string]: MultipleAndConfigs
+}
+export const APP_CHAT_WITH_MULTIPLE_MODEL = 'APP_CHAT_WITH_MULTIPLE_MODEL'
+export const APP_CHAT_WITH_MULTIPLE_MODEL_RESTART = 'APP_CHAT_WITH_MULTIPLE_MODEL_RESTART'
+export const ORCHESTRATE_CHANGED = 'ORCHESTRATE_CHANGED'
diff --git a/app/components/app/configuration/features/experience-enhance-group/index.tsx b/app/components/app/configuration/features/experience-enhance-group/index.tsx
new file mode 100644
index 0000000..4a629a6
--- /dev/null
+++ b/app/components/app/configuration/features/experience-enhance-group/index.tsx
@@ -0,0 +1,43 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import GroupName from '../../base/group-name'
+import TextToSpeech from '../chat-group/text-to-speech'
+import MoreLikeThis from './more-like-this'
+
+/*
+* Include
+* 1. More like this
+*/
+
+type ExperienceGroupProps = {
+ isShowTextToSpeech: boolean
+ isShowMoreLike: boolean
+}
+
+const ExperienceEnhanceGroup: FC<ExperienceGroupProps> = ({
+ isShowTextToSpeech,
+ isShowMoreLike,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='mt-7'>
+ <GroupName name={t('appDebug.feature.groupExperience.title')}/>
+ <div className='space-y-3'>
+ {
+ isShowMoreLike && (
+ <MoreLikeThis/>
+ )
+ }
+ {
+ isShowTextToSpeech && (
+ <TextToSpeech/>
+ )
+ }
+ </div>
+ </div>
+ )
+}
+export default React.memo(ExperienceEnhanceGroup)
diff --git a/app/components/app/configuration/features/experience-enhance-group/more-like-this/index.tsx b/app/components/app/configuration/features/experience-enhance-group/more-like-this/index.tsx
new file mode 100644
index 0000000..e110d0c
--- /dev/null
+++ b/app/components/app/configuration/features/experience-enhance-group/more-like-this/index.tsx
@@ -0,0 +1,51 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { XMarkIcon } from '@heroicons/react/24/outline'
+import { useLocalStorageState } from 'ahooks'
+import MoreLikeThisIcon from '../../../base/icons/more-like-this-icon'
+import Panel from '@/app/components/app/configuration/base/feature-panel'
+
+const GENERATE_NUM = 1
+
+const warningIcon = (
+ <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fillRule="evenodd" clipRule="evenodd" d="M6.40616 0.834307C6.14751 0.719294 5.85222 0.719294 5.59356 0.834307C5.3938 0.923133 5.26403 1.07959 5.17373 1.20708C5.08495 1.33242 4.9899 1.49664 4.88536 1.67723L0.751783 8.81705C0.646828 8.9983 0.551451 9.16302 0.486781 9.3028C0.421056 9.44487 0.349754 9.63584 0.372478 9.85381C0.401884 10.1359 0.549654 10.3922 0.779012 10.5589C0.956259 10.6878 1.15726 10.7218 1.31314 10.7361C1.46651 10.7501 1.65684 10.7501 1.86628 10.7501H10.1334C10.3429 10.7501 10.5332 10.7501 10.6866 10.7361C10.8425 10.7218 11.0435 10.6878 11.2207 10.5589C11.4501 10.3922 11.5978 10.1359 11.6272 9.85381C11.65 9.63584 11.5787 9.44487 11.5129 9.3028C11.4483 9.16303 11.3529 8.99833 11.248 8.81709L7.11436 1.67722C7.00983 1.49663 6.91477 1.33242 6.82599 1.20708C6.73569 1.07959 6.60593 0.923133 6.40616 0.834307ZM6.49988 4.50012C6.49988 4.22398 6.27602 4.00012 5.99988 4.00012C5.72374 4.00012 5.49988 4.22398 5.49988 4.50012V6.50012C5.49988 6.77626 5.72374 7.00012 5.99988 7.00012C6.27602 7.00012 6.49988 6.77626 6.49988 6.50012V4.50012ZM5.99988 8.00012C5.72374 8.00012 5.49988 8.22398 5.49988 8.50012C5.49988 8.77626 5.72374 9.00012 5.99988 9.00012H6.00488C6.28102 9.00012 6.50488 8.77626 6.50488 8.50012C6.50488 8.22398 6.28102 8.00012 6.00488 8.00012H5.99988Z" fill="#F79009" />
+ </svg>
+
+)
+const MoreLikeThis: FC = () => {
+ const { t } = useTranslation()
+
+ const [isHideTip, setIsHideTip] = useLocalStorageState('isHideMoreLikeThisTip', {
+ defaultValue: false,
+ })
+
+ const headerRight = (
+ <div className='text-xs text-gray-500'>{t('appDebug.feature.moreLikeThis.generateNumTip')} {GENERATE_NUM}</div>
+ )
+ return (
+ <Panel
+ className='mt-4'
+ title={t('appDebug.feature.moreLikeThis.title')}
+ headerIcon={<MoreLikeThisIcon />}
+ headerRight={headerRight}
+ noBodySpacing
+ >
+ {!isHideTip && (
+ <div className='flex h-9 items-center justify-between rounded-b-xl bg-[#FFFAEB] px-3 text-xs text-gray-700'>
+ <div className='flex items-center space-x-2'>
+ <div>{warningIcon}</div>
+ <div>{t('appDebug.feature.moreLikeThis.tip')}</div>
+ </div>
+ <div className='flex h-4 w-4 cursor-pointer items-center justify-center' onClick={() => setIsHideTip(true)}>
+ <XMarkIcon className="h-3 w-3" />
+ </div>
+ </div>
+ )}
+
+ </Panel>
+ )
+}
+export default React.memo(MoreLikeThis)
diff --git a/app/components/app/configuration/hooks/use-advanced-prompt-config.ts b/app/components/app/configuration/hooks/use-advanced-prompt-config.ts
new file mode 100644
index 0000000..193ac87
--- /dev/null
+++ b/app/components/app/configuration/hooks/use-advanced-prompt-config.ts
@@ -0,0 +1,194 @@
+import { useState } from 'react'
+import { clone } from 'lodash-es'
+import produce from 'immer'
+import type { ChatPromptConfig, CompletionPromptConfig, ConversationHistoriesRole, PromptItem } from '@/models/debug'
+import { PromptMode } from '@/models/debug'
+import { ModelModeType } from '@/types/app'
+import { DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/config'
+import { PRE_PROMPT_PLACEHOLDER_TEXT, checkHasContextBlock, checkHasHistoryBlock, checkHasQueryBlock } from '@/app/components/base/prompt-editor/constants'
+import { fetchPromptTemplate } from '@/service/debug'
+import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
+
+type Param = {
+ appMode: string
+ modelModeType: ModelModeType
+ modelName: string
+ promptMode: PromptMode
+ prePrompt: string
+ onUserChangedPrompt: () => void
+ hasSetDataSet: boolean
+ completionParams: FormValue
+ setCompletionParams: (params: FormValue) => void
+ setStop: (stop: string[]) => void
+}
+
+const useAdvancedPromptConfig = ({
+ appMode,
+ modelModeType,
+ modelName,
+ promptMode,
+ prePrompt,
+ onUserChangedPrompt,
+ hasSetDataSet,
+ completionParams,
+ setCompletionParams,
+ setStop,
+}: Param) => {
+ const isAdvancedPrompt = promptMode === PromptMode.advanced
+ const [chatPromptConfig, setChatPromptConfig] = useState<ChatPromptConfig>(clone(DEFAULT_CHAT_PROMPT_CONFIG))
+ const [completionPromptConfig, setCompletionPromptConfig] = useState<CompletionPromptConfig>(clone(DEFAULT_COMPLETION_PROMPT_CONFIG))
+
+ const currentAdvancedPrompt = (() => {
+ if (!isAdvancedPrompt)
+ return []
+
+ return (modelModeType === ModelModeType.chat) ? chatPromptConfig.prompt : completionPromptConfig.prompt
+ })()
+
+ const setCurrentAdvancedPrompt = (prompt: PromptItem | PromptItem[], isUserChanged?: boolean) => {
+ if (!isAdvancedPrompt)
+ return
+
+ if (modelModeType === ModelModeType.chat) {
+ setChatPromptConfig({
+ ...chatPromptConfig,
+ prompt: prompt as PromptItem[],
+ })
+ }
+ else {
+ setCompletionPromptConfig({
+ ...completionPromptConfig,
+ prompt: prompt as PromptItem,
+ })
+ }
+ if (isUserChanged)
+ onUserChangedPrompt()
+ }
+
+ const setConversationHistoriesRole = (conversationHistoriesRole: ConversationHistoriesRole) => {
+ setCompletionPromptConfig({
+ ...completionPromptConfig,
+ conversation_histories_role: conversationHistoriesRole,
+ })
+ }
+
+ const hasSetBlockStatus = (() => {
+ if (!isAdvancedPrompt) {
+ return {
+ context: checkHasContextBlock(prePrompt),
+ history: false,
+ query: false,
+ }
+ }
+ if (modelModeType === ModelModeType.chat) {
+ return {
+ context: !!chatPromptConfig.prompt.find(p => checkHasContextBlock(p.text)),
+ history: false,
+ query: !!chatPromptConfig.prompt.find(p => checkHasQueryBlock(p.text)),
+ }
+ }
+ else {
+ const prompt = completionPromptConfig.prompt?.text
+ return {
+ context: checkHasContextBlock(prompt),
+ history: checkHasHistoryBlock(prompt),
+ query: checkHasQueryBlock(prompt),
+ }
+ }
+ })()
+
+ /* prompt: simple to advanced process, or chat model to completion model
+ * 1. migrate prompt
+ * 2. change promptMode to advanced
+ */
+ const migrateToDefaultPrompt = async (isMigrateToCompetition?: boolean, toModelModeType?: ModelModeType) => {
+ const mode = modelModeType
+ const toReplacePrePrompt = prePrompt || ''
+ if (!isAdvancedPrompt) {
+ const { chat_prompt_config, completion_prompt_config, stop } = await fetchPromptTemplate({
+ appMode,
+ mode,
+ modelName,
+ hasSetDataSet,
+ })
+ if (modelModeType === ModelModeType.chat) {
+ const newPromptConfig = produce(chat_prompt_config, (draft) => {
+ draft.prompt = draft.prompt.map((p) => {
+ return {
+ ...p,
+ text: p.text.replace(PRE_PROMPT_PLACEHOLDER_TEXT, toReplacePrePrompt),
+ }
+ })
+ })
+ setChatPromptConfig(newPromptConfig)
+ }
+
+ else {
+ const newPromptConfig = produce(completion_prompt_config, (draft) => {
+ draft.prompt.text = draft.prompt.text.replace(PRE_PROMPT_PLACEHOLDER_TEXT, toReplacePrePrompt)
+ })
+ setCompletionPromptConfig(newPromptConfig)
+ setCompletionParams({
+ ...completionParams,
+ stop,
+ })
+ }
+ return
+ }
+
+ if (isMigrateToCompetition) {
+ const { completion_prompt_config, chat_prompt_config, stop } = await fetchPromptTemplate({
+ appMode,
+ mode: toModelModeType as ModelModeType,
+ modelName,
+ hasSetDataSet,
+ })
+
+ if (toModelModeType === ModelModeType.completion) {
+ const newPromptConfig = produce(completion_prompt_config, (draft) => {
+ if (!completionPromptConfig.prompt?.text)
+ draft.prompt.text = draft.prompt.text.replace(PRE_PROMPT_PLACEHOLDER_TEXT, toReplacePrePrompt)
+
+ else
+ draft.prompt.text = completionPromptConfig.prompt?.text.replace(PRE_PROMPT_PLACEHOLDER_TEXT, toReplacePrePrompt)
+
+ if (['advanced-chat', 'agent-chat', 'chat'].includes(appMode) && completionPromptConfig.conversation_histories_role.assistant_prefix && completionPromptConfig.conversation_histories_role.user_prefix)
+ draft.conversation_histories_role = completionPromptConfig.conversation_histories_role
+ })
+ setCompletionPromptConfig(newPromptConfig)
+ if (!completionParams.stop || completionParams.stop.length === 0) {
+ setCompletionParams({
+ ...completionParams,
+ stop,
+ })
+ }
+ setStop(stop) // switch mode's params is async. It may override the stop value.
+ }
+ else {
+ const newPromptConfig = produce(chat_prompt_config, (draft) => {
+ draft.prompt = draft.prompt.map((p) => {
+ return {
+ ...p,
+ text: p.text.replace(PRE_PROMPT_PLACEHOLDER_TEXT, toReplacePrePrompt),
+ }
+ })
+ })
+ setChatPromptConfig(newPromptConfig)
+ }
+ }
+ }
+
+ return {
+ chatPromptConfig,
+ setChatPromptConfig,
+ completionPromptConfig,
+ setCompletionPromptConfig,
+ currentAdvancedPrompt,
+ setCurrentAdvancedPrompt,
+ hasSetBlockStatus,
+ setConversationHistoriesRole,
+ migrateToDefaultPrompt,
+ }
+}
+
+export default useAdvancedPromptConfig
diff --git a/app/components/app/configuration/images/prompt.svg b/app/components/app/configuration/images/prompt.svg
new file mode 100644
index 0000000..88453d2
--- /dev/null
+++ b/app/components/app/configuration/images/prompt.svg
@@ -0,0 +1,19 @@
+<svg width="72" height="35" viewBox="0 0 72 35" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M17.0565 5.76794C18.2191 5.76794 19.1045 6.03461 19.7125 6.56794C20.3205 7.09061 20.6245 7.77328 20.6245 8.61594C20.6245 8.86128 20.6031 9.09061 20.5605 9.30394C20.4325 10.0506 20.1071 10.7173 19.5845 11.3039C19.0618 11.8906 18.3631 12.3066 17.4885 12.5519L19.2965 16.9999H16.2085L14.6245 12.7599H13.9685L13.2165 16.9999H10.4805L12.4645 5.76794H17.0565ZM17.7605 9.41594C17.7818 9.24528 17.7925 9.13328 17.7925 9.07994C17.7925 8.73861 17.6805 8.47728 17.4565 8.29594C17.2431 8.10394 16.9231 8.00794 16.4965 8.00794H14.8005L14.3045 10.8239H16.0005C16.5018 10.8239 16.8965 10.7013 17.1845 10.4559C17.4831 10.2106 17.6751 9.86394 17.7605 9.41594Z" fill="#1D2939"/>
+<path d="M10.0798 9.38394C9.97312 10.0346 9.72245 10.6319 9.32778 11.1759C8.93312 11.7093 8.39445 12.1413 7.71178 12.4719C7.03978 12.8026 6.24511 12.9679 5.32778 12.9679H3.63178L2.91178 16.9999H0.175781L2.15978 5.76794H6.59178C7.76511 5.76794 8.65045 6.02928 9.24778 6.55194C9.84512 7.06394 10.1438 7.76261 10.1438 8.64794C10.1438 8.91461 10.1224 9.15994 10.0798 9.38394ZM5.48778 10.8239C6.51178 10.8239 7.11445 10.3439 7.29578 9.38394C7.31711 9.21328 7.32778 9.09061 7.32778 9.01594C7.32778 8.67461 7.21578 8.41328 6.99178 8.23194C6.77845 8.03994 6.44778 7.94394 5.99978 7.94394H4.51178L4.01578 10.8239H5.48778Z" fill="#1D2939"/>
+<path d="M26.52 17.112C25.5706 17.112 24.7333 16.9147 24.008 16.52C23.2933 16.1254 22.7386 15.5707 22.344 14.856C21.9493 14.1414 21.752 13.32 21.752 12.392C21.752 11.08 22.0346 9.91203 22.6 8.88803C23.1653 7.85337 23.9493 7.04803 24.952 6.47203C25.9653 5.89603 27.112 5.60803 28.392 5.60803C29.352 5.60803 30.1946 5.80537 30.92 6.20003C31.6453 6.58403 32.2053 7.13336 32.6 7.84803C32.9946 8.55203 33.192 9.3627 33.192 10.28C33.192 11.592 32.9093 12.7707 32.344 13.816C31.7786 14.8507 30.9893 15.6614 29.976 16.248C28.9626 16.824 27.8106 17.112 26.52 17.112ZM26.936 14.584C27.64 14.584 28.2586 14.4027 28.792 14.04C29.3253 13.6774 29.736 13.192 30.024 12.584C30.3226 11.9654 30.472 11.2987 30.472 10.584C30.472 9.81603 30.2586 9.21337 29.832 8.77603C29.4053 8.3387 28.808 8.12003 28.04 8.12003C27.336 8.12003 26.712 8.30137 26.168 8.66403C25.6346 9.0267 25.2186 9.51203 24.92 10.12C24.632 10.7174 24.488 11.3787 24.488 12.104C24.488 12.872 24.7013 13.48 25.128 13.928C25.5546 14.3654 26.1573 14.584 26.936 14.584Z" fill="#1D2939"/>
+<path d="M69.5515 5.76794L69.1835 7.92794H66.1915L64.5915 16.9999H61.8555L63.4555 7.92794H60.4795L60.8635 5.76794H69.5515Z" fill="#1D2939"/>
+<path d="M59.0876 9.38394C58.9809 10.0346 58.7303 10.6319 58.3356 11.1759C57.9409 11.7093 57.4023 12.1413 56.7196 12.4719C56.0476 12.8026 55.2529 12.9679 54.3356 12.9679H52.6396L51.9196 16.9999H49.1836L51.1676 5.76794H55.5996C56.7729 5.76794 57.6583 6.02928 58.2556 6.55194C58.8529 7.06394 59.1516 7.76261 59.1516 8.64794C59.1516 8.91461 59.1303 9.15994 59.0876 9.38394ZM54.4956 10.8239C55.5196 10.8239 56.1223 10.3439 56.3036 9.38394C56.3249 9.21328 56.3356 9.09061 56.3356 9.01594C56.3356 8.67461 56.2236 8.41328 55.9996 8.23194C55.7863 8.03994 55.4556 7.94394 55.0076 7.94394H53.5196L53.0236 10.8239H54.4956Z" fill="#1D2939"/>
+<path d="M48.8798 5.76794L46.8958 16.9999H44.1598L45.3598 10.2639L41.6478 16.9999H39.4398L38.0958 10.2319L36.9118 16.9999H34.1758L36.1598 5.76794H39.3918L41.1838 13.5439L45.6638 5.76794H48.8798Z" fill="#1D2939"/>
+<path d="M67.6792 24.28C68.1912 24.28 68.6272 24.384 68.9872 24.592C69.3552 24.792 69.6192 25.044 69.7792 25.348L69.9472 24.388H71.3272L70.1512 31.108C70.0392 31.716 69.8152 32.256 69.4792 32.728C69.1432 33.208 68.7072 33.584 68.1712 33.856C67.6352 34.128 67.0312 34.264 66.3592 34.264C65.7752 34.264 65.2632 34.168 64.8232 33.976C64.3832 33.792 64.0512 33.524 63.8272 33.172C63.6032 32.82 63.5072 32.404 63.5392 31.924H64.8952C64.9352 32.268 65.1072 32.544 65.4112 32.752C65.7152 32.968 66.1032 33.076 66.5752 33.076C67.1272 33.076 67.6032 32.908 68.0032 32.572C68.4032 32.236 68.6592 31.748 68.7712 31.108L68.9632 30.004C68.6752 30.316 68.3152 30.58 67.8832 30.796C67.4512 31.004 66.9832 31.108 66.4792 31.108C65.9752 31.108 65.5272 30.996 65.1352 30.772C64.7432 30.548 64.4352 30.232 64.2112 29.824C63.9952 29.408 63.8872 28.932 63.8872 28.396C63.8872 28.156 63.9112 27.912 63.9592 27.664C64.0792 27 64.3192 26.412 64.6792 25.9C65.0472 25.388 65.4952 24.992 66.0232 24.712C66.5512 24.424 67.1032 24.28 67.6792 24.28ZM69.3712 27.688C69.4032 27.536 69.4192 27.372 69.4192 27.196C69.4192 26.66 69.2592 26.24 68.9392 25.936C68.6272 25.624 68.2352 25.468 67.7632 25.468C67.4112 25.468 67.0672 25.556 66.7312 25.732C66.3952 25.9 66.1032 26.152 65.8552 26.488C65.6072 26.816 65.4432 27.208 65.3632 27.664C65.3312 27.816 65.3152 27.98 65.3152 28.156C65.3152 28.7 65.4712 29.132 65.7832 29.452C66.1032 29.764 66.4992 29.92 66.9712 29.92C67.3232 29.92 67.6672 29.832 68.0032 29.656C68.3392 29.48 68.6312 29.224 68.8792 28.888C69.1272 28.544 69.2912 28.144 69.3712 27.688Z" fill="#667085"/>
+<path d="M60.5582 24.28C61.2542 24.28 61.8062 24.468 62.2142 24.844C62.6302 25.212 62.8382 25.744 62.8382 26.44C62.8382 26.616 62.8182 26.836 62.7782 27.1L62.0822 31H60.7262L61.3862 27.304C61.4182 27.08 61.4342 26.92 61.4342 26.824C61.4342 26.384 61.3102 26.048 61.0622 25.816C60.8222 25.584 60.4862 25.468 60.0542 25.468C59.5342 25.468 59.0942 25.628 58.7342 25.948C58.3822 26.26 58.1582 26.712 58.0622 27.304V27.268L57.4022 31H56.0342L57.1982 24.388H58.5662L58.4342 25.156C58.7062 24.884 59.0262 24.672 59.3942 24.52C59.7702 24.36 60.1582 24.28 60.5582 24.28Z" fill="#667085"/>
+<path d="M54.8861 23.512C54.6701 23.512 54.4941 23.444 54.3581 23.308C54.2221 23.172 54.1541 23 54.1541 22.792C54.1541 22.512 54.2581 22.272 54.4661 22.072C54.6821 21.864 54.9261 21.76 55.1981 21.76C55.4141 21.76 55.5861 21.828 55.7141 21.964C55.8501 22.1 55.9181 22.272 55.9181 22.48C55.9181 22.76 55.8141 23.004 55.6061 23.212C55.3981 23.412 55.1581 23.512 54.8861 23.512ZM55.4021 24.388L54.2381 31H52.8701L54.0341 24.388H55.4021Z" fill="#667085"/>
+<path d="M50.5926 25.552C50.8646 25.152 51.1846 24.84 51.5526 24.616C51.9286 24.392 52.3446 24.28 52.8006 24.28L52.5486 25.696H52.2006C51.6726 25.696 51.2486 25.828 50.9286 26.092C50.6086 26.356 50.3846 26.812 50.2566 27.46L49.6326 31H48.2646L49.4286 24.388H50.7966L50.5926 25.552Z" fill="#667085"/>
+<path d="M44.89 24.28C45.714 24.28 46.37 24.512 46.858 24.976C47.354 25.44 47.602 26.064 47.602 26.848C47.602 27.032 47.582 27.252 47.542 27.508C47.51 27.684 47.454 27.9 47.374 28.156H42.322C42.314 28.212 42.31 28.296 42.31 28.408C42.31 28.88 42.454 29.256 42.742 29.536C43.038 29.816 43.422 29.956 43.894 29.956C44.638 29.956 45.21 29.648 45.61 29.032H47.086C46.782 29.64 46.334 30.14 45.742 30.532C45.15 30.916 44.466 31.108 43.69 31.108C43.138 31.108 42.654 31 42.238 30.784C41.822 30.568 41.498 30.26 41.266 29.86C41.034 29.452 40.918 28.976 40.918 28.432C40.918 28.2 40.942 27.952 40.99 27.688C41.11 27.008 41.354 26.412 41.722 25.9C42.09 25.38 42.546 24.98 43.09 24.7C43.642 24.42 44.242 24.28 44.89 24.28ZM46.174 27.172C46.19 27.028 46.198 26.924 46.198 26.86C46.198 26.42 46.05 26.072 45.754 25.816C45.466 25.56 45.09 25.432 44.626 25.432C44.138 25.432 43.698 25.588 43.306 25.9C42.914 26.212 42.646 26.636 42.502 27.172H46.174Z" fill="#667085"/>
+<path d="M37.4837 24.28C38.3077 24.28 38.9637 24.512 39.4517 24.976C39.9477 25.44 40.1957 26.064 40.1957 26.848C40.1957 27.032 40.1757 27.252 40.1357 27.508C40.1037 27.684 40.0477 27.9 39.9677 28.156H34.9157C34.9077 28.212 34.9037 28.296 34.9037 28.408C34.9037 28.88 35.0477 29.256 35.3357 29.536C35.6317 29.816 36.0157 29.956 36.4877 29.956C37.2317 29.956 37.8037 29.648 38.2037 29.032H39.6797C39.3757 29.64 38.9277 30.14 38.3357 30.532C37.7437 30.916 37.0597 31.108 36.2837 31.108C35.7317 31.108 35.2477 31 34.8317 30.784C34.4157 30.568 34.0917 30.26 33.8597 29.86C33.6277 29.452 33.5117 28.976 33.5117 28.432C33.5117 28.2 33.5357 27.952 33.5837 27.688C33.7037 27.008 33.9477 26.412 34.3157 25.9C34.6837 25.38 35.1397 24.98 35.6837 24.7C36.2357 24.42 36.8357 24.28 37.4837 24.28ZM38.7677 27.172C38.7837 27.028 38.7917 26.924 38.7917 26.86C38.7917 26.42 38.6437 26.072 38.3477 25.816C38.0597 25.56 37.6837 25.432 37.2197 25.432C36.7317 25.432 36.2917 25.588 35.8997 25.9C35.5077 26.212 35.2397 26.636 35.0957 27.172H38.7677Z" fill="#667085"/>
+<path d="M30.1832 24.28C30.8792 24.28 31.4312 24.468 31.8392 24.844C32.2552 25.212 32.4632 25.744 32.4632 26.44C32.4632 26.616 32.4432 26.836 32.4032 27.1L31.7072 31H30.3512L31.0112 27.304C31.0432 27.08 31.0592 26.92 31.0592 26.824C31.0592 26.384 30.9352 26.048 30.6872 25.816C30.4472 25.584 30.1112 25.468 29.6792 25.468C29.1592 25.468 28.7192 25.628 28.3592 25.948C28.0072 26.26 27.7832 26.712 27.6872 27.304V27.268L27.0272 31H25.6592L26.8232 24.388H28.1912L28.0592 25.156C28.3312 24.884 28.6512 24.672 29.0192 24.52C29.3952 24.36 29.7832 24.28 30.1832 24.28Z" fill="#667085"/>
+<path d="M24.5111 23.512C24.2951 23.512 24.1191 23.444 23.9831 23.308C23.8471 23.172 23.7791 23 23.7791 22.792C23.7791 22.512 23.8831 22.272 24.0911 22.072C24.3071 21.864 24.5511 21.76 24.8231 21.76C25.0391 21.76 25.2111 21.828 25.3391 21.964C25.4751 22.1 25.5431 22.272 25.5431 22.48C25.5431 22.76 25.4391 23.004 25.2311 23.212C25.0231 23.412 24.7831 23.512 24.5111 23.512ZM25.0271 24.388L23.8631 31H22.4951L23.6591 24.388H25.0271Z" fill="#667085"/>
+<path d="M18.2144 24.28C18.7264 24.28 19.1624 24.384 19.5224 24.592C19.8904 24.792 20.1544 25.044 20.3144 25.348L20.4824 24.388H21.8624L20.6864 31.108C20.5744 31.716 20.3504 32.256 20.0144 32.728C19.6784 33.208 19.2424 33.584 18.7064 33.856C18.1704 34.128 17.5664 34.264 16.8944 34.264C16.3104 34.264 15.7984 34.168 15.3584 33.976C14.9184 33.792 14.5864 33.524 14.3624 33.172C14.1384 32.82 14.0424 32.404 14.0744 31.924H15.4304C15.4704 32.268 15.6424 32.544 15.9464 32.752C16.2504 32.968 16.6384 33.076 17.1104 33.076C17.6624 33.076 18.1384 32.908 18.5384 32.572C18.9384 32.236 19.1944 31.748 19.3064 31.108L19.4984 30.004C19.2104 30.316 18.8504 30.58 18.4184 30.796C17.9864 31.004 17.5184 31.108 17.0144 31.108C16.5104 31.108 16.0624 30.996 15.6704 30.772C15.2784 30.548 14.9704 30.232 14.7464 29.824C14.5304 29.408 14.4224 28.932 14.4224 28.396C14.4224 28.156 14.4464 27.912 14.4944 27.664C14.6144 27 14.8544 26.412 15.2144 25.9C15.5824 25.388 16.0304 24.992 16.5584 24.712C17.0864 24.424 17.6384 24.28 18.2144 24.28ZM19.9064 27.688C19.9384 27.536 19.9544 27.372 19.9544 27.196C19.9544 26.66 19.7944 26.24 19.4744 25.936C19.1624 25.624 18.7704 25.468 18.2984 25.468C17.9464 25.468 17.6024 25.556 17.2664 25.732C16.9304 25.9 16.6384 26.152 16.3904 26.488C16.1424 26.816 15.9784 27.208 15.8984 27.664C15.8664 27.816 15.8504 27.98 15.8504 28.156C15.8504 28.7 16.0064 29.132 16.3184 29.452C16.6384 29.764 17.0344 29.92 17.5064 29.92C17.8584 29.92 18.2024 29.832 18.5384 29.656C18.8744 29.48 19.1664 29.224 19.4144 28.888C19.6624 28.544 19.8264 28.144 19.9064 27.688Z" fill="#667085"/>
+<path d="M11.0933 24.28C11.7893 24.28 12.3413 24.468 12.7493 24.844C13.1653 25.212 13.3733 25.744 13.3733 26.44C13.3733 26.616 13.3533 26.836 13.3133 27.1L12.6173 31H11.2613L11.9213 27.304C11.9533 27.08 11.9693 26.92 11.9693 26.824C11.9693 26.384 11.8453 26.048 11.5973 25.816C11.3573 25.584 11.0213 25.468 10.5893 25.468C10.0693 25.468 9.62934 25.628 9.26934 25.948C8.91734 26.26 8.69334 26.712 8.59734 27.304V27.268L7.93734 31H6.56934L7.73334 24.388H9.10134L8.96934 25.156C9.24134 24.884 9.56134 24.672 9.92934 24.52C10.3053 24.36 10.6933 24.28 11.0933 24.28Z" fill="#667085"/>
+<path d="M2.92837 23.7159L2.48437 26.2479H5.36437L5.18437 27.3039H2.30437L1.83637 29.9319H5.07637L4.88437 30.9999H0.276367L1.75237 22.6479H6.36037L6.16837 23.7159H2.92837Z" fill="#667085"/>
+</svg>
diff --git a/app/components/app/configuration/index.tsx b/app/components/app/configuration/index.tsx
new file mode 100644
index 0000000..5b8f865
--- /dev/null
+++ b/app/components/app/configuration/index.tsx
@@ -0,0 +1,1068 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import useSWR from 'swr'
+import { basePath } from '@/utils/var'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { usePathname } from 'next/navigation'
+import produce from 'immer'
+import { useBoolean, useGetState } from 'ahooks'
+import { clone, isEqual } from 'lodash-es'
+import { CodeBracketIcon } from '@heroicons/react/20/solid'
+import { useShallow } from 'zustand/react/shallow'
+import AgentSettingButton from '@/app/components/app/configuration/config/agent-setting-button'
+import useAdvancedPromptConfig from '@/app/components/app/configuration/hooks/use-advanced-prompt-config'
+import EditHistoryModal from '@/app/components/app/configuration/config-prompt/conversation-history/edit-modal'
+import {
+ useDebugWithSingleOrMultipleModel,
+ useFormattingChangedDispatcher,
+} from '@/app/components/app/configuration/debug/hooks'
+import type { ModelAndParameter } from '@/app/components/app/configuration/debug/types'
+import Button from '@/app/components/base/button'
+import Divider from '@/app/components/base/divider'
+import Loading from '@/app/components/base/loading'
+import AppPublisher from '@/app/components/app/app-publisher/features-wrapper'
+import type {
+ AnnotationReplyConfig,
+ DatasetConfigs,
+ Inputs,
+ ModelConfig,
+ ModerationConfig,
+ MoreLikeThisConfig,
+ PromptConfig,
+ PromptVariable,
+ TextToSpeechConfig,
+} from '@/models/debug'
+import type { ExternalDataTool } from '@/models/common'
+import type { DataSet } from '@/models/datasets'
+import type { ModelConfig as BackendModelConfig, VisionSettings } from '@/types/app'
+import ConfigContext from '@/context/debug-configuration'
+import Config from '@/app/components/app/configuration/config'
+import Debug from '@/app/components/app/configuration/debug'
+import Confirm from '@/app/components/base/confirm'
+import { ModelFeatureEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { ToastContext } from '@/app/components/base/toast'
+import { fetchAppDetail, updateAppModelConfig } from '@/service/apps'
+import { promptVariablesToUserInputsForm, userInputsFormToPromptVariables } from '@/utils/model-config'
+import { fetchDatasets } from '@/service/datasets'
+import { useProviderContext } from '@/context/provider-context'
+import { AgentStrategy, AppType, ModelModeType, RETRIEVE_TYPE, Resolution, TransferMethod } from '@/types/app'
+import { PromptMode } from '@/models/debug'
+import { ANNOTATION_DEFAULT, DATASET_DEFAULT, DEFAULT_AGENT_SETTING, DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/config'
+import SelectDataSet from '@/app/components/app/configuration/dataset-config/select-dataset'
+import { useModalContext } from '@/context/modal-context'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import Drawer from '@/app/components/base/drawer'
+import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
+import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import {
+ useModelListAndDefaultModelAndCurrentProviderAndModel,
+ useTextGenerationCurrentProviderAndModelAndModelList,
+} from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { fetchCollectionList } from '@/service/tools'
+import type { Collection } from '@/app/components/tools/types'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import {
+ getMultipleRetrievalConfig,
+ getSelectedDatasetsMode,
+} from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
+import { FeaturesProvider } from '@/app/components/base/features'
+import type { Features as FeaturesData, FileUpload } from '@/app/components/base/features/types'
+import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
+import { fetchFileUploadConfig } from '@/service/common'
+import {
+ correctModelProvider,
+ correctToolProvider,
+} from '@/utils'
+import PluginDependency from '@/app/components/workflow/plugin-dependency'
+import { supportFunctionCall } from '@/utils/tool-call'
+
+type PublishConfig = {
+ modelConfig: ModelConfig
+ completionParams: FormValue
+}
+
+const Configuration: FC = () => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const { appDetail, showAppConfigureFeaturesModal, setAppSiderbarExpand, setShowAppConfigureFeaturesModal } = useAppStore(useShallow(state => ({
+ appDetail: state.appDetail,
+ setAppSiderbarExpand: state.setAppSiderbarExpand,
+ showAppConfigureFeaturesModal: state.showAppConfigureFeaturesModal,
+ setShowAppConfigureFeaturesModal: state.setShowAppConfigureFeaturesModal,
+ })))
+ const { data: fileUploadConfigResponse } = useSWR({ url: '/files/upload' }, fetchFileUploadConfig)
+
+ const latestPublishedAt = useMemo(() => appDetail?.model_config?.updated_at, [appDetail])
+ const [formattingChanged, setFormattingChanged] = useState(false)
+ const { setShowAccountSettingModal } = useModalContext()
+ const [hasFetchedDetail, setHasFetchedDetail] = useState(false)
+ const isLoading = !hasFetchedDetail
+ const pathname = usePathname()
+ const matched = pathname.match(/\/app\/([^/]+)/)
+ const appId = (matched?.length && matched[1]) ? matched[1] : ''
+ const [mode, setMode] = useState('')
+ const [publishedConfig, setPublishedConfig] = useState<PublishConfig | null>(null)
+
+ const [conversationId, setConversationId] = useState<string | null>('')
+
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+ const [isShowDebugPanel, { setTrue: showDebugPanel, setFalse: hideDebugPanel }] = useBoolean(false)
+
+ const [introduction, setIntroduction] = useState<string>('')
+ const [suggestedQuestions, setSuggestedQuestions] = useState<string[]>([])
+ const [controlClearChatMessage, setControlClearChatMessage] = useState(0)
+ const [prevPromptConfig, setPrevPromptConfig] = useState<PromptConfig>({
+ prompt_template: '',
+ prompt_variables: [],
+ })
+ const [moreLikeThisConfig, setMoreLikeThisConfig] = useState<MoreLikeThisConfig>({
+ enabled: false,
+ })
+ const [suggestedQuestionsAfterAnswerConfig, setSuggestedQuestionsAfterAnswerConfig] = useState<MoreLikeThisConfig>({
+ enabled: false,
+ })
+ const [speechToTextConfig, setSpeechToTextConfig] = useState<MoreLikeThisConfig>({
+ enabled: false,
+ })
+ const [textToSpeechConfig, setTextToSpeechConfig] = useState<TextToSpeechConfig>({
+ enabled: false,
+ voice: '',
+ language: '',
+ })
+ const [citationConfig, setCitationConfig] = useState<MoreLikeThisConfig>({
+ enabled: false,
+ })
+ const [annotationConfig, doSetAnnotationConfig] = useState<AnnotationReplyConfig>({
+ id: '',
+ enabled: false,
+ score_threshold: ANNOTATION_DEFAULT.score_threshold,
+ embedding_model: {
+ embedding_provider_name: '',
+ embedding_model_name: '',
+ },
+ })
+ const formattingChangedDispatcher = useFormattingChangedDispatcher()
+ const setAnnotationConfig = (config: AnnotationReplyConfig, notSetFormatChanged?: boolean) => {
+ doSetAnnotationConfig(config)
+ if (!notSetFormatChanged)
+ formattingChangedDispatcher()
+ }
+
+ const [moderationConfig, setModerationConfig] = useState<ModerationConfig>({
+ enabled: false,
+ })
+ const [externalDataToolsConfig, setExternalDataToolsConfig] = useState<ExternalDataTool[]>([])
+ const [inputs, setInputs] = useState<Inputs>({})
+ const [query, setQuery] = useState('')
+ const [completionParams, doSetCompletionParams] = useState<FormValue>({})
+ const [_, setTempStop, getTempStop] = useGetState<string[]>([])
+ const setCompletionParams = (value: FormValue) => {
+ const params = { ...value }
+
+ // eslint-disable-next-line ts/no-use-before-define
+ if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
+ params.stop = getTempStop()
+ setTempStop([])
+ }
+ doSetCompletionParams(params)
+ }
+
+ const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
+ provider: 'langgenius/openai/openai',
+ model_id: 'gpt-3.5-turbo',
+ mode: ModelModeType.unset,
+ configs: {
+ prompt_template: '',
+ prompt_variables: [] as PromptVariable[],
+ },
+ more_like_this: null,
+ opening_statement: '',
+ suggested_questions: [],
+ sensitive_word_avoidance: null,
+ speech_to_text: null,
+ text_to_speech: null,
+ file_upload: null,
+ suggested_questions_after_answer: null,
+ retriever_resource: null,
+ annotation_reply: null,
+ dataSets: [],
+ agentConfig: DEFAULT_AGENT_SETTING,
+ })
+ const isAgent = mode === 'agent-chat'
+
+ const isOpenAI = modelConfig.provider === 'langgenius/openai/openai'
+
+ const [collectionList, setCollectionList] = useState<Collection[]>([])
+ const [datasetConfigs, doSetDatasetConfigs] = useState<DatasetConfigs>({
+ retrieval_model: RETRIEVE_TYPE.multiWay,
+ reranking_model: {
+ reranking_provider_name: '',
+ reranking_model_name: '',
+ },
+ top_k: DATASET_DEFAULT.top_k,
+ score_threshold_enabled: false,
+ score_threshold: DATASET_DEFAULT.score_threshold,
+ datasets: {
+ datasets: [],
+ },
+ })
+ const datasetConfigsRef = useRef(datasetConfigs)
+ const setDatasetConfigs = useCallback((newDatasetConfigs: DatasetConfigs) => {
+ doSetDatasetConfigs(newDatasetConfigs)
+ datasetConfigsRef.current = newDatasetConfigs
+ }, [])
+
+ const setModelConfig = (newModelConfig: ModelConfig) => {
+ doSetModelConfig(newModelConfig)
+ }
+
+ const modelModeType = modelConfig.mode
+ const modeModeTypeRef = useRef(modelModeType)
+ useEffect(() => {
+ modeModeTypeRef.current = modelModeType
+ }, [modelModeType])
+
+ const [dataSets, setDataSets] = useState<DataSet[]>([])
+ const contextVar = modelConfig.configs.prompt_variables.find(item => item.is_context_var)?.key
+ const hasSetContextVar = !!contextVar
+ const [isShowSelectDataSet, { setTrue: showSelectDataSet, setFalse: hideSelectDataSet }] = useBoolean(false)
+ const selectedIds = dataSets.map(item => item.id)
+ const [rerankSettingModalOpen, setRerankSettingModalOpen] = useState(false)
+ const {
+ currentModel: currentRerankModel,
+ currentProvider: currentRerankProvider,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
+ const handleSelect = (data: DataSet[]) => {
+ if (isEqual(data.map(item => item.id), dataSets.map(item => item.id))) {
+ hideSelectDataSet()
+ return
+ }
+
+ formattingChangedDispatcher()
+ let newDatasets = data
+ if (data.find(item => !item.name)) { // has not loaded selected dataset
+ const newSelected = produce(data, (draft) => {
+ data.forEach((item, index) => {
+ if (!item.name) { // not fetched database
+ const newItem = dataSets.find(i => i.id === item.id)
+ if (newItem)
+ draft[index] = newItem
+ }
+ })
+ })
+ setDataSets(newSelected)
+ newDatasets = newSelected
+ }
+ else {
+ setDataSets(data)
+ }
+ hideSelectDataSet()
+ const {
+ allExternal,
+ allInternal,
+ mixtureInternalAndExternal,
+ mixtureHighQualityAndEconomic,
+ inconsistentEmbeddingModel,
+ } = getSelectedDatasetsMode(newDatasets)
+
+ if (
+ (allInternal && (mixtureHighQualityAndEconomic || inconsistentEmbeddingModel))
+ || mixtureInternalAndExternal
+ || allExternal
+ )
+ setRerankSettingModalOpen(true)
+
+ const { datasets, retrieval_model, score_threshold_enabled, ...restConfigs } = datasetConfigs
+
+ const retrievalConfig = getMultipleRetrievalConfig({
+ top_k: restConfigs.top_k,
+ score_threshold: restConfigs.score_threshold,
+ reranking_model: restConfigs.reranking_model && {
+ provider: restConfigs.reranking_model.reranking_provider_name,
+ model: restConfigs.reranking_model.reranking_model_name,
+ },
+ reranking_mode: restConfigs.reranking_mode,
+ weights: restConfigs.weights,
+ reranking_enable: restConfigs.reranking_enable,
+ }, newDatasets, dataSets, {
+ provider: currentRerankProvider?.provider,
+ model: currentRerankModel?.model,
+ })
+
+ setDatasetConfigs({
+ ...datasetConfigsRef.current,
+ ...retrievalConfig,
+ reranking_model: {
+ reranking_provider_name: retrievalConfig?.reranking_model?.provider || '',
+ reranking_model_name: retrievalConfig?.reranking_model?.model || '',
+ },
+ retrieval_model,
+ score_threshold_enabled,
+ datasets,
+ })
+ }
+
+ const [isShowHistoryModal, { setTrue: showHistoryModal, setFalse: hideHistoryModal }] = useBoolean(false)
+
+ const syncToPublishedConfig = (_publishedConfig: PublishConfig) => {
+ const modelConfig = _publishedConfig.modelConfig
+ setModelConfig(_publishedConfig.modelConfig)
+ setCompletionParams(_publishedConfig.completionParams)
+ setDataSets(modelConfig.dataSets || [])
+ // reset feature
+ setIntroduction(modelConfig.opening_statement!)
+ setMoreLikeThisConfig(modelConfig.more_like_this || {
+ enabled: false,
+ })
+ setSuggestedQuestionsAfterAnswerConfig(modelConfig.suggested_questions_after_answer || {
+ enabled: false,
+ })
+ setSpeechToTextConfig(modelConfig.speech_to_text || {
+ enabled: false,
+ })
+ setTextToSpeechConfig(modelConfig.text_to_speech || {
+ enabled: false,
+ voice: '',
+ language: '',
+ })
+ setCitationConfig(modelConfig.retriever_resource || {
+ enabled: false,
+ })
+ }
+
+ const { isAPIKeySet } = useProviderContext()
+ const {
+ currentModel: currModel,
+ textGenerationModelList,
+ } = useTextGenerationCurrentProviderAndModelAndModelList(
+ {
+ provider: modelConfig.provider,
+ model: modelConfig.model_id,
+ },
+ )
+
+ const isFunctionCall = supportFunctionCall(currModel?.features)
+
+ // Fill old app data missing model mode.
+ useEffect(() => {
+ if (hasFetchedDetail && !modelModeType) {
+ const mode = currModel?.model_properties.mode as (ModelModeType | undefined)
+ if (mode) {
+ const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
+ draft.mode = mode
+ })
+ setModelConfig(newModelConfig)
+ }
+ }
+ }, [textGenerationModelList, hasFetchedDetail, modelModeType, currModel, modelConfig])
+
+ const [promptMode, doSetPromptMode] = useState(PromptMode.simple)
+ const isAdvancedMode = promptMode === PromptMode.advanced
+ const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
+ const setPromptMode = async (mode: PromptMode) => {
+ if (mode === PromptMode.advanced) {
+ // eslint-disable-next-line ts/no-use-before-define
+ await migrateToDefaultPrompt()
+ setCanReturnToSimpleMode(true)
+ }
+
+ doSetPromptMode(mode)
+ }
+ const [visionConfig, doSetVisionConfig] = useState({
+ enabled: false,
+ number_limits: 2,
+ detail: Resolution.low,
+ transfer_methods: [TransferMethod.local_file],
+ })
+
+ const handleSetVisionConfig = (config: VisionSettings, notNoticeFormattingChanged?: boolean) => {
+ doSetVisionConfig({
+ enabled: config.enabled || false,
+ number_limits: config.number_limits || 2,
+ detail: config.detail || Resolution.low,
+ transfer_methods: config.transfer_methods || [TransferMethod.local_file],
+ })
+ if (!notNoticeFormattingChanged)
+ formattingChangedDispatcher()
+ }
+
+ const {
+ chatPromptConfig,
+ setChatPromptConfig,
+ completionPromptConfig,
+ setCompletionPromptConfig,
+ currentAdvancedPrompt,
+ setCurrentAdvancedPrompt,
+ hasSetBlockStatus,
+ setConversationHistoriesRole,
+ migrateToDefaultPrompt,
+ } = useAdvancedPromptConfig({
+ appMode: mode,
+ modelName: modelConfig.model_id,
+ promptMode,
+ modelModeType,
+ prePrompt: modelConfig.configs.prompt_template,
+ hasSetDataSet: dataSets.length > 0,
+ onUserChangedPrompt: () => {
+ setCanReturnToSimpleMode(false)
+ },
+ completionParams,
+ setCompletionParams,
+ setStop: setTempStop,
+ })
+ const setModel = async ({
+ modelId,
+ provider,
+ mode: modeMode,
+ features,
+ }: { modelId: string; provider: string; mode: string; features: string[] }) => {
+ if (isAdvancedMode) {
+ const appMode = mode
+
+ if (modeMode === ModelModeType.completion) {
+ if (appMode !== AppType.completion) {
+ if (!completionPromptConfig.prompt?.text || !completionPromptConfig.conversation_histories_role.assistant_prefix || !completionPromptConfig.conversation_histories_role.user_prefix)
+ await migrateToDefaultPrompt(true, ModelModeType.completion)
+ }
+ else {
+ if (!completionPromptConfig.prompt?.text)
+ await migrateToDefaultPrompt(true, ModelModeType.completion)
+ }
+ }
+ if (modeMode === ModelModeType.chat) {
+ if (chatPromptConfig.prompt.length === 0)
+ await migrateToDefaultPrompt(true, ModelModeType.chat)
+ }
+ }
+ const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
+ draft.provider = provider
+ draft.model_id = modelId
+ draft.mode = modeMode as ModelModeType
+ })
+
+ setModelConfig(newModelConfig)
+ const supportVision = features && features.includes(ModelFeatureEnum.vision)
+
+ handleSetVisionConfig({
+ ...visionConfig,
+ enabled: supportVision,
+ }, true)
+ setCompletionParams({})
+ }
+
+ const isShowVisionConfig = !!currModel?.features?.includes(ModelFeatureEnum.vision)
+ const isShowDocumentConfig = !!currModel?.features?.includes(ModelFeatureEnum.document)
+ const isAllowVideoUpload = !!currModel?.features?.includes(ModelFeatureEnum.video)
+ // *** web app features ***
+ const featuresData: FeaturesData = useMemo(() => {
+ return {
+ moreLikeThis: modelConfig.more_like_this || { enabled: false },
+ opening: {
+ enabled: !!modelConfig.opening_statement,
+ opening_statement: modelConfig.opening_statement || '',
+ suggested_questions: modelConfig.suggested_questions || [],
+ },
+ moderation: modelConfig.sensitive_word_avoidance || { enabled: false },
+ speech2text: modelConfig.speech_to_text || { enabled: false },
+ text2speech: modelConfig.text_to_speech || { enabled: false },
+ file: {
+ image: {
+ detail: modelConfig.file_upload?.image?.detail || Resolution.high,
+ enabled: !!modelConfig.file_upload?.image?.enabled,
+ number_limits: modelConfig.file_upload?.image?.number_limits || 3,
+ transfer_methods: modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
+ },
+ enabled: !!(modelConfig.file_upload?.enabled || modelConfig.file_upload?.image?.enabled),
+ allowed_file_types: modelConfig.file_upload?.allowed_file_types || [],
+ allowed_file_extensions: modelConfig.file_upload?.allowed_file_extensions || [...FILE_EXTS[SupportUploadFileTypes.image], ...FILE_EXTS[SupportUploadFileTypes.video]].map(ext => `.${ext}`),
+ allowed_file_upload_methods: modelConfig.file_upload?.allowed_file_upload_methods || modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
+ number_limits: modelConfig.file_upload?.number_limits || modelConfig.file_upload?.image?.number_limits || 3,
+ fileUploadConfig: fileUploadConfigResponse,
+ } as FileUpload,
+ suggested: modelConfig.suggested_questions_after_answer || { enabled: false },
+ citation: modelConfig.retriever_resource || { enabled: false },
+ annotationReply: modelConfig.annotation_reply || { enabled: false },
+ }
+ }, [fileUploadConfigResponse, modelConfig])
+ const handleFeaturesChange = useCallback((flag: any) => {
+ setShowAppConfigureFeaturesModal(true)
+ if (flag)
+ formattingChangedDispatcher()
+ }, [formattingChangedDispatcher, setShowAppConfigureFeaturesModal])
+ const handleAddPromptVariable = useCallback((variable: PromptVariable[]) => {
+ const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
+ draft.configs.prompt_variables = [...draft.configs.prompt_variables, ...variable]
+ })
+ setModelConfig(newModelConfig)
+ }, [modelConfig])
+
+ useEffect(() => {
+ (async () => {
+ const collectionList = await fetchCollectionList()
+ if (basePath) {
+ collectionList.forEach((item) => {
+ if (typeof item.icon == 'string' && !item.icon.includes(basePath))
+ item.icon = `${basePath}${item.icon}`
+ })
+ }
+ setCollectionList(collectionList)
+ fetchAppDetail({ url: '/apps', id: appId }).then(async (res: any) => {
+ setMode(res.mode)
+ const modelConfig = res.model_config
+ const promptMode = modelConfig.prompt_type === PromptMode.advanced ? PromptMode.advanced : PromptMode.simple
+ doSetPromptMode(promptMode)
+ if (promptMode === PromptMode.advanced) {
+ if (modelConfig.chat_prompt_config && modelConfig.chat_prompt_config.prompt.length > 0)
+ setChatPromptConfig(modelConfig.chat_prompt_config)
+ else
+ setChatPromptConfig(clone(DEFAULT_CHAT_PROMPT_CONFIG))
+ setCompletionPromptConfig(modelConfig.completion_prompt_config || clone(DEFAULT_COMPLETION_PROMPT_CONFIG) as any)
+ setCanReturnToSimpleMode(false)
+ }
+
+ const model = res.model_config.model
+
+ let datasets: any = null
+ // old dataset struct
+ if (modelConfig.agent_mode?.tools?.find(({ dataset }: any) => dataset?.enabled))
+ datasets = modelConfig.agent_mode?.tools.filter(({ dataset }: any) => dataset?.enabled)
+ // new dataset struct
+ else if (modelConfig.dataset_configs.datasets?.datasets?.length > 0)
+ datasets = modelConfig.dataset_configs?.datasets?.datasets
+
+ if (dataSets && datasets?.length && datasets?.length > 0) {
+ const { data: dataSetsWithDetail } = await fetchDatasets({ url: '/datasets', params: { page: 1, ids: datasets.map(({ dataset }: any) => dataset.id) } })
+ datasets = dataSetsWithDetail
+ setDataSets(datasets)
+ }
+
+ setIntroduction(modelConfig.opening_statement)
+ setSuggestedQuestions(modelConfig.suggested_questions || [])
+ if (modelConfig.more_like_this)
+ setMoreLikeThisConfig(modelConfig.more_like_this)
+
+ if (modelConfig.suggested_questions_after_answer)
+ setSuggestedQuestionsAfterAnswerConfig(modelConfig.suggested_questions_after_answer)
+
+ if (modelConfig.speech_to_text)
+ setSpeechToTextConfig(modelConfig.speech_to_text)
+
+ if (modelConfig.text_to_speech)
+ setTextToSpeechConfig(modelConfig.text_to_speech)
+
+ if (modelConfig.retriever_resource)
+ setCitationConfig(modelConfig.retriever_resource)
+
+ if (modelConfig.annotation_reply) {
+ let annotationConfig = modelConfig.annotation_reply
+ if (modelConfig.annotation_reply.enabled) {
+ annotationConfig = {
+ ...modelConfig.annotation_reply,
+ embedding_model: {
+ ...modelConfig.annotation_reply.embedding_model,
+ embedding_provider_name: correctModelProvider(modelConfig.annotation_reply.embedding_model.embedding_provider_name),
+ },
+ }
+ }
+ setAnnotationConfig(annotationConfig, true)
+ }
+
+ if (modelConfig.sensitive_word_avoidance)
+ setModerationConfig(modelConfig.sensitive_word_avoidance)
+
+ if (modelConfig.external_data_tools)
+ setExternalDataToolsConfig(modelConfig.external_data_tools)
+
+ const config = {
+ modelConfig: {
+ provider: correctModelProvider(model.provider),
+ model_id: model.name,
+ mode: model.mode,
+ configs: {
+ prompt_template: modelConfig.pre_prompt || '',
+ prompt_variables: userInputsFormToPromptVariables(
+ [
+ ...modelConfig.user_input_form,
+ ...(
+ modelConfig.external_data_tools?.length
+ ? modelConfig.external_data_tools.map((item: any) => {
+ return {
+ external_data_tool: {
+ variable: item.variable as string,
+ label: item.label as string,
+ enabled: item.enabled,
+ type: item.type as string,
+ config: item.config,
+ required: true,
+ icon: item.icon,
+ icon_background: item.icon_background,
+ },
+ }
+ })
+ : []
+ ),
+ ],
+ modelConfig.dataset_query_variable,
+ ),
+ },
+ more_like_this: modelConfig.more_like_this,
+ opening_statement: modelConfig.opening_statement,
+ suggested_questions: modelConfig.suggested_questions,
+ sensitive_word_avoidance: modelConfig.sensitive_word_avoidance,
+ speech_to_text: modelConfig.speech_to_text,
+ text_to_speech: modelConfig.text_to_speech,
+ file_upload: modelConfig.file_upload,
+ suggested_questions_after_answer: modelConfig.suggested_questions_after_answer,
+ retriever_resource: modelConfig.retriever_resource,
+ annotation_reply: modelConfig.annotation_reply,
+ external_data_tools: modelConfig.external_data_tools,
+ dataSets: datasets || [],
+ agentConfig: res.mode === 'agent-chat' ? {
+ max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
+ ...modelConfig.agent_mode,
+ // remove dataset
+ enabled: true, // modelConfig.agent_mode?.enabled is not correct. old app: the value of app with dataset's is always true
+ tools: modelConfig.agent_mode?.tools.filter((tool: any) => {
+ return !tool.dataset
+ }).map((tool: any) => {
+ const toolInCollectionList = collectionList.find(c => tool.provider_id === c.id)
+ return {
+ ...tool,
+ isDeleted: res.deleted_tools?.some((deletedTool: any) => deletedTool.id === tool.id && deletedTool.tool_name === tool.tool_name),
+ notAuthor: toolInCollectionList?.is_team_authorization === false,
+ ...(tool.provider_type === 'builtin' ? {
+ provider_id: correctToolProvider(tool.provider_name, !!toolInCollectionList),
+ provider_name: correctToolProvider(tool.provider_name, !!toolInCollectionList),
+ } : {}),
+ }
+ }),
+ } : DEFAULT_AGENT_SETTING,
+ },
+ completionParams: model.completion_params,
+ }
+
+ if (modelConfig.file_upload)
+ handleSetVisionConfig(modelConfig.file_upload.image, true)
+
+ syncToPublishedConfig(config)
+ setPublishedConfig(config)
+ const retrievalConfig = getMultipleRetrievalConfig({
+ ...modelConfig.dataset_configs,
+ reranking_model: modelConfig.dataset_configs.reranking_model && {
+ provider: modelConfig.dataset_configs.reranking_model.reranking_provider_name,
+ model: modelConfig.dataset_configs.reranking_model.reranking_model_name,
+ },
+ }, datasets, datasets, {
+ provider: currentRerankProvider?.provider,
+ model: currentRerankModel?.model,
+ })
+ setDatasetConfigs({
+ retrieval_model: RETRIEVE_TYPE.multiWay,
+ ...modelConfig.dataset_configs,
+ ...retrievalConfig,
+ ...(retrievalConfig.reranking_model ? {
+ reranking_model: {
+ reranking_model_name: retrievalConfig.reranking_model.model,
+ reranking_provider_name: correctModelProvider(retrievalConfig.reranking_model.provider),
+ },
+ } : {}),
+ })
+ setHasFetchedDetail(true)
+ })
+ })()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [appId])
+
+ const promptEmpty = (() => {
+ if (mode !== AppType.completion)
+ return false
+
+ if (isAdvancedMode) {
+ if (modelModeType === ModelModeType.chat)
+ return chatPromptConfig.prompt.every(({ text }: any) => !text)
+
+ else
+ return !completionPromptConfig.prompt?.text
+ }
+
+ else { return !modelConfig.configs.prompt_template }
+ })()
+ const cannotPublish = (() => {
+ if (mode !== AppType.completion) {
+ if (!isAdvancedMode)
+ return false
+
+ if (modelModeType === ModelModeType.completion) {
+ if (!hasSetBlockStatus.history || !hasSetBlockStatus.query)
+ return true
+
+ return false
+ }
+
+ return false
+ }
+ else { return promptEmpty }
+ })()
+ const contextVarEmpty = mode === AppType.completion && dataSets.length > 0 && !hasSetContextVar
+ const onPublish = async (modelAndParameter?: ModelAndParameter, features?: FeaturesData) => {
+ const modelId = modelAndParameter?.model || modelConfig.model_id
+ const promptTemplate = modelConfig.configs.prompt_template
+ const promptVariables = modelConfig.configs.prompt_variables
+
+ if (promptEmpty) {
+ notify({ type: 'error', message: t('appDebug.otherError.promptNoBeEmpty') })
+ return
+ }
+ if (isAdvancedMode && mode !== AppType.completion) {
+ if (modelModeType === ModelModeType.completion) {
+ if (!hasSetBlockStatus.history) {
+ notify({ type: 'error', message: t('appDebug.otherError.historyNoBeEmpty') })
+ return
+ }
+ if (!hasSetBlockStatus.query) {
+ notify({ type: 'error', message: t('appDebug.otherError.queryNoBeEmpty') })
+ return
+ }
+ }
+ }
+ if (contextVarEmpty) {
+ notify({ type: 'error', message: t('appDebug.feature.dataSet.queryVariable.contextVarNotEmpty') })
+ return
+ }
+ const postDatasets = dataSets.map(({ id }) => ({
+ dataset: {
+ enabled: true,
+ id,
+ },
+ }))
+
+ const fileUpload = { ...features?.file }
+ delete fileUpload?.fileUploadConfig
+
+ // new model config data struct
+ const data: BackendModelConfig = {
+ // Simple Mode prompt
+ pre_prompt: !isAdvancedMode ? promptTemplate : '',
+ prompt_type: promptMode,
+ chat_prompt_config: {},
+ completion_prompt_config: {},
+ user_input_form: promptVariablesToUserInputsForm(promptVariables),
+ dataset_query_variable: contextVar || '',
+ // features
+ more_like_this: features?.moreLikeThis as any,
+ opening_statement: features?.opening?.enabled ? (features.opening?.opening_statement || '') : '',
+ suggested_questions: features?.opening?.enabled ? (features.opening?.suggested_questions || []) : [],
+ sensitive_word_avoidance: features?.moderation as any,
+ speech_to_text: features?.speech2text as any,
+ text_to_speech: features?.text2speech as any,
+ file_upload: fileUpload as any,
+ suggested_questions_after_answer: features?.suggested as any,
+ retriever_resource: features?.citation as any,
+ agent_mode: {
+ ...modelConfig.agentConfig,
+ strategy: isFunctionCall ? AgentStrategy.functionCall : AgentStrategy.react,
+ },
+ model: {
+ provider: modelAndParameter?.provider || modelConfig.provider,
+ name: modelId,
+ mode: modelConfig.mode,
+ completion_params: modelAndParameter?.parameters || completionParams as any,
+ },
+ dataset_configs: {
+ ...datasetConfigs,
+ datasets: {
+ datasets: [...postDatasets],
+ } as any,
+ },
+ }
+
+ if (isAdvancedMode) {
+ data.chat_prompt_config = chatPromptConfig
+ data.completion_prompt_config = completionPromptConfig
+ }
+
+ await updateAppModelConfig({ url: `/apps/${appId}/model-config`, body: data })
+ const newModelConfig = produce(modelConfig, (draft: any) => {
+ draft.opening_statement = introduction
+ draft.more_like_this = moreLikeThisConfig
+ draft.suggested_questions_after_answer = suggestedQuestionsAfterAnswerConfig
+ draft.speech_to_text = speechToTextConfig
+ draft.text_to_speech = textToSpeechConfig
+ draft.retriever_resource = citationConfig
+ draft.dataSets = dataSets
+ })
+ setPublishedConfig({
+ modelConfig: newModelConfig,
+ completionParams,
+ })
+ notify({ type: 'success', message: t('common.api.success') })
+
+ setCanReturnToSimpleMode(false)
+ return true
+ }
+
+ const [showUseGPT4Confirm, setShowUseGPT4Confirm] = useState(false)
+
+ const {
+ debugWithMultipleModel,
+ multipleModelConfigs,
+ handleMultipleModelConfigsChange,
+ } = useDebugWithSingleOrMultipleModel(appId)
+
+ const handleDebugWithMultipleModelChange = () => {
+ handleMultipleModelConfigsChange(
+ true,
+ [
+ { id: `${Date.now()}`, model: modelConfig.model_id, provider: modelConfig.provider, parameters: completionParams },
+ { id: `${Date.now()}-no-repeat`, model: '', provider: '', parameters: {} },
+ ],
+ )
+ setAppSiderbarExpand('collapse')
+ }
+
+ if (isLoading) {
+ return <div className='flex h-full items-center justify-center'>
+ <Loading type='area' />
+ </div>
+ }
+
+ return (
+ <ConfigContext.Provider value={{
+ appId,
+ isAPIKeySet,
+ isTrailFinished: false,
+ mode,
+ modelModeType,
+ promptMode,
+ isAdvancedMode,
+ isAgent,
+ isOpenAI,
+ isFunctionCall,
+ collectionList,
+ setPromptMode,
+ canReturnToSimpleMode,
+ setCanReturnToSimpleMode,
+ chatPromptConfig,
+ completionPromptConfig,
+ currentAdvancedPrompt,
+ setCurrentAdvancedPrompt,
+ conversationHistoriesRole: completionPromptConfig.conversation_histories_role,
+ showHistoryModal,
+ setConversationHistoriesRole,
+ hasSetBlockStatus,
+ conversationId,
+ introduction,
+ setIntroduction,
+ suggestedQuestions,
+ setSuggestedQuestions,
+ setConversationId,
+ controlClearChatMessage,
+ setControlClearChatMessage,
+ prevPromptConfig,
+ setPrevPromptConfig,
+ moreLikeThisConfig,
+ setMoreLikeThisConfig,
+ suggestedQuestionsAfterAnswerConfig,
+ setSuggestedQuestionsAfterAnswerConfig,
+ speechToTextConfig,
+ setSpeechToTextConfig,
+ textToSpeechConfig,
+ setTextToSpeechConfig,
+ citationConfig,
+ setCitationConfig,
+ annotationConfig,
+ setAnnotationConfig,
+ moderationConfig,
+ setModerationConfig,
+ externalDataToolsConfig,
+ setExternalDataToolsConfig,
+ formattingChanged,
+ setFormattingChanged,
+ inputs,
+ setInputs,
+ query,
+ setQuery,
+ completionParams,
+ setCompletionParams,
+ modelConfig,
+ setModelConfig,
+ showSelectDataSet,
+ dataSets,
+ setDataSets,
+ datasetConfigs,
+ datasetConfigsRef,
+ setDatasetConfigs,
+ hasSetContextVar,
+ isShowVisionConfig,
+ visionConfig,
+ setVisionConfig: handleSetVisionConfig,
+ isAllowVideoUpload,
+ isShowDocumentConfig,
+ rerankSettingModalOpen,
+ setRerankSettingModalOpen,
+ }}
+ >
+ <FeaturesProvider features={featuresData}>
+ <>
+ <div className="flex h-full flex-col">
+ <div className='relative flex h-[200px] grow pt-14'>
+ {/* Header */}
+ <div className='bg-default-subtle absolute left-0 top-0 h-14 w-full'>
+ <div className='flex h-14 items-center justify-between px-6'>
+ <div className='flex items-center'>
+ <div className='system-xl-semibold text-text-primary'>{t('appDebug.orchestrate')}</div>
+ <div className='flex h-[14px] items-center space-x-1 text-xs'>
+ {isAdvancedMode && (
+ <div className='system-xs-medium-uppercase ml-1 flex h-5 items-center rounded-md border border-components-button-secondary-border px-1.5 uppercase text-text-tertiary'>{t('appDebug.promptMode.advanced')}</div>
+ )}
+ </div>
+ </div>
+ <div className='flex items-center'>
+ {/* Agent Setting */}
+ {isAgent && (
+ <AgentSettingButton
+ isChatModel={modelConfig.mode === ModelModeType.chat}
+ agentConfig={modelConfig.agentConfig}
+
+ isFunctionCall={isFunctionCall}
+ onAgentSettingChange={(config) => {
+ const nextConfig = produce(modelConfig, (draft: ModelConfig) => {
+ draft.agentConfig = config
+ })
+ setModelConfig(nextConfig)
+ }}
+ />
+ )}
+ {/* Model and Parameters */}
+ {!debugWithMultipleModel && (
+ <>
+ <ModelParameterModal
+ isAdvancedMode={isAdvancedMode}
+ mode={mode}
+ provider={modelConfig.provider}
+ completionParams={completionParams}
+ modelId={modelConfig.model_id}
+ setModel={setModel as any}
+ onCompletionParamsChange={(newParams: FormValue) => {
+ setCompletionParams(newParams)
+ }}
+ debugWithMultipleModel={debugWithMultipleModel}
+ onDebugWithMultipleModelChange={handleDebugWithMultipleModelChange}
+ />
+ <Divider type='vertical' className='mx-2 h-[14px]' />
+ </>
+ )}
+ {isMobile && (
+ <Button className='mr-2 !h-8 !text-[13px] font-medium' onClick={showDebugPanel}>
+ <span className='mr-1'>{t('appDebug.operation.debugConfig')}</span>
+ <CodeBracketIcon className="h-4 w-4 text-text-tertiary" />
+ </Button>
+ )}
+ <AppPublisher {...{
+ publishDisabled: cannotPublish,
+ publishedAt: (latestPublishedAt || 0) * 1000,
+ debugWithMultipleModel,
+ multipleModelConfigs,
+ onPublish,
+ publishedConfig: publishedConfig!,
+ resetAppConfig: () => syncToPublishedConfig(publishedConfig!),
+ }} />
+ </div>
+ </div>
+ </div>
+ <div className={`flex h-full w-full shrink-0 flex-col sm:w-1/2 ${debugWithMultipleModel && 'max-w-[560px]'}`}>
+ <Config />
+ </div>
+ {!isMobile && <div className="relative flex h-full w-1/2 grow flex-col overflow-y-auto " style={{ borderColor: 'rgba(0, 0, 0, 0.02)' }}>
+ <div className='flex grow flex-col rounded-tl-2xl border-l-[0.5px] border-t-[0.5px] border-components-panel-border bg-chatbot-bg '>
+ <Debug
+ isAPIKeySet={isAPIKeySet}
+ onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
+ inputs={inputs}
+ modelParameterParams={{
+ setModel: setModel as any,
+ onCompletionParamsChange: setCompletionParams,
+ }}
+ debugWithMultipleModel={debugWithMultipleModel}
+ multipleModelConfigs={multipleModelConfigs}
+ onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
+ />
+ </div>
+ </div>}
+ </div>
+ </div>
+ {showUseGPT4Confirm && (
+ <Confirm
+ title={t('appDebug.trailUseGPT4Info.title')}
+ content={t('appDebug.trailUseGPT4Info.description')}
+ isShow={showUseGPT4Confirm}
+ onConfirm={() => {
+ setShowAccountSettingModal({ payload: 'provider' })
+ setShowUseGPT4Confirm(false)
+ }}
+ onCancel={() => setShowUseGPT4Confirm(false)}
+ />
+ )}
+
+ {isShowSelectDataSet && (
+ <SelectDataSet
+ isShow={isShowSelectDataSet}
+ onClose={hideSelectDataSet}
+ selectedIds={selectedIds}
+ onSelect={handleSelect}
+ />
+ )}
+
+ {isShowHistoryModal && (
+ <EditHistoryModal
+ isShow={isShowHistoryModal}
+ saveLoading={false}
+ onClose={hideHistoryModal}
+ data={completionPromptConfig.conversation_histories_role}
+ onSave={(data) => {
+ setConversationHistoriesRole(data)
+ hideHistoryModal()
+ }}
+ />
+ )}
+ {isMobile && (
+ <Drawer showClose isOpen={isShowDebugPanel} onClose={hideDebugPanel} mask footer={null}>
+ <Debug
+ isAPIKeySet={isAPIKeySet}
+ onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
+ inputs={inputs}
+ modelParameterParams={{
+ setModel: setModel as any,
+ onCompletionParamsChange: setCompletionParams,
+ }}
+ debugWithMultipleModel={debugWithMultipleModel}
+ multipleModelConfigs={multipleModelConfigs}
+ onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
+ />
+ </Drawer>
+ )}
+ {showAppConfigureFeaturesModal && (
+ <NewFeaturePanel
+ show
+ inWorkflow={false}
+ showFileUpload={false}
+ isChatMode={mode !== 'completion'}
+ disabled={false}
+ onChange={handleFeaturesChange}
+ onClose={() => setShowAppConfigureFeaturesModal(false)}
+ promptVariables={modelConfig.configs.prompt_variables}
+ onAutoAddPromptVariable={handleAddPromptVariable}
+ />
+ )}
+ <PluginDependency />
+ </>
+ </FeaturesProvider>
+ </ConfigContext.Provider>
+ )
+}
+export default React.memo(Configuration)
diff --git a/app/components/app/configuration/prompt-mode/advanced-mode-waring.tsx b/app/components/app/configuration/prompt-mode/advanced-mode-waring.tsx
new file mode 100644
index 0000000..cca775c
--- /dev/null
+++ b/app/components/app/configuration/prompt-mode/advanced-mode-waring.tsx
@@ -0,0 +1,52 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+type Props = {
+ onReturnToSimpleMode: () => void
+}
+
+const AdvancedModeWarning: FC<Props> = ({
+ onReturnToSimpleMode,
+}) => {
+ const { t } = useTranslation()
+ const { locale } = useContext(I18n)
+ const [show, setShow] = React.useState(true)
+ if (!show)
+ return null
+ return (
+ <div className='mb-3 rounded-xl border border-[#FEF0C7] bg-[#FFFAEB] px-4 py-3' >
+ <div className='mb-2 text-xs font-bold leading-[18px] text-[#DC6803]'>{t('appDebug.promptMode.advancedWarning.title')}</div>
+ <div className='flex items-center justify-between'>
+ <div className='text-xs leading-[18px] '>
+ <span className='text-gray-700'>{t('appDebug.promptMode.advancedWarning.description')}</span>
+ <a
+ className='font-medium text-[#155EEF]'
+ href={`https://docs.dify.ai/${locale === LanguagesSupported[1] ? '/guides/features/prompt-engineering' : 'features/prompt-engineering'}`}
+ target='_blank' rel='noopener noreferrer'
+ >
+ {t('appDebug.promptMode.advancedWarning.learnMore')}
+ </a>
+ </div>
+
+ <div className='flex items-center space-x-1'>
+ <div
+ onClick={onReturnToSimpleMode}
+ className='flex h-6 shrink-0 cursor-pointer items-center space-x-1 rounded-lg border border-gray-200 bg-indigo-600 px-2 text-xs font-semibold text-white shadow-xs'
+ >
+ <div className='text-xs font-semibold uppercase'>{t('appDebug.promptMode.switchBack')}</div>
+ </div>
+ <div
+ className='flex h-6 cursor-pointer items-center rounded-md border border-gray-200 bg-[#fff] px-2 text-xs font-medium text-primary-600 shadow-xs'
+ onClick={() => setShow(false)}
+ >{t('appDebug.promptMode.advancedWarning.ok')}</div>
+ </div>
+
+ </div>
+ </div>
+ )
+}
+export default React.memo(AdvancedModeWarning)
diff --git a/app/components/app/configuration/prompt-value-panel/index.tsx b/app/components/app/configuration/prompt-value-panel/index.tsx
new file mode 100644
index 0000000..e509ee5
--- /dev/null
+++ b/app/components/app/configuration/prompt-value-panel/index.tsx
@@ -0,0 +1,214 @@
+'use client'
+import type { FC } from 'react'
+import React, { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import {
+ RiArrowDownSLine,
+ RiArrowRightSLine,
+ RiPlayLargeFill,
+} from '@remixicon/react'
+import ConfigContext from '@/context/debug-configuration'
+import type { Inputs } from '@/models/debug'
+import { AppType, ModelModeType } from '@/types/app'
+import Select from '@/app/components/base/select'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import Tooltip from '@/app/components/base/tooltip'
+import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader'
+import FeatureBar from '@/app/components/base/features/new-feature-panel/feature-bar'
+import type { VisionFile, VisionSettings } from '@/types/app'
+import { DEFAULT_VALUE_MAX_LEN } from '@/config'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import cn from '@/utils/classnames'
+
+export type IPromptValuePanelProps = {
+ appType: AppType
+ onSend?: () => void
+ inputs: Inputs
+ visionConfig: VisionSettings
+ onVisionFilesChange: (files: VisionFile[]) => void
+}
+
+const PromptValuePanel: FC<IPromptValuePanelProps> = ({
+ appType,
+ onSend,
+ inputs,
+ visionConfig,
+ onVisionFilesChange,
+}) => {
+ const { t } = useTranslation()
+ const { modelModeType, modelConfig, setInputs, mode, isAdvancedMode, completionPromptConfig, chatPromptConfig } = useContext(ConfigContext)
+ const [userInputFieldCollapse, setUserInputFieldCollapse] = useState(false)
+ const promptVariables = modelConfig.configs.prompt_variables.filter(({ key, name }) => {
+ return key && key?.trim() && name && name?.trim()
+ })
+
+ const promptVariableObj = useMemo(() => {
+ const obj: Record<string, boolean> = {}
+ promptVariables.forEach((input) => {
+ obj[input.key] = true
+ })
+ return obj
+ }, [promptVariables])
+
+ const canNotRun = useMemo(() => {
+ if (mode !== AppType.completion)
+ return true
+
+ if (isAdvancedMode) {
+ if (modelModeType === ModelModeType.chat)
+ return chatPromptConfig.prompt.every(({ text }) => !text)
+ return !completionPromptConfig.prompt?.text
+ }
+
+ else { return !modelConfig.configs.prompt_template }
+ }, [chatPromptConfig.prompt, completionPromptConfig.prompt?.text, isAdvancedMode, mode, modelConfig.configs.prompt_template, modelModeType])
+
+ const handleInputValueChange = (key: string, value: string) => {
+ if (!(key in promptVariableObj))
+ return
+
+ const newInputs = { ...inputs }
+ promptVariables.forEach((input) => {
+ if (input.key === key)
+ newInputs[key] = value
+ })
+ setInputs(newInputs)
+ }
+
+ const onClear = () => {
+ const newInputs: Inputs = {}
+ promptVariables.forEach((item) => {
+ newInputs[item.key] = ''
+ })
+ setInputs(newInputs)
+ }
+
+ const setShowAppConfigureFeaturesModal = useAppStore(s => s.setShowAppConfigureFeaturesModal)
+
+ return (
+ <>
+ <div className='relative z-[1] mx-3 rounded-xl border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg shadow-md'>
+ <div className={cn('px-4 pt-3', userInputFieldCollapse ? 'pb-3' : 'pb-1')}>
+ <div className='flex cursor-pointer items-center gap-0.5 py-0.5' onClick={() => setUserInputFieldCollapse(!userInputFieldCollapse)}>
+ <div className='system-md-semibold-uppercase text-text-secondary'>{t('appDebug.inputs.userInputField')}</div>
+ {userInputFieldCollapse && <RiArrowRightSLine className='h-4 w-4 text-text-secondary'/>}
+ {!userInputFieldCollapse && <RiArrowDownSLine className='h-4 w-4 text-text-secondary'/>}
+ </div>
+ {!userInputFieldCollapse && (
+ <div className='system-xs-regular mt-1 text-text-tertiary'>{t('appDebug.inputs.completionVarTip')}</div>
+ )}
+ </div>
+ {!userInputFieldCollapse && promptVariables.length > 0 && (
+ <div className='px-4 pb-4 pt-3'>
+ {promptVariables.map(({ key, name, type, options, max_length, required }, index) => (
+ <div
+ key={key}
+ className='mb-4 last-of-type:mb-0'
+ >
+ <div>
+ <div className='system-sm-semibold mb-1 flex h-6 items-center gap-1 text-text-secondary'>
+ <div className='truncate'>{name || key}</div>
+ {!required && <span className='system-xs-regular text-text-tertiary'>{t('workflow.panel.optional')}</span>}
+ </div>
+ <div className='grow'>
+ {type === 'string' && (
+ <Input
+ value={inputs[key] ? `${inputs[key]}` : ''}
+ onChange={(e) => { handleInputValueChange(key, e.target.value) }}
+ placeholder={name}
+ autoFocus={index === 0}
+ maxLength={max_length || DEFAULT_VALUE_MAX_LEN}
+ />
+ )}
+ {type === 'paragraph' && (
+ <Textarea
+ className='h-[120px] grow'
+ placeholder={name}
+ value={inputs[key] ? `${inputs[key]}` : ''}
+ onChange={(e) => { handleInputValueChange(key, e.target.value) }}
+ />
+ )}
+ {type === 'select' && (
+ <Select
+ className='w-full'
+ defaultValue={inputs[key] as string}
+ onSelect={(i) => { handleInputValueChange(key, i.value as string) }}
+ items={(options || []).map(i => ({ name: i, value: i }))}
+ allowSearch={false}
+ bgClassName='bg-gray-50'
+ />
+ )}
+ {type === 'number' && (
+ <Input
+ type='number'
+ value={inputs[key] ? `${inputs[key]}` : ''}
+ onChange={(e) => { handleInputValueChange(key, e.target.value) }}
+ placeholder={name}
+ autoFocus={index === 0}
+ maxLength={max_length || DEFAULT_VALUE_MAX_LEN}
+ />
+ )}
+ </div>
+ </div>
+ </div>
+ ))}
+ {visionConfig?.enabled && (
+ <div className="mt-3 justify-between xl:flex">
+ <div className="mr-1 w-[120px] shrink-0 py-2 text-sm text-text-primary">{t('common.imageUploader.imageUpload')}</div>
+ <div className='grow'>
+ <TextGenerationImageUploader
+ settings={visionConfig}
+ onFilesChange={files => onVisionFilesChange(files.filter(file => file.progress !== -1).map(fileItem => ({
+ type: 'image',
+ transfer_method: fileItem.type,
+ url: fileItem.url,
+ upload_file_id: fileItem.fileId,
+ })))}
+ />
+ </div>
+ </div>
+ )}
+ </div>
+ )}
+ {!userInputFieldCollapse && (
+ <div className='flex justify-between border-t border-divider-subtle p-4 pt-3'>
+ <Button className='w-[72px]' onClick={onClear}>{t('common.operation.clear')}</Button>
+ {canNotRun && (
+ <Tooltip popupContent={t('appDebug.otherError.promptNoBeEmpty')} needsDelay>
+ <Button
+ variant="primary"
+ disabled={canNotRun}
+ onClick={() => onSend && onSend()}
+ className="w-[96px]">
+ <RiPlayLargeFill className="mr-0.5 h-4 w-4 shrink-0" aria-hidden="true" />
+ {t('appDebug.inputs.run')}
+ </Button>
+ </Tooltip>
+ )}
+ {!canNotRun && (
+ <Button
+ variant="primary"
+ disabled={canNotRun}
+ onClick={() => onSend && onSend()}
+ className="w-[96px]">
+ <RiPlayLargeFill className="mr-0.5 h-4 w-4 shrink-0" aria-hidden="true" />
+ {t('appDebug.inputs.run')}
+ </Button>
+ )}
+ </div>
+ )}
+ </div>
+ <div className='mx-3'>
+ <FeatureBar
+ showFileUpload={false}
+ isChatMode={appType !== AppType.completion}
+ onFeatureBarClick={setShowAppConfigureFeaturesModal} />
+ </div>
+ </>
+ )
+}
+
+export default React.memo(PromptValuePanel)
diff --git a/app/components/app/configuration/prompt-value-panel/utils.ts b/app/components/app/configuration/prompt-value-panel/utils.ts
new file mode 100644
index 0000000..bc4656d
--- /dev/null
+++ b/app/components/app/configuration/prompt-value-panel/utils.ts
@@ -0,0 +1,13 @@
+import type { PromptVariable } from '@/models/debug'
+
+export function replaceStringWithValues(str: string, promptVariables: PromptVariable[], inputs: Record<string, any>) {
+ return str.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
+ const name = inputs[key]
+ if (name) { // has set value
+ return name
+ }
+
+ const valueObj: PromptVariable | undefined = promptVariables.find(v => v.key === key)
+ return valueObj ? `{{${valueObj.name}}}` : match
+ })
+}
diff --git a/app/components/app/configuration/style.module.css b/app/components/app/configuration/style.module.css
new file mode 100644
index 0000000..01f2c93
--- /dev/null
+++ b/app/components/app/configuration/style.module.css
@@ -0,0 +1,14 @@
+.advancedPromptMode {
+ position: relative;
+}
+
+.advancedPromptMode::before {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: -1px;
+ width: 100%;
+ height: 3px;
+ background-color: rgba(68, 76, 231, 0.18);
+ transform: skewX(-30deg);
+}
diff --git a/app/components/app/configuration/tools/external-data-tool-modal.tsx b/app/components/app/configuration/tools/external-data-tool-modal.tsx
new file mode 100644
index 0000000..ee4bd57
--- /dev/null
+++ b/app/components/app/configuration/tools/external-data-tool-modal.tsx
@@ -0,0 +1,304 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import useSWR from 'swr'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import FormGeneration from '@/app/components/base/features/new-feature-panel/moderation/form-generation'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import EmojiPicker from '@/app/components/base/emoji-picker'
+import ApiBasedExtensionSelector from '@/app/components/header/account-setting/api-based-extension-page/selector'
+import { BookOpen01 } from '@/app/components/base/icons/src/vender/line/education'
+import { fetchCodeBasedExtensionList } from '@/service/common'
+import { SimpleSelect } from '@/app/components/base/select'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+import type {
+ CodeBasedExtensionItem,
+ ExternalDataTool,
+} from '@/models/common'
+import { useToastContext } from '@/app/components/base/toast'
+import AppIcon from '@/app/components/base/app-icon'
+import { noop } from 'lodash-es'
+
+const systemTypes = ['api']
+type ExternalDataToolModalProps = {
+ data: ExternalDataTool
+ onCancel: () => void
+ onSave: (externalDataTool: ExternalDataTool) => void
+ onValidateBeforeSave?: (externalDataTool: ExternalDataTool) => boolean
+}
+type Provider = {
+ key: string
+ name: string
+ form_schema?: CodeBasedExtensionItem['form_schema']
+}
+const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
+ data,
+ onCancel,
+ onSave,
+ onValidateBeforeSave,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const { locale } = useContext(I18n)
+ const [localeData, setLocaleData] = useState(data.type ? data : { ...data, type: 'api' })
+ const [showEmojiPicker, setShowEmojiPicker] = useState(false)
+ const { data: codeBasedExtensionList } = useSWR(
+ '/code-based-extension?module=external_data_tool',
+ fetchCodeBasedExtensionList,
+ )
+
+ const providers: Provider[] = [
+ {
+ key: 'api',
+ name: t('common.apiBasedExtension.selector.title'),
+ },
+ ...(
+ codeBasedExtensionList
+ ? codeBasedExtensionList.data.map((item) => {
+ return {
+ key: item.name,
+ name: locale === 'zh-Hans' ? item.label['zh-Hans'] : item.label['en-US'],
+ form_schema: item.form_schema,
+ }
+ })
+ : []
+ ),
+ ]
+ const currentProvider = providers.find(provider => provider.key === localeData.type)
+
+ const handleDataTypeChange = (type: string) => {
+ let config: undefined | Record<string, any>
+ const currProvider = providers.find(provider => provider.key === type)
+
+ if (systemTypes.findIndex(t => t === type) < 0 && currProvider?.form_schema) {
+ config = currProvider?.form_schema.reduce((prev, next) => {
+ prev[next.variable] = next.default
+ return prev
+ }, {} as Record<string, any>)
+ }
+ setLocaleData({
+ ...localeData,
+ type,
+ config,
+ })
+ }
+
+ const handleDataExtraChange = (extraValue: Record<string, string>) => {
+ setLocaleData({
+ ...localeData,
+ config: {
+ ...localeData.config,
+ ...extraValue,
+ },
+ })
+ }
+
+ const handleValueChange = (value: Record<string, string>) => {
+ setLocaleData({
+ ...localeData,
+ ...value,
+ })
+ }
+
+ const handleDataApiBasedChange = (apiBasedExtensionId: string) => {
+ setLocaleData({
+ ...localeData,
+ config: {
+ ...localeData.config,
+ api_based_extension_id: apiBasedExtensionId,
+ },
+ })
+ }
+
+ const formatData = (originData: ExternalDataTool) => {
+ const { type, config } = originData
+ const params: Record<string, string | undefined> = {}
+
+ if (type === 'api')
+ params.api_based_extension_id = config?.api_based_extension_id
+
+ if (systemTypes.findIndex(t => t === type) < 0 && currentProvider?.form_schema) {
+ currentProvider.form_schema.forEach((form) => {
+ params[form.variable] = config?.[form.variable]
+ })
+ }
+
+ return {
+ ...originData,
+ type,
+ enabled: data.type ? data.enabled : true,
+ config: {
+ ...params,
+ },
+ }
+ }
+
+ const handleSave = () => {
+ if (!localeData.type) {
+ notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: t('appDebug.feature.tools.modal.toolType.title') }) })
+ return
+ }
+
+ if (!localeData.label) {
+ notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: t('appDebug.feature.tools.modal.name.title') }) })
+ return
+ }
+
+ if (!localeData.variable) {
+ notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: t('appDebug.feature.tools.modal.variableName.title') }) })
+ return
+ }
+
+ if (localeData.variable && !/[a-zA-Z_]\w{0,29}/g.test(localeData.variable)) {
+ notify({ type: 'error', message: t('appDebug.varKeyError.notValid', { key: t('appDebug.feature.tools.modal.variableName.title') }) })
+ return
+ }
+
+ if (localeData.type === 'api' && !localeData.config?.api_based_extension_id) {
+ notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale !== LanguagesSupported[1] ? 'API Extension' : 'API 鎵╁睍' }) })
+ return
+ }
+
+ if (systemTypes.findIndex(t => t === localeData.type) < 0 && currentProvider?.form_schema) {
+ for (let i = 0; i < currentProvider.form_schema.length; i++) {
+ if (!localeData.config?.[currentProvider.form_schema[i].variable] && currentProvider.form_schema[i].required) {
+ notify({
+ type: 'error',
+ message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale !== LanguagesSupported[1] ? currentProvider.form_schema[i].label['en-US'] : currentProvider.form_schema[i].label['zh-Hans'] }),
+ })
+ return
+ }
+ }
+ }
+
+ const formattedData = formatData(localeData)
+
+ if (onValidateBeforeSave && !onValidateBeforeSave(formattedData))
+ return
+
+ onSave(formatData(formattedData))
+ }
+
+ const action = data.type ? t('common.operation.edit') : t('common.operation.add')
+
+ return (
+ <Modal
+ isShow
+ onClose={noop}
+ className='!w-[640px] !max-w-none !p-8 !pb-6'
+ >
+ <div className='mb-2 text-xl font-semibold text-gray-900'>
+ {`${action} ${t('appDebug.variableConfig.apiBasedVar')}`}
+ </div>
+ <div className='py-2'>
+ <div className='text-sm font-medium leading-9 text-gray-900'>
+ {t('common.apiBasedExtension.type')}
+ </div>
+ <SimpleSelect
+ defaultValue={localeData.type}
+ items={providers.map((option) => {
+ return {
+ value: option.key,
+ name: option.name,
+ }
+ })}
+ onSelect={item => handleDataTypeChange(item.value as string)}
+ />
+ </div>
+ <div className='py-2'>
+ <div className='text-sm font-medium leading-9 text-gray-900'>
+ {t('appDebug.feature.tools.modal.name.title')}
+ </div>
+ <div className='flex items-center'>
+ <input
+ value={localeData.label || ''}
+ onChange={e => handleValueChange({ label: e.target.value })}
+ className='mr-2 block h-9 grow appearance-none rounded-lg bg-gray-100 px-3 text-sm text-gray-900 outline-none'
+ placeholder={t('appDebug.feature.tools.modal.name.placeholder') || ''}
+ />
+ <AppIcon size='large'
+ onClick={() => { setShowEmojiPicker(true) }}
+ className='!h-9 !w-9 cursor-pointer rounded-lg border-[0.5px] border-black/5 '
+ icon={localeData.icon}
+ background={localeData.icon_background}
+ />
+ </div>
+ </div>
+ <div className='py-2'>
+ <div className='text-sm font-medium leading-9 text-gray-900'>
+ {t('appDebug.feature.tools.modal.variableName.title')}
+ </div>
+ <input
+ value={localeData.variable || ''}
+ onChange={e => handleValueChange({ variable: e.target.value })}
+ className='block h-9 w-full appearance-none rounded-lg bg-gray-100 px-3 text-sm text-gray-900 outline-none'
+ placeholder={t('appDebug.feature.tools.modal.variableName.placeholder') || ''}
+ />
+ </div>
+ {
+ localeData.type === 'api' && (
+ <div className='py-2'>
+ <div className='flex h-9 items-center justify-between text-sm font-medium text-gray-900'>
+ {t('common.apiBasedExtension.selector.title')}
+ <a
+ href={t('common.apiBasedExtension.linkUrl') || '/'}
+ target='_blank' rel='noopener noreferrer'
+ className='group flex items-center text-xs font-normal text-gray-500 hover:text-primary-600'
+ >
+ <BookOpen01 className='mr-1 h-3 w-3 text-gray-500 group-hover:text-primary-600' />
+ {t('common.apiBasedExtension.link')}
+ </a>
+ </div>
+ <ApiBasedExtensionSelector
+ value={localeData.config?.api_based_extension_id || ''}
+ onChange={handleDataApiBasedChange}
+ />
+ </div>
+ )
+ }
+ {
+ systemTypes.findIndex(t => t === localeData.type) < 0
+ && currentProvider?.form_schema
+ && (
+ <FormGeneration
+ forms={currentProvider?.form_schema}
+ value={localeData.config}
+ onChange={handleDataExtraChange}
+ />
+ )
+ }
+ <div className='mt-6 flex items-center justify-end'>
+ <Button
+ onClick={onCancel}
+ className='mr-2'
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ onClick={handleSave}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ {
+ showEmojiPicker && (
+ <EmojiPicker
+ onSelect={(icon, icon_background) => {
+ handleValueChange({ icon, icon_background })
+ setShowEmojiPicker(false)
+ }}
+ onClose={() => {
+ handleValueChange({ icon: '', icon_background: '' })
+ setShowEmojiPicker(false)
+ }}
+ />
+ )
+ }
+ </Modal>
+ )
+}
+
+export default ExternalDataToolModal
diff --git a/app/components/app/configuration/tools/index.tsx b/app/components/app/configuration/tools/index.tsx
new file mode 100644
index 0000000..ba586bb
--- /dev/null
+++ b/app/components/app/configuration/tools/index.tsx
@@ -0,0 +1,191 @@
+// abandoned
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import copy from 'copy-to-clipboard'
+import { useContext } from 'use-context-selector'
+import {
+ RiAddLine,
+ RiArrowDownSLine,
+ RiDeleteBinLine,
+} from '@remixicon/react'
+import ConfigContext from '@/context/debug-configuration'
+import Switch from '@/app/components/base/switch'
+import Tooltip from '@/app/components/base/tooltip'
+import { Tool03 } from '@/app/components/base/icons/src/vender/solid/general'
+import {
+ Settings01,
+} from '@/app/components/base/icons/src/vender/line/general'
+import { useModalContext } from '@/context/modal-context'
+import type { ExternalDataTool } from '@/models/common'
+import AppIcon from '@/app/components/base/app-icon'
+import { useToastContext } from '@/app/components/base/toast'
+
+const Tools = () => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const { setShowExternalDataToolModal } = useModalContext()
+ const {
+ externalDataToolsConfig,
+ setExternalDataToolsConfig,
+ modelConfig,
+ } = useContext(ConfigContext)
+ const [expanded, setExpanded] = useState(true)
+ const [copied, setCopied] = useState(false)
+
+ const handleSaveExternalDataToolModal = (externalDataTool: ExternalDataTool, index: number) => {
+ if (index > -1) {
+ setExternalDataToolsConfig([
+ ...externalDataToolsConfig.slice(0, index),
+ externalDataTool,
+ ...externalDataToolsConfig.slice(index + 1),
+ ])
+ }
+ else {
+ setExternalDataToolsConfig([...externalDataToolsConfig, externalDataTool])
+ }
+ }
+ const handleValidateBeforeSaveExternalDataToolModal = (newExternalDataTool: ExternalDataTool, index: number) => {
+ const promptVariables = modelConfig?.configs?.prompt_variables || []
+ for (let i = 0; i < promptVariables.length; i++) {
+ if (promptVariables[i].key === newExternalDataTool.variable) {
+ notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
+ return false
+ }
+ }
+
+ let existedExternalDataTools = []
+ if (index > -1) {
+ existedExternalDataTools = [
+ ...externalDataToolsConfig.slice(0, index),
+ ...externalDataToolsConfig.slice(index + 1),
+ ]
+ }
+ else {
+ existedExternalDataTools = [...externalDataToolsConfig]
+ }
+
+ for (let i = 0; i < existedExternalDataTools.length; i++) {
+ if (existedExternalDataTools[i].variable === newExternalDataTool.variable) {
+ notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: existedExternalDataTools[i].variable }) })
+ return false
+ }
+ }
+
+ return true
+ }
+ const handleOpenExternalDataToolModal = (payload: ExternalDataTool, index: number) => {
+ setShowExternalDataToolModal({
+ payload,
+ onSaveCallback: (externalDataTool: ExternalDataTool) => handleSaveExternalDataToolModal(externalDataTool, index),
+ onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => handleValidateBeforeSaveExternalDataToolModal(newExternalDataTool, index),
+ })
+ }
+
+ return (
+ <div className='mt-3 rounded-xl bg-gray-50 px-3'>
+ <div className='flex h-12 items-center'>
+ <div className='flex grow items-center'>
+ <div
+ className={`
+ group mr-1 flex h-6 w-6 items-center justify-center rounded-md
+ ${externalDataToolsConfig.length && 'hover:bg-white hover:shadow-xs'}
+ `}
+ onClick={() => setExpanded(v => !v)}
+ >
+ {
+ externalDataToolsConfig.length
+ ? <Tool03 className='h-4 w-4 text-[#444CE7] group-hover:hidden' />
+ : <Tool03 className='h-4 w-4 text-[#444CE7]' />
+ }
+ {
+ !!externalDataToolsConfig.length && (
+ <RiArrowDownSLine className={`hidden h-4 w-4 cursor-pointer text-primary-600 group-hover:block ${expanded ? 'rotate-180' : 'rotate-0'}`} />
+ )
+ }
+ </div>
+ <div className='mr-1 text-sm font-semibold text-gray-800'>
+ {t('appDebug.feature.tools.title')}
+ </div>
+ <Tooltip
+ popupContent={
+ <div className='max-w-[160px]'>
+ {t('appDebug.feature.tools.tips')}
+ </div>
+ }
+ />
+ </div>
+ {
+ !expanded && !!externalDataToolsConfig.length && (
+ <>
+ <div className='mr-3 text-xs text-gray-500'>{t('appDebug.feature.tools.toolsInUse', { count: externalDataToolsConfig.length })}</div>
+ <div className='mr-1 h-3.5 w-[1px] bg-gray-200' />
+ </>
+ )
+ }
+ <div
+ className='flex h-7 cursor-pointer items-center px-3 text-xs font-medium text-gray-700'
+ onClick={() => handleOpenExternalDataToolModal({}, -1)}
+ >
+ <RiAddLine className='mr-[5px] h-3.5 w-3.5 ' />
+ {t('common.operation.add')}
+ </div>
+ </div>
+ {
+ expanded && !!externalDataToolsConfig.length && (
+ <div className='pb-3'>
+ {
+ externalDataToolsConfig.map((item, index: number) => (
+ <div
+ key={`${index}-${item.type}-${item.label}-${item.variable}`}
+ className='group mb-1 flex items-center rounded-lg border-[0.5px] border-gray-200 bg-white px-2.5 py-2 shadow-xs last-of-type:mb-0'
+ >
+ <div className='flex grow items-center'>
+ <AppIcon size='large'
+ className='mr-2 !h-6 !w-6 rounded-md border-[0.5px] border-black/5'
+ icon={item.icon}
+ background={item.icon_background}
+ />
+ <div className='mr-2 text-[13px] font-medium text-gray-800'>{item.label}</div>
+ <Tooltip
+ popupContent={copied ? t('appApi.copied') : `${item.variable}, ${t('appApi.copy')}`}
+ >
+ <div
+ className='text-xs text-gray-500'
+ onClick={() => {
+ copy(item.variable || '')
+ setCopied(true)
+ }}
+ >
+ {item.variable}
+ </div>
+ </Tooltip>
+ </div>
+ <div
+ className='mr-1 hidden h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-black/5 group-hover:flex'
+ onClick={() => handleOpenExternalDataToolModal(item, index)}
+ >
+ <Settings01 className='h-4 w-4 text-gray-500' />
+ </div>
+ <div
+ className='group/action hidden h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-[#FEE4E2] group-hover:flex'
+ onClick={() => setExternalDataToolsConfig([...externalDataToolsConfig.slice(0, index), ...externalDataToolsConfig.slice(index + 1)])}
+ >
+ <RiDeleteBinLine className='h-4 w-4 text-gray-500 group-hover/action:text-[#D92D20]' />
+ </div>
+ <div className='ml-2 mr-3 hidden h-3.5 w-[1px] bg-gray-200 group-hover:block' />
+ <Switch
+ size='l'
+ defaultValue={item.enabled}
+ onChange={(enabled: boolean) => handleSaveExternalDataToolModal({ ...item, enabled }, index)}
+ />
+ </div>
+ ))
+ }
+ </div>
+ )
+ }
+ </div>
+ )
+}
+
+export default Tools
diff --git a/app/components/app/create-app-dialog/app-card/index.tsx b/app/components/app/create-app-dialog/app-card/index.tsx
new file mode 100644
index 0000000..7f7ede0
--- /dev/null
+++ b/app/components/app/create-app-dialog/app-card/index.tsx
@@ -0,0 +1,60 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { PlusIcon } from '@heroicons/react/20/solid'
+import { AppTypeIcon, AppTypeLabel } from '../../type-selector'
+import Button from '@/app/components/base/button'
+import cn from '@/utils/classnames'
+import type { App } from '@/models/explore'
+import AppIcon from '@/app/components/base/app-icon'
+
+export type AppCardProps = {
+ app: App
+ canCreate: boolean
+ onCreate: () => void
+}
+
+const AppCard = ({
+ app,
+ onCreate,
+}: AppCardProps) => {
+ const { t } = useTranslation()
+ const { app: appBasicInfo } = app
+ return (
+ <div className={cn('group relative flex h-[132px] cursor-pointer flex-col overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg p-4 shadow-xs hover:shadow-lg')}>
+ <div className='flex shrink-0 grow-0 items-center gap-3 pb-2'>
+ <div className='relative shrink-0'>
+ <AppIcon
+ size='large'
+ iconType={appBasicInfo.icon_type}
+ icon={appBasicInfo.icon}
+ background={appBasicInfo.icon_background}
+ imageUrl={appBasicInfo.icon_url}
+ />
+ <AppTypeIcon wrapperClassName='absolute -bottom-0.5 -right-0.5 w-4 h-4 rounded-[4px] border border-divider-regular outline outline-components-panel-on-panel-item-bg'
+ className='h-3 w-3' type={appBasicInfo.mode} />
+ </div>
+ <div className='flex grow flex-col gap-1'>
+ <div className='line-clamp-1'>
+ <span className='system-md-semibold text-text-secondary' title={appBasicInfo.name}>{appBasicInfo.name}</span>
+ </div>
+ <AppTypeLabel className='system-2xs-medium-uppercase text-text-tertiary' type={app.app.mode} />
+ </div>
+ </div>
+ <div className="system-xs-regular py-1 text-text-tertiary">
+ <div className='line-clamp-3'>
+ {app.description}
+ </div>
+ </div>
+ <div className={cn('absolute bottom-0 left-0 right-0 hidden bg-gradient-to-t from-components-panel-gradient-2 from-[60.27%] to-transparent p-4 pt-8 group-hover:flex')}>
+ <div className={cn('flex h-8 w-full items-center space-x-2')}>
+ <Button variant='primary' className='grow' onClick={() => onCreate()}>
+ <PlusIcon className='mr-1 h-4 w-4' />
+ <span className='text-xs'>{t('app.newApp.useTemplate')}</span>
+ </Button>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default AppCard
diff --git a/app/components/app/create-app-dialog/app-list/index.tsx b/app/components/app/create-app-dialog/app-list/index.tsx
new file mode 100644
index 0000000..0b0b325
--- /dev/null
+++ b/app/components/app/create-app-dialog/app-list/index.tsx
@@ -0,0 +1,253 @@
+'use client'
+
+import React, { useMemo, useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import useSWR from 'swr'
+import { useDebounceFn } from 'ahooks'
+import { RiRobot2Line } from '@remixicon/react'
+import AppCard from '../app-card'
+import Sidebar, { AppCategories, AppCategoryLabel } from './sidebar'
+import Toast from '@/app/components/base/toast'
+import Divider from '@/app/components/base/divider'
+import cn from '@/utils/classnames'
+import ExploreContext from '@/context/explore-context'
+import type { App } from '@/models/explore'
+import { fetchAppDetail, fetchAppList } from '@/service/explore'
+import { importDSL } from '@/service/apps'
+import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
+import CreateAppModal from '@/app/components/explore/create-app-modal'
+import AppTypeSelector from '@/app/components/app/type-selector'
+import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
+import Loading from '@/app/components/base/loading'
+import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
+import { useAppContext } from '@/context/app-context'
+import { getRedirection } from '@/utils/app-redirection'
+import Input from '@/app/components/base/input'
+import type { AppMode } from '@/types/app'
+import { DSLImportMode } from '@/models/app'
+import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks'
+
+type AppsProps = {
+ onSuccess?: () => void
+ onCreateFromBlank?: () => void
+}
+
+// export enum PageType {
+// EXPLORE = 'explore',
+// CREATE = 'create',
+// }
+
+const Apps = ({
+ onSuccess,
+ onCreateFromBlank,
+}: AppsProps) => {
+ const { t } = useTranslation()
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const { push } = useRouter()
+ const { hasEditPermission } = useContext(ExploreContext)
+ const allCategoriesEn = AppCategories.RECOMMENDED
+
+ const [keywords, setKeywords] = useState('')
+ const [searchKeywords, setSearchKeywords] = useState('')
+
+ const { run: handleSearch } = useDebounceFn(() => {
+ setSearchKeywords(keywords)
+ }, { wait: 500 })
+
+ const handleKeywordsChange = (value: string) => {
+ setKeywords(value)
+ handleSearch()
+ }
+
+ const [currentType, setCurrentType] = useState<AppMode[]>([])
+ const [currCategory, setCurrCategory] = useTabSearchParams({
+ defaultTab: allCategoriesEn,
+ disableSearchParams: true,
+ })
+
+ const {
+ data: { categories, allList },
+ } = useSWR(
+ ['/explore/apps'],
+ () =>
+ fetchAppList().then(({ categories, recommended_apps }) => ({
+ categories,
+ allList: recommended_apps.sort((a, b) => a.position - b.position),
+ })),
+ {
+ fallbackData: {
+ categories: [],
+ allList: [],
+ },
+ },
+ )
+
+ const filteredList = useMemo(() => {
+ const filteredByCategory = allList.filter((item) => {
+ if (currCategory === allCategoriesEn)
+ return true
+ return item.category === currCategory
+ })
+ if (currentType.length === 0)
+ return filteredByCategory
+ return filteredByCategory.filter((item) => {
+ if (currentType.includes('chat') && item.app.mode === 'chat')
+ return true
+ if (currentType.includes('advanced-chat') && item.app.mode === 'advanced-chat')
+ return true
+ if (currentType.includes('agent-chat') && item.app.mode === 'agent-chat')
+ return true
+ if (currentType.includes('completion') && item.app.mode === 'completion')
+ return true
+ if (currentType.includes('workflow') && item.app.mode === 'workflow')
+ return true
+ return false
+ })
+ }, [currentType, currCategory, allCategoriesEn, allList])
+
+ const searchFilteredList = useMemo(() => {
+ if (!searchKeywords || !filteredList || filteredList.length === 0)
+ return filteredList
+
+ const lowerCaseSearchKeywords = searchKeywords.toLowerCase()
+
+ return filteredList.filter(item =>
+ item.app && item.app.name && item.app.name.toLowerCase().includes(lowerCaseSearchKeywords),
+ )
+ }, [searchKeywords, filteredList])
+
+ const [currApp, setCurrApp] = React.useState<App | null>(null)
+ const [isShowCreateModal, setIsShowCreateModal] = React.useState(false)
+ const { handleCheckPluginDependencies } = usePluginDependencies()
+ const onCreate: CreateAppModalProps['onConfirm'] = async ({
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ description,
+ }) => {
+ const { export_data, mode } = await fetchAppDetail(
+ currApp?.app.id as string,
+ )
+ try {
+ const app = await importDSL({
+ mode: DSLImportMode.YAML_CONTENT,
+ yaml_content: export_data,
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ description,
+ })
+ setIsShowCreateModal(false)
+ Toast.notify({
+ type: 'success',
+ message: t('app.newApp.appCreated'),
+ })
+ if (onSuccess)
+ onSuccess()
+ if (app.app_id)
+ await handleCheckPluginDependencies(app.app_id)
+ localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
+ getRedirection(isCurrentWorkspaceEditor, { id: app.app_id!, mode }, push)
+ }
+ catch {
+ Toast.notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
+ }
+ }
+
+ if (!categories || categories.length === 0) {
+ return (
+ <div className="flex h-full items-center">
+ <Loading type="area" />
+ </div>
+ )
+ }
+
+ return (
+ <div className='flex h-full flex-col'>
+ <div className='flex items-center justify-between border-b border-divider-burn py-3'>
+ <div className='min-w-[180px] pl-5'>
+ <span className='title-xl-semi-bold text-text-primary'>{t('app.newApp.startFromTemplate')}</span>
+ </div>
+ <div className='flex max-w-[548px] flex-1 items-center rounded-xl border border-components-panel-border bg-components-panel-bg-blur p-1.5 shadow-md'>
+ <AppTypeSelector value={currentType} onChange={setCurrentType} />
+ <div className='h-[14px]'>
+ <Divider type='vertical' />
+ </div>
+ <Input
+ showClearIcon
+ wrapperClassName='w-full flex-1'
+ className='bg-transparent hover:border-transparent hover:bg-transparent focus:border-transparent focus:bg-transparent focus:shadow-none'
+ placeholder={t('app.newAppFromTemplate.searchAllTemplate') as string}
+ value={keywords}
+ onChange={e => handleKeywordsChange(e.target.value)}
+ onClear={() => handleKeywordsChange('')}
+ />
+ </div>
+ <div className='h-8 w-[180px]'></div>
+ </div>
+ <div className='relative flex flex-1 overflow-y-auto'>
+ {!searchKeywords && <div className='h-full w-[200px] p-4'>
+ <Sidebar current={currCategory as AppCategories} categories={categories} onClick={(category) => { setCurrCategory(category) }} onCreateFromBlank={onCreateFromBlank} />
+ </div>}
+ <div className='h-full flex-1 shrink-0 grow overflow-auto border-l border-divider-burn p-6 pt-2'>
+ {searchFilteredList && searchFilteredList.length > 0 && <>
+ <div className='pb-1 pt-4'>
+ {searchKeywords
+ ? <p className='title-md-semi-bold text-text-tertiary'>{searchFilteredList.length > 1 ? t('app.newApp.foundResults', { count: searchFilteredList.length }) : t('app.newApp.foundResult', { count: searchFilteredList.length })}</p>
+ : <div className='flex h-[22px] items-center'>
+ <AppCategoryLabel category={currCategory as AppCategories} className='title-md-semi-bold text-text-primary' />
+ </div>}
+ </div>
+ <div
+ className={cn(
+ 'grid shrink-0 grid-cols-1 content-start gap-3 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 2k:grid-cols-6',
+ )}>
+ {searchFilteredList.map(app => (
+ <AppCard
+ key={app.app_id}
+ app={app}
+ canCreate={hasEditPermission}
+ onCreate={() => {
+ setCurrApp(app)
+ setIsShowCreateModal(true)
+ }}
+ />
+ ))}
+ </div>
+ </>}
+ {(!searchFilteredList || searchFilteredList.length === 0) && <NoTemplateFound />}
+ </div>
+ </div>
+ {isShowCreateModal && (
+ <CreateAppModal
+ appIconType={currApp?.app.icon_type || 'emoji'}
+ appIcon={currApp?.app.icon || ''}
+ appIconBackground={currApp?.app.icon_background || ''}
+ appIconUrl={currApp?.app.icon_url}
+ appName={currApp?.app.name || ''}
+ appDescription={currApp?.app.description || ''}
+ show={isShowCreateModal}
+ onConfirm={onCreate}
+ onHide={() => setIsShowCreateModal(false)}
+ />
+ )}
+ </div>
+ )
+}
+
+export default React.memo(Apps)
+
+function NoTemplateFound() {
+ const { t } = useTranslation()
+ return <div className='w-full rounded-lg bg-workflow-process-bg p-4'>
+ <div className='mb-2 inline-flex h-8 w-8 items-center justify-center rounded-lg bg-components-card-bg shadow-lg'>
+ <RiRobot2Line className='h-5 w-5 text-text-tertiary' />
+ </div>
+ <p className='title-md-semi-bold text-text-primary'>{t('app.newApp.noTemplateFound')}</p>
+ <p className='system-sm-regular text-text-tertiary'>{t('app.newApp.noTemplateFoundTip')}</p>
+ </div>
+}
diff --git a/app/components/app/create-app-dialog/app-list/sidebar.tsx b/app/components/app/create-app-dialog/app-list/sidebar.tsx
new file mode 100644
index 0000000..346de07
--- /dev/null
+++ b/app/components/app/create-app-dialog/app-list/sidebar.tsx
@@ -0,0 +1,60 @@
+'use client'
+import { RiStickyNoteAddLine, RiThumbUpLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import classNames from '@/utils/classnames'
+import Divider from '@/app/components/base/divider'
+
+export enum AppCategories {
+ RECOMMENDED = 'Recommended',
+}
+
+type SidebarProps = {
+ current: AppCategories | string
+ categories: string[]
+ onClick?: (category: AppCategories | string) => void
+ onCreateFromBlank?: () => void
+}
+
+export default function Sidebar({ current, categories, onClick, onCreateFromBlank }: SidebarProps) {
+ const { t } = useTranslation()
+ return <div className="flex h-full w-full flex-col">
+ <ul className='pt-0.5'>
+ <CategoryItem category={AppCategories.RECOMMENDED} active={current === AppCategories.RECOMMENDED} onClick={onClick} />
+ </ul>
+ <div className='system-xs-medium-uppercase mb-0.5 mt-3 px-3 pb-1 pt-2 text-text-tertiary'>{t('app.newAppFromTemplate.byCategories')}</div>
+ <ul className='flex grow flex-col gap-0.5'>
+ {categories.map(category => (<CategoryItem key={category} category={category} active={current === category} onClick={onClick} />))}
+ </ul>
+ <Divider bgStyle='gradient' />
+ <div className='flex cursor-pointer items-center gap-1 px-3 py-1 text-text-tertiary' onClick={onCreateFromBlank}>
+ <RiStickyNoteAddLine className='h-3.5 w-3.5' />
+ <span className='system-xs-regular'>{t('app.newApp.startFromBlank')}</span>
+ </div>
+ </div>
+}
+
+type CategoryItemProps = {
+ active: boolean
+ category: AppCategories | string
+ onClick?: (category: AppCategories | string) => void
+}
+function CategoryItem({ category, active, onClick }: CategoryItemProps) {
+ return <li
+ className={classNames('p-1 pl-3 h-8 rounded-lg flex items-center gap-2 group cursor-pointer hover:bg-state-base-hover [&.active]:bg-state-base-active', active && 'active')}
+ onClick={() => { onClick?.(category) }}>
+ {category === AppCategories.RECOMMENDED && <div className='inline-flex h-5 w-5 items-center justify-center rounded-md'>
+ <RiThumbUpLine className='h-4 w-4 text-components-menu-item-text group-[.active]:text-components-menu-item-text-active' />
+ </div>}
+ <AppCategoryLabel category={category}
+ className={classNames('system-sm-medium text-components-menu-item-text group-[.active]:text-components-menu-item-text-active group-hover:text-components-menu-item-text-hover', active && 'system-sm-semibold')} />
+ </li >
+}
+
+type AppCategoryLabelProps = {
+ category: AppCategories | string
+ className?: string
+}
+export function AppCategoryLabel({ category, className }: AppCategoryLabelProps) {
+ const { t } = useTranslation()
+ return <span className={className}>{category === AppCategories.RECOMMENDED ? t('app.newAppFromTemplate.sidebar.Recommended') : category}</span>
+}
diff --git a/app/components/app/create-app-dialog/index.tsx b/app/components/app/create-app-dialog/index.tsx
new file mode 100644
index 0000000..794bbbf
--- /dev/null
+++ b/app/components/app/create-app-dialog/index.tsx
@@ -0,0 +1,36 @@
+'use client'
+import { useCallback } from 'react'
+import { useKeyPress } from 'ahooks'
+import AppList from './app-list'
+import FullScreenModal from '@/app/components/base/fullscreen-modal'
+
+type CreateAppDialogProps = {
+ show: boolean
+ onSuccess: () => void
+ onClose: () => void
+ onCreateFromBlank?: () => void
+}
+
+const CreateAppTemplateDialog = ({ show, onSuccess, onClose, onCreateFromBlank }: CreateAppDialogProps) => {
+ const handleEscKeyPress = useCallback(() => {
+ if (show)
+ onClose()
+ }, [show, onClose])
+
+ useKeyPress('esc', handleEscKeyPress)
+
+ return (
+ <FullScreenModal
+ open={show}
+ closable
+ onClose={onClose}
+ >
+ <AppList onCreateFromBlank={onCreateFromBlank} onSuccess={() => {
+ onSuccess()
+ onClose()
+ }} />
+ </FullScreenModal>
+ )
+}
+
+export default CreateAppTemplateDialog
diff --git a/app/components/app/create-app-modal/index.tsx b/app/components/app/create-app-modal/index.tsx
new file mode 100644
index 0000000..f91f440
--- /dev/null
+++ b/app/components/app/create-app-modal/index.tsx
@@ -0,0 +1,364 @@
+'use client'
+
+import { useCallback, useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+
+import { useRouter, useSearchParams } from 'next/navigation'
+import { useContext, useContextSelector } from 'use-context-selector'
+import { RiArrowRightLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react'
+import Link from 'next/link'
+import { useDebounceFn, useKeyPress } from 'ahooks'
+import Image from 'next/image'
+import AppIconPicker from '../../base/app-icon-picker'
+import type { AppIconSelection } from '../../base/app-icon-picker'
+import Button from '@/app/components/base/button'
+import Divider from '@/app/components/base/divider'
+import cn from '@/utils/classnames'
+import { WEB_PREFIX } from '@/config'
+import AppsContext, { useAppContext } from '@/context/app-context'
+import { useProviderContext } from '@/context/provider-context'
+import { ToastContext } from '@/app/components/base/toast'
+import type { AppMode } from '@/types/app'
+import { AppModes } from '@/types/app'
+import { createApp } from '@/service/apps'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import AppIcon from '@/app/components/base/app-icon'
+import AppsFull from '@/app/components/billing/apps-full-in-dialog'
+import { BubbleTextMod, ChatBot, ListSparkle, Logic } from '@/app/components/base/icons/src/vender/solid/communication'
+import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
+import { getRedirection } from '@/utils/app-redirection'
+import FullScreenModal from '@/app/components/base/fullscreen-modal'
+import useTheme from '@/hooks/use-theme'
+
+type CreateAppProps = {
+ onSuccess: () => void
+ onClose: () => void
+ onCreateFromTemplate?: () => void
+}
+
+function CreateApp({ onClose, onSuccess, onCreateFromTemplate }: CreateAppProps) {
+ const { t } = useTranslation()
+ const { push } = useRouter()
+ const { notify } = useContext(ToastContext)
+ const mutateApps = useContextSelector(AppsContext, state => state.mutateApps)
+
+ const [appMode, setAppMode] = useState<AppMode>('chat')
+ const [appIcon, setAppIcon] = useState<AppIconSelection>({ type: 'emoji', icon: '馃', background: '#FFEAD5' })
+ const [showAppIconPicker, setShowAppIconPicker] = useState(false)
+ const [name, setName] = useState('')
+ const [description, setDescription] = useState('')
+
+ const { plan, enableBilling } = useProviderContext()
+ const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
+ const { isCurrentWorkspaceEditor } = useAppContext()
+
+ const isCreatingRef = useRef(false)
+
+ const searchParams = useSearchParams()
+
+ useEffect(() => {
+ const category = searchParams.get('category')
+ if (category && AppModes.includes(category as AppMode))
+ setAppMode(category as AppMode)
+ }, [searchParams])
+
+ const onCreate = useCallback(async () => {
+ if (!appMode) {
+ notify({ type: 'error', message: t('app.newApp.appTypeRequired') })
+ return
+ }
+ if (!name.trim()) {
+ notify({ type: 'error', message: t('app.newApp.nameNotEmpty') })
+ return
+ }
+ if (isCreatingRef.current)
+ return
+ isCreatingRef.current = true
+ try {
+ const app = await createApp({
+ name,
+ description,
+ icon_type: appIcon.type,
+ icon: appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId,
+ icon_background: appIcon.type === 'emoji' ? appIcon.background : undefined,
+ mode: appMode,
+ })
+ notify({ type: 'success', message: t('app.newApp.appCreated') })
+ onSuccess()
+ onClose()
+ mutateApps()
+ localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
+ getRedirection(isCurrentWorkspaceEditor, app, push)
+ }
+ catch {
+ notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
+ }
+ isCreatingRef.current = false
+ }, [name, notify, t, appMode, appIcon, description, onSuccess, onClose, mutateApps, push, isCurrentWorkspaceEditor])
+
+ const { run: handleCreateApp } = useDebounceFn(onCreate, { wait: 300 })
+ useKeyPress(['meta.enter', 'ctrl.enter'], () => {
+ if (isAppsFull)
+ return
+ handleCreateApp()
+ })
+ return <>
+ <div className='flex h-full justify-center overflow-y-auto overflow-x-hidden'>
+ <div className='flex flex-1 shrink-0 justify-end'>
+ <div className='px-10'>
+ <div className='h-6 w-full 2xl:h-[139px]' />
+ <div className='pb-6 pt-1'>
+ <span className='title-2xl-semi-bold text-text-primary'>{t('app.newApp.startFromBlank')}</span>
+ </div>
+ <div className='mb-2 leading-6'>
+ <span className='system-sm-semibold text-text-secondary'>{t('app.newApp.chooseAppType')}</span>
+ </div>
+ <div className='flex w-[660px] flex-col gap-4'>
+ <div>
+ <div className='mb-2'>
+ <span className='system-2xs-medium-uppercase text-text-tertiary'>{t('app.newApp.forBeginners')}</span>
+ </div>
+ <div className='flex flex-row gap-2'>
+ <AppTypeCard
+ active={appMode === 'chat'}
+ title={t('app.types.chatbot')}
+ description={t('app.newApp.chatbotShortDescription')}
+ icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-solid'>
+ <ChatBot className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
+ </div>}
+ onClick={() => {
+ setAppMode('chat')
+ }} />
+ <AppTypeCard
+ active={appMode === 'agent-chat'}
+ title={t('app.types.agent')}
+ description={t('app.newApp.agentShortDescription')}
+ icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-violet-solid'>
+ <Logic className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
+ </div>}
+ onClick={() => {
+ setAppMode('agent-chat')
+ }} />
+ <AppTypeCard
+ active={appMode === 'completion'}
+ title={t('app.newApp.completeApp')}
+ description={t('app.newApp.completionShortDescription')}
+ icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-teal-solid'>
+ <ListSparkle className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
+ </div>}
+ onClick={() => {
+ setAppMode('completion')
+ }} />
+ </div>
+ </div>
+ <div>
+ <div className='mb-2'>
+ <span className='system-2xs-medium-uppercase text-text-tertiary'>{t('app.newApp.forAdvanced')}</span>
+ </div>
+ <div className='flex flex-row gap-2'>
+ <AppTypeCard
+ active={appMode === 'advanced-chat'}
+ title={t('app.types.advanced')}
+ description={t('app.newApp.advancedShortDescription')}
+ icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-light-solid'>
+ <BubbleTextMod className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
+ </div>}
+ onClick={() => {
+ setAppMode('advanced-chat')
+ }} />
+ <AppTypeCard
+ active={appMode === 'workflow'}
+ title={t('app.types.workflow')}
+ description={t('app.newApp.workflowShortDescription')}
+ icon={<div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-indigo-solid'>
+ <RiExchange2Fill className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
+ </div>}
+ onClick={() => {
+ setAppMode('workflow')
+ }} />
+ </div>
+ </div>
+ <Divider style={{ margin: 0 }} />
+ <div className='flex items-center space-x-3'>
+ <div className='flex-1'>
+ <div className='mb-1 flex h-6 items-center'>
+ <label className='system-sm-semibold text-text-secondary'>{t('app.newApp.captionName')}</label>
+ </div>
+ <Input
+ value={name}
+ onChange={e => setName(e.target.value)}
+ placeholder={t('app.newApp.appNamePlaceholder') || ''}
+ />
+ </div>
+ <AppIcon
+ iconType={appIcon.type}
+ icon={appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId}
+ background={appIcon.type === 'emoji' ? appIcon.background : undefined}
+ imageUrl={appIcon.type === 'image' ? appIcon.url : undefined}
+ size='xxl' className='cursor-pointer rounded-2xl'
+ onClick={() => { setShowAppIconPicker(true) }}
+ />
+ {showAppIconPicker && <AppIconPicker
+ onSelect={(payload) => {
+ setAppIcon(payload)
+ setShowAppIconPicker(false)
+ }}
+ onClose={() => {
+ setShowAppIconPicker(false)
+ }}
+ />}
+ </div>
+ <div>
+ <div className='mb-1 flex h-6 items-center'>
+ <label className='system-sm-semibold text-text-secondary'>{t('app.newApp.captionDescription')}</label>
+ <span className='system-xs-regular ml-1 text-text-tertiary'>({t('app.newApp.optional')})</span>
+ </div>
+ <Textarea
+ className='resize-none'
+ placeholder={t('app.newApp.appDescriptionPlaceholder') || ''}
+ value={description}
+ onChange={e => setDescription(e.target.value)}
+ />
+ </div>
+ </div>
+ {isAppsFull && <AppsFull className='mt-4' loc='app-create' />}
+ <div className='flex items-center justify-between pb-10 pt-5'>
+ <div className='system-xs-regular flex cursor-pointer items-center gap-1 text-text-tertiary' onClick={onCreateFromTemplate}>
+ <span>{t('app.newApp.noIdeaTip')}</span>
+ <div className='p-[1px]'>
+ <RiArrowRightLine className='h-3.5 w-3.5' />
+ </div>
+ </div>
+ <div className='flex gap-2'>
+ <Button onClick={onClose}>{t('app.newApp.Cancel')}</Button>
+ <Button disabled={isAppsFull || !name} className='gap-1' variant="primary" onClick={handleCreateApp}>
+ <span>{t('app.newApp.Create')}</span>
+ <div className='flex gap-0.5'>
+ <RiCommandLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' />
+ <RiCornerDownLeftLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' />
+ </div>
+ </Button>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div className='relative flex h-full flex-1 shrink justify-start overflow-hidden'>
+ <div className='absolute left-0 right-0 top-0 h-6 border-b border-b-divider-subtle 2xl:h-[139px]'></div>
+ <div className='max-w-[760px] border-x border-x-divider-subtle'>
+ <div className='h-6 2xl:h-[139px]' />
+ <AppPreview mode={appMode} />
+ <div className='absolute left-0 right-0 border-b border-b-divider-subtle'></div>
+ <div className='flex h-[448px] w-[664px] items-center justify-center' style={{ background: 'repeating-linear-gradient(135deg, transparent, transparent 2px, rgba(16,24,40,0.04) 4px,transparent 3px, transparent 6px)' }}>
+ <AppScreenShot show={appMode === 'chat'} mode='chat' />
+ <AppScreenShot show={appMode === 'advanced-chat'} mode='advanced-chat' />
+ <AppScreenShot show={appMode === 'agent-chat'} mode='agent-chat' />
+ <AppScreenShot show={appMode === 'completion'} mode='completion' />
+ <AppScreenShot show={appMode === 'workflow'} mode='workflow' />
+ </div>
+ <div className='absolute left-0 right-0 border-b border-b-divider-subtle'></div>
+ </div>
+ </div>
+ </div>
+ </>
+}
+type CreateAppDialogProps = CreateAppProps & {
+ show: boolean
+}
+const CreateAppModal = ({ show, onClose, onSuccess, onCreateFromTemplate }: CreateAppDialogProps) => {
+ return (
+ <FullScreenModal
+ overflowVisible
+ closable
+ open={show}
+ onClose={onClose}
+ >
+ <CreateApp onClose={onClose} onSuccess={onSuccess} onCreateFromTemplate={onCreateFromTemplate} />
+ </FullScreenModal>
+ )
+}
+
+export default CreateAppModal
+
+type AppTypeCardProps = {
+ icon: React.JSX.Element
+ title: string
+ description: string
+ active: boolean
+ onClick: () => void
+}
+function AppTypeCard({ icon, title, description, active, onClick }: AppTypeCardProps) {
+ return <div
+ className={
+ cn(`relative box-content h-[84px] w-[191px] cursor-pointer rounded-xl
+ border-[0.5px] border-components-option-card-option-border
+ bg-components-panel-on-panel-item-bg p-3 shadow-xs hover:shadow-md`, active
+ ? 'shadow-md outline outline-[1.5px] outline-components-option-card-option-selected-border'
+ : '')
+ }
+ onClick={onClick}
+ >
+ {icon}
+ <div className='system-sm-semibold mb-0.5 mt-2 text-text-secondary'>{title}</div>
+ <div className='system-xs-regular text-text-tertiary'>{description}</div>
+ </div>
+}
+
+function AppPreview({ mode }: { mode: AppMode }) {
+ const { t } = useTranslation()
+ const modeToPreviewInfoMap = {
+ 'chat': {
+ title: t('app.types.chatbot'),
+ description: t('app.newApp.chatbotUserDescription'),
+ link: 'https://docs.dify.ai/guides/application-orchestrate/readme',
+ },
+ 'advanced-chat': {
+ title: t('app.types.advanced'),
+ description: t('app.newApp.advancedUserDescription'),
+ link: 'https://docs.dify.ai/en/guides/workflow/README',
+ },
+ 'agent-chat': {
+ title: t('app.types.agent'),
+ description: t('app.newApp.agentUserDescription'),
+ link: 'https://docs.dify.ai/en/guides/application-orchestrate/agent',
+ },
+ 'completion': {
+ title: t('app.newApp.completeApp'),
+ description: t('app.newApp.completionUserDescription'),
+ link: null,
+ },
+ 'workflow': {
+ title: t('app.types.workflow'),
+ description: t('app.newApp.workflowUserDescription'),
+ link: 'https://docs.dify.ai/en/guides/workflow/README',
+ },
+ }
+ const previewInfo = modeToPreviewInfoMap[mode]
+ return <div className='px-8 py-4'>
+ <h4 className='system-sm-semibold-uppercase text-text-secondary'>{previewInfo.title}</h4>
+ <div className='system-xs-regular mt-1 min-h-8 max-w-96 text-text-tertiary'>
+ <span>{previewInfo.description}</span>
+ {previewInfo.link && <Link target='_blank' href={previewInfo.link} className='ml-1 text-text-accent'>{t('app.newApp.learnMore')}</Link>}
+ </div>
+ </div>
+}
+
+function AppScreenShot({ mode, show }: { mode: AppMode; show: boolean }) {
+ const { theme } = useTheme()
+ const modeToImageMap = {
+ 'chat': 'Chatbot',
+ 'advanced-chat': 'Chatflow',
+ 'agent-chat': 'Agent',
+ 'completion': 'TextGenerator',
+ 'workflow': 'Workflow',
+ }
+ return <picture>
+ <source media="(resolution: 1x)" srcSet={`${WEB_PREFIX}/screenshots/${theme}/${modeToImageMap[mode]}.png`} />
+ <source media="(resolution: 2x)" srcSet={`${WEB_PREFIX}/screenshots/${theme}/${modeToImageMap[mode]}@2x.png`} />
+ <source media="(resolution: 3x)" srcSet={`${WEB_PREFIX}/screenshots/${theme}/${modeToImageMap[mode]}@3x.png`} />
+ <Image className={show ? '' : 'hidden'}
+ src={`${WEB_PREFIX}/screenshots/${theme}/${modeToImageMap[mode]}.png`}
+ alt='App Screen Shot'
+ width={664} height={448} />
+ </picture>
+}
diff --git a/app/components/app/create-from-dsl-modal/dsl-confirm-modal.tsx b/app/components/app/create-from-dsl-modal/dsl-confirm-modal.tsx
new file mode 100644
index 0000000..e6aadaa
--- /dev/null
+++ b/app/components/app/create-from-dsl-modal/dsl-confirm-modal.tsx
@@ -0,0 +1,46 @@
+import { useTranslation } from 'react-i18next'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+
+type DSLConfirmModalProps = {
+ versions?: {
+ importedVersion: string
+ systemVersion: string
+ }
+ onCancel: () => void
+ onConfirm: () => void
+ confirmDisabled?: boolean
+}
+const DSLConfirmModal = ({
+ versions = { importedVersion: '', systemVersion: '' },
+ onCancel,
+ onConfirm,
+ confirmDisabled = false,
+}: DSLConfirmModalProps) => {
+ const { t } = useTranslation()
+
+ return (
+ <Modal
+ isShow
+ onClose={() => onCancel()}
+ className='w-[480px]'
+ >
+ <div className='flex flex-col items-start gap-2 self-stretch pb-4'>
+ <div className='title-2xl-semi-bold text-text-primary'>{t('app.newApp.appCreateDSLErrorTitle')}</div>
+ <div className='system-md-regular flex grow flex-col text-text-secondary'>
+ <div>{t('app.newApp.appCreateDSLErrorPart1')}</div>
+ <div>{t('app.newApp.appCreateDSLErrorPart2')}</div>
+ <br />
+ <div>{t('app.newApp.appCreateDSLErrorPart3')}<span className='system-md-medium'>{versions.importedVersion}</span></div>
+ <div>{t('app.newApp.appCreateDSLErrorPart4')}<span className='system-md-medium'>{versions.systemVersion}</span></div>
+ </div>
+ </div>
+ <div className='flex items-start justify-end gap-2 self-stretch pt-6'>
+ <Button variant='secondary' onClick={() => onCancel()}>{t('app.newApp.Cancel')}</Button>
+ <Button variant='primary' destructive onClick={onConfirm} disabled={confirmDisabled}>{t('app.newApp.Confirm')}</Button>
+ </div>
+ </Modal>
+ )
+}
+
+export default DSLConfirmModal
diff --git a/app/components/app/create-from-dsl-modal/index.tsx b/app/components/app/create-from-dsl-modal/index.tsx
new file mode 100644
index 0000000..9739ac4
--- /dev/null
+++ b/app/components/app/create-from-dsl-modal/index.tsx
@@ -0,0 +1,320 @@
+'use client'
+
+import type { MouseEventHandler } from 'react'
+import { useMemo, useRef, useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine, RiCommandLine, RiCornerDownLeftLine } from '@remixicon/react'
+import { useDebounceFn, useKeyPress } from 'ahooks'
+import Uploader from './uploader'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Modal from '@/app/components/base/modal'
+import { ToastContext } from '@/app/components/base/toast'
+import {
+ importDSL,
+ importDSLConfirm,
+} from '@/service/apps'
+import {
+ DSLImportMode,
+ DSLImportStatus,
+} from '@/models/app'
+import { useAppContext } from '@/context/app-context'
+import { useProviderContext } from '@/context/provider-context'
+import AppsFull from '@/app/components/billing/apps-full-in-dialog'
+import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
+import { getRedirection } from '@/utils/app-redirection'
+import cn from '@/utils/classnames'
+import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks'
+import { noop } from 'lodash-es'
+
+type CreateFromDSLModalProps = {
+ show: boolean
+ onSuccess?: () => void
+ onClose: () => void
+ activeTab?: string
+ dslUrl?: string
+}
+
+export enum CreateFromDSLModalTab {
+ FROM_FILE = 'from-file',
+ FROM_URL = 'from-url',
+}
+
+const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDSLModalTab.FROM_FILE, dslUrl = '' }: CreateFromDSLModalProps) => {
+ const { push } = useRouter()
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const [currentFile, setDSLFile] = useState<File>()
+ const [fileContent, setFileContent] = useState<string>()
+ const [currentTab, setCurrentTab] = useState(activeTab)
+ const [dslUrlValue, setDslUrlValue] = useState(dslUrl)
+ const [showErrorModal, setShowErrorModal] = useState(false)
+ const [versions, setVersions] = useState<{ importedVersion: string; systemVersion: string }>()
+ const [importId, setImportId] = useState<string>()
+ const { handleCheckPluginDependencies } = usePluginDependencies()
+
+ const readFile = (file: File) => {
+ const reader = new FileReader()
+ reader.onload = function (event) {
+ const content = event.target?.result
+ setFileContent(content as string)
+ }
+ reader.readAsText(file)
+ }
+
+ const handleFile = (file?: File) => {
+ setDSLFile(file)
+ if (file)
+ readFile(file)
+ if (!file)
+ setFileContent('')
+ }
+
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const { plan, enableBilling } = useProviderContext()
+ const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
+
+ const isCreatingRef = useRef(false)
+
+ const onCreate: MouseEventHandler = async () => {
+ if (currentTab === CreateFromDSLModalTab.FROM_FILE && !currentFile)
+ return
+ if (currentTab === CreateFromDSLModalTab.FROM_URL && !dslUrlValue)
+ return
+ if (isCreatingRef.current)
+ return
+ isCreatingRef.current = true
+ try {
+ let response
+
+ if (currentTab === CreateFromDSLModalTab.FROM_FILE) {
+ response = await importDSL({
+ mode: DSLImportMode.YAML_CONTENT,
+ yaml_content: fileContent || '',
+ })
+ }
+ if (currentTab === CreateFromDSLModalTab.FROM_URL) {
+ response = await importDSL({
+ mode: DSLImportMode.YAML_URL,
+ yaml_url: dslUrlValue || '',
+ })
+ }
+
+ if (!response)
+ return
+ const { id, status, app_id, app_mode, imported_dsl_version, current_dsl_version } = response
+ if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) {
+ if (onSuccess)
+ onSuccess()
+ if (onClose)
+ onClose()
+
+ notify({
+ type: status === DSLImportStatus.COMPLETED ? 'success' : 'warning',
+ message: t(status === DSLImportStatus.COMPLETED ? 'app.newApp.appCreated' : 'app.newApp.caution'),
+ children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('app.newApp.appCreateDSLWarning'),
+ })
+ localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
+ if (app_id)
+ await handleCheckPluginDependencies(app_id)
+ getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push)
+ }
+ else if (status === DSLImportStatus.PENDING) {
+ setVersions({
+ importedVersion: imported_dsl_version ?? '',
+ systemVersion: current_dsl_version ?? '',
+ })
+ if (onClose)
+ onClose()
+ setTimeout(() => {
+ setShowErrorModal(true)
+ }, 300)
+ setImportId(id)
+ }
+ else {
+ notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
+ }
+ }
+ // eslint-disable-next-line unused-imports/no-unused-vars
+ catch (e) {
+ notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
+ }
+ isCreatingRef.current = false
+ }
+
+ const { run: handleCreateApp } = useDebounceFn(onCreate, { wait: 300 })
+
+ useKeyPress(['meta.enter', 'ctrl.enter'], () => {
+ if (show && !isAppsFull && ((currentTab === CreateFromDSLModalTab.FROM_FILE && currentFile) || (currentTab === CreateFromDSLModalTab.FROM_URL && dslUrlValue)))
+ handleCreateApp()
+ })
+
+ useKeyPress('esc', () => {
+ if (show && !showErrorModal)
+ onClose()
+ })
+
+ const onDSLConfirm: MouseEventHandler = async () => {
+ try {
+ if (!importId)
+ return
+ const response = await importDSLConfirm({
+ import_id: importId,
+ })
+
+ const { status, app_id, app_mode } = response
+
+ if (status === DSLImportStatus.COMPLETED) {
+ if (onSuccess)
+ onSuccess()
+ if (onClose)
+ onClose()
+
+ notify({
+ type: 'success',
+ message: t('app.newApp.appCreated'),
+ })
+ if (app_id)
+ await handleCheckPluginDependencies(app_id)
+ localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
+ getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push)
+ }
+ else if (status === DSLImportStatus.FAILED) {
+ notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
+ }
+ }
+ // eslint-disable-next-line unused-imports/no-unused-vars
+ catch (e) {
+ notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
+ }
+ }
+
+ const tabs = [
+ {
+ key: CreateFromDSLModalTab.FROM_FILE,
+ label: t('app.importFromDSLFile'),
+ },
+ {
+ key: CreateFromDSLModalTab.FROM_URL,
+ label: t('app.importFromDSLUrl'),
+ },
+ ]
+
+ const buttonDisabled = useMemo(() => {
+ if (isAppsFull)
+ return true
+ if (currentTab === CreateFromDSLModalTab.FROM_FILE)
+ return !currentFile
+ if (currentTab === CreateFromDSLModalTab.FROM_URL)
+ return !dslUrlValue
+ return false
+ }, [isAppsFull, currentTab, currentFile, dslUrlValue])
+
+ return (
+ <>
+ <Modal
+ className='w-[520px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-0 shadow-xl'
+ isShow={show}
+ onClose={noop}
+ >
+ <div className='title-2xl-semi-bold flex items-center justify-between pb-3 pl-6 pr-5 pt-6 text-text-primary'>
+ {t('app.importFromDSL')}
+ <div
+ className='flex h-8 w-8 cursor-pointer items-center'
+ onClick={() => onClose()}
+ >
+ <RiCloseLine className='h-5 w-5 text-text-tertiary' />
+ </div>
+ </div>
+ <div className='system-md-semibold flex h-9 items-center space-x-6 border-b border-divider-subtle px-6 text-text-tertiary'>
+ {
+ tabs.map(tab => (
+ <div
+ key={tab.key}
+ className={cn(
+ 'relative flex h-full cursor-pointer items-center',
+ currentTab === tab.key && 'text-text-primary',
+ )}
+ onClick={() => setCurrentTab(tab.key)}
+ >
+ {tab.label}
+ {
+ currentTab === tab.key && (
+ <div className='absolute bottom-0 h-[2px] w-full bg-util-colors-blue-brand-blue-brand-600'></div>
+ )
+ }
+ </div>
+ ))
+ }
+ </div>
+ <div className='px-6 py-4'>
+ {
+ currentTab === CreateFromDSLModalTab.FROM_FILE && (
+ <Uploader
+ className='mt-0'
+ file={currentFile}
+ updateFile={handleFile}
+ />
+ )
+ }
+ {
+ currentTab === CreateFromDSLModalTab.FROM_URL && (
+ <div>
+ <div className='system-md-semibold mb-1 text-text-secondary'>DSL URL</div>
+ <Input
+ placeholder={t('app.importFromDSLUrlPlaceholder') || ''}
+ value={dslUrlValue}
+ onChange={e => setDslUrlValue(e.target.value)}
+ />
+ </div>
+ )
+ }
+ </div>
+ {isAppsFull && (
+ <div className='px-6'>
+ <AppsFull className='mt-0' loc='app-create-dsl' />
+ </div>
+ )}
+ <div className='flex justify-end px-6 py-5'>
+ <Button className='mr-2' onClick={onClose}>{t('app.newApp.Cancel')}</Button>
+ <Button
+ disabled={buttonDisabled}
+ variant="primary"
+ onClick={handleCreateApp}
+ className="gap-1"
+ >
+ <span>{t('app.newApp.Create')}</span>
+ <div className='flex gap-0.5'>
+ <RiCommandLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' />
+ <RiCornerDownLeftLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' />
+ </div>
+ </Button>
+ </div>
+ </Modal>
+ <Modal
+ isShow={showErrorModal}
+ onClose={() => setShowErrorModal(false)}
+ className='w-[480px]'
+ >
+ <div className='flex flex-col items-start gap-2 self-stretch pb-4'>
+ <div className='title-2xl-semi-bold text-text-primary'>{t('app.newApp.appCreateDSLErrorTitle')}</div>
+ <div className='system-md-regular flex grow flex-col text-text-secondary'>
+ <div>{t('app.newApp.appCreateDSLErrorPart1')}</div>
+ <div>{t('app.newApp.appCreateDSLErrorPart2')}</div>
+ <br />
+ <div>{t('app.newApp.appCreateDSLErrorPart3')}<span className='system-md-medium'>{versions?.importedVersion}</span></div>
+ <div>{t('app.newApp.appCreateDSLErrorPart4')}<span className='system-md-medium'>{versions?.systemVersion}</span></div>
+ </div>
+ </div>
+ <div className='flex items-start justify-end gap-2 self-stretch pt-6'>
+ <Button variant='secondary' onClick={() => setShowErrorModal(false)}>{t('app.newApp.Cancel')}</Button>
+ <Button variant='primary' destructive onClick={onDSLConfirm}>{t('app.newApp.Confirm')}</Button>
+ </div>
+ </Modal>
+ </>
+ )
+}
+
+export default CreateFromDSLModal
diff --git a/app/components/app/create-from-dsl-modal/uploader.tsx b/app/components/app/create-from-dsl-modal/uploader.tsx
new file mode 100644
index 0000000..6ad4116
--- /dev/null
+++ b/app/components/app/create-from-dsl-modal/uploader.tsx
@@ -0,0 +1,141 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
+import {
+ RiDeleteBinLine,
+ RiUploadCloud2Line,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { formatFileSize } from '@/utils/format'
+import cn from '@/utils/classnames'
+import { Yaml as YamlIcon } from '@/app/components/base/icons/src/public/files'
+import { ToastContext } from '@/app/components/base/toast'
+import ActionButton from '@/app/components/base/action-button'
+
+export type Props = {
+ file: File | undefined
+ updateFile: (file?: File) => void
+ className?: string
+}
+
+const Uploader: FC<Props> = ({
+ file,
+ updateFile,
+ className,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const [dragging, setDragging] = useState(false)
+ const dropRef = useRef<HTMLDivElement>(null)
+ const dragRef = useRef<HTMLDivElement>(null)
+ const fileUploader = useRef<HTMLInputElement>(null)
+
+ const handleDragEnter = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ e.target !== dragRef.current && setDragging(true)
+ }
+ const handleDragOver = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }
+ const handleDragLeave = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ e.target === dragRef.current && setDragging(false)
+ }
+ const handleDrop = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setDragging(false)
+ if (!e.dataTransfer)
+ return
+ const files = [...e.dataTransfer.files]
+ if (files.length > 1) {
+ notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.count') })
+ return
+ }
+ updateFile(files[0])
+ }
+ const selectHandle = () => {
+ const originalFile = file
+ if (fileUploader.current) {
+ fileUploader.current.value = ''
+ fileUploader.current.click()
+ // If no file is selected, restore the original file
+ fileUploader.current.oncancel = () => updateFile(originalFile)
+ }
+ }
+ const removeFile = () => {
+ if (fileUploader.current)
+ fileUploader.current.value = ''
+ updateFile()
+ }
+ const fileChangeHandle = (e: React.ChangeEvent<HTMLInputElement>) => {
+ const currentFile = e.target.files?.[0]
+ updateFile(currentFile)
+ }
+
+ useEffect(() => {
+ dropRef.current?.addEventListener('dragenter', handleDragEnter)
+ dropRef.current?.addEventListener('dragover', handleDragOver)
+ dropRef.current?.addEventListener('dragleave', handleDragLeave)
+ dropRef.current?.addEventListener('drop', handleDrop)
+ return () => {
+ dropRef.current?.removeEventListener('dragenter', handleDragEnter)
+ dropRef.current?.removeEventListener('dragover', handleDragOver)
+ dropRef.current?.removeEventListener('dragleave', handleDragLeave)
+ dropRef.current?.removeEventListener('drop', handleDrop)
+ }
+ }, [])
+
+ return (
+ <div className={cn('mt-6', className)}>
+ <input
+ ref={fileUploader}
+ style={{ display: 'none' }}
+ type="file"
+ id="fileUploader"
+ accept='.yaml,.yml'
+ onChange={fileChangeHandle}
+ />
+ <div ref={dropRef}>
+ {!file && (
+ <div className={cn('flex h-12 items-center rounded-[10px] border border-dashed border-components-dropzone-border bg-components-dropzone-bg text-sm font-normal', dragging && 'border-components-dropzone-border-accent bg-components-dropzone-bg-accent')}>
+ <div className='flex w-full items-center justify-center space-x-2'>
+ <RiUploadCloud2Line className='h-6 w-6 text-text-tertiary' />
+ <div className='text-text-tertiary'>
+ {t('datasetCreation.stepOne.uploader.button')}
+ <span className='cursor-pointer pl-1 text-text-accent' onClick={selectHandle}>{t('datasetDocuments.list.batchModal.browse')}</span>
+ </div>
+ </div>
+ {dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />}
+ </div>
+ )}
+ {file && (
+ <div className={cn('group flex items-center rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg shadow-xs', ' hover:bg-components-panel-on-panel-item-bg-hover')}>
+ <div className='flex items-center justify-center p-3'>
+ <YamlIcon className="h-6 w-6 shrink-0" />
+ </div>
+ <div className='flex grow flex-col items-start gap-0.5 py-1 pr-2'>
+ <span className='font-inter max-w-[calc(100%_-_30px)] overflow-hidden text-ellipsis whitespace-nowrap text-[12px] font-medium leading-4 text-text-secondary'>{file.name}</span>
+ <div className='font-inter flex h-3 items-center gap-1 self-stretch text-[10px] font-medium uppercase leading-3 text-text-tertiary'>
+ <span>YAML</span>
+ <span className='text-text-quaternary'>路</span>
+ <span>{formatFileSize(file.size)}</span>
+ </div>
+ </div>
+ <div className='hidden items-center pr-3 group-hover:flex'>
+ <ActionButton onClick={removeFile}>
+ <RiDeleteBinLine className='h-4 w-4 text-text-tertiary' />
+ </ActionButton>
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(Uploader)
diff --git a/app/components/app/duplicate-modal/index.tsx b/app/components/app/duplicate-modal/index.tsx
new file mode 100644
index 0000000..f98fb83
--- /dev/null
+++ b/app/components/app/duplicate-modal/index.tsx
@@ -0,0 +1,124 @@
+'use client'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import AppIconPicker from '../../base/app-icon-picker'
+import cn from '@/utils/classnames'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Toast from '@/app/components/base/toast'
+import AppIcon from '@/app/components/base/app-icon'
+import { useProviderContext } from '@/context/provider-context'
+import AppsFull from '@/app/components/billing/apps-full-in-dialog'
+import type { AppIconType } from '@/types/app'
+import { noop } from 'lodash-es'
+
+export type DuplicateAppModalProps = {
+ appName: string
+ icon_type: AppIconType | null
+ icon: string
+ icon_background?: string | null
+ icon_url?: string | null
+ show: boolean
+ onConfirm: (info: {
+ name: string
+ icon_type: AppIconType
+ icon: string
+ icon_background?: string | null
+ }) => Promise<void>
+ onHide: () => void
+}
+
+const DuplicateAppModal = ({
+ appName,
+ icon_type,
+ icon,
+ icon_background,
+ icon_url,
+ show = false,
+ onConfirm,
+ onHide,
+}: DuplicateAppModalProps) => {
+ const { t } = useTranslation()
+
+ const [name, setName] = React.useState(appName)
+
+ const [showAppIconPicker, setShowAppIconPicker] = useState(false)
+ const [appIcon, setAppIcon] = useState(
+ icon_type === 'image'
+ ? { type: 'image' as const, url: icon_url, fileId: icon }
+ : { type: 'emoji' as const, icon, background: icon_background },
+ )
+
+ const { plan, enableBilling } = useProviderContext()
+ const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
+
+ const submit = () => {
+ if (!name.trim()) {
+ Toast.notify({ type: 'error', message: t('explore.appCustomize.nameRequired') })
+ return
+ }
+ onConfirm({
+ name,
+ icon_type: appIcon.type,
+ icon: appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId,
+ icon_background: appIcon.type === 'emoji' ? appIcon.background : undefined,
+ })
+ onHide()
+ }
+
+ return (
+ <>
+ <Modal
+ isShow={show}
+ onClose={noop}
+ className={cn('relative !max-w-[480px]', 'px-8')}
+ >
+ <div className='absolute right-4 top-4 cursor-pointer p-2' onClick={onHide}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div className='relative mb-9 mt-3 text-xl font-semibold leading-[30px] text-text-primary'>{t('app.duplicateTitle')}</div>
+ <div className='system-sm-regular mb-9 text-text-secondary'>
+ <div className='system-md-medium mb-2'>{t('explore.appCustomize.subTitle')}</div>
+ <div className='flex items-center justify-between space-x-2'>
+ <AppIcon
+ size='large'
+ onClick={() => { setShowAppIconPicker(true) }}
+ className='cursor-pointer'
+ iconType={appIcon.type}
+ icon={appIcon.type === 'image' ? appIcon.fileId : appIcon.icon}
+ background={appIcon.type === 'image' ? undefined : appIcon.background}
+ imageUrl={appIcon.type === 'image' ? appIcon.url : undefined}
+ />
+ <Input
+ value={name}
+ onChange={e => setName(e.target.value)}
+ className='h-10'
+ />
+ </div>
+ {isAppsFull && <AppsFull className='mt-4' loc='app-duplicate-create' />}
+ </div>
+ <div className='flex flex-row-reverse'>
+ <Button disabled={isAppsFull} className='ml-2 w-24' variant='primary' onClick={submit}>{t('app.duplicate')}</Button>
+ <Button className='w-24' onClick={onHide}>{t('common.operation.cancel')}</Button>
+ </div>
+ </Modal>
+ {showAppIconPicker && <AppIconPicker
+ onSelect={(payload) => {
+ setAppIcon(payload)
+ setShowAppIconPicker(false)
+ }}
+ onClose={() => {
+ setAppIcon(icon_type === 'image'
+ ? { type: 'image', url: icon_url!, fileId: icon }
+ : { type: 'emoji', icon, background: icon_background! })
+ setShowAppIconPicker(false)
+ }}
+ />}
+ </>
+
+ )
+}
+
+export default DuplicateAppModal
diff --git a/app/components/app/log-annotation/index.tsx b/app/components/app/log-annotation/index.tsx
new file mode 100644
index 0000000..12a611e
--- /dev/null
+++ b/app/components/app/log-annotation/index.tsx
@@ -0,0 +1,63 @@
+'use client'
+import type { FC } from 'react'
+import React, { useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useRouter } from 'next/navigation'
+import cn from '@/utils/classnames'
+import Log from '@/app/components/app/log'
+import WorkflowLog from '@/app/components/app/workflow-log'
+import Annotation from '@/app/components/app/annotation'
+import Loading from '@/app/components/base/loading'
+import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
+import TabSlider from '@/app/components/base/tab-slider-plain'
+import { useStore as useAppStore } from '@/app/components/app/store'
+
+type Props = {
+ pageType: PageType
+}
+
+const LogAnnotation: FC<Props> = ({
+ pageType,
+}) => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const appDetail = useAppStore(state => state.appDetail)
+
+ const options = useMemo(() => {
+ if (appDetail?.mode === 'completion')
+ return [{ value: PageType.log, text: t('appLog.title') }]
+ return [
+ { value: PageType.log, text: t('appLog.title') },
+ { value: PageType.annotation, text: t('appAnnotation.title') },
+ ]
+ }, [appDetail?.mode, t])
+
+ if (!appDetail) {
+ return (
+ <div className='flex h-full items-center justify-center bg-background-body'>
+ <Loading />
+ </div>
+ )
+ }
+
+ return (
+ <div className='flex h-full flex-col px-6 pt-3'>
+ {appDetail.mode !== 'workflow' && (
+ <TabSlider
+ className='shrink-0'
+ value={pageType}
+ onChange={(value) => {
+ router.push(`/app/${appDetail.id}/${value === PageType.log ? 'logs' : 'annotations'}`)
+ }}
+ options={options}
+ />
+ )}
+ <div className={cn('h-0 grow', appDetail.mode !== 'workflow' && 'mt-3')}>
+ {pageType === PageType.log && appDetail.mode !== 'workflow' && (<Log appDetail={appDetail} />)}
+ {pageType === PageType.annotation && (<Annotation appDetail={appDetail} />)}
+ {pageType === PageType.log && appDetail.mode === 'workflow' && (<WorkflowLog appDetail={appDetail} />)}
+ </div>
+ </div>
+ )
+}
+export default React.memo(LogAnnotation)
diff --git a/app/components/app/log/filter.tsx b/app/components/app/log/filter.tsx
new file mode 100644
index 0000000..6e259a2
--- /dev/null
+++ b/app/components/app/log/filter.tsx
@@ -0,0 +1,101 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import dayjs from 'dayjs'
+import { RiCalendarLine } from '@remixicon/react'
+import quarterOfYear from 'dayjs/plugin/quarterOfYear'
+import type { QueryParam } from './index'
+import Chip from '@/app/components/base/chip'
+import Input from '@/app/components/base/input'
+import Sort from '@/app/components/base/sort'
+import { fetchAnnotationsCount } from '@/service/log'
+dayjs.extend(quarterOfYear)
+
+const today = dayjs()
+
+export const TIME_PERIOD_MAPPING: { [key: string]: { value: number; name: string } } = {
+ 1: { value: 0, name: 'today' },
+ 2: { value: 7, name: 'last7days' },
+ 3: { value: 28, name: 'last4weeks' },
+ 4: { value: today.diff(today.subtract(3, 'month'), 'day'), name: 'last3months' },
+ 5: { value: today.diff(today.subtract(12, 'month'), 'day'), name: 'last12months' },
+ 6: { value: today.diff(today.startOf('month'), 'day'), name: 'monthToDate' },
+ 7: { value: today.diff(today.startOf('quarter'), 'day'), name: 'quarterToDate' },
+ 8: { value: today.diff(today.startOf('year'), 'day'), name: 'yearToDate' },
+ 9: { value: -1, name: 'allTime' },
+}
+
+type IFilterProps = {
+ isChatMode?: boolean
+ appId: string
+ queryParams: QueryParam
+ setQueryParams: (v: QueryParam) => void
+}
+
+const Filter: FC<IFilterProps> = ({ isChatMode, appId, queryParams, setQueryParams }: IFilterProps) => {
+ const { data } = useSWR({ url: `/apps/${appId}/annotations/count` }, fetchAnnotationsCount)
+ const { t } = useTranslation()
+ if (!data)
+ return null
+ return (
+ <div className='mb-2 flex flex-row flex-wrap items-center gap-2'>
+ <Chip
+ className='min-w-[150px]'
+ panelClassName='w-[270px]'
+ leftIcon={<RiCalendarLine className='h-4 w-4 text-text-secondary' />}
+ value={queryParams.period}
+ onSelect={(item) => {
+ setQueryParams({ ...queryParams, period: item.value })
+ }}
+ onClear={() => setQueryParams({ ...queryParams, period: '9' })}
+ items={Object.entries(TIME_PERIOD_MAPPING).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}`) }))}
+ />
+ <Chip
+ className='min-w-[150px]'
+ panelClassName='w-[270px]'
+ showLeftIcon={false}
+ value={queryParams.annotation_status || 'all'}
+ onSelect={(item) => {
+ setQueryParams({ ...queryParams, annotation_status: item.value as string })
+ }}
+ onClear={() => setQueryParams({ ...queryParams, annotation_status: 'all' })}
+ items={[
+ { value: 'all', name: t('appLog.filter.annotation.all') },
+ { value: 'annotated', name: t('appLog.filter.annotation.annotated', { count: data?.count }) },
+ { value: 'not_annotated', name: t('appLog.filter.annotation.not_annotated') },
+ ]}
+ />
+ <Input
+ wrapperClassName='w-[200px]'
+ showLeftIcon
+ showClearIcon
+ value={queryParams.keyword}
+ placeholder={t('common.operation.search')!}
+ onChange={(e) => {
+ setQueryParams({ ...queryParams, keyword: e.target.value })
+ }}
+ onClear={() => setQueryParams({ ...queryParams, keyword: '' })}
+ />
+ {isChatMode && (
+ <>
+ <div className='h-3.5 w-px bg-divider-regular'></div>
+ <Sort
+ order={queryParams.sort_by?.startsWith('-') ? '-' : ''}
+ value={queryParams.sort_by?.replace('-', '') || 'created_at'}
+ items={[
+ { value: 'created_at', name: t('appLog.table.header.time') },
+ { value: 'updated_at', name: t('appLog.table.header.updatedTime') },
+ ]}
+ onSelect={(value) => {
+ setQueryParams({ ...queryParams, sort_by: value as string })
+ }}
+ />
+ </>
+ )}
+ </div>
+ )
+}
+
+export default Filter
diff --git a/app/components/app/log/index.tsx b/app/components/app/log/index.tsx
new file mode 100644
index 0000000..8e523b7
--- /dev/null
+++ b/app/components/app/log/index.tsx
@@ -0,0 +1,129 @@
+'use client'
+import type { FC, SVGProps } from 'react'
+import React, { useState } from 'react'
+import useSWR from 'swr'
+import Link from 'next/link'
+import { usePathname } from 'next/navigation'
+import { useDebounce } from 'ahooks'
+import { omit } from 'lodash-es'
+import dayjs from 'dayjs'
+import { Trans, useTranslation } from 'react-i18next'
+import List from './list'
+import Filter, { TIME_PERIOD_MAPPING } from './filter'
+import Pagination from '@/app/components/base/pagination'
+import Loading from '@/app/components/base/loading'
+import { fetchChatConversations, fetchCompletionConversations } from '@/service/log'
+import { APP_PAGE_LIMIT } from '@/config'
+import type { App, AppMode } from '@/types/app'
+export type ILogsProps = {
+ appDetail: App
+}
+
+export type QueryParam = {
+ period: string
+ annotation_status?: string
+ keyword?: string
+ sort_by?: string
+}
+
+const ThreeDotsIcon = ({ className }: SVGProps<SVGElement>) => {
+ return <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
+ <path d="M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103" stroke="#374151" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+}
+
+const EmptyElement: FC<{ appUrl: string }> = ({ appUrl }) => {
+ const { t } = useTranslation()
+ const pathname = usePathname()
+ const pathSegments = pathname.split('/')
+ pathSegments.pop()
+ return <div className='flex h-full items-center justify-center'>
+ <div className='box-border h-fit w-[560px] rounded-2xl bg-background-section-burn px-5 py-4'>
+ <span className='system-md-semibold text-text-secondary'>{t('appLog.table.empty.element.title')}<ThreeDotsIcon className='relative -left-1.5 -top-3 inline' /></span>
+ <div className='system-sm-regular mt-2 text-text-tertiary'>
+ <Trans
+ i18nKey="appLog.table.empty.element.content"
+ components={{ shareLink: <Link href={`${pathSegments.join('/')}/overview`} className='text-util-colors-blue-blue-600' />, testLink: <Link href={appUrl} className='text-util-colors-blue-blue-600' target='_blank' rel='noopener noreferrer' /> }}
+ />
+ </div>
+ </div>
+ </div>
+}
+
+const Logs: FC<ILogsProps> = ({ appDetail }) => {
+ const { t } = useTranslation()
+ const [queryParams, setQueryParams] = useState<QueryParam>({
+ period: '2',
+ annotation_status: 'all',
+ sort_by: '-created_at',
+ })
+ const [currPage, setCurrPage] = React.useState<number>(0)
+ const [limit, setLimit] = React.useState<number>(APP_PAGE_LIMIT)
+ const debouncedQueryParams = useDebounce(queryParams, { wait: 500 })
+
+ // Get the app type first
+ const isChatMode = appDetail.mode !== 'completion'
+
+ const query = {
+ page: currPage + 1,
+ limit,
+ ...((debouncedQueryParams.period !== '9')
+ ? {
+ start: dayjs().subtract(TIME_PERIOD_MAPPING[debouncedQueryParams.period].value, 'day').startOf('day').format('YYYY-MM-DD HH:mm'),
+ end: dayjs().endOf('day').format('YYYY-MM-DD HH:mm'),
+ }
+ : {}),
+ ...(isChatMode ? { sort_by: debouncedQueryParams.sort_by } : {}),
+ ...omit(debouncedQueryParams, ['period']),
+ }
+
+ const getWebAppType = (appType: AppMode) => {
+ if (appType !== 'completion' && appType !== 'workflow')
+ return 'chat'
+ return appType
+ }
+
+ // When the details are obtained, proceed to the next request
+ const { data: chatConversations, mutate: mutateChatList } = useSWR(() => isChatMode
+ ? {
+ url: `/apps/${appDetail.id}/chat-conversations`,
+ params: query,
+ }
+ : null, fetchChatConversations)
+
+ const { data: completionConversations, mutate: mutateCompletionList } = useSWR(() => !isChatMode
+ ? {
+ url: `/apps/${appDetail.id}/completion-conversations`,
+ params: query,
+ }
+ : null, fetchCompletionConversations)
+
+ const total = isChatMode ? chatConversations?.total : completionConversations?.total
+
+ return (
+ <div className='flex h-full grow flex-col'>
+ <p className='system-sm-regular shrink-0 text-text-tertiary'>{t('appLog.description')}</p>
+ <div className='flex max-h-[calc(100%-16px)] flex-1 grow flex-col py-4'>
+ <Filter isChatMode={isChatMode} appId={appDetail.id} queryParams={queryParams} setQueryParams={setQueryParams} />
+ {total === undefined
+ ? <Loading type='app' />
+ : total > 0
+ ? <List logs={isChatMode ? chatConversations : completionConversations} appDetail={appDetail} onRefresh={isChatMode ? mutateChatList : mutateCompletionList} />
+ : <EmptyElement appUrl={`${appDetail.site.app_base_url}/${getWebAppType(appDetail.mode)}/${appDetail.site.access_token}`} />
+ }
+ {/* Show Pagination only if the total is more than the limit */}
+ {(total && total > APP_PAGE_LIMIT)
+ ? <Pagination
+ current={currPage}
+ onChange={setCurrPage}
+ total={total}
+ limit={limit}
+ onLimitChange={setLimit}
+ />
+ : null}
+ </div>
+ </div>
+ )
+}
+
+export default Logs
diff --git a/app/components/app/log/list.tsx b/app/components/app/log/list.tsx
new file mode 100644
index 0000000..7ce164c
--- /dev/null
+++ b/app/components/app/log/list.tsx
@@ -0,0 +1,764 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import useSWR from 'swr'
+import {
+ HandThumbDownIcon,
+ HandThumbUpIcon,
+} from '@heroicons/react/24/outline'
+import { RiCloseLine, RiEditFill } from '@remixicon/react'
+import { get } from 'lodash-es'
+import InfiniteScroll from 'react-infinite-scroll-component'
+import dayjs from 'dayjs'
+import utc from 'dayjs/plugin/utc'
+import timezone from 'dayjs/plugin/timezone'
+import { createContext, useContext } from 'use-context-selector'
+import { useShallow } from 'zustand/react/shallow'
+import { useTranslation } from 'react-i18next'
+import type { ChatItemInTree } from '../../base/chat/types'
+import Indicator from '../../header/indicator'
+import VarPanel from './var-panel'
+import type { FeedbackFunc, FeedbackType, IChatItem, SubmitAnnotationFunc } from '@/app/components/base/chat/chat/type'
+import type { Annotation, ChatConversationGeneralDetail, ChatConversationsResponse, ChatMessage, ChatMessagesRequest, CompletionConversationGeneralDetail, CompletionConversationsResponse, LogAnnotation } from '@/models/log'
+import type { App } from '@/types/app'
+import ActionButton from '@/app/components/base/action-button'
+import Loading from '@/app/components/base/loading'
+import Drawer from '@/app/components/base/drawer'
+import Chat from '@/app/components/base/chat/chat'
+import { ToastContext } from '@/app/components/base/toast'
+import { fetchChatConversationDetail, fetchChatMessages, fetchCompletionConversationDetail, updateLogMessageAnnotations, updateLogMessageFeedbacks } from '@/service/log'
+import ModelInfo from '@/app/components/app/log/model-info'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import TextGeneration from '@/app/components/app/text-generate/item'
+import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
+import MessageLogModal from '@/app/components/base/message-log-modal'
+import PromptLogModal from '@/app/components/base/prompt-log-modal'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import { useAppContext } from '@/context/app-context'
+import useTimestamp from '@/hooks/use-timestamp'
+import Tooltip from '@/app/components/base/tooltip'
+import { CopyIcon } from '@/app/components/base/copy-icon'
+import { buildChatItemTree, getThreadMessages } from '@/app/components/base/chat/utils'
+import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
+import cn from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+dayjs.extend(utc)
+dayjs.extend(timezone)
+
+type IConversationList = {
+ logs?: ChatConversationsResponse | CompletionConversationsResponse
+ appDetail: App
+ onRefresh: () => void
+}
+
+const defaultValue = 'N/A'
+
+type IDrawerContext = {
+ onClose: () => void
+ appDetail?: App
+}
+
+type StatusCount = {
+ success: number
+ failed: number
+ partial_success: number
+}
+
+const DrawerContext = createContext<IDrawerContext>({} as IDrawerContext)
+
+/**
+ * Icon component with numbers
+ */
+const HandThumbIconWithCount: FC<{ count: number; iconType: 'up' | 'down' }> = ({ count, iconType }) => {
+ const classname = iconType === 'up' ? 'text-primary-600 bg-primary-50' : 'text-red-600 bg-red-50'
+ const Icon = iconType === 'up' ? HandThumbUpIcon : HandThumbDownIcon
+ return <div className={`inline-flex w-fit items-center rounded-md p-1 text-xs ${classname} mr-1 last:mr-0`}>
+ <Icon className={'mr-0.5 h-3 w-3 rounded-md'} />
+ {count > 0 ? count : null}
+ </div>
+}
+
+const statusTdRender = (statusCount: StatusCount) => {
+ if (!statusCount)
+ return null
+
+ if (statusCount.partial_success + statusCount.failed === 0) {
+ return (
+ <div className='system-xs-semibold-uppercase inline-flex items-center gap-1'>
+ <Indicator color={'green'} />
+ <span className='text-util-colors-green-green-600'>Success</span>
+ </div>
+ )
+ }
+ else if (statusCount.failed === 0) {
+ return (
+ <div className='system-xs-semibold-uppercase inline-flex items-center gap-1'>
+ <Indicator color={'green'} />
+ <span className='text-util-colors-green-green-600'>Partial Success</span>
+ </div>
+ )
+ }
+ else {
+ return (
+ <div className='system-xs-semibold-uppercase inline-flex items-center gap-1'>
+ <Indicator color={'red'} />
+ <span className='text-util-colors-red-red-600'>{statusCount.failed} {`${statusCount.failed > 1 ? 'Failures' : 'Failure'}`}</span>
+ </div>
+ )
+ }
+}
+
+const getFormattedChatList = (messages: ChatMessage[], conversationId: string, timezone: string, format: string) => {
+ const newChatList: IChatItem[] = []
+ messages.forEach((item: ChatMessage) => {
+ const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || []
+ newChatList.push({
+ id: `question-${item.id}`,
+ content: item.inputs.query || item.inputs.default_input || item.query, // text generation: item.inputs.query; chat: item.query
+ isAnswer: false,
+ message_files: getProcessedFilesFromResponse(questionFiles.map((item: any) => ({ ...item, related_id: item.id }))),
+ parentMessageId: item.parent_message_id || undefined,
+ })
+
+ const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || []
+ newChatList.push({
+ id: item.id,
+ content: item.answer,
+ agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files),
+ feedback: item.feedbacks.find(item => item.from_source === 'user'), // user feedback
+ adminFeedback: item.feedbacks.find(item => item.from_source === 'admin'), // admin feedback
+ feedbackDisabled: false,
+ isAnswer: true,
+ message_files: getProcessedFilesFromResponse(answerFiles.map((item: any) => ({ ...item, related_id: item.id }))),
+ log: [
+ ...item.message,
+ ...(item.message[item.message.length - 1]?.role !== 'assistant'
+ ? [
+ {
+ role: 'assistant',
+ text: item.answer,
+ files: item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [],
+ },
+ ]
+ : []),
+ ] as IChatItem['log'],
+ workflow_run_id: item.workflow_run_id,
+ conversationId,
+ input: {
+ inputs: item.inputs,
+ query: item.query,
+ },
+ more: {
+ time: dayjs.unix(item.created_at).tz(timezone).format(format),
+ tokens: item.answer_tokens + item.message_tokens,
+ latency: item.provider_response_latency.toFixed(2),
+ },
+ citation: item.metadata?.retriever_resources,
+ annotation: (() => {
+ if (item.annotation_hit_history) {
+ return {
+ id: item.annotation_hit_history.annotation_id,
+ authorName: item.annotation_hit_history.annotation_create_account?.name || 'N/A',
+ created_at: item.annotation_hit_history.created_at,
+ }
+ }
+
+ if (item.annotation) {
+ return {
+ id: item.annotation.id,
+ authorName: item.annotation.account.name,
+ logAnnotation: item.annotation,
+ created_at: 0,
+ }
+ }
+
+ return undefined
+ })(),
+ parentMessageId: `question-${item.id}`,
+ })
+ })
+ return newChatList
+}
+
+type IDetailPanel = {
+ detail: any
+ onFeedback: FeedbackFunc
+ onSubmitAnnotation: SubmitAnnotationFunc
+}
+
+function DetailPanel({ detail, onFeedback }: IDetailPanel) {
+ const { userProfile: { timezone } } = useAppContext()
+ const { formatTime } = useTimestamp()
+ const { onClose, appDetail } = useContext(DrawerContext)
+ const { currentLogItem, setCurrentLogItem, showMessageLogModal, setShowMessageLogModal, showPromptLogModal, setShowPromptLogModal, currentLogModalActiveTab } = useAppStore(useShallow(state => ({
+ currentLogItem: state.currentLogItem,
+ setCurrentLogItem: state.setCurrentLogItem,
+ showMessageLogModal: state.showMessageLogModal,
+ setShowMessageLogModal: state.setShowMessageLogModal,
+ showPromptLogModal: state.showPromptLogModal,
+ setShowPromptLogModal: state.setShowPromptLogModal,
+ currentLogModalActiveTab: state.currentLogModalActiveTab,
+ })))
+ const { t } = useTranslation()
+ const [hasMore, setHasMore] = useState(true)
+ const [varValues, setVarValues] = useState<Record<string, string>>({})
+
+ const [allChatItems, setAllChatItems] = useState<IChatItem[]>([])
+ const [chatItemTree, setChatItemTree] = useState<ChatItemInTree[]>([])
+ const [threadChatItems, setThreadChatItems] = useState<IChatItem[]>([])
+
+ const fetchData = useCallback(async () => {
+ try {
+ if (!hasMore)
+ return
+
+ const params: ChatMessagesRequest = {
+ conversation_id: detail.id,
+ limit: 10,
+ }
+ if (allChatItems[0]?.id)
+ params.first_id = allChatItems[0]?.id.replace('question-', '')
+ const messageRes = await fetchChatMessages({
+ url: `/apps/${appDetail?.id}/chat-messages`,
+ params,
+ })
+ if (messageRes.data.length > 0) {
+ const varValues = messageRes.data.at(-1)!.inputs
+ setVarValues(varValues)
+ }
+ setHasMore(messageRes.has_more)
+
+ const newAllChatItems = [
+ ...getFormattedChatList(messageRes.data, detail.id, timezone!, t('appLog.dateTimeFormat') as string),
+ ...allChatItems,
+ ]
+ setAllChatItems(newAllChatItems)
+
+ let tree = buildChatItemTree(newAllChatItems)
+ if (messageRes.has_more === false && detail?.model_config?.configs?.introduction) {
+ tree = [{
+ id: 'introduction',
+ isAnswer: true,
+ isOpeningStatement: true,
+ content: detail?.model_config?.configs?.introduction ?? 'hello',
+ feedbackDisabled: true,
+ children: tree,
+ }]
+ }
+ setChatItemTree(tree)
+
+ setThreadChatItems(getThreadMessages(tree, newAllChatItems.at(-1)?.id))
+ }
+ catch (err) {
+ console.error(err)
+ }
+ }, [allChatItems, detail.id, hasMore, timezone, t, appDetail, detail?.model_config?.configs?.introduction])
+
+ const switchSibling = useCallback((siblingMessageId: string) => {
+ setThreadChatItems(getThreadMessages(chatItemTree, siblingMessageId))
+ }, [chatItemTree])
+
+ const handleAnnotationEdited = useCallback((query: string, answer: string, index: number) => {
+ setAllChatItems(allChatItems.map((item, i) => {
+ if (i === index - 1) {
+ return {
+ ...item,
+ content: query,
+ }
+ }
+ if (i === index) {
+ return {
+ ...item,
+ annotation: {
+ ...item.annotation,
+ logAnnotation: {
+ ...item.annotation?.logAnnotation,
+ content: answer,
+ },
+ } as any,
+ }
+ }
+ return item
+ }))
+ }, [allChatItems])
+ const handleAnnotationAdded = useCallback((annotationId: string, authorName: string, query: string, answer: string, index: number) => {
+ setAllChatItems(allChatItems.map((item, i) => {
+ if (i === index - 1) {
+ return {
+ ...item,
+ content: query,
+ }
+ }
+ if (i === index) {
+ const answerItem = {
+ ...item,
+ content: item.content,
+ annotation: {
+ id: annotationId,
+ authorName,
+ logAnnotation: {
+ content: answer,
+ account: {
+ id: '',
+ name: authorName,
+ email: '',
+ },
+ },
+ } as Annotation,
+ }
+ return answerItem
+ }
+ return item
+ }))
+ }, [allChatItems])
+ const handleAnnotationRemoved = useCallback((index: number) => {
+ setAllChatItems(allChatItems.map((item, i) => {
+ if (i === index) {
+ return {
+ ...item,
+ content: item.content,
+ annotation: undefined,
+ }
+ }
+ return item
+ }))
+ }, [allChatItems])
+
+ const fetchInitiated = useRef(false)
+
+ useEffect(() => {
+ if (appDetail?.id && detail.id && appDetail?.mode !== 'completion' && !fetchInitiated.current) {
+ fetchInitiated.current = true
+ fetchData()
+ }
+ }, [appDetail?.id, detail.id, appDetail?.mode, fetchData])
+
+ const isChatMode = appDetail?.mode !== 'completion'
+ const isAdvanced = appDetail?.mode === 'advanced-chat'
+
+ const varList = (detail.model_config as any).user_input_form?.map((item: any) => {
+ const itemContent = item[Object.keys(item)[0]]
+ return {
+ label: itemContent.variable,
+ value: varValues[itemContent.variable] || detail.message?.inputs?.[itemContent.variable],
+ }
+ }) || []
+ const message_files = (!isChatMode && detail.message.message_files && detail.message.message_files.length > 0)
+ ? detail.message.message_files.map((item: any) => item.url)
+ : []
+
+ const [width, setWidth] = useState(0)
+ const ref = useRef<HTMLDivElement>(null)
+
+ const adjustModalWidth = () => {
+ if (ref.current)
+ setWidth(document.body.clientWidth - (ref.current?.clientWidth + 16) - 8)
+ }
+
+ useEffect(() => {
+ adjustModalWidth()
+ }, [])
+
+ return (
+ <div ref={ref} className='flex h-full flex-col rounded-xl border-[0.5px] border-components-panel-border'>
+ {/* Panel Header */}
+ <div className='flex shrink-0 items-center gap-2 rounded-t-xl bg-components-panel-bg pb-2 pl-4 pr-3 pt-3'>
+ <div className='shrink-0'>
+ <div className='system-xs-semibold-uppercase mb-0.5 text-text-primary'>{isChatMode ? t('appLog.detail.conversationId') : t('appLog.detail.time')}</div>
+ {isChatMode && (
+ <div className='system-2xs-regular-uppercase flex items-center text-text-secondary'>
+ <Tooltip
+ popupContent={detail.id}
+ >
+ <div className='truncate'>{detail.id}</div>
+ </Tooltip>
+ <CopyIcon content={detail.id} />
+ </div>
+ )}
+ {!isChatMode && (
+ <div className='system-2xs-regular-uppercase text-text-secondary'>{formatTime(detail.created_at, t('appLog.dateTimeFormat') as string)}</div>
+ )}
+ </div>
+ <div className='flex grow flex-wrap items-center justify-end gap-y-1'>
+ {!isAdvanced && <ModelInfo model={detail.model_config.model} />}
+ </div>
+ <ActionButton size='l' onClick={onClose}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </ActionButton>
+ </div>
+ {/* Panel Body */}
+ <div className='shrink-0 px-1 pt-1'>
+ <div className='rounded-t-xl bg-background-section-burn p-3 pb-2'>
+ {(varList.length > 0 || (!isChatMode && message_files.length > 0)) && (
+ <VarPanel
+ varList={varList}
+ message_files={message_files}
+ />
+ )}
+ </div>
+ </div>
+ <div className='mx-1 mb-1 grow overflow-auto rounded-b-xl bg-background-section-burn'>
+ {!isChatMode
+ ? <div className="px-6 py-4">
+ <div className='flex h-[18px] items-center space-x-3'>
+ <div className='system-xs-semibold-uppercase text-text-tertiary'>{t('appLog.table.header.output')}</div>
+ <div className='h-[1px] grow' style={{
+ background: 'linear-gradient(270deg, rgba(243, 244, 246, 0) 0%, rgb(243, 244, 246) 100%)',
+ }}></div>
+ </div>
+ <TextGeneration
+ className='mt-2'
+ content={detail.message.answer}
+ messageId={detail.message.id}
+ isError={false}
+ onRetry={noop}
+ isInstalledApp={false}
+ supportFeedback
+ feedback={detail.message.feedbacks.find((item: any) => item.from_source === 'admin')}
+ onFeedback={feedback => onFeedback(detail.message.id, feedback)}
+ isShowTextToSpeech
+ siteInfo={null}
+ />
+ </div>
+ : threadChatItems.length < 8
+ ? <div className="mb-4 pt-4">
+ <Chat
+ config={{
+ appId: appDetail?.id,
+ text_to_speech: {
+ enabled: true,
+ },
+ questionEditEnable: false,
+ supportAnnotation: true,
+ annotation_reply: {
+ enabled: true,
+ },
+ supportFeedback: true,
+ } as any}
+ chatList={threadChatItems}
+ onAnnotationAdded={handleAnnotationAdded}
+ onAnnotationEdited={handleAnnotationEdited}
+ onAnnotationRemoved={handleAnnotationRemoved}
+ onFeedback={onFeedback}
+ noChatInput
+ showPromptLog
+ hideProcessDetail
+ chatContainerInnerClassName='px-3'
+ switchSibling={switchSibling}
+ />
+ </div>
+ : <div
+ className="py-4"
+ id="scrollableDiv"
+ style={{
+ height: 1000, // Specify a value
+ overflow: 'auto',
+ display: 'flex',
+ flexDirection: 'column-reverse',
+ }}>
+ {/* Put the scroll bar always on the bottom */}
+ <InfiniteScroll
+ scrollableTarget="scrollableDiv"
+ dataLength={threadChatItems.length}
+ next={fetchData}
+ hasMore={hasMore}
+ loader={<div className='system-xs-regular text-center text-text-tertiary'>{t('appLog.detail.loading')}...</div>}
+ // endMessage={<div className='text-center'>Nothing more to show</div>}
+ // below props only if you need pull down functionality
+ refreshFunction={fetchData}
+ pullDownToRefresh
+ pullDownToRefreshThreshold={50}
+ // pullDownToRefreshContent={
+ // <div className='text-center'>Pull down to refresh</div>
+ // }
+ // releaseToRefreshContent={
+ // <div className='text-center'>Release to refresh</div>
+ // }
+ // To put endMessage and loader to the top.
+ style={{ display: 'flex', flexDirection: 'column-reverse' }}
+ inverse={true}
+ >
+ <Chat
+ config={{
+ appId: appDetail?.id,
+ text_to_speech: {
+ enabled: true,
+ },
+ questionEditEnable: false,
+ supportAnnotation: true,
+ annotation_reply: {
+ enabled: true,
+ },
+ supportFeedback: true,
+ } as any}
+ chatList={threadChatItems}
+ onAnnotationAdded={handleAnnotationAdded}
+ onAnnotationEdited={handleAnnotationEdited}
+ onAnnotationRemoved={handleAnnotationRemoved}
+ onFeedback={onFeedback}
+ noChatInput
+ showPromptLog
+ hideProcessDetail
+ chatContainerInnerClassName='px-3'
+ switchSibling={switchSibling}
+ />
+ </InfiniteScroll>
+ </div>
+ }
+ </div>
+ {showMessageLogModal && (
+ <MessageLogModal
+ width={width}
+ currentLogItem={currentLogItem}
+ onCancel={() => {
+ setCurrentLogItem()
+ setShowMessageLogModal(false)
+ }}
+ defaultTab={currentLogModalActiveTab}
+ />
+ )}
+ {showPromptLogModal && (
+ <PromptLogModal
+ width={width}
+ currentLogItem={currentLogItem}
+ onCancel={() => {
+ setCurrentLogItem()
+ setShowPromptLogModal(false)
+ }}
+ />
+ )}
+ </div>
+ )
+}
+
+/**
+ * Text App Conversation Detail Component
+ */
+const CompletionConversationDetailComp: FC<{ appId?: string; conversationId?: string }> = ({ appId, conversationId }) => {
+ // Text Generator App Session Details Including Message List
+ const detailParams = ({ url: `/apps/${appId}/completion-conversations/${conversationId}` })
+ const { data: conversationDetail, mutate: conversationDetailMutate } = useSWR(() => (appId && conversationId) ? detailParams : null, fetchCompletionConversationDetail)
+ const { notify } = useContext(ToastContext)
+ const { t } = useTranslation()
+
+ const handleFeedback = async (mid: string, { rating }: FeedbackType): Promise<boolean> => {
+ try {
+ await updateLogMessageFeedbacks({ url: `/apps/${appId}/feedbacks`, body: { message_id: mid, rating } })
+ conversationDetailMutate()
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ return true
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ return false
+ }
+ }
+
+ const handleAnnotation = async (mid: string, value: string): Promise<boolean> => {
+ try {
+ await updateLogMessageAnnotations({ url: `/apps/${appId}/annotations`, body: { message_id: mid, content: value } })
+ conversationDetailMutate()
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ return true
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ return false
+ }
+ }
+
+ if (!conversationDetail)
+ return null
+
+ return <DetailPanel
+ detail={conversationDetail}
+ onFeedback={handleFeedback}
+ onSubmitAnnotation={handleAnnotation}
+ />
+}
+
+/**
+ * Chat App Conversation Detail Component
+ */
+const ChatConversationDetailComp: FC<{ appId?: string; conversationId?: string }> = ({ appId, conversationId }) => {
+ const detailParams = { url: `/apps/${appId}/chat-conversations/${conversationId}` }
+ const { data: conversationDetail } = useSWR(() => (appId && conversationId) ? detailParams : null, fetchChatConversationDetail)
+ const { notify } = useContext(ToastContext)
+ const { t } = useTranslation()
+
+ const handleFeedback = async (mid: string, { rating }: FeedbackType): Promise<boolean> => {
+ try {
+ await updateLogMessageFeedbacks({ url: `/apps/${appId}/feedbacks`, body: { message_id: mid, rating } })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ return true
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ return false
+ }
+ }
+
+ const handleAnnotation = async (mid: string, value: string): Promise<boolean> => {
+ try {
+ await updateLogMessageAnnotations({ url: `/apps/${appId}/annotations`, body: { message_id: mid, content: value } })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ return true
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ return false
+ }
+ }
+
+ if (!conversationDetail)
+ return null
+
+ return <DetailPanel
+ detail={conversationDetail}
+ onFeedback={handleFeedback}
+ onSubmitAnnotation={handleAnnotation}
+ />
+}
+
+/**
+ * Conversation list component including basic information
+ */
+const ConversationList: FC<IConversationList> = ({ logs, appDetail, onRefresh }) => {
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ const [showDrawer, setShowDrawer] = useState<boolean>(false) // Whether to display the chat details drawer
+ const [currentConversation, setCurrentConversation] = useState<ChatConversationGeneralDetail | CompletionConversationGeneralDetail | undefined>() // Currently selected conversation
+ const isChatMode = appDetail.mode !== 'completion' // Whether the app is a chat app
+ const isChatflow = appDetail.mode === 'advanced-chat' // Whether the app is a chatflow app
+ const { setShowPromptLogModal, setShowAgentLogModal, setShowMessageLogModal } = useAppStore(useShallow(state => ({
+ setShowPromptLogModal: state.setShowPromptLogModal,
+ setShowAgentLogModal: state.setShowAgentLogModal,
+ setShowMessageLogModal: state.setShowMessageLogModal,
+ })))
+
+ // Annotated data needs to be highlighted
+ const renderTdValue = (value: string | number | null, isEmptyStyle: boolean, isHighlight = false, annotation?: LogAnnotation) => {
+ return (
+ <Tooltip
+ popupContent={
+ <span className='inline-flex items-center text-xs text-text-tertiary'>
+ <RiEditFill className='mr-1 h-3 w-3' />{`${t('appLog.detail.annotationTip', { user: annotation?.account?.name })} ${formatTime(annotation?.created_at || dayjs().unix(), 'MM-DD hh:mm A')}`}
+ </span>
+ }
+ popupClassName={(isHighlight && !isChatMode) ? '' : '!hidden'}
+ >
+ <div className={cn(isEmptyStyle ? 'text-text-quaternary' : 'text-text-secondary', !isHighlight ? '' : 'bg-orange-100', 'system-sm-regular overflow-hidden text-ellipsis whitespace-nowrap')}>
+ {value || '-'}
+ </div>
+ </Tooltip>
+ )
+ }
+
+ const onCloseDrawer = () => {
+ onRefresh()
+ setShowDrawer(false)
+ setCurrentConversation(undefined)
+ setShowPromptLogModal(false)
+ setShowAgentLogModal(false)
+ setShowMessageLogModal(false)
+ }
+
+ if (!logs)
+ return <Loading />
+
+ return (
+ <div className='overflow-x-auto'>
+ <table className={cn('mt-2 w-full min-w-[440px] border-collapse border-0')}>
+ <thead className='system-xs-medium-uppercase text-text-tertiary'>
+ <tr>
+ <td className='w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1'></td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{isChatMode ? t('appLog.table.header.summary') : t('appLog.table.header.input')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.endUser')}</td>
+ {isChatflow && <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.status')}</td>}
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{isChatMode ? t('appLog.table.header.messageCount') : t('appLog.table.header.output')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.userRate')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.adminRate')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.updatedTime')}</td>
+ <td className='whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.time')}</td>
+ </tr>
+ </thead>
+ <tbody className="system-sm-regular text-text-secondary">
+ {logs.data.map((log: any) => {
+ const endUser = log.from_end_user_session_id || log.from_account_name
+ const leftValue = get(log, isChatMode ? 'name' : 'message.inputs.query') || (!isChatMode ? (get(log, 'message.query') || get(log, 'message.inputs.default_input')) : '') || ''
+ const rightValue = get(log, isChatMode ? 'message_count' : 'message.answer')
+ return <tr
+ key={log.id}
+ className={cn('cursor-pointer border-b border-divider-subtle hover:bg-background-default-hover', currentConversation?.id !== log.id ? '' : 'bg-background-default-hover')}
+ onClick={() => {
+ setShowDrawer(true)
+ setCurrentConversation(log)
+ }}>
+ <td className='h-4'>
+ {!log.read_at && (
+ <div className='flex items-center p-3 pr-0.5'>
+ <span className='inline-block h-1.5 w-1.5 rounded bg-util-colors-blue-blue-500'></span>
+ </div>
+ )}
+ </td>
+ <td className='w-[160px] p-3 pr-2' style={{ maxWidth: isChatMode ? 300 : 200 }}>
+ {renderTdValue(leftValue || t('appLog.table.empty.noChat'), !leftValue, isChatMode && log.annotated)}
+ </td>
+ <td className='p-3 pr-2'>{renderTdValue(endUser || defaultValue, !endUser)}</td>
+ {isChatflow && <td className='w-[160px] p-3 pr-2' style={{ maxWidth: isChatMode ? 300 : 200 }}>
+ {statusTdRender(log.status_count)}
+ </td>}
+ <td className='p-3 pr-2' style={{ maxWidth: isChatMode ? 100 : 200 }}>
+ {renderTdValue(rightValue === 0 ? 0 : (rightValue || t('appLog.table.empty.noOutput')), !rightValue, !isChatMode && !!log.annotation?.content, log.annotation)}
+ </td>
+ <td className='p-3 pr-2'>
+ {(!log.user_feedback_stats.like && !log.user_feedback_stats.dislike)
+ ? renderTdValue(defaultValue, true)
+ : <>
+ {!!log.user_feedback_stats.like && <HandThumbIconWithCount iconType='up' count={log.user_feedback_stats.like} />}
+ {!!log.user_feedback_stats.dislike && <HandThumbIconWithCount iconType='down' count={log.user_feedback_stats.dislike} />}
+ </>
+ }
+ </td>
+ <td className='p-3 pr-2'>
+ {(!log.admin_feedback_stats.like && !log.admin_feedback_stats.dislike)
+ ? renderTdValue(defaultValue, true)
+ : <>
+ {!!log.admin_feedback_stats.like && <HandThumbIconWithCount iconType='up' count={log.admin_feedback_stats.like} />}
+ {!!log.admin_feedback_stats.dislike && <HandThumbIconWithCount iconType='down' count={log.admin_feedback_stats.dislike} />}
+ </>
+ }
+ </td>
+ <td className='w-[160px] p-3 pr-2'>{formatTime(log.updated_at, t('appLog.dateTimeFormat') as string)}</td>
+ <td className='w-[160px] p-3 pr-2'>{formatTime(log.created_at, t('appLog.dateTimeFormat') as string)}</td>
+ </tr>
+ })}
+ </tbody>
+ </table>
+ <Drawer
+ isOpen={showDrawer}
+ onClose={onCloseDrawer}
+ mask={isMobile}
+ footer={null}
+ panelClassName='mt-16 mx-2 sm:mr-2 mb-4 !p-0 !max-w-[640px] rounded-xl bg-components-panel-bg'
+ >
+ <DrawerContext.Provider value={{
+ onClose: onCloseDrawer,
+ appDetail,
+ }}>
+ {isChatMode
+ ? <ChatConversationDetailComp appId={appDetail.id} conversationId={currentConversation?.id} />
+ : <CompletionConversationDetailComp appId={appDetail.id} conversationId={currentConversation?.id} />
+ }
+ </DrawerContext.Provider>
+ </Drawer>
+ </div>
+ )
+}
+
+export default ConversationList
diff --git a/app/components/app/log/model-info.tsx b/app/components/app/log/model-info.tsx
new file mode 100644
index 0000000..626ef09
--- /dev/null
+++ b/app/components/app/log/model-info.tsx
@@ -0,0 +1,107 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiInformation2Line,
+} from '@remixicon/react'
+import ModelIcon from '@/app/components/header/account-setting/model-provider-page/model-icon'
+import ModelName from '@/app/components/header/account-setting/model-provider-page/model-name'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { useTextGenerationCurrentProviderAndModelAndModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import cn from '@/utils/classnames'
+
+const PARAM_MAP = {
+ temperature: 'Temperature',
+ top_p: 'Top P',
+ presence_penalty: 'Presence Penalty',
+ max_tokens: 'Max Token',
+ stop: 'Stop',
+ frequency_penalty: 'Frequency Penalty',
+}
+
+type Props = {
+ model: any
+}
+
+const ModelInfo: FC<Props> = ({
+ model,
+}) => {
+ const { t } = useTranslation()
+ const modelName = model.name
+ const provideName = model.provider as any
+ const {
+ currentModel,
+ currentProvider,
+ } = useTextGenerationCurrentProviderAndModelAndModelList(
+ { provider: provideName, model: modelName },
+ )
+
+ const [open, setOpen] = React.useState(false)
+
+ const getParamValue = (param: string) => {
+ const value = model.completion_params?.[param] || '-'
+ if (param === 'stop') {
+ if (Array.isArray(value))
+ return value.join(',')
+ else
+ return '-'
+ }
+
+ return value
+ }
+
+ return (
+ <div className={cn('flex items-center rounded-lg')}>
+ <div className='mr-px flex h-8 shrink-0 items-center gap-1 rounded-l-lg bg-components-input-bg-normal pl-1.5 pr-2'>
+ <ModelIcon
+ className='!h-5 !w-5'
+ provider={currentProvider}
+ modelName={currentModel?.model}
+ />
+ <ModelName
+ modelItem={currentModel!}
+ showMode
+ />
+ </div>
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={4}
+ >
+ <div className='relative'>
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ className='block'
+ >
+ <div className={cn(
+ 'cursor-pointer rounded-r-lg bg-components-button-tertiary-bg p-2 hover:bg-components-button-tertiary-bg-hover',
+ open && 'bg-components-button-tertiary-bg-hover',
+ )}>
+ <RiInformation2Line className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1002]'>
+ <div className='relative w-[280px] overflow-hidden rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg px-4 pb-2 pt-3 shadow-xl'>
+ <div className='system-sm-semibold-uppercase mb-1 h-6 text-text-secondary'>{t('appLog.detail.modelParams')}</div>
+ <div className='py-1'>
+ {['temperature', 'top_p', 'presence_penalty', 'max_tokens', 'stop'].map((param: string, index: number) => {
+ return <div className='flex justify-between py-1.5' key={index}>
+ <span className='system-xs-medium-uppercase text-text-tertiary'>{PARAM_MAP[param as keyof typeof PARAM_MAP]}</span>
+ <span className='system-xs-medium-uppercase text-text-secondary'>{getParamValue(param)}</span>
+ </div>
+ })}
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </div>
+ </PortalToFollowElem>
+ </div>
+ )
+}
+export default React.memo(ModelInfo)
diff --git a/app/components/app/log/var-panel.tsx b/app/components/app/log/var-panel.tsx
new file mode 100644
index 0000000..dd8c231
--- /dev/null
+++ b/app/components/app/log/var-panel.tsx
@@ -0,0 +1,83 @@
+'use client'
+import { useBoolean } from 'ahooks'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiArrowDownSLine,
+ RiArrowRightSLine,
+} from '@remixicon/react'
+import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
+import ImagePreview from '@/app/components/base/image-uploader/image-preview'
+import cn from '@/utils/classnames'
+
+type Props = {
+ varList: { label: string; value: string }[]
+ message_files: string[]
+}
+
+const VarPanel: FC<Props> = ({
+ varList,
+ message_files,
+}) => {
+ const { t } = useTranslation()
+ const [isCollapse, { toggle: toggleCollapse }] = useBoolean(false)
+ const [imagePreviewUrl, setImagePreviewUrl] = useState('')
+
+ return (
+ <div className='rounded-[10px] border border-divider-subtle bg-chat-bubble-bg'>
+ <div
+ className={cn('flex cursor-pointer items-center gap-1 border-b border-divider-subtle px-3 pb-2 pt-2.5 text-text-secondary', isCollapse && 'border-0 pb-2.5')}
+ onClick={toggleCollapse}
+ >
+ <Variable02 className='h-4 w-4' />
+ <div className='system-md-medium grow'>{t('appLog.detail.variables')}</div>
+ {
+ isCollapse
+ ? <RiArrowRightSLine className='h-4 w-4' />
+ : <RiArrowDownSLine className='h-4 w-4' />
+ }
+ </div>
+ {!isCollapse && (
+ <div className='flex max-h-[500px] flex-col gap-2 overflow-y-auto p-3'>
+ {varList.map(({ label, value }, index) => (
+ <div key={index} className='system-xs-medium flex py-2'>
+ <div className='flex w-[128px] shrink-0 text-text-accent'>
+ <span className='shrink-0 opacity-60'>{'{{'}</span>
+ <span className='truncate'>{label}</span>
+ <span className='shrink-0 opacity-60'>{'}}'}</span>
+ </div>
+ <div className='whitespace-pre-wrap pl-2.5 text-text-secondary'>{value}</div>
+ </div>
+ ))}
+
+ {message_files.length > 0 && (
+ <div className='mt-1 flex py-2'>
+ <div className='system-xs-medium w-[128px] shrink-0 text-text-tertiary'>{t('appLog.detail.uploadImages')}</div>
+ <div className="flex space-x-2">
+ {message_files.map((url, index) => (
+ <div
+ key={index}
+ className="ml-2.5 h-16 w-16 cursor-pointer rounded-lg bg-cover bg-center bg-no-repeat"
+ style={{ backgroundImage: `url(${url})` }}
+ onClick={() => setImagePreviewUrl(url)}
+ />
+ ))}
+ </div>
+ </div>
+ )}
+ </div>
+ )}
+ {
+ imagePreviewUrl && (
+ <ImagePreview
+ url={imagePreviewUrl}
+ title={imagePreviewUrl}
+ onCancel={() => setImagePreviewUrl('')}
+ />
+ )
+ }
+ </div>
+ )
+}
+export default React.memo(VarPanel)
diff --git a/app/components/app/overview/apikey-info-panel/index.tsx b/app/components/app/overview/apikey-info-panel/index.tsx
new file mode 100644
index 0000000..7654d49
--- /dev/null
+++ b/app/components/app/overview/apikey-info-panel/index.tsx
@@ -0,0 +1,73 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import Button from '@/app/components/base/button'
+import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
+import { IS_CE_EDITION } from '@/config'
+import { useProviderContext } from '@/context/provider-context'
+import { useModalContext } from '@/context/modal-context'
+
+const APIKeyInfoPanel: FC = () => {
+ const isCloud = !IS_CE_EDITION
+
+ const { isAPIKeySet } = useProviderContext()
+ const { setShowAccountSettingModal } = useModalContext()
+
+ const { t } = useTranslation()
+
+ const [isShow, setIsShow] = useState(true)
+
+ if (isAPIKeySet)
+ return null
+
+ if (!(isShow))
+ return null
+
+ return (
+ <div className={cn('border-components-panel-border bg-components-panel-bg', 'relative mb-6 rounded-2xl border p-8 shadow-md ')}>
+ <div className={cn('text-[24px] font-semibold text-text-primary', isCloud ? 'flex h-8 items-center space-x-1' : 'mb-6 leading-8')}>
+ {isCloud && <em-emoji id={'馃榾'} />}
+ {isCloud
+ ? (
+ <div>{t('appOverview.apiKeyInfo.cloud.trial.title', { providerName: 'OpenAI' })}</div>
+ )
+ : (
+ <div>
+ <div>{t('appOverview.apiKeyInfo.selfHost.title.row1')}</div>
+ <div>{t('appOverview.apiKeyInfo.selfHost.title.row2')}</div>
+ </div>
+ )}
+ </div>
+ {isCloud && (
+ <div className='mt-1 text-sm font-normal text-text-tertiary'>{t(`appOverview.apiKeyInfo.cloud.${'trial'}.description`)}</div>
+ )}
+ <Button
+ variant='primary'
+ className='mt-2 space-x-2'
+ onClick={() => setShowAccountSettingModal({ payload: 'provider' })}
+ >
+ <div className='text-sm font-medium'>{t('appOverview.apiKeyInfo.setAPIBtn')}</div>
+ <LinkExternal02 className='h-4 w-4' />
+ </Button>
+ {!isCloud && (
+ <a
+ className='mt-2 flex h-[26px] items-center space-x-1 p-1 text-xs font-medium text-[#155EEF]'
+ href='https://cloud.dify.ai/apps'
+ target='_blank' rel='noopener noreferrer'
+ >
+ <div>{t('appOverview.apiKeyInfo.tryCloud')}</div>
+ <LinkExternal02 className='h-3 w-3' />
+ </a>
+ )}
+ <div
+ onClick={() => setIsShow(false)}
+ className='absolute right-4 top-4 flex h-8 w-8 cursor-pointer items-center justify-center '>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ )
+}
+export default React.memo(APIKeyInfoPanel)
diff --git a/app/components/app/overview/appCard.tsx b/app/components/app/overview/appCard.tsx
new file mode 100644
index 0000000..04fc8f2
--- /dev/null
+++ b/app/components/app/overview/appCard.tsx
@@ -0,0 +1,273 @@
+'use client'
+import React, { useMemo, useState } from 'react'
+import { usePathname, useRouter } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import {
+ RiBookOpenLine,
+ RiEqualizer2Line,
+ RiExternalLinkLine,
+ RiPaintBrushLine,
+ RiWindowLine,
+} from '@remixicon/react'
+import SettingsModal from './settings'
+import EmbeddedModal from './embedded'
+import CustomizeModal from './customize'
+import style from './style.module.css'
+import type { ConfigParams } from './settings'
+import Tooltip from '@/app/components/base/tooltip'
+import AppBasic from '@/app/components/app-sidebar/basic'
+import { asyncRunSafe, randomString } from '@/utils'
+import Button from '@/app/components/base/button'
+import Switch from '@/app/components/base/switch'
+import Divider from '@/app/components/base/divider'
+import CopyFeedback from '@/app/components/base/copy-feedback'
+import Confirm from '@/app/components/base/confirm'
+import ShareQRCode from '@/app/components/base/qrcode'
+import SecretKeyButton from '@/app/components/develop/secret-key/secret-key-button'
+import type { AppDetailResponse } from '@/models/app'
+import { useAppContext } from '@/context/app-context'
+import type { AppSSO } from '@/types/app'
+import Indicator from '@/app/components/header/indicator'
+
+export type IAppCardProps = {
+ className?: string
+ appInfo: AppDetailResponse & Partial<AppSSO>
+ isInPanel?: boolean
+ cardType?: 'api' | 'webapp'
+ customBgColor?: string
+ onChangeStatus: (val: boolean) => Promise<void>
+ onSaveSiteConfig?: (params: ConfigParams) => Promise<void>
+ onGenerateCode?: () => Promise<void>
+}
+
+function AppCard({
+ appInfo,
+ isInPanel,
+ cardType = 'webapp',
+ customBgColor,
+ onChangeStatus,
+ onSaveSiteConfig,
+ onGenerateCode,
+ className,
+}: IAppCardProps) {
+ const router = useRouter()
+ const pathname = usePathname()
+ const { isCurrentWorkspaceManager, isCurrentWorkspaceEditor } = useAppContext()
+ const [showSettingsModal, setShowSettingsModal] = useState(false)
+ const [showEmbedded, setShowEmbedded] = useState(false)
+ const [showCustomizeModal, setShowCustomizeModal] = useState(false)
+ const [genLoading, setGenLoading] = useState(false)
+ const [showConfirmDelete, setShowConfirmDelete] = useState(false)
+
+ const { t } = useTranslation()
+
+ const OPERATIONS_MAP = useMemo(() => {
+ const operationsMap = {
+ webapp: [
+ { opName: t('appOverview.overview.appInfo.launch'), opIcon: RiExternalLinkLine },
+ ] as { opName: string; opIcon: any }[],
+ api: [{ opName: t('appOverview.overview.apiInfo.doc'), opIcon: RiBookOpenLine }],
+ app: [],
+ }
+ if (appInfo.mode !== 'completion' && appInfo.mode !== 'workflow')
+ operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.embedded.entry'), opIcon: RiWindowLine })
+
+ operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.customize.entry'), opIcon: RiPaintBrushLine })
+
+ if (isCurrentWorkspaceEditor)
+ operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.settings.entry'), opIcon: RiEqualizer2Line })
+
+ return operationsMap
+ }, [isCurrentWorkspaceEditor, appInfo, t])
+
+ const isApp = cardType === 'webapp'
+ const basicName = isApp
+ ? appInfo?.site?.title
+ : t('appOverview.overview.apiInfo.title')
+ const toggleDisabled = isApp ? !isCurrentWorkspaceEditor : !isCurrentWorkspaceManager
+ const runningStatus = isApp ? appInfo.enable_site : appInfo.enable_api
+ const { app_base_url, access_token } = appInfo.site ?? {}
+ const appMode = (appInfo.mode !== 'completion' && appInfo.mode !== 'workflow') ? 'chat' : appInfo.mode
+ const appUrl = `${app_base_url}/${appMode}/${access_token}`
+ const apiUrl = appInfo?.api_base_url
+
+ const genClickFuncByName = (opName: string) => {
+ switch (opName) {
+ case t('appOverview.overview.appInfo.launch'):
+ return () => {
+ window.open(appUrl, '_blank')
+ }
+ case t('appOverview.overview.appInfo.customize.entry'):
+ return () => {
+ setShowCustomizeModal(true)
+ }
+ case t('appOverview.overview.appInfo.settings.entry'):
+ return () => {
+ setShowSettingsModal(true)
+ }
+ case t('appOverview.overview.appInfo.embedded.entry'):
+ return () => {
+ setShowEmbedded(true)
+ }
+ default:
+ // jump to page develop
+ return () => {
+ const pathSegments = pathname.split('/')
+ pathSegments.pop()
+ router.push(`${pathSegments.join('/')}/develop`)
+ }
+ }
+ }
+
+ const onGenCode = async () => {
+ if (onGenerateCode) {
+ setGenLoading(true)
+ await asyncRunSafe(onGenerateCode())
+ setGenLoading(false)
+ }
+ }
+
+ return (
+ <div
+ className={
+ `${isInPanel ? 'border-l-[0.5px] border-t' : 'border-[0.5px] shadow-xs'} w-full max-w-full rounded-xl border-effects-highlight ${className ?? ''}`}
+ >
+ <div className={`${customBgColor ?? 'bg-background-default'} rounded-xl`}>
+ <div className='flex w-full flex-col items-start justify-center gap-3 self-stretch border-b-[0.5px] border-divider-subtle p-3'>
+ <div className='flex w-full items-center gap-3 self-stretch'>
+ <AppBasic
+ iconType={cardType}
+ icon={appInfo.icon}
+ icon_background={appInfo.icon_background}
+ name={basicName}
+ type={
+ isApp
+ ? t('appOverview.overview.appInfo.explanation')
+ : t('appOverview.overview.apiInfo.explanation')
+ }
+ />
+ <div className='flex items-center gap-1'>
+ <Indicator color={runningStatus ? 'green' : 'yellow'} />
+ <div className={`${runningStatus ? 'text-text-success' : 'text-text-warning'} system-xs-semibold-uppercase`}>
+ {runningStatus
+ ? t('appOverview.overview.status.running')
+ : t('appOverview.overview.status.disable')}
+ </div>
+ </div>
+ <Switch defaultValue={runningStatus} onChange={onChangeStatus} disabled={toggleDisabled} />
+ </div>
+ <div className='flex flex-col items-start justify-center self-stretch'>
+ <div className="system-xs-medium pb-1 text-text-tertiary">
+ {isApp
+ ? t('appOverview.overview.appInfo.accessibleAddress')
+ : t('appOverview.overview.apiInfo.accessibleAddress')}
+ </div>
+ <div className="inline-flex h-9 w-full items-center gap-0.5 rounded-lg bg-components-input-bg-normal p-1 pl-2">
+ <div className="flex h-4 min-w-0 flex-1 items-start justify-start gap-2 px-1">
+ <div className="overflow-hidden text-ellipsis whitespace-nowrap text-xs font-medium text-text-secondary">
+ {isApp ? appUrl : apiUrl}
+ </div>
+ </div>
+ <CopyFeedback
+ content={isApp ? appUrl : apiUrl}
+ className={'!size-6'}
+ />
+ {isApp && <ShareQRCode content={isApp ? appUrl : apiUrl} className='z-50 !size-6 rounded-md hover:bg-state-base-hover' selectorId={randomString(8)} />}
+ {isApp && <Divider type="vertical" className="!mx-0.5 !h-3.5 shrink-0" />}
+ {/* button copy link/ button regenerate */}
+ {showConfirmDelete && (
+ <Confirm
+ type='warning'
+ title={t('appOverview.overview.appInfo.regenerate')}
+ content={t('appOverview.overview.appInfo.regenerateNotice')}
+ isShow={showConfirmDelete}
+ onConfirm={() => {
+ onGenCode()
+ setShowConfirmDelete(false)
+ }}
+ onCancel={() => setShowConfirmDelete(false)}
+ />
+ )}
+ {isApp && isCurrentWorkspaceManager && (
+ <Tooltip
+ popupContent={t('appOverview.overview.appInfo.regenerate') || ''}
+ >
+ <div
+ className="h-6 w-6 cursor-pointer rounded-md hover:bg-state-base-hover"
+ onClick={() => setShowConfirmDelete(true)}
+ >
+ <div
+ className={
+ `h-full w-full ${style.refreshIcon} ${genLoading ? style.generateLogo : ''}`}
+ ></div>
+ </div>
+ </Tooltip>
+ )}
+ </div>
+ </div>
+ </div>
+ <div className={'flex items-center gap-1 self-stretch p-3'}>
+ {!isApp && <SecretKeyButton appId={appInfo.id} />}
+ {OPERATIONS_MAP[cardType].map((op) => {
+ const disabled
+ = op.opName === t('appOverview.overview.appInfo.settings.entry')
+ ? false
+ : !runningStatus
+ return (
+ <Button
+ className="mr-1 min-w-[88px]"
+ size="small"
+ variant={'ghost'}
+ key={op.opName}
+ onClick={genClickFuncByName(op.opName)}
+ disabled={disabled}
+ >
+ <Tooltip
+ popupContent={
+ t('appOverview.overview.appInfo.preUseReminder') ?? ''
+ }
+ popupClassName={disabled ? 'mt-[-8px]' : '!hidden'}
+ >
+ <div className="flex items-center justify-center gap-[1px]">
+ <op.opIcon className="h-3.5 w-3.5" />
+ <div className={`${runningStatus ? 'text-text-tertiary' : 'text-components-button-ghost-text-disabled'} system-xs-medium px-[3px]`}>{op.opName}</div>
+ </div>
+ </Tooltip>
+ </Button>
+ )
+ })}
+ </div>
+ </div>
+ {isApp
+ ? (
+ <>
+ <SettingsModal
+ isChat={appMode === 'chat'}
+ appInfo={appInfo}
+ isShow={showSettingsModal}
+ onClose={() => setShowSettingsModal(false)}
+ onSave={onSaveSiteConfig}
+ />
+ <EmbeddedModal
+ siteInfo={appInfo.site}
+ isShow={showEmbedded}
+ onClose={() => setShowEmbedded(false)}
+ appBaseUrl={app_base_url}
+ accessToken={access_token}
+ />
+ <CustomizeModal
+ isShow={showCustomizeModal}
+ linkUrl=""
+ onClose={() => setShowCustomizeModal(false)}
+ appId={appInfo.id}
+ api_base_url={appInfo.api_base_url}
+ mode={appInfo.mode}
+ />
+ </>
+ )
+ : null}
+ </div>
+ )
+}
+
+export default AppCard
diff --git a/app/components/app/overview/appChart.tsx b/app/components/app/overview/appChart.tsx
new file mode 100644
index 0000000..4e74eda
--- /dev/null
+++ b/app/components/app/overview/appChart.tsx
@@ -0,0 +1,450 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import ReactECharts from 'echarts-for-react'
+import type { EChartsOption } from 'echarts'
+import useSWR from 'swr'
+import dayjs from 'dayjs'
+import { get } from 'lodash-es'
+import Decimal from 'decimal.js'
+import { useTranslation } from 'react-i18next'
+import { formatNumber } from '@/utils/format'
+import Basic from '@/app/components/app-sidebar/basic'
+import Loading from '@/app/components/base/loading'
+import type { AppDailyConversationsResponse, AppDailyEndUsersResponse, AppDailyMessagesResponse, AppTokenCostsResponse } from '@/models/app'
+import { getAppDailyConversations, getAppDailyEndUsers, getAppDailyMessages, getAppStatistics, getAppTokenCosts, getWorkflowDailyConversations } from '@/service/apps'
+const valueFormatter = (v: string | number) => v
+
+const COLOR_TYPE_MAP = {
+ green: {
+ lineColor: 'rgba(6, 148, 162, 1)',
+ bgColor: ['rgba(6, 148, 162, 0.2)', 'rgba(67, 174, 185, 0.08)'],
+ },
+ orange: {
+ lineColor: 'rgba(255, 138, 76, 1)',
+ bgColor: ['rgba(254, 145, 87, 0.2)', 'rgba(255, 138, 76, 0.1)'],
+ },
+ blue: {
+ lineColor: 'rgba(28, 100, 242, 1)',
+ bgColor: ['rgba(28, 100, 242, 0.3)', 'rgba(28, 100, 242, 0.1)'],
+ },
+}
+
+const COMMON_COLOR_MAP = {
+ label: '#9CA3AF',
+ splitLineLight: '#F3F4F6',
+ splitLineDark: '#E5E7EB',
+}
+
+type IColorType = 'green' | 'orange' | 'blue'
+type IChartType = 'messages' | 'conversations' | 'endUsers' | 'costs' | 'workflowCosts'
+type IChartConfigType = { colorType: IColorType; showTokens?: boolean }
+
+const commonDateFormat = 'MMM D, YYYY'
+
+const CHART_TYPE_CONFIG: Record<string, IChartConfigType> = {
+ messages: {
+ colorType: 'green',
+ },
+ conversations: {
+ colorType: 'green',
+ },
+ endUsers: {
+ colorType: 'orange',
+ },
+ costs: {
+ colorType: 'blue',
+ showTokens: true,
+ },
+ workflowCosts: {
+ colorType: 'blue',
+ },
+}
+
+const sum = (arr: Decimal.Value[]): number => {
+ return Decimal.sum(...arr).toNumber()
+}
+
+const defaultPeriod = {
+ start: dayjs().subtract(7, 'day').format(commonDateFormat),
+ end: dayjs().format(commonDateFormat),
+}
+
+export type PeriodParams = {
+ name: string
+ query?: {
+ start: string
+ end: string
+ }
+}
+
+export type IBizChartProps = {
+ period: PeriodParams
+ id: string
+}
+
+export type IChartProps = {
+ className?: string
+ basicInfo: { title: string; explanation: string; timePeriod: string }
+ valueKey?: string
+ isAvg?: boolean
+ unit?: string
+ yMax?: number
+ chartType: IChartType
+ chartData: AppDailyMessagesResponse | AppDailyConversationsResponse | AppDailyEndUsersResponse | AppTokenCostsResponse | { data: Array<{ date: string; count: number }> }
+}
+
+const Chart: React.FC<IChartProps> = ({
+ basicInfo: { title, explanation, timePeriod },
+ chartType = 'conversations',
+ chartData,
+ valueKey,
+ isAvg,
+ unit = '',
+ yMax,
+ className,
+}) => {
+ const { t } = useTranslation()
+ const statistics = chartData.data
+ const statisticsLen = statistics.length
+ const extraDataForMarkLine = new Array(statisticsLen >= 2 ? statisticsLen - 2 : statisticsLen).fill('1')
+ extraDataForMarkLine.push('')
+ extraDataForMarkLine.unshift('')
+
+ const xData = statistics.map(({ date }) => date)
+ const yField = valueKey || Object.keys(statistics[0]).find(name => name.includes('count')) || ''
+ const yData = statistics.map((item) => {
+ // @ts-expect-error field is valid
+ return item[yField] || 0
+ })
+
+ const options: EChartsOption = {
+ dataset: {
+ dimensions: ['date', yField],
+ source: statistics,
+ },
+ grid: { top: 8, right: 36, bottom: 0, left: 0, containLabel: true },
+ tooltip: {
+ trigger: 'item',
+ position: 'top',
+ borderWidth: 0,
+ },
+ xAxis: [{
+ type: 'category',
+ boundaryGap: false,
+ axisLabel: {
+ color: COMMON_COLOR_MAP.label,
+ hideOverlap: true,
+ overflow: 'break',
+ formatter(value) {
+ return dayjs(value).format(commonDateFormat)
+ },
+ },
+ axisLine: { show: false },
+ axisTick: { show: false },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ color: COMMON_COLOR_MAP.splitLineLight,
+ width: 1,
+ type: [10, 10],
+ },
+ interval(index) {
+ return index === 0 || index === xData.length - 1
+ },
+ },
+ }, {
+ position: 'bottom',
+ boundaryGap: false,
+ data: extraDataForMarkLine,
+ axisLabel: { show: false },
+ axisLine: { show: false },
+ axisTick: { show: false },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ color: COMMON_COLOR_MAP.splitLineDark,
+ },
+ interval(index, value) {
+ return !!value
+ },
+ },
+ }],
+ yAxis: {
+ max: yMax ?? 'dataMax',
+ type: 'value',
+ axisLabel: { color: COMMON_COLOR_MAP.label, hideOverlap: true },
+ splitLine: {
+ lineStyle: {
+ color: COMMON_COLOR_MAP.splitLineLight,
+ },
+ },
+ },
+ series: [
+ {
+ type: 'line',
+ showSymbol: true,
+ // symbol: 'circle',
+ // triggerLineEvent: true,
+ symbolSize: 4,
+ lineStyle: {
+ color: COLOR_TYPE_MAP[CHART_TYPE_CONFIG[chartType].colorType].lineColor,
+ width: 2,
+ },
+ itemStyle: {
+ color: COLOR_TYPE_MAP[CHART_TYPE_CONFIG[chartType].colorType].lineColor,
+ },
+ areaStyle: {
+ color: {
+ type: 'linear',
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0, color: COLOR_TYPE_MAP[CHART_TYPE_CONFIG[chartType].colorType].bgColor[0],
+ }, {
+ offset: 1, color: COLOR_TYPE_MAP[CHART_TYPE_CONFIG[chartType].colorType].bgColor[1],
+ }],
+ global: false,
+ },
+ },
+ tooltip: {
+ padding: [8, 12, 8, 12],
+ formatter(params) {
+ return `<div style='color:#6B7280;font-size:12px'>${params.name}</div>
+ <div style='font-size:14px;color:#1F2A37'>${valueFormatter((params.data as any)[yField])}
+ ${!CHART_TYPE_CONFIG[chartType].showTokens
+ ? ''
+ : `<span style='font-size:12px'>
+ <span style='margin-left:4px;color:#6B7280'>(</span>
+ <span style='color:#FF8A4C'>~$${get(params.data, 'total_price', 0)}</span>
+ <span style='color:#6B7280'>)</span>
+ </span>`}
+ </div>`
+ },
+ },
+ },
+ ],
+ }
+ const sumData = isAvg ? (sum(yData) / yData.length) : sum(yData)
+
+ return (
+ <div className={`flex w-full flex-col rounded-xl bg-components-chart-bg px-6 py-4 shadow-xs ${className ?? ''}`}>
+ <div className='mb-3'>
+ <Basic name={title} type={timePeriod} hoverTip={explanation} />
+ </div>
+ <div className='mb-4 flex-1'>
+ <Basic
+ isExtraInLine={CHART_TYPE_CONFIG[chartType].showTokens}
+ name={chartType !== 'costs' ? (`${sumData.toLocaleString()} ${unit}`) : `${sumData < 1000 ? sumData : (`${formatNumber(Math.round(sumData / 1000))}k`)}`}
+ type={!CHART_TYPE_CONFIG[chartType].showTokens
+ ? ''
+ : <span>{t('appOverview.analysis.tokenUsage.consumed')} Tokens<span className='text-sm'>
+ <span className='ml-1 text-text-tertiary'>(</span>
+ <span className='text-orange-400'>~{sum(statistics.map(item => Number.parseFloat(get(item, 'total_price', '0')))).toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 4 })}</span>
+ <span className='text-text-tertiary'>)</span>
+ </span></span>}
+ textStyle={{ main: `!text-3xl !font-normal ${sumData === 0 ? '!text-text-quaternary' : ''}` }} />
+ </div>
+ <ReactECharts option={options} style={{ height: 160 }} />
+ </div>
+ )
+}
+
+const getDefaultChartData = ({ start, end, key = 'count' }: { start: string; end: string; key?: string }) => {
+ const diffDays = dayjs(end).diff(dayjs(start), 'day')
+ return Array.from({ length: diffDays || 1 }, () => ({ date: '', [key]: 0 })).map((item, index) => {
+ item.date = dayjs(start).add(index, 'day').format(commonDateFormat)
+ return item
+ })
+}
+
+export const MessagesChart: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+ const { data: response } = useSWR({ url: `/apps/${id}/statistics/daily-messages`, params: period.query }, getAppDailyMessages)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.totalMessages.title'), explanation: t('appOverview.analysis.totalMessages.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData(period.query ?? defaultPeriod) }}
+ chartType='messages'
+ {...(noDataFlag && { yMax: 500 })}
+ />
+}
+
+export const ConversationsChart: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+ const { data: response } = useSWR({ url: `/apps/${id}/statistics/daily-conversations`, params: period.query }, getAppDailyConversations)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.totalConversations.title'), explanation: t('appOverview.analysis.totalConversations.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData(period.query ?? defaultPeriod) }}
+ chartType='conversations'
+ {...(noDataFlag && { yMax: 500 })}
+ />
+}
+
+export const EndUsersChart: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+
+ const { data: response } = useSWR({ url: `/apps/${id}/statistics/daily-end-users`, id, params: period.query }, getAppDailyEndUsers)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.activeUsers.title'), explanation: t('appOverview.analysis.activeUsers.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData(period.query ?? defaultPeriod) }}
+ chartType='endUsers'
+ {...(noDataFlag && { yMax: 500 })}
+ />
+}
+
+export const AvgSessionInteractions: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+ const { data: response } = useSWR({ url: `/apps/${id}/statistics/average-session-interactions`, params: period.query }, getAppStatistics)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.avgSessionInteractions.title'), explanation: t('appOverview.analysis.avgSessionInteractions.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData({ ...(period.query ?? defaultPeriod), key: 'interactions' }) } as any}
+ chartType='conversations'
+ valueKey='interactions'
+ isAvg
+ {...(noDataFlag && { yMax: 500 })}
+ />
+}
+
+export const AvgResponseTime: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+ const { data: response } = useSWR({ url: `/apps/${id}/statistics/average-response-time`, params: period.query }, getAppStatistics)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.avgResponseTime.title'), explanation: t('appOverview.analysis.avgResponseTime.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData({ ...(period.query ?? defaultPeriod), key: 'latency' }) } as any}
+ valueKey='latency'
+ chartType='conversations'
+ isAvg
+ unit={t('appOverview.analysis.ms') as string}
+ {...(noDataFlag && { yMax: 500 })}
+ />
+}
+
+export const TokenPerSecond: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+ const { data: response } = useSWR({ url: `/apps/${id}/statistics/tokens-per-second`, params: period.query }, getAppStatistics)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.tps.title'), explanation: t('appOverview.analysis.tps.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData({ ...(period.query ?? defaultPeriod), key: 'tps' }) } as any}
+ valueKey='tps'
+ chartType='conversations'
+ isAvg
+ unit={t('appOverview.analysis.tokenPS') as string}
+ {...(noDataFlag && { yMax: 100 })}
+ className="min-w-0"
+ />
+}
+
+export const UserSatisfactionRate: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+ const { data: response } = useSWR({ url: `/apps/${id}/statistics/user-satisfaction-rate`, params: period.query }, getAppStatistics)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.userSatisfactionRate.title'), explanation: t('appOverview.analysis.userSatisfactionRate.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData({ ...(period.query ?? defaultPeriod), key: 'rate' }) } as any}
+ valueKey='rate'
+ chartType='endUsers'
+ isAvg
+ {...(noDataFlag && { yMax: 1000 })}
+ className='h-full'
+ />
+}
+
+export const CostChart: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+
+ const { data: response } = useSWR({ url: `/apps/${id}/statistics/token-costs`, params: period.query }, getAppTokenCosts)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.tokenUsage.title'), explanation: t('appOverview.analysis.tokenUsage.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData(period.query ?? defaultPeriod) }}
+ chartType='costs'
+ {...(noDataFlag && { yMax: 100 })}
+ />
+}
+
+export const WorkflowMessagesChart: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+ const { data: response } = useSWR({ url: `/apps/${id}/workflow/statistics/daily-conversations`, params: period.query }, getWorkflowDailyConversations)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.totalMessages.title'), explanation: t('appOverview.analysis.totalMessages.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData({ ...(period.query ?? defaultPeriod), key: 'runs' }) }}
+ chartType='conversations'
+ valueKey='runs'
+ {...(noDataFlag && { yMax: 500 })}
+ />
+}
+
+export const WorkflowDailyTerminalsChart: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+
+ const { data: response } = useSWR({ url: `/apps/${id}/workflow/statistics/daily-terminals`, id, params: period.query }, getAppDailyEndUsers)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.activeUsers.title'), explanation: t('appOverview.analysis.activeUsers.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData(period.query ?? defaultPeriod) }}
+ chartType='endUsers'
+ {...(noDataFlag && { yMax: 500 })}
+ />
+}
+
+export const WorkflowCostChart: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+
+ const { data: response } = useSWR({ url: `/apps/${id}/workflow/statistics/token-costs`, params: period.query }, getAppTokenCosts)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.tokenUsage.title'), explanation: t('appOverview.analysis.tokenUsage.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData(period.query ?? defaultPeriod) }}
+ chartType='workflowCosts'
+ {...(noDataFlag && { yMax: 100 })}
+ />
+}
+
+export const AvgUserInteractions: FC<IBizChartProps> = ({ id, period }) => {
+ const { t } = useTranslation()
+ const { data: response } = useSWR({ url: `/apps/${id}/workflow/statistics/average-app-interactions`, params: period.query }, getAppStatistics)
+ if (!response)
+ return <Loading />
+ const noDataFlag = !response.data || response.data.length === 0
+ return <Chart
+ basicInfo={{ title: t('appOverview.analysis.avgUserInteractions.title'), explanation: t('appOverview.analysis.avgUserInteractions.explanation'), timePeriod: period.name }}
+ chartData={!noDataFlag ? response : { data: getDefaultChartData({ ...(period.query ?? defaultPeriod), key: 'interactions' }) } as any}
+ chartType='conversations'
+ valueKey='interactions'
+ isAvg
+ {...(noDataFlag && { yMax: 500 })}
+ />
+}
+
+export default Chart
diff --git a/app/components/app/overview/assets/chromeplugin-install.svg b/app/components/app/overview/assets/chromeplugin-install.svg
new file mode 100644
index 0000000..a94d0d9
--- /dev/null
+++ b/app/components/app/overview/assets/chromeplugin-install.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.91722 6.7298L3.08403 3.65525C2.93723 3.40905 2.86384 3.28596 2.84729 3.14436C2.83386 3.02937 2.85797 2.8842 2.90785 2.77973C2.96928 2.65108 3.06488 2.5699 3.2561 2.40754C4.53491 1.32168 6.19097 0.666626 8.00002 0.666626C10.5383 0.666626 12.7753 1.95619 14.0918 3.91589C14.2371 4.13226 14.3098 4.24045 14.3034 4.35234C14.2981 4.44429 14.2454 4.54327 14.172 4.59892C14.0827 4.66663 13.9425 4.66663 13.6621 4.66663H8.00002C6.60882 4.66663 5.41668 5.51889 4.91722 6.7298Z" fill="white"/>
+<path d="M0.666687 7.99996C0.666687 6.87421 0.92035 5.80771 1.37364 4.85449C1.48535 4.61957 1.5412 4.50211 1.64056 4.45053C1.72221 4.40813 1.83412 4.40288 1.91938 4.43744C2.02313 4.4795 2.0948 4.5997 2.23814 4.8401L5.06356 9.57876C5.62637 10.6234 6.73029 11.3333 8.00002 11.3333C8.13686 11.3333 8.27178 11.325 8.4043 11.309L6.62101 14.4166C6.4785 14.665 6.40724 14.7891 6.29186 14.873C6.19827 14.941 6.05961 14.9912 5.94418 14.9988C5.80188 15.0083 5.68457 14.9648 5.44995 14.8778C2.65701 13.8418 0.666687 11.1533 0.666687 7.99996Z" fill="white"/>
+<path d="M7.81791 15.0098C7.73532 15.1537 7.83408 15.3333 8.00002 15.3333C12.0501 15.3333 15.3334 12.05 15.3334 7.99996C15.3334 7.58673 15.2992 7.18148 15.2335 6.78688C15.1924 6.53989 15.1718 6.41639 15.0928 6.29755C15.0287 6.20113 14.9162 6.10577 14.8105 6.05838C14.6803 5.99996 14.5371 5.99996 14.2505 5.99996H10.6669C11.0854 6.55707 11.3334 7.24956 11.3334 7.99996C11.3334 8.65299 11.1456 9.26216 10.821 9.77642L7.81791 15.0098Z" fill="white"/>
+<path d="M10 7.99996C10 9.10453 9.10459 9.99996 8.00002 9.99996C6.89545 9.99996 6.00002 9.10453 6.00002 7.99996C6.00002 6.89539 6.89545 5.99996 8.00002 5.99996C9.10459 5.99996 10 6.89539 10 7.99996Z" fill="white"/>
+</svg>
diff --git a/app/components/app/overview/assets/chromeplugin-option.svg b/app/components/app/overview/assets/chromeplugin-option.svg
new file mode 100644
index 0000000..c35a083
--- /dev/null
+++ b/app/components/app/overview/assets/chromeplugin-option.svg
@@ -0,0 +1,159 @@
+<svg width="180" height="131" viewBox="0 0 180 131" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g filter="url(#filter0_d_40_1547)">
+<g clip-path="url(#clip0_40_1547)">
+<rect width="180" height="128" rx="6" fill="#FCFCFD"/>
+<mask id="path-3-inside-1_40_1547" fill="white">
+<path d="M0 0H180V10H0V0Z"/>
+</mask>
+<path d="M0 0H180V10H0V0Z" fill="#F2F4F7"/>
+<circle cx="5.5" cy="5" r="1.5" fill="#D9D9D9"/>
+<circle cx="10.5" cy="5" r="1.5" fill="#D9D9D9"/>
+<circle cx="15.5" cy="5" r="1.5" fill="#D9D9D9"/>
+<g opacity="0.05">
+<rect x="58" y="3" width="64" height="4" rx="1.28571" fill="#101828"/>
+</g>
+<path d="M156.499 3C156.92 3 157.289 3.08357 157.604 3.25071C157.919 3.41785 158.162 3.65337 158.333 3.95726C158.508 4.25736 158.595 4.60494 158.595 5C158.595 5.39126 158.508 5.73884 158.333 6.04274C158.162 6.34663 157.917 6.58215 157.598 6.74929C157.283 6.91643 156.916 7 156.499 7H155V3H156.499Z" fill="white" fill-opacity="0.9"/>
+<path d="M156.499 3C156.92 3 157.289 3.08357 157.604 3.25071C157.919 3.41785 158.162 3.65337 158.333 3.95726C158.508 4.25736 158.595 4.60494 158.595 5C158.595 5.39126 158.508 5.73884 158.333 6.04274C158.162 6.34663 157.917 6.58215 157.598 6.74929C157.283 6.91643 156.916 7 156.499 7H155V3H156.499Z" fill="url(#paint0_angular_40_1547)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M162.595 3.16669C161.583 3.16669 160.762 3.9875 160.762 5.00002C160.762 6.01254 161.583 6.83335 162.595 6.83335C163.608 6.83335 164.429 6.01254 164.429 5.00002C164.429 3.9875 163.608 3.16669 162.595 3.16669ZM162.38 4.28454C162.445 4.21945 162.445 4.11392 162.38 4.04884C162.315 3.98375 162.209 3.98375 162.144 4.04884L161.644 4.54884C161.579 4.61392 161.579 4.71945 161.644 4.78454L162.144 5.28454C162.209 5.34963 162.315 5.34963 162.38 5.28454C162.445 5.21945 162.445 5.11392 162.38 5.04884L161.998 4.66669L162.38 4.28454ZM163.047 4.7155C162.982 4.65042 162.876 4.65042 162.811 4.7155C162.746 4.78059 162.746 4.88612 162.811 4.9512L163.193 5.33335L162.811 5.7155C162.746 5.78059 162.746 5.88612 162.811 5.9512C162.876 6.01629 162.982 6.01629 163.047 5.9512L163.547 5.4512C163.612 5.38612 163.612 5.28059 163.547 5.2155L163.047 4.7155Z" fill="#D0D5DD"/>
+<path d="M168.663 3.19751C168.618 3.1884 168.573 3.1884 168.528 3.19751C168.477 3.20804 168.431 3.23368 168.395 3.25406L168.385 3.2596C168.091 3.42284 167.594 3.69911 167.314 3.85488C167.246 3.8927 167.212 3.91161 167.2 3.9366C167.191 3.95839 167.19 3.98339 167.2 4.00523C167.212 4.03028 167.245 4.04938 167.313 4.08758L168.53 4.77196C168.554 4.78537 168.566 4.79208 168.578 4.79471C168.59 4.79703 168.601 4.79703 168.612 4.79471C168.625 4.79208 168.637 4.78537 168.661 4.77196L169.877 4.08757C169.945 4.04938 169.979 4.03028 169.991 4.00523C170 3.98339 170 3.95839 169.99 3.9366C169.979 3.91161 169.945 3.8927 169.877 3.85488C169.597 3.69911 169.1 3.42284 168.806 3.2596L168.796 3.25406C168.76 3.23368 168.714 3.20804 168.663 3.19751Z" fill="#D0D5DD"/>
+<path d="M170.261 4.48169C170.261 4.40697 170.261 4.36961 170.246 4.34779C170.232 4.32876 170.211 4.31641 170.187 4.31378C170.161 4.31076 170.128 4.32912 170.063 4.36582L168.83 5.0592C168.805 5.07312 168.793 5.08008 168.784 5.08992C168.776 5.09863 168.77 5.10893 168.766 5.12015C168.762 5.13282 168.762 5.14702 168.762 5.17541V6.53795C168.762 6.61248 168.762 6.64975 168.778 6.67155C168.791 6.69056 168.812 6.70295 168.836 6.70567C168.862 6.70879 168.895 6.69076 168.96 6.65469C169.238 6.50047 169.742 6.22017 170.039 6.05524L170.05 6.04943C170.088 6.02821 170.137 6.00153 170.174 5.96117C170.206 5.92627 170.23 5.88491 170.245 5.83985C170.262 5.78774 170.262 5.73244 170.262 5.68846L170.262 5.67644C170.262 5.34926 170.262 4.79272 170.261 4.48169Z" fill="#D0D5DD"/>
+<path d="M168.231 6.65469C168.296 6.69075 168.328 6.70879 168.355 6.70567C168.378 6.70295 168.399 6.69056 168.413 6.67155C168.429 6.64975 168.429 6.61248 168.429 6.53795V5.17541C168.429 5.14702 168.429 5.13283 168.425 5.12015C168.421 5.10894 168.415 5.09864 168.407 5.08993C168.398 5.08008 168.386 5.07312 168.361 5.0592L167.128 4.36583C167.063 4.32912 167.03 4.31077 167.004 4.31378C166.98 4.31641 166.959 4.32876 166.945 4.3478C166.93 4.36961 166.93 4.40697 166.929 4.4817C166.929 4.79272 166.929 5.34926 166.929 5.67644L166.929 5.68846C166.929 5.73244 166.928 5.78774 166.946 5.83985C166.96 5.88491 166.985 5.92627 167.017 5.96117C167.054 6.00153 167.103 6.02821 167.141 6.04943L167.152 6.05524C167.449 6.22017 167.953 6.50047 168.231 6.65469Z" fill="#D0D5DD"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M173.679 3.75002C173.679 3.42785 173.94 3.16669 174.262 3.16669C174.584 3.16669 174.845 3.42785 174.845 3.75002V3.83335L174.851 3.83335C174.963 3.83335 175.055 3.83335 175.13 3.8385C175.209 3.84383 175.281 3.85526 175.351 3.8841C175.514 3.95176 175.644 4.08155 175.711 4.2449C175.74 4.31453 175.752 4.38688 175.757 4.4651C175.759 4.5007 175.761 4.54002 175.761 4.58335H175.845C176.168 4.58335 176.429 4.84452 176.429 5.16669C176.429 5.48885 176.168 5.75002 175.845 5.75002H175.762V5.87357C175.762 6.00773 175.762 6.11846 175.755 6.20866C175.747 6.30234 175.731 6.38846 175.689 6.46935C175.626 6.59479 175.524 6.69678 175.398 6.76069C175.317 6.80191 175.231 6.81833 175.137 6.82599C175.047 6.83336 174.937 6.83336 174.802 6.83335H174.679C174.587 6.83335 174.512 6.75873 174.512 6.66669V6.37502C174.512 6.25996 174.419 6.16669 174.304 6.16669C174.189 6.16669 174.095 6.25996 174.095 6.37502V6.66669C174.095 6.75873 174.021 6.83335 173.929 6.83335H173.722C173.588 6.83336 173.477 6.83336 173.387 6.82599C173.293 6.81833 173.207 6.80191 173.126 6.76069C173.001 6.69678 172.899 6.59479 172.835 6.46935C172.794 6.38846 172.777 6.30234 172.77 6.20866C172.762 6.11846 172.762 6.00773 172.762 5.87357L172.762 5.58335C172.762 5.49131 172.837 5.41669 172.929 5.41669H173.179C173.317 5.41669 173.429 5.30476 173.429 5.16669C173.429 5.02862 173.317 4.91669 173.179 4.91669H172.929C172.837 4.91669 172.762 4.84207 172.762 4.75002L172.762 4.74431C172.762 4.63268 172.762 4.54053 172.767 4.4651C172.773 4.38688 172.784 4.31453 172.813 4.2449C172.881 4.08155 173.01 3.95176 173.174 3.8841C173.243 3.85526 173.316 3.84383 173.394 3.8385C173.469 3.83335 173.561 3.83335 173.673 3.83335L173.679 3.83335L173.679 3.75002Z" fill="#D0D5DD"/>
+<path d="M180 9.5H0V10.5H180V9.5Z" fill="#EAECF0" mask="url(#path-3-inside-1_40_1547)"/>
+<rect width="180" height="118" transform="translate(0 10)" fill="#F2F4F7"/>
+<mask id="path-13-inside-2_40_1547" fill="white">
+<path d="M0 10H180V22H0V10Z"/>
+</mask>
+<path d="M0 10H180V22H0V10Z" fill="#FCFCFD"/>
+<circle opacity="0.1" cx="10.5" cy="16" r="2.5" fill="#101828"/>
+<g opacity="0.1">
+<rect x="15" y="15.1429" width="15.4286" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="130.286" y="15.1429" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="141.714" y="15.1429" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="153.143" y="15.1429" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="164.571" y="15.1429" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<path d="M180 21.5H0V22.5H180V21.5Z" fill="black" fill-opacity="0.05" mask="url(#path-13-inside-2_40_1547)"/>
+<rect width="67" height="118" transform="translate(113 10)" fill="url(#paint1_radial_40_1547)"/>
+<g filter="url(#filter1_dd_40_1547)">
+<g clip-path="url(#clip1_40_1547)">
+<rect x="118" y="12" width="60" height="86" rx="4" fill="#F2F4F7"/>
+<mask id="path-23-inside-3_40_1547" fill="white">
+<path d="M118 12H178V21.8578H118V12Z"/>
+</mask>
+<path d="M118 12H178V21.8578H118V12Z" fill="#F9FAFB"/>
+<g opacity="0.12">
+<rect x="138.571" y="16.0718" width="18.8571" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<path d="M178 21.763H118V21.9526H178V21.763Z" fill="#EAECF0" mask="url(#path-23-inside-3_40_1547)"/>
+<g clip-path="url(#clip2_40_1547)">
+<rect width="60" height="76.1422" transform="translate(118 21.8578)" fill="#F9FAFB"/>
+<rect width="60" height="76.1422" transform="translate(118 21.8578)" fill="white"/>
+<g clip-path="url(#clip3_40_1547)">
+<rect x="120.934" y="25.9667" width="12" height="12" rx="6" fill="#D5F5F6"/>
+<path d="M123.434 35.4567H130.434V28.4567H123.434V35.4567Z" fill="url(#pattern0)"/>
+<rect x="121.014" y="26.047" width="11.8393" height="11.8393" rx="5.91964" stroke="black" stroke-opacity="0.05" stroke-width="0.160714"/>
+<path d="M137.033 25.8578H166.738C169.619 25.8578 171.059 25.8578 172.159 26.4183C173.126 26.9114 173.913 27.6981 174.406 28.6658C174.967 29.766 174.967 31.2061 174.967 34.0864V35.6292C174.967 38.5095 174.967 39.9496 174.406 41.0497C173.913 42.0174 173.126 42.8042 172.159 43.2973C171.059 43.8578 169.619 43.8578 166.738 43.8578H145.262C142.382 43.8578 140.941 43.8578 139.841 43.2973C138.874 42.8042 138.087 42.0174 137.594 41.0497C137.033 39.9496 137.033 38.5095 137.033 35.6292V25.8578Z" fill="#F2F4F7"/>
+<g opacity="0.1">
+<rect x="142.176" y="29.715" width="27.6479" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="142.176" y="34.0007" width="27.6479" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="142.176" y="38.2864" width="23.4286" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<path d="M134.794 26.3574C134.652 26.1438 134.805 25.8577 135.062 25.8577H137.033V29.7148L134.794 26.3574Z" fill="#F2F4F7"/>
+</g>
+<rect width="60" height="15.1659" transform="translate(118.066 82.6727)" fill="url(#paint2_linear_40_1547)"/>
+<g filter="url(#filter2_b_40_1547)">
+<rect x="118.066" y="90.6794" width="59.9337" height="7.58293" fill="white" fill-opacity="0.01"/>
+</g>
+<rect x="121.242" y="85.8481" width="53.6493" height="8.81516" rx="2.1327" fill="white"/>
+<g clip-path="url(#clip4_40_1547)">
+<path d="M162.079 90.003V90.2558C162.079 90.7444 161.683 91.1404 161.194 91.1404M160.31 90.003V90.2558C160.31 90.7444 160.706 91.1404 161.194 91.1404M161.194 91.1404V91.5196M160.689 91.5196H161.7M161.194 90.6349C160.985 90.6349 160.815 90.4652 160.815 90.2558V89.3711C160.815 89.1617 160.985 88.9919 161.194 88.9919C161.404 88.9919 161.574 89.1617 161.574 89.3711V90.2558C161.574 90.4652 161.404 90.6349 161.194 90.6349Z" stroke="#667085" stroke-width="0.236967" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<rect x="165.744" y="88.7391" width="0.189573" height="3.03317" fill="black" fill-opacity="0.05"/>
+<path d="M172.083 90.3607C172.116 90.2945 172.116 90.2169 172.083 90.1507C172.055 90.0924 172.004 90.0618 171.978 90.0471C171.95 90.0312 171.913 90.0149 171.877 89.9987L169.226 88.8056C169.189 88.789 169.152 88.7724 169.121 88.7617C169.093 88.7518 169.035 88.7338 168.972 88.7515C168.9 88.7714 168.842 88.8239 168.815 88.8932C168.791 88.9546 168.803 89.0134 168.81 89.0428C168.817 89.0747 168.83 89.113 168.843 89.1514L169.099 89.9246C169.12 89.9868 169.13 90.0179 169.15 90.041C169.167 90.0613 169.188 90.077 169.213 90.0867C169.241 90.0977 169.274 90.0977 169.339 90.0977H170.484C170.571 90.0977 170.642 90.1684 170.642 90.2557C170.642 90.3429 170.571 90.4137 170.484 90.4137H169.342C169.277 90.4137 169.244 90.4137 169.216 90.4246C169.192 90.4343 169.17 90.4499 169.153 90.4702C169.134 90.4931 169.123 90.5241 169.103 90.5862L168.844 91.3589C168.831 91.3974 168.818 91.4357 168.811 91.4677C168.804 91.497 168.791 91.556 168.815 91.6175C168.842 91.6869 168.901 91.7396 168.972 91.7596C169.036 91.7774 169.093 91.7593 169.122 91.7494C169.153 91.7387 169.19 91.7221 169.227 91.7054L171.877 90.5127C171.913 90.4964 171.95 90.4802 171.978 90.4643C172.004 90.4496 172.055 90.419 172.083 90.3607Z" fill="#D0D5DD"/>
+<rect x="121.242" y="85.8481" width="53.6493" height="8.81516" rx="2.1327" stroke="#EAECF0" stroke-width="0.28436"/>
+</g>
+</g>
+<rect x="118.5" y="12.5" width="59" height="85" rx="3.5" stroke="#B2CCFF"/>
+</g>
+</g>
+<rect x="0.25" y="0.25" width="179.5" height="127.5" rx="5.75" stroke="#EAECF0" stroke-width="0.5"/>
+</g>
+<defs>
+<filter id="filter0_d_40_1547" x="-2" y="-1" width="184" height="132" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_40_1547"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_40_1547" result="shape"/>
+</filter>
+<filter id="filter1_dd_40_1547" x="114.209" y="12" width="67.5829" height="93.5829" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feMorphology radius="0.758293" operator="erode" in="SourceAlpha" result="effect1_dropShadow_40_1547"/>
+<feOffset dy="1.51659"/>
+<feGaussianBlur stdDeviation="0.758293"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.03 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_40_1547"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feMorphology radius="0.758293" operator="erode" in="SourceAlpha" result="effect2_dropShadow_40_1547"/>
+<feOffset dy="3.79147"/>
+<feGaussianBlur stdDeviation="2.27488"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.08 0"/>
+<feBlend mode="normal" in2="effect1_dropShadow_40_1547" result="effect2_dropShadow_40_1547"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_40_1547" result="shape"/>
+</filter>
+<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
+<use xlink:href="#image0_40_1547" transform="scale(0.00625)"/>
+</pattern>
+<filter id="filter2_b_40_1547" x="116.55" y="89.1629" width="62.9668" height="10.6161" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feGaussianBlur in="BackgroundImageFix" stdDeviation="0.758293"/>
+<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_40_1547"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_40_1547" result="shape"/>
+</filter>
+<radialGradient id="paint0_angular_40_1547" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(156.667 5) rotate(90) scale(2 1.91353)">
+<stop stop-color="#001FC2"/>
+<stop offset="0.711334" stop-color="#0667F8" stop-opacity="0.2"/>
+<stop offset="1" stop-color="#155EEF" stop-opacity="0"/>
+</radialGradient>
+<radialGradient id="paint1_radial_40_1547" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(64.5) rotate(135.735) scale(55.1589 31.9368)">
+<stop stop-color="#101828" stop-opacity="0.1"/>
+<stop offset="1" stop-color="#101828" stop-opacity="0"/>
+</radialGradient>
+<linearGradient id="paint2_linear_40_1547" x1="30" y1="0" x2="30" y2="15.1659" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<clipPath id="clip0_40_1547">
+<rect width="180" height="128" rx="6" fill="white"/>
+</clipPath>
+<clipPath id="clip1_40_1547">
+<rect x="118" y="12" width="60" height="86" rx="4" fill="white"/>
+</clipPath>
+<clipPath id="clip2_40_1547">
+<rect width="60" height="76.1422" fill="white" transform="translate(118 21.8578)"/>
+</clipPath>
+<clipPath id="clip3_40_1547">
+<rect width="60" height="76.1422" fill="white" transform="translate(118 21.8578)"/>
+</clipPath>
+<clipPath id="clip4_40_1547">
+<rect width="3.03317" height="3.03317" fill="white" transform="translate(159.678 88.7391)"/>
+</clipPath>
+<image id="image0_40_1547" width="160" height="160" xlink:href="data:image/png;base64,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"/>
+</defs>
+</svg>
diff --git a/app/components/app/overview/assets/code-browser.svg b/app/components/app/overview/assets/code-browser.svg
new file mode 100644
index 0000000..33434d7
--- /dev/null
+++ b/app/components/app/overview/assets/code-browser.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.6667 6H1.33337M9.33337 11.6667L11 10L9.33337 8.33333M6.66671 8.33333L5.00004 10L6.66671 11.6667M1.33337 5.2L1.33337 10.8C1.33337 11.9201 1.33337 12.4802 1.55136 12.908C1.74311 13.2843 2.04907 13.5903 2.42539 13.782C2.85322 14 3.41327 14 4.53337 14H11.4667C12.5868 14 13.1469 14 13.5747 13.782C13.951 13.5903 14.257 13.2843 14.4487 12.908C14.6667 12.4802 14.6667 11.9201 14.6667 10.8V5.2C14.6667 4.0799 14.6667 3.51984 14.4487 3.09202C14.257 2.7157 13.951 2.40973 13.5747 2.21799C13.1469 2 12.5868 2 11.4667 2L4.53337 2C3.41327 2 2.85322 2 2.42539 2.21799C2.04907 2.40973 1.74311 2.71569 1.55136 3.09202C1.33337 3.51984 1.33337 4.0799 1.33337 5.2Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/app/overview/assets/iframe-option.svg b/app/components/app/overview/assets/iframe-option.svg
new file mode 100644
index 0000000..d9ffc02
--- /dev/null
+++ b/app/components/app/overview/assets/iframe-option.svg
@@ -0,0 +1,102 @@
+<svg width="192" height="132" viewBox="0 0 192 132" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g filter="url(#filter0_d_6785_52470)">
+<g clip-path="url(#clip0_6785_52470)">
+<rect x="2" y="1" width="188" height="128" rx="6" fill="#FCFCFD"/>
+<mask id="path-3-inside-1_6785_52470" fill="white">
+<path d="M2 1H190V11H2V1Z"/>
+</mask>
+<path d="M2 1H190V11H2V1Z" fill="#F2F4F7"/>
+<circle cx="7.5" cy="6" r="1.5" fill="#D9D9D9"/>
+<circle cx="12.5" cy="6" r="1.5" fill="#D9D9D9"/>
+<circle cx="17.5" cy="6" r="1.5" fill="#D9D9D9"/>
+<path d="M190 10.5H2V11.5H190V10.5Z" fill="#EAECF0" mask="url(#path-3-inside-1_6785_52470)"/>
+<rect width="188" height="118" transform="translate(2 11)" fill="#F2F4F7"/>
+<mask id="path-8-inside-2_6785_52470" fill="white">
+<path d="M2 11H190V23H2V11Z"/>
+</mask>
+<path d="M2 11H190V23H2V11Z" fill="#FCFCFD"/>
+<circle opacity="0.1" cx="12.5" cy="17" r="2.5" fill="#101828"/>
+<g opacity="0.1">
+<rect x="17" y="16.1428" width="15.4286" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="140.286" y="16.1428" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="151.714" y="16.1428" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="163.143" y="16.1428" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="174.571" y="16.1428" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<path d="M190 22.5H2V23.5H190V22.5Z" fill="black" fill-opacity="0.05" mask="url(#path-8-inside-2_6785_52470)"/>
+<g clip-path="url(#clip1_6785_52470)">
+<rect x="36" y="35" width="120" height="80" rx="4" fill="#F2F4F7"/>
+<rect width="120" height="80" transform="translate(36 35)" fill="white"/>
+<rect x="40.9004" y="40.1089" width="12" height="12" rx="6" fill="#D5F5F6"/>
+<path d="M43.4004 49.5989H50.4004V42.5989H43.4004V49.5989Z" fill="url(#pattern0)"/>
+<rect x="40.9807" y="40.1892" width="11.8393" height="11.8393" rx="5.91964" stroke="black" stroke-opacity="0.05" stroke-width="0.160714"/>
+<path d="M57 40H142.771C145.652 40 147.092 40 148.192 40.5605C149.16 41.0536 149.946 41.8404 150.439 42.8081C151 43.9082 151 45.3483 151 48.2286V49.7714C151 52.6517 151 54.0918 150.439 55.192C149.946 56.1597 149.16 56.9464 148.192 57.4395C147.092 58 145.652 58 142.771 58H65.2286C62.3483 58 60.9082 58 59.8081 57.4395C58.8404 56.9464 58.0536 56.1597 57.5605 55.192C57 54.0918 57 52.6517 57 49.7714V40Z" fill="#F2F4F7"/>
+<g opacity="0.1">
+<rect x="62.1428" y="43.8572" width="83.7143" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="62.1428" y="48.1428" width="83.7143" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="62.1428" y="52.4287" width="23.4286" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<path d="M54.7611 40.4995C54.6187 40.2859 54.7718 39.9998 55.0286 39.9998H56.9994V43.8569L54.7611 40.4995Z" fill="#F2F4F7"/>
+<rect width="119.934" height="15.1659" transform="translate(36 100.303)" fill="url(#paint0_linear_6785_52470)"/>
+<g filter="url(#filter1_b_6785_52470)">
+<rect x="36" y="108.31" width="119.934" height="7.58293" fill="white" fill-opacity="0.01"/>
+</g>
+<rect x="39.1754" y="103.479" width="113.583" height="8.81516" rx="2.1327" fill="white"/>
+<g clip-path="url(#clip2_6785_52470)">
+<path d="M139.946 107.633V107.886C139.946 108.374 139.55 108.771 139.061 108.771M138.177 107.633V107.886C138.177 108.374 138.573 108.771 139.061 108.771M139.061 108.771V109.15M138.556 109.15H139.567M139.061 108.265C138.852 108.265 138.682 108.095 138.682 107.886V107.001C138.682 106.792 138.852 106.622 139.061 106.622C139.271 106.622 139.441 106.792 139.441 107.001V107.886C139.441 108.095 139.271 108.265 139.061 108.265Z" stroke="#667085" stroke-width="0.236967" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<rect x="143.612" y="106.369" width="0.189573" height="3.03317" fill="black" fill-opacity="0.05"/>
+<path d="M149.951 107.991C149.984 107.925 149.984 107.847 149.951 107.781C149.922 107.723 149.872 107.692 149.845 107.678C149.817 107.662 149.781 107.645 149.745 107.629L147.094 106.436C147.057 106.419 147.02 106.403 146.989 106.392C146.96 106.382 146.903 106.364 146.84 106.382C146.768 106.402 146.71 106.454 146.683 106.524C146.658 106.585 146.671 106.644 146.677 106.673C146.685 106.705 146.698 106.743 146.71 106.782L146.967 107.555C146.988 107.617 146.998 107.648 147.017 107.671C147.034 107.692 147.056 107.708 147.081 107.717C147.109 107.728 147.141 107.728 147.207 107.728H148.351C148.439 107.728 148.509 107.799 148.509 107.886C148.509 107.973 148.439 108.044 148.351 108.044H147.21C147.144 108.044 147.112 108.044 147.084 108.055C147.059 108.065 147.038 108.08 147.021 108.101C147.001 108.124 146.991 108.155 146.97 108.217L146.712 108.989C146.699 109.028 146.686 109.066 146.678 109.098C146.671 109.128 146.659 109.187 146.683 109.248C146.71 109.317 146.768 109.37 146.84 109.39C146.904 109.408 146.961 109.39 146.99 109.38C147.021 109.369 147.057 109.353 147.094 109.336L149.745 108.143C149.781 108.127 149.817 108.111 149.845 108.095C149.872 108.08 149.922 108.05 149.951 107.991Z" fill="#D0D5DD"/>
+<rect x="39.1754" y="103.479" width="113.583" height="8.81516" rx="2.1327" stroke="#EAECF0" stroke-width="0.28436"/>
+</g>
+<rect x="36.5" y="35.5" width="119" height="79" rx="3.5" stroke="#B2CCFF"/>
+</g>
+<rect x="2.25" y="1.25" width="187.5" height="127.5" rx="5.75" stroke="#EAECF0" stroke-width="0.5"/>
+</g>
+<defs>
+<filter id="filter0_d_6785_52470" x="0" y="0" width="192" height="132" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6785_52470"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6785_52470" result="shape"/>
+</filter>
+<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
+<use xlink:href="#image0_6785_52470" transform="scale(0.00625)"/>
+</pattern>
+<filter id="filter1_b_6785_52470" x="34.4834" y="106.793" width="122.967" height="10.6162" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feGaussianBlur in="BackgroundImageFix" stdDeviation="0.758293"/>
+<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_6785_52470"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_6785_52470" result="shape"/>
+</filter>
+<linearGradient id="paint0_linear_6785_52470" x1="59.9668" y1="0" x2="59.9668" y2="15.1659" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<clipPath id="clip0_6785_52470">
+<rect x="2" y="1" width="188" height="128" rx="6" fill="white"/>
+</clipPath>
+<clipPath id="clip1_6785_52470">
+<rect x="36" y="35" width="120" height="80" rx="4" fill="white"/>
+</clipPath>
+<clipPath id="clip2_6785_52470">
+<rect width="3.03317" height="3.03317" fill="white" transform="translate(137.545 106.369)"/>
+</clipPath>
+<image id="image0_6785_52470" width="160" height="160" xlink:href="data:image/png;base64,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"/>
+</defs>
+</svg>
diff --git a/app/components/app/overview/assets/refresh-hover.svg b/app/components/app/overview/assets/refresh-hover.svg
new file mode 100644
index 0000000..b2d2813
--- /dev/null
+++ b/app/components/app/overview/assets/refresh-hover.svg
@@ -0,0 +1,3 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M21.6353 16.5954C21.4501 18.3353 20.4643 19.9658 18.833 20.9076C16.1226 22.4724 12.6569 21.5438 11.0921 18.8335L10.9255 18.5448M10.3641 15.4047C10.5493 13.6647 11.5352 12.0343 13.1665 11.0924C15.8768 9.5276 19.3425 10.4562 20.9073 13.1666L21.074 13.4552M10.3288 20.044L10.8168 18.2227L12.6382 18.7107M19.3616 13.2893L21.183 13.7774L21.671 11.956" stroke="#1D2939" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/app/overview/assets/refresh.svg b/app/components/app/overview/assets/refresh.svg
new file mode 100644
index 0000000..be35d3c
--- /dev/null
+++ b/app/components/app/overview/assets/refresh.svg
@@ -0,0 +1,3 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M21.6353 16.5954C21.4501 18.3353 20.4643 19.9658 18.833 20.9076C16.1226 22.4724 12.6569 21.5438 11.0921 18.8335L10.9255 18.5448M10.3641 15.4047C10.5493 13.6647 11.5352 12.0343 13.1665 11.0924C15.8768 9.5276 19.3425 10.4562 20.9073 13.1666L21.074 13.4552M10.3288 20.044L10.8168 18.2227L12.6382 18.7107M19.3616 13.2893L21.183 13.7774L21.671 11.956" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/app/overview/assets/scripts-option.svg b/app/components/app/overview/assets/scripts-option.svg
new file mode 100644
index 0000000..fee4040
--- /dev/null
+++ b/app/components/app/overview/assets/scripts-option.svg
@@ -0,0 +1,160 @@
+<svg width="188" height="128" viewBox="0 0 188 128" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g filter="url(#filter0_d_6785_52392)">
+<g clip-path="url(#clip0_6785_52392)">
+<rect width="188" height="128" rx="6" fill="#FCFCFD"/>
+<mask id="path-3-inside-1_6785_52392" fill="white">
+<path d="M0 0H188V10H0V0Z"/>
+</mask>
+<path d="M0 0H188V10H0V0Z" fill="#F2F4F7"/>
+<circle cx="5.5" cy="5" r="1.5" fill="#D9D9D9"/>
+<circle cx="10.5" cy="5" r="1.5" fill="#D9D9D9"/>
+<circle cx="15.5" cy="5" r="1.5" fill="#D9D9D9"/>
+<g opacity="0.05">
+<rect x="62" y="3" width="64" height="4" rx="1.28571" fill="#101828"/>
+</g>
+<path d="M188 9.5H0V10.5H188V9.5Z" fill="#EAECF0" mask="url(#path-3-inside-1_6785_52392)"/>
+<rect width="188" height="118" transform="translate(0 10)" fill="#F2F4F7"/>
+<mask id="path-9-inside-2_6785_52392" fill="white">
+<path d="M0 10H188V22H0V10Z"/>
+</mask>
+<path d="M0 10H188V22H0V10Z" fill="#FCFCFD"/>
+<circle opacity="0.1" cx="10.5" cy="16" r="2.5" fill="#101828"/>
+<g opacity="0.1">
+<rect x="15" y="15.1428" width="15.4286" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="138.286" y="15.1428" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="149.714" y="15.1428" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="161.143" y="15.1428" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="172.571" y="15.1428" width="7.42857" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<path d="M188 21.5H0V22.5H188V21.5Z" fill="black" fill-opacity="0.05" mask="url(#path-9-inside-2_6785_52392)"/>
+<rect width="70" height="101.1" transform="translate(117.934 27.3269)" fill="url(#paint0_radial_6785_52392)"/>
+<g filter="url(#filter1_dd_6785_52392)">
+<g clip-path="url(#clip1_6785_52392)">
+<rect x="122.934" y="32.3269" width="60" height="80" rx="4" fill="#F2F4F7"/>
+<mask id="path-19-inside-3_6785_52392" fill="white">
+<path d="M122.934 32.3269H182.934V42.1847H122.934V32.3269Z"/>
+</mask>
+<path d="M122.934 32.3269H182.934V42.1847H122.934V32.3269Z" fill="#F9FAFB"/>
+<g opacity="0.12">
+<rect x="143.505" y="36.3987" width="18.8571" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<path d="M182.934 42.0899H122.934V42.2795H182.934V42.0899Z" fill="#EAECF0" mask="url(#path-19-inside-3_6785_52392)"/>
+<g clip-path="url(#clip2_6785_52392)">
+<rect width="60" height="70.1422" transform="translate(122.934 42.1848)" fill="#F9FAFB"/>
+<rect width="60" height="70.1422" transform="translate(122.934 42.1848)" fill="white"/>
+<g clip-path="url(#clip3_6785_52392)">
+<rect x="125.867" y="46.2937" width="12" height="12" rx="6" fill="#D5F5F6"/>
+<path d="M128.367 55.7837H135.367V48.7837H128.367V55.7837Z" fill="url(#pattern0)"/>
+<rect x="125.948" y="46.3741" width="11.8393" height="11.8393" rx="5.91964" stroke="black" stroke-opacity="0.05" stroke-width="0.160714"/>
+<path d="M141.967 46.1848H171.672C174.552 46.1848 175.992 46.1848 177.092 46.7454C178.06 47.2384 178.847 48.0252 179.34 48.9929C179.9 50.093 179.9 51.5331 179.9 54.4134V55.9562C179.9 58.8365 179.9 60.2767 179.34 61.3768C178.847 62.3445 178.06 63.1312 177.092 63.6243C175.992 64.1848 174.552 64.1848 171.672 64.1848H150.195C147.315 64.1848 145.875 64.1848 144.775 63.6243C143.807 63.1312 143.02 62.3445 142.527 61.3768C141.967 60.2767 141.967 58.8365 141.967 55.9562V46.1848Z" fill="#F2F4F7"/>
+<g opacity="0.1">
+<rect x="147.11" y="50.042" width="27.6479" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="147.11" y="54.3276" width="27.6479" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<g opacity="0.1">
+<rect x="147.11" y="58.6135" width="23.4286" height="1.71429" rx="0.857144" fill="#101828"/>
+</g>
+<path d="M139.728 46.6843C139.586 46.4707 139.739 46.1846 139.995 46.1846H141.966V50.0417L139.728 46.6843Z" fill="#F2F4F7"/>
+</g>
+<rect width="60" height="15.1659" transform="translate(123 96.9998)" fill="url(#paint1_linear_6785_52392)"/>
+<g filter="url(#filter2_b_6785_52392)">
+<rect x="123" y="105.007" width="59.9337" height="7.58293" fill="white" fill-opacity="0.01"/>
+</g>
+<rect x="126.175" y="100.175" width="53.6493" height="8.81516" rx="2.1327" fill="white"/>
+<g clip-path="url(#clip4_6785_52392)">
+<path d="M167.012 104.33V104.582C167.012 105.071 166.616 105.467 166.128 105.467M165.243 104.33V104.582C165.243 105.071 165.639 105.467 166.128 105.467M166.128 105.467V105.846M165.622 105.846H166.633M166.128 104.962C165.918 104.962 165.748 104.792 165.748 104.582V103.698C165.748 103.488 165.918 103.319 166.128 103.319C166.337 103.319 166.507 103.488 166.507 103.698V104.582C166.507 104.792 166.337 104.962 166.128 104.962Z" stroke="#667085" stroke-width="0.236967" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<rect x="170.678" y="103.066" width="0.189573" height="3.03317" fill="black" fill-opacity="0.05"/>
+<path d="M177.017 104.688C177.05 104.622 177.05 104.544 177.017 104.478C176.988 104.419 176.938 104.389 176.912 104.374C176.883 104.358 176.847 104.342 176.811 104.326L174.16 103.133C174.123 103.116 174.086 103.099 174.055 103.089C174.027 103.079 173.969 103.061 173.906 103.078C173.834 103.098 173.776 103.151 173.749 103.22C173.725 103.282 173.737 103.34 173.744 103.37C173.751 103.402 173.764 103.44 173.777 103.478L174.033 104.252C174.054 104.314 174.064 104.345 174.083 104.368C174.1 104.388 174.122 104.404 174.147 104.414C174.175 104.425 174.207 104.425 174.273 104.425H175.417C175.505 104.425 175.575 104.495 175.575 104.583C175.575 104.67 175.505 104.741 175.417 104.741H174.276C174.211 104.741 174.178 104.741 174.15 104.752C174.125 104.761 174.104 104.777 174.087 104.797C174.068 104.82 174.057 104.851 174.036 104.913L173.778 105.686C173.765 105.724 173.752 105.763 173.744 105.795C173.737 105.824 173.725 105.883 173.749 105.945C173.776 106.014 173.834 106.067 173.906 106.087C173.97 106.104 174.027 106.086 174.056 106.076C174.087 106.066 174.124 106.049 174.161 106.032L176.811 104.84C176.847 104.823 176.883 104.807 176.912 104.791C176.938 104.777 176.988 104.746 177.017 104.688Z" fill="#D0D5DD"/>
+<rect x="126.175" y="100.175" width="53.6493" height="8.81516" rx="2.1327" stroke="#EAECF0" stroke-width="0.28436"/>
+</g>
+</g>
+<rect x="123.434" y="32.8269" width="59" height="79" rx="3.5" stroke="#B2CCFF"/>
+</g>
+<g filter="url(#filter3_d_6785_52392)">
+<rect x="173.834" y="114.327" width="9.09953" height="9.09952" rx="4.54976" fill="#004EEB"/>
+<path d="M179.521 120.014L177.246 117.739M177.246 120.014L179.521 117.739" stroke="white" stroke-width="0.379147" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</g>
+<rect x="0.25" y="0.25" width="187.5" height="127.5" rx="5.75" stroke="#EAECF0" stroke-width="0.5"/>
+</g>
+<defs>
+<filter id="filter0_d_6785_52392" x="-2" y="-1" width="192" height="132" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6785_52392"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6785_52392" result="shape"/>
+</filter>
+<filter id="filter1_dd_6785_52392" x="119.142" y="32.3269" width="67.5829" height="87.5829" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feMorphology radius="0.758293" operator="erode" in="SourceAlpha" result="effect1_dropShadow_6785_52392"/>
+<feOffset dy="1.51659"/>
+<feGaussianBlur stdDeviation="0.758293"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.03 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6785_52392"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feMorphology radius="0.758293" operator="erode" in="SourceAlpha" result="effect2_dropShadow_6785_52392"/>
+<feOffset dy="3.79147"/>
+<feGaussianBlur stdDeviation="2.27488"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.08 0"/>
+<feBlend mode="normal" in2="effect1_dropShadow_6785_52392" result="effect2_dropShadow_6785_52392"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow_6785_52392" result="shape"/>
+</filter>
+<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
+<use xlink:href="#image0_6785_52392" transform="scale(0.00625)"/>
+</pattern>
+<filter id="filter2_b_6785_52392" x="121.483" y="103.49" width="62.9668" height="10.6162" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feGaussianBlur in="BackgroundImageFix" stdDeviation="0.758293"/>
+<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_6785_52392"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_6785_52392" result="shape"/>
+</filter>
+<filter id="filter3_d_6785_52392" x="173.455" y="114.137" width="9.8579" height="9.8579" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="0.189573"/>
+<feGaussianBlur stdDeviation="0.189573"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6785_52392"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6785_52392" result="shape"/>
+</filter>
+<radialGradient id="paint0_radial_6785_52392" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(70 101.1) rotate(180) scale(68.8389 32.6854)">
+<stop stop-color="#101828" stop-opacity="0.1"/>
+<stop offset="1" stop-color="#101828" stop-opacity="0"/>
+</radialGradient>
+<linearGradient id="paint1_linear_6785_52392" x1="30" y1="0" x2="30" y2="15.1659" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<clipPath id="clip0_6785_52392">
+<rect width="188" height="128" rx="6" fill="white"/>
+</clipPath>
+<clipPath id="clip1_6785_52392">
+<rect x="122.934" y="32.3269" width="60" height="80" rx="4" fill="white"/>
+</clipPath>
+<clipPath id="clip2_6785_52392">
+<rect width="60" height="70.1422" fill="white" transform="translate(122.934 42.1848)"/>
+</clipPath>
+<clipPath id="clip3_6785_52392">
+<rect width="60" height="70.1422" fill="white" transform="translate(122.934 42.1848)"/>
+</clipPath>
+<clipPath id="clip4_6785_52392">
+<rect width="3.03317" height="3.03317" fill="white" transform="translate(164.611 103.066)"/>
+</clipPath>
+<image id="image0_6785_52392" width="160" height="160" xlink:href="data:image/png;base64,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"/>
+</defs>
+</svg>
diff --git a/app/components/app/overview/customize/index.tsx b/app/components/app/overview/customize/index.tsx
new file mode 100644
index 0000000..4e84dd8
--- /dev/null
+++ b/app/components/app/overview/customize/index.tsx
@@ -0,0 +1,119 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import type { AppMode } from '@/types/app'
+import I18n from '@/context/i18n'
+import Button from '@/app/components/base/button'
+import Modal from '@/app/components/base/modal'
+import Tag from '@/app/components/base/tag'
+import { LanguagesSupported } from '@/i18n/language'
+
+type IShareLinkProps = {
+ isShow: boolean
+ onClose: () => void
+ linkUrl: string
+ api_base_url: string
+ appId: string
+ mode: AppMode
+}
+
+const StepNum: FC<{ children: React.ReactNode }> = ({ children }) =>
+ <div className='mr-3 flex h-7 w-7 shrink-0 items-center justify-center rounded-2xl bg-util-colors-blue-blue-50 text-text-accent'>
+ {children}
+ </div>
+
+const GithubIcon = ({ className }: { className: string }) => {
+ return (
+ <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
+ <path d="M5.80078 13.7109C5.80078 13.6406 5.73047 13.5703 5.625 13.5703C5.51953 13.5703 5.44922 13.6406 5.44922 13.7109C5.44922 13.7812 5.51953 13.8516 5.625 13.8164C5.73047 13.8164 5.80078 13.7812 5.80078 13.7109ZM4.71094 13.5352C4.71094 13.6055 4.78125 13.7109 4.88672 13.7109C4.95703 13.7461 5.0625 13.7109 5.09766 13.6406C5.09766 13.5703 5.0625 13.5 4.95703 13.4648C4.85156 13.4297 4.74609 13.4648 4.71094 13.5352ZM6.29297 13.5C6.1875 13.5 6.11719 13.5703 6.11719 13.6758C6.11719 13.7461 6.22266 13.7812 6.32812 13.7461C6.43359 13.7109 6.50391 13.6758 6.46875 13.6055C6.46875 13.5352 6.36328 13.4648 6.29297 13.5ZM8.57812 0C3.72656 0 0 3.72656 0 8.57812C0 12.4805 2.42578 15.8203 5.94141 17.0156C6.39844 17.0859 6.53906 16.8047 6.53906 16.5938C6.53906 16.3477 6.53906 15.1523 6.53906 14.4141C6.53906 14.4141 4.07812 14.9414 3.55078 13.3594C3.55078 13.3594 3.16406 12.3398 2.60156 12.0938C2.60156 12.0938 1.79297 11.5312 2.63672 11.5312C2.63672 11.5312 3.51562 11.6016 4.00781 12.4453C4.78125 13.8164 6.04688 13.4297 6.57422 13.1836C6.64453 12.6211 6.85547 12.2344 7.13672 11.9883C5.16797 11.7773 3.16406 11.4961 3.16406 8.12109C3.16406 7.13672 3.44531 6.67969 4.00781 6.04688C3.90234 5.80078 3.62109 4.88672 4.11328 3.65625C4.81641 3.44531 6.53906 4.60547 6.53906 4.60547C7.24219 4.39453 7.98047 4.32422 8.71875 4.32422C9.49219 4.32422 10.2305 4.39453 10.9336 4.60547C10.9336 4.60547 12.6211 3.41016 13.3594 3.65625C13.8516 4.88672 13.5352 5.80078 13.4648 6.04688C14.0273 6.67969 14.3789 7.13672 14.3789 8.12109C14.3789 11.4961 12.3047 11.7773 10.3359 11.9883C10.6523 12.2695 10.9336 12.7969 10.9336 13.6406C10.9336 14.8008 10.8984 16.2773 10.8984 16.5586C10.8984 16.8047 11.0742 17.0859 11.5312 16.9805C15.0469 15.8203 17.4375 12.4805 17.4375 8.57812C17.4375 3.72656 13.4648 0 8.57812 0ZM3.41016 12.1289C3.33984 12.1641 3.375 12.2695 3.41016 12.3398C3.48047 12.375 3.55078 12.4102 3.62109 12.375C3.65625 12.3398 3.65625 12.2344 3.58594 12.1641C3.51562 12.1289 3.44531 12.0938 3.41016 12.1289ZM3.02344 11.8477C2.98828 11.918 3.02344 11.9531 3.09375 11.9883C3.16406 12.0234 3.23438 12.0234 3.26953 11.9531C3.26953 11.918 3.23438 11.8828 3.16406 11.8477C3.09375 11.8125 3.05859 11.8125 3.02344 11.8477ZM4.14844 13.1133C4.11328 13.1484 4.11328 13.2539 4.21875 13.3242C4.28906 13.3945 4.39453 13.4297 4.42969 13.3594C4.46484 13.3242 4.46484 13.2188 4.39453 13.1484C4.32422 13.0781 4.21875 13.043 4.14844 13.1133ZM3.76172 12.5859C3.69141 12.6211 3.69141 12.7266 3.76172 12.7969C3.83203 12.8672 3.90234 12.9023 3.97266 12.8672C4.00781 12.832 4.00781 12.7266 3.97266 12.6562C3.90234 12.5859 3.83203 12.5508 3.76172 12.5859Z" fill="#1F2A37" />
+ </svg>
+ )
+}
+
+const prefixCustomize = 'appOverview.overview.appInfo.customize'
+
+const CustomizeModal: FC<IShareLinkProps> = ({
+ isShow,
+ onClose,
+ appId,
+ api_base_url,
+ mode,
+}) => {
+ const { t } = useTranslation()
+ const { locale } = useContext(I18n)
+ const isChatApp = mode === 'chat' || mode === 'advanced-chat'
+
+ return <Modal
+ title={t(`${prefixCustomize}.title`)}
+ description={t(`${prefixCustomize}.explanation`)}
+ isShow={isShow}
+ onClose={onClose}
+ className='w-[640px] !max-w-2xl'
+ closable={true}
+ >
+ <div className='mt-4 w-full rounded-lg border-[0.5px] border-components-panel-border px-6 py-5'>
+ <Tag bordered={true} hideBg={true} className='border-text-accent-secondary uppercase text-text-accent-secondary'>{t(`${prefixCustomize}.way`)} 1</Tag>
+ <p className='system-sm-medium my-2 text-text-secondary'>{t(`${prefixCustomize}.way1.name`)}</p>
+ <div className='flex py-4'>
+ <StepNum>1</StepNum>
+ <div className='flex flex-col'>
+ <div className='text-text-primary'>{t(`${prefixCustomize}.way1.step1`)}</div>
+ <div className='mb-2 mt-1 text-xs text-text-tertiary'>{t(`${prefixCustomize}.way1.step1Tip`)}</div>
+ <a href={`https://github.com/langgenius/${isChatApp ? 'webapp-conversation' : 'webapp-text-generator'}`} target='_blank' rel='noopener noreferrer'>
+ <Button><GithubIcon className='mr-2 text-text-secondary' />{t(`${prefixCustomize}.way1.step1Operation`)}</Button>
+ </a>
+ </div>
+ </div>
+ <div className='flex pt-4'>
+ <StepNum>2</StepNum>
+ <div className='flex flex-col'>
+ <div className='text-text-primary'>{t(`${prefixCustomize}.way1.step3`)}</div>
+ <div className='mb-2 mt-1 text-xs text-text-tertiary'>{t(`${prefixCustomize}.way1.step2Tip`)}</div>
+ <a href="https://vercel.com/docs/concepts/deployments/git/vercel-for-github" target='_blank' rel='noopener noreferrer'>
+ <Button>
+ <div className='mr-1.5 border-b-[12px] border-l-[7px] border-r-[7px] border-t-0 border-solid border-text-primary border-l-transparent border-r-transparent border-t-transparent'></div>
+ <span>{t(`${prefixCustomize}.way1.step2Operation`)}</span>
+ </Button>
+ </a>
+ </div>
+ </div>
+ <div className='flex py-4'>
+ <StepNum>3</StepNum>
+ <div className='flex w-full flex-col overflow-hidden'>
+ <div className='text-text-primary'>{t(`${prefixCustomize}.way1.step3`)}</div>
+ <div className='mb-2 mt-1 text-xs text-text-tertiary'>{t(`${prefixCustomize}.way1.step3Tip`)}</div>
+ <pre className='box-border select-text overflow-x-scroll rounded-lg border-[0.5px] border-components-panel-border bg-background-section px-4 py-3 text-xs font-medium text-text-secondary'>
+ NEXT_PUBLIC_APP_ID={`'${appId}'`} <br />
+ NEXT_PUBLIC_APP_KEY={'\'<Web API Key From Dify>\''} <br />
+ NEXT_PUBLIC_API_URL={`'${api_base_url}'`}
+ </pre>
+ </div>
+ </div>
+
+ </div>
+ <div className='mt-4 w-full rounded-lg border-[0.5px] border-components-panel-border px-6 py-5'>
+ <Tag bordered={true} hideBg={true} className='border-text-accent-secondary uppercase text-text-accent-secondary'>{t(`${prefixCustomize}.way`)} 2</Tag>
+ <p className='system-sm-medium my-2 text-text-secondary'>{t(`${prefixCustomize}.way2.name`)}</p>
+ <Button
+ className='mt-2'
+ onClick={() =>
+ window.open(
+ `https://docs.dify.ai/${locale !== LanguagesSupported[1]
+ ? 'user-guide/launching-dify-apps/developing-with-apis'
+ : `${locale.toLowerCase()}/guides/application-publishing/developing-with-apis`
+ }`,
+ '_blank',
+ )
+ }
+ >
+ <span className='text-sm text-text-secondary'>{t(`${prefixCustomize}.way2.operation`)}</span>
+ <ArrowTopRightOnSquareIcon className='ml-1 h-4 w-4 shrink-0 text-text-secondary' />
+ </Button>
+ </div>
+ </Modal>
+}
+
+export default CustomizeModal
diff --git a/app/components/app/overview/embedded/index.tsx b/app/components/app/overview/embedded/index.tsx
new file mode 100644
index 0000000..e047b4f
--- /dev/null
+++ b/app/components/app/overview/embedded/index.tsx
@@ -0,0 +1,193 @@
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiClipboardFill,
+ RiClipboardLine,
+} from '@remixicon/react'
+import copy from 'copy-to-clipboard'
+import style from './style.module.css'
+import Modal from '@/app/components/base/modal'
+import Tooltip from '@/app/components/base/tooltip'
+import { useAppContext } from '@/context/app-context'
+import { IS_CE_EDITION } from '@/config'
+import type { SiteInfo } from '@/models/share'
+import { useThemeContext } from '@/app/components/base/chat/embedded-chatbot/theme/theme-context'
+import ActionButton from '@/app/components/base/action-button'
+import cn from '@/utils/classnames'
+
+type Props = {
+ siteInfo?: SiteInfo
+ isShow: boolean
+ onClose: () => void
+ accessToken: string
+ appBaseUrl: string
+ className?: string
+}
+
+const OPTION_MAP = {
+ iframe: {
+ getContent: (url: string, token: string) =>
+ `<iframe
+ src="${url}/chatbot/${token}"
+ style="width: 100%; height: 100%; min-height: 700px"
+ frameborder="0"
+ allow="microphone">
+</iframe>`,
+ },
+ scripts: {
+ getContent: (url: string, token: string, primaryColor: string, isTestEnv?: boolean) =>
+ `<script>
+ window.difyChatbotConfig = {
+ token: '${token}'${isTestEnv
+ ? `,
+ isDev: true`
+ : ''}${IS_CE_EDITION
+ ? `,
+ baseUrl: '${url}'`
+ : ''},
+ systemVariables: {
+ // user_id: 'YOU CAN DEFINE USER ID HERE',
+ // conversation_id: 'YOU CAN DEFINE CONVERSATION ID HERE, IT MUST BE A VALID UUID',
+ },
+ }
+</script>
+<script
+ src="${url}/embed.min.js"
+ id="${token}"
+ defer>
+</script>
+<style>
+ #dify-chatbot-bubble-button {
+ background-color: ${primaryColor} !important;
+ }
+ #dify-chatbot-bubble-window {
+ width: 24rem !important;
+ height: 40rem !important;
+ }
+</style>`,
+ },
+ chromePlugin: {
+ getContent: (url: string, token: string) => `ChatBot URL: ${url}/chatbot/${token}`,
+ },
+}
+const prefixEmbedded = 'appOverview.overview.appInfo.embedded'
+
+type Option = keyof typeof OPTION_MAP
+
+type OptionStatus = {
+ iframe: boolean
+ scripts: boolean
+ chromePlugin: boolean
+}
+
+const Embedded = ({ siteInfo, isShow, onClose, appBaseUrl, accessToken, className }: Props) => {
+ const { t } = useTranslation()
+ const [option, setOption] = useState<Option>('iframe')
+ const [isCopied, setIsCopied] = useState<OptionStatus>({ iframe: false, scripts: false, chromePlugin: false })
+
+ const { langeniusVersionInfo } = useAppContext()
+ const themeBuilder = useThemeContext()
+ themeBuilder.buildTheme(siteInfo?.chat_color_theme ?? null, siteInfo?.chat_color_theme_inverted ?? false)
+ const isTestEnv = langeniusVersionInfo.current_env === 'TESTING' || langeniusVersionInfo.current_env === 'DEVELOPMENT'
+ const onClickCopy = () => {
+ if (option === 'chromePlugin') {
+ const splitUrl = OPTION_MAP[option].getContent(appBaseUrl, accessToken).split(': ')
+ if (splitUrl.length > 1)
+ copy(splitUrl[1])
+ }
+ else {
+ copy(OPTION_MAP[option].getContent(appBaseUrl, accessToken, themeBuilder.theme?.primaryColor ?? '#1C64F2', isTestEnv))
+ }
+ setIsCopied({ ...isCopied, [option]: true })
+ }
+
+ // when toggle option, reset then copy status
+ const resetCopyStatus = () => {
+ const cache = { ...isCopied }
+ Object.keys(cache).forEach((key) => {
+ cache[key as keyof OptionStatus] = false
+ })
+ setIsCopied(cache)
+ }
+
+ const navigateToChromeUrl = () => {
+ window.open('https://chrome.google.com/webstore/detail/dify-chatbot/ceehdapohffmjmkdcifjofadiaoeggaf', '_blank', 'noopener,noreferrer')
+ }
+
+ useEffect(() => {
+ resetCopyStatus()
+ }, [isShow])
+
+ return (
+ <Modal
+ title={t(`${prefixEmbedded}.title`)}
+ isShow={isShow}
+ onClose={onClose}
+ className="w-[640px] !max-w-2xl"
+ wrapperClassName={className}
+ closable={true}
+ >
+ <div className="system-sm-medium mb-4 mt-8 text-text-primary">
+ {t(`${prefixEmbedded}.explanation`)}
+ </div>
+ <div className="flex flex-wrap items-center justify-between gap-y-2">
+ {Object.keys(OPTION_MAP).map((v, index) => {
+ return (
+ <div
+ key={index}
+ className={cn(
+ style.option,
+ style[`${v}Icon`],
+ option === v && style.active,
+ )}
+ onClick={() => {
+ setOption(v as Option)
+ resetCopyStatus()
+ }}
+ ></div>
+ )
+ })}
+ </div>
+ {option === 'chromePlugin' && (
+ <div className="mt-6 w-full">
+ <div className={cn('inline-flex w-full items-center justify-center gap-2 rounded-lg py-3',
+ 'shrink-0 cursor-pointer bg-primary-600 text-white hover:bg-primary-600/75 hover:shadow-sm')}>
+ <div className={`relative h-4 w-4 ${style.pluginInstallIcon}`}></div>
+ <div className="font-['Inter'] text-sm font-medium leading-tight text-white" onClick={navigateToChromeUrl}>{t(`${prefixEmbedded}.chromePlugin`)}</div>
+ </div>
+ </div>
+ )}
+ <div className={cn('inline-flex w-full flex-col items-start justify-start rounded-lg border-[0.5px] border-components-panel-border bg-background-section',
+ 'mt-6')}>
+ <div className="inline-flex items-center justify-start gap-2 self-stretch rounded-t-lg bg-background-section-burn py-1 pl-3 pr-1">
+ <div className="system-sm-medium shrink-0 grow text-text-secondary">
+ {t(`${prefixEmbedded}.${option}`)}
+ </div>
+ <Tooltip
+ popupContent={
+ (isCopied[option]
+ ? t(`${prefixEmbedded}.copied`)
+ : t(`${prefixEmbedded}.copy`)) || ''
+ }
+ >
+ <ActionButton>
+ <div
+ onClick={onClickCopy}
+ >
+ {isCopied[option] && <RiClipboardFill className='h-4 w-4' />}
+ {!isCopied[option] && <RiClipboardLine className='h-4 w-4' />}
+ </div>
+ </ActionButton>
+ </Tooltip>
+ </div>
+ <div className="flex w-full items-start justify-start gap-2 overflow-x-auto p-3">
+ <div className="shrink grow basis-0 font-mono text-[13px] leading-tight text-text-secondary">
+ <pre className='select-text'>{OPTION_MAP[option].getContent(appBaseUrl, accessToken, themeBuilder.theme?.primaryColor ?? '#1C64F2', isTestEnv)}</pre>
+ </div>
+ </div>
+ </div>
+ </Modal>
+ )
+}
+
+export default Embedded
diff --git a/app/components/app/overview/embedded/style.module.css b/app/components/app/overview/embedded/style.module.css
new file mode 100644
index 0000000..f2a4d2d
--- /dev/null
+++ b/app/components/app/overview/embedded/style.module.css
@@ -0,0 +1,20 @@
+.option {
+ width: 188px;
+ height: 128px;
+ @apply box-border cursor-pointer bg-auto bg-no-repeat bg-center rounded-md;
+}
+.active {
+ @apply border-[1.5px] border-[#2970FF];
+}
+.iframeIcon {
+ background-image: url(../assets/iframe-option.svg);
+}
+.scriptsIcon {
+ background-image: url(../assets/scripts-option.svg);
+}
+.chromePluginIcon {
+ background-image: url(../assets/chromeplugin-option.svg);
+}
+.pluginInstallIcon {
+ background-image: url(../assets/chromeplugin-install.svg);
+}
diff --git a/app/components/app/overview/settings/index.tsx b/app/components/app/overview/settings/index.tsx
new file mode 100644
index 0000000..c0a5fdf
--- /dev/null
+++ b/app/components/app/overview/settings/index.tsx
@@ -0,0 +1,474 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import { RiArrowRightSLine, RiCloseLine } from '@remixicon/react'
+import Link from 'next/link'
+import { Trans, useTranslation } from 'react-i18next'
+import { useContext, useContextSelector } from 'use-context-selector'
+import { SparklesSoft } from '@/app/components/base/icons/src/public/common'
+import Modal from '@/app/components/base/modal'
+import ActionButton from '@/app/components/base/action-button'
+import Button from '@/app/components/base/button'
+import Divider from '@/app/components/base/divider'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import AppIcon from '@/app/components/base/app-icon'
+import Switch from '@/app/components/base/switch'
+import PremiumBadge from '@/app/components/base/premium-badge'
+import { SimpleSelect } from '@/app/components/base/select'
+import type { AppDetailResponse } from '@/models/app'
+import type { AppIconType, AppSSO, Language } from '@/types/app'
+import { useToastContext } from '@/app/components/base/toast'
+import { LanguagesSupported, languages } from '@/i18n/language'
+import Tooltip from '@/app/components/base/tooltip'
+import AppContext, { useAppContext } from '@/context/app-context'
+import { useProviderContext } from '@/context/provider-context'
+import { useModalContext } from '@/context/modal-context'
+import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
+import AppIconPicker from '@/app/components/base/app-icon-picker'
+import I18n from '@/context/i18n'
+import cn from '@/utils/classnames'
+
+export type ISettingsModalProps = {
+ isChat: boolean
+ appInfo: AppDetailResponse & Partial<AppSSO>
+ isShow: boolean
+ defaultValue?: string
+ onClose: () => void
+ onSave?: (params: ConfigParams) => Promise<void>
+}
+
+export type ConfigParams = {
+ title: string
+ description: string
+ default_language: string
+ chat_color_theme: string
+ chat_color_theme_inverted: boolean
+ prompt_public: boolean
+ copyright: string
+ privacy_policy: string
+ custom_disclaimer: string
+ icon_type: AppIconType
+ icon: string
+ icon_background?: string
+ show_workflow_steps: boolean
+ use_icon_as_answer_icon: boolean
+ enable_sso?: boolean
+}
+
+const prefixSettings = 'appOverview.overview.appInfo.settings'
+
+const SettingsModal: FC<ISettingsModalProps> = ({
+ isChat,
+ appInfo,
+ isShow = false,
+ onClose,
+ onSave,
+}) => {
+ const systemFeatures = useContextSelector(AppContext, state => state.systemFeatures)
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const { notify } = useToastContext()
+ const [isShowMore, setIsShowMore] = useState(false)
+ const {
+ title,
+ icon_type,
+ icon,
+ icon_background,
+ icon_url,
+ description,
+ chat_color_theme,
+ chat_color_theme_inverted,
+ copyright,
+ privacy_policy,
+ custom_disclaimer,
+ default_language,
+ show_workflow_steps,
+ use_icon_as_answer_icon,
+ } = appInfo.site
+ const [inputInfo, setInputInfo] = useState({
+ title,
+ desc: description,
+ chatColorTheme: chat_color_theme,
+ chatColorThemeInverted: chat_color_theme_inverted,
+ copyright,
+ copyrightSwitchValue: !!copyright,
+ privacyPolicy: privacy_policy,
+ customDisclaimer: custom_disclaimer,
+ show_workflow_steps,
+ use_icon_as_answer_icon,
+ enable_sso: appInfo.enable_sso,
+ })
+ const [language, setLanguage] = useState(default_language)
+ const [saveLoading, setSaveLoading] = useState(false)
+ const { t } = useTranslation()
+ const { locale } = useContext(I18n)
+
+ const [showAppIconPicker, setShowAppIconPicker] = useState(false)
+ const [appIcon, setAppIcon] = useState<AppIconSelection>(
+ icon_type === 'image'
+ ? { type: 'image', url: icon_url!, fileId: icon }
+ : { type: 'emoji', icon, background: icon_background! },
+ )
+
+ const { enableBilling, plan } = useProviderContext()
+ const { setShowPricingModal, setShowAccountSettingModal } = useModalContext()
+ const isFreePlan = plan.type === 'sandbox'
+ const handlePlanClick = useCallback(() => {
+ if (isFreePlan)
+ setShowPricingModal()
+ else
+ setShowAccountSettingModal({ payload: 'billing' })
+ }, [isFreePlan, setShowAccountSettingModal, setShowPricingModal])
+
+ useEffect(() => {
+ setInputInfo({
+ title,
+ desc: description,
+ chatColorTheme: chat_color_theme,
+ chatColorThemeInverted: chat_color_theme_inverted,
+ copyright,
+ copyrightSwitchValue: !!copyright,
+ privacyPolicy: privacy_policy,
+ customDisclaimer: custom_disclaimer,
+ show_workflow_steps,
+ use_icon_as_answer_icon,
+ enable_sso: appInfo.enable_sso,
+ })
+ setLanguage(default_language)
+ setAppIcon(icon_type === 'image'
+ ? { type: 'image', url: icon_url!, fileId: icon }
+ : { type: 'emoji', icon, background: icon_background! })
+ }, [appInfo])
+
+ const onHide = () => {
+ onClose()
+ setTimeout(() => {
+ setIsShowMore(false)
+ }, 200)
+ }
+
+ const onClickSave = async () => {
+ if (!inputInfo.title) {
+ notify({ type: 'error', message: t('app.newApp.nameNotEmpty') })
+ return
+ }
+
+ const validateColorHex = (hex: string | null) => {
+ if (hex === null || hex?.length === 0)
+ return true
+
+ const regex = /#([A-Fa-f0-9]{6})/
+ const check = regex.test(hex)
+ return check
+ }
+
+ const validatePrivacyPolicy = (privacyPolicy: string | null) => {
+ if (privacyPolicy === null || privacyPolicy?.length === 0)
+ return true
+
+ return privacyPolicy.startsWith('http://') || privacyPolicy.startsWith('https://')
+ }
+
+ if (inputInfo !== null) {
+ if (!validateColorHex(inputInfo.chatColorTheme)) {
+ notify({ type: 'error', message: t(`${prefixSettings}.invalidHexMessage`) })
+ return
+ }
+ if (!validatePrivacyPolicy(inputInfo.privacyPolicy)) {
+ notify({ type: 'error', message: t(`${prefixSettings}.invalidPrivacyPolicy`) })
+ return
+ }
+ }
+
+ setSaveLoading(true)
+ const params = {
+ title: inputInfo.title,
+ description: inputInfo.desc,
+ default_language: language,
+ chat_color_theme: inputInfo.chatColorTheme,
+ chat_color_theme_inverted: inputInfo.chatColorThemeInverted,
+ prompt_public: false,
+ copyright: isFreePlan
+ ? ''
+ : inputInfo.copyrightSwitchValue
+ ? inputInfo.copyright
+ : '',
+ privacy_policy: inputInfo.privacyPolicy,
+ custom_disclaimer: inputInfo.customDisclaimer,
+ icon_type: appIcon.type,
+ icon: appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId,
+ icon_background: appIcon.type === 'emoji' ? appIcon.background : undefined,
+ show_workflow_steps: inputInfo.show_workflow_steps,
+ use_icon_as_answer_icon: inputInfo.use_icon_as_answer_icon,
+ enable_sso: inputInfo.enable_sso,
+ }
+ await onSave?.(params)
+ setSaveLoading(false)
+ onHide()
+ }
+
+ const onChange = (field: string) => {
+ return (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
+ let value: string | boolean
+ if (e.target.type === 'checkbox')
+ value = (e.target as HTMLInputElement).checked
+ else
+ value = e.target.value
+
+ setInputInfo(item => ({ ...item, [field]: value }))
+ }
+ }
+
+ const onDesChange = (value: string) => {
+ setInputInfo(item => ({ ...item, desc: value }))
+ }
+
+ return (
+ <>
+ <Modal
+ isShow={isShow}
+ closable={false}
+ onClose={onHide}
+ className='max-w-[520px] p-0'
+ >
+ {/* header */}
+ <div className='pb-3 pl-6 pr-5 pt-5'>
+ <div className='flex items-center gap-1'>
+ <div className='title-2xl-semi-bold grow text-text-primary'>{t(`${prefixSettings}.title`)}</div>
+ <ActionButton className='shrink-0' onClick={onHide}>
+ <RiCloseLine className='h-4 w-4' />
+ </ActionButton>
+ </div>
+ <div className='system-xs-regular mt-0.5 text-text-tertiary'>
+ <span>{t(`${prefixSettings}.modalTip`)}</span>
+ <Link href={`${locale === LanguagesSupported[1] ? 'https://docs.dify.ai/zh-hans/guides/application-publishing/launch-your-webapp-quickly#she-zhi-ni-de-ai-zhan-dian' : 'https://docs.dify.ai/en/guides/application-publishing/launch-your-webapp-quickly/README'}`} target='_blank' rel='noopener noreferrer' className='text-text-accent'>{t('common.operation.learnMore')}</Link>
+ </div>
+ </div>
+ {/* form body */}
+ <div className='space-y-5 px-6 py-3'>
+ {/* name & icon */}
+ <div className='flex gap-4'>
+ <div className='grow'>
+ <div className={cn('system-sm-semibold mb-1 py-1 text-text-secondary')}>{t(`${prefixSettings}.webName`)}</div>
+ <Input
+ className='w-full'
+ value={inputInfo.title}
+ onChange={onChange('title')}
+ placeholder={t('app.appNamePlaceholder') || ''}
+ />
+ </div>
+ <AppIcon
+ size='xxl'
+ onClick={() => { setShowAppIconPicker(true) }}
+ className='mt-2 cursor-pointer'
+ iconType={appIcon.type}
+ icon={appIcon.type === 'image' ? appIcon.fileId : appIcon.icon}
+ background={appIcon.type === 'image' ? undefined : appIcon.background}
+ imageUrl={appIcon.type === 'image' ? appIcon.url : undefined}
+ />
+ </div>
+ {/* description */}
+ <div className='relative'>
+ <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.webDesc`)}</div>
+ <Textarea
+ className='mt-1'
+ value={inputInfo.desc}
+ onChange={e => onDesChange(e.target.value)}
+ placeholder={t(`${prefixSettings}.webDescPlaceholder`) as string}
+ />
+ <p className={cn('body-xs-regular pb-0.5 text-text-tertiary')}>{t(`${prefixSettings}.webDescTip`)}</p>
+ </div>
+ <Divider className="my-0 h-px" />
+ {/* answer icon */}
+ {isChat && (
+ <div className='w-full'>
+ <div className='flex items-center justify-between'>
+ <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t('app.answerIcon.title')}</div>
+ <Switch
+ defaultValue={inputInfo.use_icon_as_answer_icon}
+ onChange={v => setInputInfo({ ...inputInfo, use_icon_as_answer_icon: v })}
+ />
+ </div>
+ <p className='body-xs-regular pb-0.5 text-text-tertiary'>{t('app.answerIcon.description')}</p>
+ </div>
+ )}
+ {/* language */}
+ <div className='flex items-center'>
+ <div className={cn('system-sm-semibold grow py-1 text-text-secondary')}>{t(`${prefixSettings}.language`)}</div>
+ <SimpleSelect
+ wrapperClassName='w-[200px]'
+ items={languages.filter(item => item.supported)}
+ defaultValue={language}
+ onSelect={item => setLanguage(item.value as Language)}
+ notClearable
+ />
+ </div>
+ {/* theme color */}
+ {isChat && (
+ <div className='flex items-center'>
+ <div className='grow'>
+ <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.chatColorTheme`)}</div>
+ <div className='body-xs-regular pb-0.5 text-text-tertiary'>{t(`${prefixSettings}.chatColorThemeDesc`)}</div>
+ </div>
+ <div className='shrink-0'>
+ <Input
+ className='mb-1 w-[200px]'
+ value={inputInfo.chatColorTheme ?? ''}
+ onChange={onChange('chatColorTheme')}
+ placeholder='E.g #A020F0'
+ />
+ <div className='flex items-center justify-between'>
+ <p className={cn('body-xs-regular text-text-tertiary')}>{t(`${prefixSettings}.chatColorThemeInverted`)}</p>
+ <Switch defaultValue={inputInfo.chatColorThemeInverted} onChange={v => setInputInfo({ ...inputInfo, chatColorThemeInverted: v })}></Switch>
+ </div>
+ </div>
+ </div>
+ )}
+ {/* workflow detail */}
+ <div className='w-full'>
+ <div className='flex items-center justify-between'>
+ <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.workflow.subTitle`)}</div>
+ <Switch
+ disabled={!(appInfo.mode === 'workflow' || appInfo.mode === 'advanced-chat')}
+ defaultValue={inputInfo.show_workflow_steps}
+ onChange={v => setInputInfo({ ...inputInfo, show_workflow_steps: v })}
+ />
+ </div>
+ <p className='body-xs-regular pb-0.5 text-text-tertiary'>{t(`${prefixSettings}.workflow.showDesc`)}</p>
+ </div>
+ {/* SSO */}
+ {systemFeatures.enable_web_sso_switch_component && (
+ <>
+ <Divider className="my-0 h-px" />
+ <div className='w-full'>
+ <p className='system-xs-medium-uppercase mb-1 text-text-tertiary'>{t(`${prefixSettings}.sso.label`)}</p>
+ <div className='flex items-center justify-between'>
+ <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.sso.title`)}</div>
+ <Tooltip
+ disabled={systemFeatures.sso_enforced_for_web}
+ popupContent={
+ <div className='w-[180px]'>{t(`${prefixSettings}.sso.tooltip`)}</div>
+ }
+ asChild={false}
+ >
+ <Switch disabled={!systemFeatures.sso_enforced_for_web || !isCurrentWorkspaceEditor} defaultValue={systemFeatures.sso_enforced_for_web && inputInfo.enable_sso} onChange={v => setInputInfo({ ...inputInfo, enable_sso: v })}></Switch>
+ </Tooltip>
+ </div>
+ <p className='body-xs-regular pb-0.5 text-text-tertiary'>{t(`${prefixSettings}.sso.description`)}</p>
+ </div>
+ </>
+ )}
+ {/* more settings switch */}
+ <Divider className="my-0 h-px" />
+ {!isShowMore && (
+ <div className='flex cursor-pointer items-center' onClick={() => setIsShowMore(true)}>
+ <div className='grow'>
+ <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.more.entry`)}</div>
+ <p className={cn('body-xs-regular pb-0.5 text-text-tertiary')}>{t(`${prefixSettings}.more.copyRightPlaceholder`)} & {t(`${prefixSettings}.more.privacyPolicyPlaceholder`)}</p>
+ </div>
+ <RiArrowRightSLine className='ml-1 h-4 w-4 shrink-0 text-text-secondary' />
+ </div>
+ )}
+ {/* more settings */}
+ {isShowMore && (
+ <>
+ {/* copyright */}
+ <div className='w-full'>
+ <div className='flex items-center'>
+ <div className='flex grow items-center'>
+ <div className={cn('system-sm-semibold mr-1 py-1 text-text-secondary')}>{t(`${prefixSettings}.more.copyright`)}</div>
+ {/* upgrade button */}
+ {enableBilling && isFreePlan && (
+ <div className='h-[18px] select-none'>
+ <PremiumBadge size='s' color='blue' allowHover={true} onClick={handlePlanClick}>
+ <SparklesSoft className='flex h-3.5 w-3.5 items-center py-[1px] pl-[3px] text-components-premium-badge-indigo-text-stop-0' />
+ <div className='system-xs-medium'>
+ <span className='p-1'>
+ {t('billing.upgradeBtn.encourageShort')}
+ </span>
+ </div>
+ </PremiumBadge>
+ </div>
+ )}
+ </div>
+ <Tooltip
+ disabled={!isFreePlan}
+ popupContent={
+ <div className='w-[260px]'>{t(`${prefixSettings}.more.copyrightTooltip`)}</div>
+ }
+ asChild={false}
+ >
+ <Switch
+ disabled={isFreePlan}
+ defaultValue={inputInfo.copyrightSwitchValue}
+ onChange={v => setInputInfo({ ...inputInfo, copyrightSwitchValue: v })}
+ />
+ </Tooltip>
+ </div>
+ <p className='body-xs-regular pb-0.5 text-text-tertiary'>{t(`${prefixSettings}.more.copyrightTip`)}</p>
+ {inputInfo.copyrightSwitchValue && (
+ <Input
+ className='mt-2 h-10'
+ value={inputInfo.copyright}
+ onChange={onChange('copyright')}
+ placeholder={t(`${prefixSettings}.more.copyRightPlaceholder`) as string}
+ />
+ )}
+ </div>
+ {/* privacy policy */}
+ <div className='w-full'>
+ <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.more.privacyPolicy`)}</div>
+ <p className={cn('body-xs-regular pb-0.5 text-text-tertiary')}>
+ <Trans
+ i18nKey={`${prefixSettings}.more.privacyPolicyTip`}
+ components={{ privacyPolicyLink: <Link href={'https://dify.ai/privacy'} target='_blank' rel='noopener noreferrer' className='text-text-accent' /> }}
+ />
+ </p>
+ <Input
+ className='mt-1'
+ value={inputInfo.privacyPolicy}
+ onChange={onChange('privacyPolicy')}
+ placeholder={t(`${prefixSettings}.more.privacyPolicyPlaceholder`) as string}
+ />
+ </div>
+ {/* custom disclaimer */}
+ <div className='w-full'>
+ <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.more.customDisclaimer`)}</div>
+ <p className={cn('body-xs-regular pb-0.5 text-text-tertiary')}>{t(`${prefixSettings}.more.customDisclaimerTip`)}</p>
+ <Textarea
+ className='mt-1'
+ value={inputInfo.customDisclaimer}
+ onChange={onChange('customDisclaimer')}
+ placeholder={t(`${prefixSettings}.more.customDisclaimerPlaceholder`) as string}
+ />
+ </div>
+ </>
+ )}
+ </div>
+ {/* footer */}
+ <div className='flex justify-end p-6 pt-5'>
+ <Button className='mr-2' onClick={onHide}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' onClick={onClickSave} loading={saveLoading}>{t('common.operation.save')}</Button>
+ </div>
+
+ {showAppIconPicker && (
+ <div onClick={e => e.stopPropagation()}>
+ <AppIconPicker
+ onSelect={(payload) => {
+ setAppIcon(payload)
+ setShowAppIconPicker(false)
+ }}
+ onClose={() => {
+ setAppIcon(icon_type === 'image'
+ ? { type: 'image', url: icon_url!, fileId: icon }
+ : { type: 'emoji', icon, background: icon_background! })
+ setShowAppIconPicker(false)
+ }}
+ />
+ </div>
+ )}
+ </Modal>
+ </>
+ )
+}
+export default React.memo(SettingsModal)
diff --git a/app/components/app/overview/style.module.css b/app/components/app/overview/style.module.css
new file mode 100644
index 0000000..ad63b29
--- /dev/null
+++ b/app/components/app/overview/style.module.css
@@ -0,0 +1,31 @@
+.generateLogo {
+ animation: 2s rotate linear infinite;
+}
+
+@keyframes rotate {
+ from {
+ transform: rotate(0deg);
+ }
+
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.codeBrowserIcon {
+ @apply w-4 h-4 bg-center bg-no-repeat;
+ background-image: url(./assets/code-browser.svg);
+}
+
+.refreshIcon {
+ background-image: url(./assets/refresh.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.refreshIcon:hover {
+ background-image: url(./assets/refresh-hover.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
diff --git a/app/components/app/store.ts b/app/components/app/store.ts
new file mode 100644
index 0000000..5f02f92
--- /dev/null
+++ b/app/components/app/store.ts
@@ -0,0 +1,54 @@
+import { create } from 'zustand'
+import type { App, AppSSO } from '@/types/app'
+import type { IChatItem } from '@/app/components/base/chat/chat/type'
+
+type State = {
+ appDetail?: App & Partial<AppSSO>
+ appSidebarExpand: string
+ currentLogItem?: IChatItem
+ currentLogModalActiveTab: string
+ showPromptLogModal: boolean
+ showAgentLogModal: boolean
+ showMessageLogModal: boolean
+ showAppConfigureFeaturesModal: boolean
+}
+
+type Action = {
+ setAppDetail: (appDetail?: App & Partial<AppSSO>) => void
+ setAppSiderbarExpand: (state: string) => void
+ setCurrentLogItem: (item?: IChatItem) => void
+ setCurrentLogModalActiveTab: (tab: string) => void
+ setShowPromptLogModal: (showPromptLogModal: boolean) => void
+ setShowAgentLogModal: (showAgentLogModal: boolean) => void
+ setShowMessageLogModal: (showMessageLogModal: boolean) => void
+ setShowAppConfigureFeaturesModal: (showAppConfigureFeaturesModal: boolean) => void
+}
+
+export const useStore = create<State & Action>(set => ({
+ appDetail: undefined,
+ setAppDetail: appDetail => set(() => ({ appDetail })),
+ appSidebarExpand: '',
+ setAppSiderbarExpand: appSidebarExpand => set(() => ({ appSidebarExpand })),
+ currentLogItem: undefined,
+ currentLogModalActiveTab: 'DETAIL',
+ setCurrentLogItem: currentLogItem => set(() => ({ currentLogItem })),
+ setCurrentLogModalActiveTab: currentLogModalActiveTab => set(() => ({ currentLogModalActiveTab })),
+ showPromptLogModal: false,
+ setShowPromptLogModal: showPromptLogModal => set(() => ({ showPromptLogModal })),
+ showAgentLogModal: false,
+ setShowAgentLogModal: showAgentLogModal => set(() => ({ showAgentLogModal })),
+ showMessageLogModal: false,
+ setShowMessageLogModal: showMessageLogModal => set(() => {
+ if (showMessageLogModal) {
+ return { showMessageLogModal }
+ }
+ else {
+ return {
+ showMessageLogModal,
+ currentLogModalActiveTab: 'DETAIL',
+ }
+ }
+ }),
+ showAppConfigureFeaturesModal: false,
+ setShowAppConfigureFeaturesModal: showAppConfigureFeaturesModal => set(() => ({ showAppConfigureFeaturesModal })),
+}))
diff --git a/app/components/app/switch-app-modal/index.tsx b/app/components/app/switch-app-modal/index.tsx
new file mode 100644
index 0000000..f1654eb
--- /dev/null
+++ b/app/components/app/switch-app-modal/index.tsx
@@ -0,0 +1,174 @@
+'use client'
+
+import { useEffect, useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import AppIconPicker from '../../base/app-icon-picker'
+import cn from '@/utils/classnames'
+import Checkbox from '@/app/components/base/checkbox'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Modal from '@/app/components/base/modal'
+import Confirm from '@/app/components/base/confirm'
+import { ToastContext } from '@/app/components/base/toast'
+import { deleteApp, switchApp } from '@/service/apps'
+import { useAppContext } from '@/context/app-context'
+import { useProviderContext } from '@/context/provider-context'
+import AppsFull from '@/app/components/billing/apps-full-in-dialog'
+import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
+import { getRedirection } from '@/utils/app-redirection'
+import type { App } from '@/types/app'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
+import AppIcon from '@/app/components/base/app-icon'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import { noop } from 'lodash-es'
+
+type SwitchAppModalProps = {
+ show: boolean
+ appDetail: App
+ onSuccess?: () => void
+ onClose: () => void
+ inAppDetail?: boolean
+}
+
+const SwitchAppModal = ({ show, appDetail, inAppDetail = false, onSuccess, onClose }: SwitchAppModalProps) => {
+ const { push, replace } = useRouter()
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const setAppDetail = useAppStore(s => s.setAppDetail)
+
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const { plan, enableBilling } = useProviderContext()
+ const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
+
+ const [showAppIconPicker, setShowAppIconPicker] = useState(false)
+ const [appIcon, setAppIcon] = useState(
+ appDetail.icon_type === 'image'
+ ? { type: 'image' as const, url: appDetail.icon_url, fileId: appDetail.icon }
+ : { type: 'emoji' as const, icon: appDetail.icon, background: appDetail.icon_background },
+ )
+
+ const [name, setName] = useState(`${appDetail.name}(copy)`)
+ const [removeOriginal, setRemoveOriginal] = useState<boolean>(false)
+ const [showConfirmDelete, setShowConfirmDelete] = useState(false)
+
+ const goStart = async () => {
+ try {
+ const { new_app_id: newAppID } = await switchApp({
+ appID: appDetail.id,
+ name,
+ icon_type: appIcon.type,
+ icon: appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId,
+ icon_background: appIcon.type === 'emoji' ? appIcon.background : undefined,
+ })
+ if (onSuccess)
+ onSuccess()
+ if (onClose)
+ onClose()
+ notify({ type: 'success', message: t('app.newApp.appCreated') })
+ if (inAppDetail)
+ setAppDetail()
+ if (removeOriginal)
+ await deleteApp(appDetail.id)
+ localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
+ getRedirection(
+ isCurrentWorkspaceEditor,
+ {
+ id: newAppID,
+ mode: appDetail.mode === 'completion' ? 'workflow' : 'advanced-chat',
+ },
+ removeOriginal ? replace : push,
+ )
+ }
+ catch {
+ notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
+ }
+ }
+
+ useEffect(() => {
+ if (removeOriginal)
+ setShowConfirmDelete(true)
+ }, [removeOriginal])
+
+ return (
+ <>
+ <Modal
+ className={cn('w-[600px] max-w-[600px] p-8')}
+ isShow={show}
+ onClose={noop}
+ >
+ <div className='absolute right-4 top-4 cursor-pointer p-2' onClick={onClose}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div className='h-12 w-12 rounded-xl border-[0.5px] border-divider-regular bg-background-default-burn p-3 shadow-xl'>
+ <AlertTriangle className='h-6 w-6 text-[rgb(247,144,9)]' />
+ </div>
+ <div className='relative mt-3 text-xl font-semibold leading-[30px] text-text-primary'>{t('app.switch')}</div>
+ <div className='my-1 text-sm leading-5 text-text-tertiary'>
+ <span>{t('app.switchTipStart')}</span>
+ <span className='font-medium text-text-secondary'>{t('app.switchTip')}</span>
+ <span>{t('app.switchTipEnd')}</span>
+ </div>
+ <div className='pb-4'>
+ <div className='py-2 text-sm font-medium leading-[20px] text-text-primary'>{t('app.switchLabel')}</div>
+ <div className='flex items-center justify-between space-x-2'>
+ <AppIcon
+ size='large'
+ onClick={() => { setShowAppIconPicker(true) }}
+ className='cursor-pointer'
+ iconType={appIcon.type}
+ icon={appIcon.type === 'image' ? appIcon.fileId : appIcon.icon}
+ background={appIcon.type === 'image' ? undefined : appIcon.background}
+ imageUrl={appIcon.type === 'image' ? appIcon.url : undefined}
+ />
+ <Input
+ value={name}
+ onChange={e => setName(e.target.value)}
+ placeholder={t('app.newApp.appNamePlaceholder') || ''}
+ className='h-10 grow'
+ />
+ </div>
+ {showAppIconPicker && <AppIconPicker
+ onSelect={(payload) => {
+ setAppIcon(payload)
+ setShowAppIconPicker(false)
+ }}
+ onClose={() => {
+ setAppIcon(appDetail.icon_type === 'image'
+ ? { type: 'image' as const, url: appDetail.icon_url, fileId: appDetail.icon }
+ : { type: 'emoji' as const, icon: appDetail.icon, background: appDetail.icon_background })
+ setShowAppIconPicker(false)
+ }}
+ />}
+ </div>
+ {isAppsFull && <AppsFull loc='app-switch' />}
+ <div className='flex items-center justify-between pt-6'>
+ <div className='flex items-center'>
+ <Checkbox className='shrink-0' checked={removeOriginal} onCheck={() => setRemoveOriginal(!removeOriginal)} />
+ <div className="ml-2 cursor-pointer text-sm leading-5 text-text-secondary" onClick={() => setRemoveOriginal(!removeOriginal)}>{t('app.removeOriginal')}</div>
+ </div>
+ <div className='flex items-center'>
+ <Button className='mr-2' onClick={onClose}>{t('app.newApp.Cancel')}</Button>
+ <Button className='border-red-700' disabled={isAppsFull || !name} variant="warning" onClick={goStart}>{t('app.switchStart')}</Button>
+ </div>
+ </div>
+ </Modal>
+ {showConfirmDelete && (
+ <Confirm
+ title={t('app.deleteAppConfirmTitle')}
+ content={t('app.deleteAppConfirmContent')}
+ isShow={showConfirmDelete}
+ onConfirm={() => setShowConfirmDelete(false)}
+ onCancel={() => {
+ setShowConfirmDelete(false)
+ setRemoveOriginal(false)
+ }}
+ />
+ )}
+ </>
+ )
+}
+
+export default SwitchAppModal
diff --git a/app/components/app/text-generate/item/index.tsx b/app/components/app/text-generate/item/index.tsx
new file mode 100644
index 0000000..aa3ffa3
--- /dev/null
+++ b/app/components/app/text-generate/item/index.tsx
@@ -0,0 +1,383 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiBookmark3Line,
+ RiClipboardLine,
+ RiFileList3Line,
+ RiPlayList2Line,
+ RiReplay15Line,
+ RiSparklingFill,
+ RiSparklingLine,
+ RiThumbDownLine,
+ RiThumbUpLine,
+} from '@remixicon/react'
+import copy from 'copy-to-clipboard'
+import { useParams } from 'next/navigation'
+import { useBoolean } from 'ahooks'
+import ResultTab from './result-tab'
+import { Markdown } from '@/app/components/base/markdown'
+import Loading from '@/app/components/base/loading'
+import Toast from '@/app/components/base/toast'
+import type { FeedbackType } from '@/app/components/base/chat/chat/type'
+import { fetchMoreLikeThis, updateFeedback } from '@/service/share'
+import { fetchTextGenerationMessage } from '@/service/debug'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import WorkflowProcessItem from '@/app/components/base/chat/chat/answer/workflow-process'
+import type { WorkflowProcess } from '@/app/components/base/chat/types'
+import type { SiteInfo } from '@/models/share'
+import { useChatContext } from '@/app/components/base/chat/chat/context'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+import NewAudioButton from '@/app/components/base/new-audio-button'
+import cn from '@/utils/classnames'
+
+const MAX_DEPTH = 3
+
+export type IGenerationItemProps = {
+ isWorkflow?: boolean
+ workflowProcessData?: WorkflowProcess
+ className?: string
+ isError: boolean
+ onRetry: () => void
+ content: any
+ messageId?: string | null
+ conversationId?: string
+ isLoading?: boolean
+ isResponding?: boolean
+ isInWebApp?: boolean
+ moreLikeThis?: boolean
+ depth?: number
+ feedback?: FeedbackType
+ onFeedback?: (feedback: FeedbackType) => void
+ onSave?: (messageId: string) => void
+ isMobile?: boolean
+ isInstalledApp: boolean
+ installedAppId?: string
+ taskId?: string
+ controlClearMoreLikeThis?: number
+ supportFeedback?: boolean
+ isShowTextToSpeech?: boolean
+ hideProcessDetail?: boolean
+ siteInfo: SiteInfo | null
+ inSidePanel?: boolean
+}
+
+export const copyIcon = (
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M9.3335 2.33341C9.87598 2.33341 10.1472 2.33341 10.3698 2.39304C10.9737 2.55486 11.4454 3.02657 11.6072 3.63048C11.6668 3.85302 11.6668 4.12426 11.6668 4.66675V10.0334C11.6668 11.0135 11.6668 11.5036 11.4761 11.8779C11.3083 12.2072 11.0406 12.4749 10.7113 12.6427C10.337 12.8334 9.84692 12.8334 8.86683 12.8334H5.1335C4.1534 12.8334 3.66336 12.8334 3.28901 12.6427C2.95973 12.4749 2.69201 12.2072 2.52423 11.8779C2.3335 11.5036 2.3335 11.0135 2.3335 10.0334V4.66675C2.3335 4.12426 2.3335 3.85302 2.39313 3.63048C2.55494 3.02657 3.02665 2.55486 3.63056 2.39304C3.8531 2.33341 4.12435 2.33341 4.66683 2.33341M5.60016 3.50008H8.40016C8.72686 3.50008 8.89021 3.50008 9.01499 3.4365C9.12475 3.38058 9.21399 3.29134 9.26992 3.18158C9.3335 3.05679 9.3335 2.89345 9.3335 2.56675V2.10008C9.3335 1.77338 9.3335 1.61004 9.26992 1.48525C9.21399 1.37549 9.12475 1.28625 9.01499 1.23033C8.89021 1.16675 8.72686 1.16675 8.40016 1.16675H5.60016C5.27347 1.16675 5.11012 1.16675 4.98534 1.23033C4.87557 1.28625 4.78634 1.37549 4.73041 1.48525C4.66683 1.61004 4.66683 1.77338 4.66683 2.10008V2.56675C4.66683 2.89345 4.66683 3.05679 4.73041 3.18158C4.78634 3.29134 4.87557 3.38058 4.98534 3.4365C5.11012 3.50008 5.27347 3.50008 5.60016 3.50008Z" stroke="#344054" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+)
+
+const GenerationItem: FC<IGenerationItemProps> = ({
+ isWorkflow,
+ workflowProcessData,
+ className,
+ isError,
+ onRetry,
+ content,
+ messageId,
+ isLoading,
+ isResponding,
+ moreLikeThis,
+ isInWebApp = false,
+ feedback,
+ onFeedback,
+ onSave,
+ depth = 1,
+ isMobile,
+ isInstalledApp,
+ installedAppId,
+ taskId,
+ controlClearMoreLikeThis,
+ supportFeedback,
+ isShowTextToSpeech,
+ hideProcessDetail,
+ siteInfo,
+ inSidePanel,
+}) => {
+ const { t } = useTranslation()
+ const params = useParams()
+ const isTop = depth === 1
+ const [completionRes, setCompletionRes] = useState('')
+ const [childMessageId, setChildMessageId] = useState<string | null>(null)
+ const [childFeedback, setChildFeedback] = useState<FeedbackType>({
+ rating: null,
+ })
+ const {
+ config,
+ } = useChatContext()
+
+ const setCurrentLogItem = useAppStore(s => s.setCurrentLogItem)
+ const setShowPromptLogModal = useAppStore(s => s.setShowPromptLogModal)
+
+ const handleFeedback = async (childFeedback: FeedbackType) => {
+ await updateFeedback({ url: `/messages/${childMessageId}/feedbacks`, body: { rating: childFeedback.rating } }, isInstalledApp, installedAppId)
+ setChildFeedback(childFeedback)
+ }
+
+ const [isQuerying, { setTrue: startQuerying, setFalse: stopQuerying }] = useBoolean(false)
+
+ const childProps = {
+ isInWebApp: true,
+ content: completionRes,
+ messageId: childMessageId,
+ depth: depth + 1,
+ moreLikeThis: true,
+ onFeedback: handleFeedback,
+ isLoading: isQuerying,
+ feedback: childFeedback,
+ onSave,
+ isShowTextToSpeech,
+ isMobile,
+ isInstalledApp,
+ installedAppId,
+ controlClearMoreLikeThis,
+ isWorkflow,
+ siteInfo,
+ taskId,
+ }
+
+ const handleMoreLikeThis = async () => {
+ if (isQuerying || !messageId) {
+ Toast.notify({ type: 'warning', message: t('appDebug.errorMessage.waitForResponse') })
+ return
+ }
+ startQuerying()
+ const res: any = await fetchMoreLikeThis(messageId as string, isInstalledApp, installedAppId)
+ setCompletionRes(res.answer)
+ setChildFeedback({
+ rating: null,
+ })
+ setChildMessageId(res.id)
+ stopQuerying()
+ }
+
+ useEffect(() => {
+ if (controlClearMoreLikeThis) {
+ setChildMessageId(null)
+ setCompletionRes('')
+ }
+ }, [controlClearMoreLikeThis])
+
+ // regeneration clear child
+ useEffect(() => {
+ if (isLoading)
+ setChildMessageId(null)
+ }, [isLoading])
+
+ const handleOpenLogModal = async () => {
+ const data = await fetchTextGenerationMessage({
+ appId: params.appId as string,
+ messageId: messageId!,
+ })
+ const logItem = {
+ ...data,
+ log: [
+ ...data.message,
+ ...(data.message[data.message.length - 1].role !== 'assistant'
+ ? [
+ {
+ role: 'assistant',
+ text: data.answer,
+ files: data.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [],
+ },
+ ]
+ : []),
+ ],
+ }
+ setCurrentLogItem(logItem)
+ setShowPromptLogModal(true)
+ }
+
+ const [currentTab, setCurrentTab] = useState<string>('DETAIL')
+ const showResultTabs = !!workflowProcessData?.resultText || !!workflowProcessData?.files?.length
+ const switchTab = async (tab: string) => {
+ setCurrentTab(tab)
+ }
+ useEffect(() => {
+ if (workflowProcessData?.resultText || !!workflowProcessData?.files?.length)
+ switchTab('RESULT')
+ else
+ switchTab('DETAIL')
+ }, [workflowProcessData?.files?.length, workflowProcessData?.resultText])
+
+ return (
+ <>
+ <div className={cn('relative', !isTop && 'mt-3', className)}>
+ {isLoading && (
+ <div className={cn('flex h-10 items-center', !inSidePanel && 'rounded-2xl border-t border-divider-subtle bg-chat-bubble-bg')}><Loading type='area' /></div>
+ )}
+ {!isLoading && (
+ <>
+ {/* result content */}
+ <div className={cn(
+ 'relative',
+ !inSidePanel && 'rounded-2xl border-t border-divider-subtle bg-chat-bubble-bg',
+ )}>
+ {workflowProcessData && (
+ <>
+ <div className={cn(
+ 'p-3',
+ showResultTabs && 'border-b border-divider-subtle',
+ )}>
+ {taskId && (
+ <div className={cn('system-2xs-medium-uppercase mb-2 flex items-center text-text-accent-secondary', isError && 'text-text-destructive')}>
+ <RiPlayList2Line className='mr-1 h-3 w-3' />
+ <span>{t('share.generation.execution')}</span>
+ <span className='px-1'>路</span>
+ <span>{taskId}</span>
+ </div>
+ )}
+ {siteInfo && workflowProcessData && (
+ <WorkflowProcessItem
+ data={workflowProcessData}
+ expand={workflowProcessData.expand}
+ hideProcessDetail={hideProcessDetail}
+ hideInfo={hideProcessDetail}
+ readonly={!siteInfo.show_workflow_steps}
+ />
+ )}
+ {showResultTabs && (
+ <div className='flex items-center space-x-6 px-1'>
+ <div
+ className={cn(
+ 'system-sm-semibold-uppercase cursor-pointer border-b-2 border-transparent py-3 text-text-tertiary',
+ currentTab === 'RESULT' && 'border-util-colors-blue-brand-blue-brand-600 text-text-primary',
+ )}
+ onClick={() => switchTab('RESULT')}
+ >{t('runLog.result')}</div>
+ <div
+ className={cn(
+ 'system-sm-semibold-uppercase cursor-pointer border-b-2 border-transparent py-3 text-text-tertiary',
+ currentTab === 'DETAIL' && 'border-util-colors-blue-brand-blue-brand-600 text-text-primary',
+ )}
+ onClick={() => switchTab('DETAIL')}
+ >{t('runLog.detail')}</div>
+ </div>
+ )}
+ </div>
+ {!isError && (
+ <ResultTab data={workflowProcessData} content={content} currentTab={currentTab} />
+ )}
+ </>
+ )}
+ {!workflowProcessData && taskId && (
+ <div className={cn('system-2xs-medium-uppercase sticky left-0 top-0 flex w-full items-center rounded-t-2xl bg-components-actionbar-bg p-4 pb-3 text-text-accent-secondary', isError && 'text-text-destructive')}>
+ <RiPlayList2Line className='mr-1 h-3 w-3' />
+ <span>{t('share.generation.execution')}</span>
+ <span className='px-1'>路</span>
+ <span>{`${taskId}${depth > 1 ? `-${depth - 1}` : ''}`}</span>
+ </div>
+ )}
+ {isError && (
+ <div className='body-lg-regular p-4 pt-0 text-text-quaternary'>{t('share.generation.batchFailed.outputPlaceholder')}</div>
+ )}
+ {!workflowProcessData && !isError && (typeof content === 'string') && (
+ <div className={cn('p-4', taskId && 'pt-0')}>
+ <Markdown content={content} />
+ </div>
+ )}
+ </div>
+ {/* meta data */}
+ <div className={cn(
+ 'system-xs-regular relative mt-1 h-4 px-4 text-text-quaternary',
+ isMobile && ((childMessageId || isQuerying) && depth < 3) && 'pl-10',
+ )}>
+ {!isWorkflow && <span>{content?.length} {t('common.unit.char')}</span>}
+ {/* action buttons */}
+ <div className='absolute bottom-1 right-2 flex items-center'>
+ {!isInWebApp && !isInstalledApp && !isResponding && (
+ <div className='ml-1 flex items-center gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm'>
+ <ActionButton disabled={isError || !messageId} onClick={handleOpenLogModal}>
+ <RiFileList3Line className='h-4 w-4' />
+ {/* <div>{t('common.operation.log')}</div> */}
+ </ActionButton>
+ </div>
+ )}
+ <div className='ml-1 flex items-center gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm'>
+ {moreLikeThis && (
+ <ActionButton state={depth === MAX_DEPTH ? ActionButtonState.Disabled : ActionButtonState.Default} disabled={depth === MAX_DEPTH} onClick={handleMoreLikeThis}>
+ <RiSparklingLine className='h-4 w-4' />
+ </ActionButton>
+ )}
+ {isShowTextToSpeech && (
+ <NewAudioButton
+ id={messageId!}
+ voice={config?.text_to_speech?.voice}
+ />
+ )}
+ {((currentTab === 'RESULT' && workflowProcessData?.resultText) || !isWorkflow) && (
+ <ActionButton disabled={isError || !messageId} onClick={() => {
+ const copyContent = isWorkflow ? workflowProcessData?.resultText : content
+ if (typeof copyContent === 'string')
+ copy(copyContent)
+ else
+ copy(JSON.stringify(copyContent))
+ Toast.notify({ type: 'success', message: t('common.actionMsg.copySuccessfully') })
+ }}>
+ <RiClipboardLine className='h-4 w-4' />
+ </ActionButton>
+ )}
+ {isInWebApp && isError && (
+ <ActionButton onClick={onRetry}>
+ <RiReplay15Line className='h-4 w-4' />
+ </ActionButton>
+ )}
+ {isInWebApp && !isWorkflow && (
+ <ActionButton disabled={isError || !messageId} onClick={() => { onSave?.(messageId as string) }}>
+ <RiBookmark3Line className='h-4 w-4' />
+ </ActionButton>
+ )}
+ </div>
+ {(supportFeedback || isInWebApp) && !isWorkflow && !isError && messageId && (
+ <div className='ml-1 flex items-center gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm'>
+ {!feedback?.rating && (
+ <>
+ <ActionButton onClick={() => onFeedback?.({ rating: 'like' })}>
+ <RiThumbUpLine className='h-4 w-4' />
+ </ActionButton>
+ <ActionButton onClick={() => onFeedback?.({ rating: 'dislike' })}>
+ <RiThumbDownLine className='h-4 w-4' />
+ </ActionButton>
+ </>
+ )}
+ {feedback?.rating === 'like' && (
+ <ActionButton state={ActionButtonState.Active} onClick={() => onFeedback?.({ rating: null })}>
+ <RiThumbUpLine className='h-4 w-4' />
+ </ActionButton>
+ )}
+ {feedback?.rating === 'dislike' && (
+ <ActionButton state={ActionButtonState.Destructive} onClick={() => onFeedback?.({ rating: null })}>
+ <RiThumbDownLine className='h-4 w-4' />
+ </ActionButton>
+ )}
+ </div>
+ )}
+ </div>
+ </div>
+ {/* more like this elements */}
+ {!isTop && (
+ <div className={cn(
+ 'absolute top-[-32px] flex h-[33px] w-4 justify-center',
+ isMobile ? 'left-[17px]' : 'left-[50%] translate-x-[-50%]',
+ )}>
+ <div className='h-full w-0.5 bg-divider-regular'></div>
+ <div className={cn(
+ 'absolute left-0 flex h-4 w-4 items-center justify-center rounded-2xl border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-500 shadow-xs',
+ isMobile ? 'top-[3.5px]' : 'top-2',
+ )}>
+ <RiSparklingFill className='h-3 w-3 text-text-primary-on-surface' />
+ </div>
+ </div>
+ )}
+ </>
+ )}
+ </div>
+ {((childMessageId || isQuerying) && depth < 3) && (
+ <GenerationItem {...childProps as any} />
+ )}
+ </>
+ )
+}
+export default React.memo(GenerationItem)
diff --git a/app/components/app/text-generate/item/result-tab.tsx b/app/components/app/text-generate/item/result-tab.tsx
new file mode 100644
index 0000000..94d5ded
--- /dev/null
+++ b/app/components/app/text-generate/item/result-tab.tsx
@@ -0,0 +1,56 @@
+import {
+ memo,
+} from 'react'
+import { Markdown } from '@/app/components/base/markdown'
+import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
+import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
+import type { WorkflowProcess } from '@/app/components/base/chat/types'
+import { FileList } from '@/app/components/base/file-uploader'
+
+const ResultTab = ({
+ data,
+ content,
+ currentTab,
+}: {
+ data?: WorkflowProcess
+ content: any
+ currentTab: string
+}) => {
+ return (
+ <>
+ {currentTab === 'RESULT' && (
+ <div className='space-y-3 p-4'>
+ {data?.resultText && <Markdown content={data?.resultText || ''} />}
+ {!!data?.files?.length && (
+ <div className='flex flex-col gap-2'>
+ {data?.files.map((item: any) => (
+ <div key={item.varName} className='system-xs-regular flex flex-col gap-1'>
+ <div className='py-1 text-text-tertiary '>{item.varName}</div>
+ <FileList
+ files={item.list}
+ showDeleteAction={false}
+ showDownloadAction
+ canPreview
+ />
+ </div>
+ ))}
+ </div>
+ )}
+ </div>
+ )}
+ {currentTab === 'DETAIL' && content && (
+ <div className='p-4'>
+ <CodeEditor
+ readOnly
+ title={<div>JSON OUTPUT</div>}
+ language={CodeLanguage.json}
+ value={content}
+ isJSONStringifyBeauty
+ />
+ </div>
+ )}
+ </>
+ )
+}
+
+export default memo(ResultTab)
diff --git a/app/components/app/text-generate/saved-items/index.tsx b/app/components/app/text-generate/saved-items/index.tsx
new file mode 100644
index 0000000..c22a4ca
--- /dev/null
+++ b/app/components/app/text-generate/saved-items/index.tsx
@@ -0,0 +1,75 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import {
+ RiClipboardLine,
+ RiDeleteBinLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import copy from 'copy-to-clipboard'
+import NoData from './no-data'
+import cn from '@/utils/classnames'
+import type { SavedMessage } from '@/models/debug'
+import { Markdown } from '@/app/components/base/markdown'
+import Toast from '@/app/components/base/toast'
+import ActionButton from '@/app/components/base/action-button'
+import NewAudioButton from '@/app/components/base/new-audio-button'
+
+export type ISavedItemsProps = {
+ className?: string
+ isShowTextToSpeech?: boolean
+ list: SavedMessage[]
+ onRemove: (id: string) => void
+ onStartCreateContent: () => void
+}
+
+const SavedItems: FC<ISavedItemsProps> = ({
+ className,
+ isShowTextToSpeech,
+ list,
+ onRemove,
+ onStartCreateContent,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={cn('space-y-4', className)}>
+ {list.length === 0
+ ? (
+ <NoData onStartCreateContent={onStartCreateContent} />
+ )
+ : (<>
+ {list.map(({ id, answer }) => (
+ <div key={id} className='relative'>
+ <div className={cn(
+ 'rounded-2xl bg-background-section-burn p-4',
+ )}>
+ <Markdown content={answer} />
+ </div>
+ <div className='system-xs-regular mt-1 h-4 px-4 text-text-quaternary'>
+ <span>{answer.length} {t('common.unit.char')}</span>
+ </div>
+ <div className='absolute bottom-1 right-2'>
+ <div className='ml-1 flex items-center gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm'>
+ {isShowTextToSpeech && <NewAudioButton value={answer}/>}
+ <ActionButton onClick={() => {
+ copy(answer)
+ Toast.notify({ type: 'success', message: t('common.actionMsg.copySuccessfully') })
+ }}>
+ <RiClipboardLine className='h-4 w-4' />
+ </ActionButton>
+ <ActionButton onClick={() => {
+ onRemove(id)
+ }}>
+ <RiDeleteBinLine className='h-4 w-4' />
+ </ActionButton>
+ </div>
+ </div>
+ </div>
+ ))}
+ </>)}
+
+ </div>
+ )
+}
+export default React.memo(SavedItems)
diff --git a/app/components/app/text-generate/saved-items/no-data/index.tsx b/app/components/app/text-generate/saved-items/no-data/index.tsx
new file mode 100644
index 0000000..69c4966
--- /dev/null
+++ b/app/components/app/text-generate/saved-items/no-data/index.tsx
@@ -0,0 +1,42 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiAddLine,
+ RiBookmark3Line,
+} from '@remixicon/react'
+import Button from '@/app/components/base/button'
+export type INoDataProps = {
+ onStartCreateContent: () => void
+}
+
+const NoData: FC<INoDataProps> = ({
+ onStartCreateContent,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='rounded-xl bg-background-section-burn p-6 '>
+ <div className='flex h-10 w-10 items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg-alt shadow-lg backdrop-blur-sm'>
+ <RiBookmark3Line className='h-4 w-4 text-text-accent'/>
+ </div>
+ <div className='mt-3'>
+ <span className='system-xl-semibold text-text-secondary'>{t('share.generation.savedNoData.title')}</span>
+ </div>
+ <div className='system-sm-regular mt-1 text-text-tertiary'>
+ {t('share.generation.savedNoData.description')}
+ </div>
+ <Button
+ variant='primary'
+ className='mt-3'
+ onClick={onStartCreateContent}
+ >
+ <RiAddLine className='mr-1 h-4 w-4' />
+ <span>{t('share.generation.savedNoData.startCreateContent')}</span>
+ </Button>
+ </div>
+ )
+}
+
+export default React.memo(NoData)
diff --git a/app/components/app/type-selector/index.tsx b/app/components/app/type-selector/index.tsx
new file mode 100644
index 0000000..0accafd
--- /dev/null
+++ b/app/components/app/type-selector/index.tsx
@@ -0,0 +1,168 @@
+import { useTranslation } from 'react-i18next'
+import React, { useState } from 'react'
+import { RiArrowDownSLine, RiCloseCircleFill, RiExchange2Fill, RiFilter3Line } from '@remixicon/react'
+import Checkbox from '../../base/checkbox'
+import cn from '@/utils/classnames'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { BubbleTextMod, ChatBot, ListSparkle, Logic } from '@/app/components/base/icons/src/vender/solid/communication'
+import type { AppMode } from '@/types/app'
+export type AppSelectorProps = {
+ value: Array<AppMode>
+ onChange: (value: AppSelectorProps['value']) => void
+}
+
+const allTypes: AppMode[] = ['chat', 'agent-chat', 'completion', 'advanced-chat', 'workflow']
+
+const AppTypeSelector = ({ value, onChange }: AppSelectorProps) => {
+ const [open, setOpen] = useState(false)
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <div className='relative'>
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ className='block'
+ >
+ <div className={cn(
+ 'flex cursor-pointer items-center justify-between space-x-1 rounded-md px-2 hover:bg-state-base-hover',
+ )}>
+ <AppTypeSelectTrigger values={value} />
+ {value && value.length > 0 && <div className='h-4 w-4' onClick={(e) => {
+ e.stopPropagation()
+ onChange([])
+ }}>
+ <RiCloseCircleFill className='h-3.5 w-3.5 cursor-pointer text-text-quaternary hover:text-text-tertiary' />
+ </div>}
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1002]'>
+ <ul className='relative w-[240px] rounded-xl border border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-[5px]'>
+ {allTypes.map(mode => (
+ <AppTypeSelectorItem key={mode} type={mode}
+ checked={Boolean(value.length > 0 && value?.indexOf(mode) !== -1)}
+ onClick={() => {
+ if (value?.indexOf(mode) !== -1)
+ onChange(value?.filter(v => v !== mode) ?? [])
+ else
+ onChange([...(value || []), mode])
+ }} />
+ ))}
+ </ul>
+ </PortalToFollowElemContent>
+ </div >
+ </PortalToFollowElem >
+ )
+}
+
+export default AppTypeSelector
+
+function AppTypeSelectTrigger({ values }: { values: AppSelectorProps['value'] }) {
+ const { t } = useTranslation()
+ if (!values || values.length === 0) {
+ return <div className={cn(
+ 'flex h-8 items-center justify-between gap-1',
+ )}>
+ <RiFilter3Line className='h-4 w-4 text-text-tertiary' />
+ <div className='system-sm-medium min-w-[65px] grow text-center text-text-tertiary'>{t('app.typeSelector.all')}</div>
+ <RiArrowDownSLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ }
+ if (values.length === 1) {
+ return <div className={cn(
+ 'flex h-8 flex-nowrap items-center justify-between gap-1',
+ )}>
+ <AppTypeIcon type={values[0]} />
+ <div className='line-clamp-1 flex flex-1 items-center text-center'>
+ <AppTypeLabel type={values[0]} className="system-sm-medium text-components-menu-item-text" />
+ </div>
+ </div>
+ }
+ return <div className={cn(
+ 'relative flex h-8 items-center justify-between -space-x-2',
+ )}>
+ {values.map((mode, index) => (<AppTypeIcon key={mode} type={mode} wrapperClassName='border border-components-panel-on-panel-item-bg' style={{ zIndex: 5 - index }} />))}
+ </div>
+}
+
+type AppTypeSelectorItemProps = {
+ checked: boolean
+ type: AppMode
+ onClick: () => void
+}
+function AppTypeSelectorItem({ checked, type, onClick }: AppTypeSelectorItemProps) {
+ return <li className='flex cursor-pointer items-center space-x-2 rounded-lg py-1 pl-2 pr-1 hover:bg-state-base-hover' onClick={onClick}>
+ <Checkbox checked={checked} />
+ <AppTypeIcon type={type} />
+ <div className='grow p-1 pl-0'>
+ <AppTypeLabel type={type} className="system-sm-medium text-components-menu-item-text" />
+ </div>
+ </li>
+}
+
+type AppTypeIconProps = {
+ type: AppMode
+ style?: React.CSSProperties
+ className?: string
+ wrapperClassName?: string
+}
+
+export function AppTypeIcon({ type, className, wrapperClassName, style }: AppTypeIconProps) {
+ const wrapperClassNames = cn('inline-flex h-5 w-5 items-center justify-center rounded-md border border-divider-regular', wrapperClassName)
+ const iconClassNames = cn('h-3.5 w-3.5 text-components-avatar-shape-fill-stop-100', className)
+ if (type === 'chat') {
+ return <div style={style} className={cn(wrapperClassNames, 'bg-components-icon-bg-blue-solid')}>
+ <ChatBot className={iconClassNames} />
+ </div>
+ }
+ if (type === 'agent-chat') {
+ return <div style={style} className={cn(wrapperClassNames, 'bg-components-icon-bg-violet-solid')}>
+ <Logic className={iconClassNames} />
+ </div>
+ }
+ if (type === 'advanced-chat') {
+ return <div style={style} className={cn(wrapperClassNames, 'bg-components-icon-bg-blue-light-solid')}>
+ <BubbleTextMod className={iconClassNames} />
+ </div>
+ }
+ if (type === 'workflow') {
+ return <div style={style} className={cn(wrapperClassNames, 'bg-components-icon-bg-indigo-solid')}>
+ <RiExchange2Fill className={iconClassNames} />
+ </div>
+ }
+ if (type === 'completion') {
+ return <div style={style} className={cn(wrapperClassNames, 'bg-components-icon-bg-teal-solid')}>
+ <ListSparkle className={iconClassNames} />
+ </div>
+ }
+ return null
+}
+
+type AppTypeLabelProps = {
+ type: AppMode
+ className?: string
+}
+export function AppTypeLabel({ type, className }: AppTypeLabelProps) {
+ const { t } = useTranslation()
+ let label = ''
+ if (type === 'chat')
+ label = t('app.typeSelector.chatbot')
+ if (type === 'agent-chat')
+ label = t('app.typeSelector.agent')
+ if (type === 'completion')
+ label = t('app.typeSelector.completion')
+ if (type === 'advanced-chat')
+ label = t('app.typeSelector.advanced')
+ if (type === 'workflow')
+ label = t('app.typeSelector.workflow')
+
+ return <span className={className}>{label}</span>
+}
diff --git a/app/components/app/workflow-log/detail.tsx b/app/components/app/workflow-log/detail.tsx
new file mode 100644
index 0000000..dc3eb89
--- /dev/null
+++ b/app/components/app/workflow-log/detail.tsx
@@ -0,0 +1,26 @@
+'use client'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import Run from '@/app/components/workflow/run'
+
+type ILogDetail = {
+ runID: string
+ onClose: () => void
+}
+
+const DetailPanel: FC<ILogDetail> = ({ runID, onClose }) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='relative flex grow flex-col pt-3'>
+ <span className='absolute right-3 top-4 z-20 cursor-pointer p-1' onClick={onClose}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </span>
+ <h1 className='system-xl-semibold shrink-0 px-4 py-1 text-text-primary'>{t('appLog.runDetail.workflowTitle')}</h1>
+ <Run runID={runID}/>
+ </div>
+ )
+}
+
+export default DetailPanel
diff --git a/app/components/app/workflow-log/filter.tsx b/app/components/app/workflow-log/filter.tsx
new file mode 100644
index 0000000..f60e1f9
--- /dev/null
+++ b/app/components/app/workflow-log/filter.tsx
@@ -0,0 +1,74 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import dayjs from 'dayjs'
+import { RiCalendarLine } from '@remixicon/react'
+import quarterOfYear from 'dayjs/plugin/quarterOfYear'
+import type { QueryParam } from './index'
+import Chip from '@/app/components/base/chip'
+import Input from '@/app/components/base/input'
+dayjs.extend(quarterOfYear)
+
+const today = dayjs()
+
+export const TIME_PERIOD_MAPPING: { [key: string]: { value: number; name: string } } = {
+ 1: { value: 0, name: 'today' },
+ 2: { value: 7, name: 'last7days' },
+ 3: { value: 28, name: 'last4weeks' },
+ 4: { value: today.diff(today.subtract(3, 'month'), 'day'), name: 'last3months' },
+ 5: { value: today.diff(today.subtract(12, 'month'), 'day'), name: 'last12months' },
+ 6: { value: today.diff(today.startOf('month'), 'day'), name: 'monthToDate' },
+ 7: { value: today.diff(today.startOf('quarter'), 'day'), name: 'quarterToDate' },
+ 8: { value: today.diff(today.startOf('year'), 'day'), name: 'yearToDate' },
+ 9: { value: -1, name: 'allTime' },
+}
+
+type IFilterProps = {
+ queryParams: QueryParam
+ setQueryParams: (v: QueryParam) => void
+}
+
+const Filter: FC<IFilterProps> = ({ queryParams, setQueryParams }: IFilterProps) => {
+ const { t } = useTranslation()
+ return (
+ <div className='mb-2 flex flex-row flex-wrap gap-2'>
+ <Chip
+ value={queryParams.status || 'all'}
+ onSelect={(item) => {
+ setQueryParams({ ...queryParams, status: item.value as string })
+ }}
+ onClear={() => setQueryParams({ ...queryParams, status: 'all' })}
+ items={[{ value: 'all', name: 'All' },
+ { value: 'succeeded', name: 'Success' },
+ { value: 'failed', name: 'Fail' },
+ { value: 'stopped', name: 'Stop' },
+ ]}
+ />
+ <Chip
+ className='min-w-[150px]'
+ panelClassName='w-[270px]'
+ leftIcon={<RiCalendarLine className='h-4 w-4 text-text-secondary' />}
+ value={queryParams.period}
+ onSelect={(item) => {
+ setQueryParams({ ...queryParams, period: item.value })
+ }}
+ onClear={() => setQueryParams({ ...queryParams, period: '9' })}
+ items={Object.entries(TIME_PERIOD_MAPPING).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}`) }))}
+ />
+ <Input
+ wrapperClassName='w-[200px]'
+ showLeftIcon
+ showClearIcon
+ value={queryParams.keyword}
+ placeholder={t('common.operation.search')!}
+ onChange={(e) => {
+ setQueryParams({ ...queryParams, keyword: e.target.value })
+ }}
+ onClear={() => setQueryParams({ ...queryParams, keyword: '' })}
+ />
+ </div>
+ )
+}
+
+export default Filter
diff --git a/app/components/app/workflow-log/index.tsx b/app/components/app/workflow-log/index.tsx
new file mode 100644
index 0000000..c350a8b
--- /dev/null
+++ b/app/components/app/workflow-log/index.tsx
@@ -0,0 +1,120 @@
+'use client'
+import type { FC, SVGProps } from 'react'
+import React, { useState } from 'react'
+import useSWR from 'swr'
+import { usePathname } from 'next/navigation'
+import { useDebounce } from 'ahooks'
+import { omit } from 'lodash-es'
+import dayjs from 'dayjs'
+import utc from 'dayjs/plugin/utc'
+import timezone from 'dayjs/plugin/timezone'
+import { Trans, useTranslation } from 'react-i18next'
+import Link from 'next/link'
+import List from './list'
+import Filter, { TIME_PERIOD_MAPPING } from './filter'
+import Pagination from '@/app/components/base/pagination'
+import Loading from '@/app/components/base/loading'
+import { fetchWorkflowLogs } from '@/service/log'
+import { APP_PAGE_LIMIT } from '@/config'
+import type { App, AppMode } from '@/types/app'
+import { useAppContext } from '@/context/app-context'
+
+dayjs.extend(utc)
+dayjs.extend(timezone)
+
+export type ILogsProps = {
+ appDetail: App
+}
+
+export type QueryParam = {
+ period: string
+ status?: string
+ keyword?: string
+}
+
+const ThreeDotsIcon = ({ className }: SVGProps<SVGElement>) => {
+ return <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
+ <path d="M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103" stroke="#374151" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+}
+const EmptyElement: FC<{ appUrl: string }> = ({ appUrl }) => {
+ const { t } = useTranslation()
+ const pathname = usePathname()
+ const pathSegments = pathname.split('/')
+ pathSegments.pop()
+ return <div className='flex h-full items-center justify-center'>
+ <div className='box-border h-fit w-[560px] rounded-2xl bg-background-section-burn px-5 py-4'>
+ <span className='system-md-semibold text-text-secondary'>{t('appLog.table.empty.element.title')}<ThreeDotsIcon className='relative -left-1.5 -top-3 inline' /></span>
+ <div className='system-sm-regular mt-2 text-text-tertiary'>
+ <Trans
+ i18nKey="appLog.table.empty.element.content"
+ components={{ shareLink: <Link href={`${pathSegments.join('/')}/overview`} className='text-util-colors-blue-blue-600' />, testLink: <Link href={appUrl} className='text-util-colors-blue-blue-600' target='_blank' rel='noopener noreferrer' /> }}
+ />
+ </div>
+ </div>
+ </div>
+}
+
+const Logs: FC<ILogsProps> = ({ appDetail }) => {
+ const { t } = useTranslation()
+ const { userProfile: { timezone } } = useAppContext()
+ const [queryParams, setQueryParams] = useState<QueryParam>({ status: 'all', period: '2' })
+ const [currPage, setCurrPage] = React.useState<number>(0)
+ const debouncedQueryParams = useDebounce(queryParams, { wait: 500 })
+ const [limit, setLimit] = React.useState<number>(APP_PAGE_LIMIT)
+
+ const query = {
+ page: currPage + 1,
+ limit,
+ ...(debouncedQueryParams.status !== 'all' ? { status: debouncedQueryParams.status } : {}),
+ ...(debouncedQueryParams.keyword ? { keyword: debouncedQueryParams.keyword } : {}),
+ ...((debouncedQueryParams.period !== '9')
+ ? {
+ created_at__after: dayjs().subtract(TIME_PERIOD_MAPPING[debouncedQueryParams.period].value, 'day').startOf('day').tz(timezone).format('YYYY-MM-DDTHH:mm:ssZ'),
+ created_at__before: dayjs().endOf('day').tz(timezone).format('YYYY-MM-DDTHH:mm:ssZ'),
+ }
+ : {}),
+ ...omit(debouncedQueryParams, ['period', 'status']),
+ }
+
+ const getWebAppType = (appType: AppMode) => {
+ if (appType !== 'completion' && appType !== 'workflow')
+ return 'chat'
+ return appType
+ }
+
+ const { data: workflowLogs, mutate } = useSWR({
+ url: `/apps/${appDetail.id}/workflow-app-logs`,
+ params: query,
+ }, fetchWorkflowLogs)
+ const total = workflowLogs?.total
+
+ return (
+ <div className='flex h-full flex-col'>
+ <h1 className='system-xl-semibold text-text-primary'>{t('appLog.workflowTitle')}</h1>
+ <p className='system-sm-regular text-text-tertiary'>{t('appLog.workflowSubtitle')}</p>
+ <div className='flex max-h-[calc(100%-16px)] flex-1 flex-col py-4'>
+ <Filter queryParams={queryParams} setQueryParams={setQueryParams} />
+ {/* workflow log */}
+ {total === undefined
+ ? <Loading type='app' />
+ : total > 0
+ ? <List logs={workflowLogs} appDetail={appDetail} onRefresh={mutate} />
+ : <EmptyElement appUrl={`${appDetail.site.app_base_url}/${getWebAppType(appDetail.mode)}/${appDetail.site.access_token}`} />
+ }
+ {/* Show Pagination only if the total is more than the limit */}
+ {(total && total > APP_PAGE_LIMIT)
+ ? <Pagination
+ current={currPage}
+ onChange={setCurrPage}
+ total={total}
+ limit={limit}
+ onLimitChange={setLimit}
+ />
+ : null}
+ </div>
+ </div>
+ )
+}
+
+export default Logs
diff --git a/app/components/app/workflow-log/list.tsx b/app/components/app/workflow-log/list.tsx
new file mode 100644
index 0000000..b01c049
--- /dev/null
+++ b/app/components/app/workflow-log/list.tsx
@@ -0,0 +1,145 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import DetailPanel from './detail'
+import type { WorkflowAppLogDetail, WorkflowLogsResponse } from '@/models/log'
+import type { App } from '@/types/app'
+import Loading from '@/app/components/base/loading'
+import Drawer from '@/app/components/base/drawer'
+import Indicator from '@/app/components/header/indicator'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import useTimestamp from '@/hooks/use-timestamp'
+import cn from '@/utils/classnames'
+
+type ILogs = {
+ logs?: WorkflowLogsResponse
+ appDetail?: App
+ onRefresh: () => void
+}
+
+const defaultValue = 'N/A'
+
+const WorkflowAppLogList: FC<ILogs> = ({ logs, appDetail, onRefresh }) => {
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ const [showDrawer, setShowDrawer] = useState<boolean>(false)
+ const [currentLog, setCurrentLog] = useState<WorkflowAppLogDetail | undefined>()
+
+ const statusTdRender = (status: string) => {
+ if (status === 'succeeded') {
+ return (
+ <div className='system-xs-semibold-uppercase inline-flex items-center gap-1'>
+ <Indicator color={'green'} />
+ <span className='text-util-colors-green-green-600'>Success</span>
+ </div>
+ )
+ }
+ if (status === 'failed') {
+ return (
+ <div className='system-xs-semibold-uppercase inline-flex items-center gap-1'>
+ <Indicator color={'red'} />
+ <span className='text-util-colors-red-red-600'>Fail</span>
+ </div>
+ )
+ }
+ if (status === 'stopped') {
+ return (
+ <div className='system-xs-semibold-uppercase inline-flex items-center gap-1'>
+ <Indicator color={'yellow'} />
+ <span className='text-util-colors-warning-warning-600'>Stop</span>
+ </div>
+ )
+ }
+ if (status === 'running') {
+ return (
+ <div className='system-xs-semibold-uppercase inline-flex items-center gap-1'>
+ <Indicator color={'blue'} />
+ <span className='text-util-colors-blue-light-blue-light-600'>Running</span>
+ </div>
+ )
+ }
+ if (status === 'partial-succeeded') {
+ return (
+ <div className='system-xs-semibold-uppercase inline-flex items-center gap-1'>
+ <Indicator color={'green'} />
+ <span className='text-util-colors-green-green-600'>Partial Success</span>
+ </div>
+ )
+ }
+ }
+
+ const onCloseDrawer = () => {
+ onRefresh()
+ setShowDrawer(false)
+ setCurrentLog(undefined)
+ }
+
+ if (!logs || !appDetail)
+ return <Loading />
+
+ return (
+ <div className='overflow-x-auto'>
+ <table className={cn('mt-2 w-full min-w-[440px] border-collapse border-0')}>
+ <thead className='system-xs-medium-uppercase text-text-tertiary'>
+ <tr>
+ <td className='w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1'></td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.startTime')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.status')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.runtime')}</td>
+ <td className='whitespace-nowrap bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.tokens')}</td>
+ <td className='whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3'>{t('appLog.table.header.user')}</td>
+ </tr>
+ </thead>
+ <tbody className="system-sm-regular text-text-secondary">
+ {logs.data.map((log: WorkflowAppLogDetail) => {
+ const endUser = log.created_by_end_user ? log.created_by_end_user.session_id : log.created_by_account ? log.created_by_account.name : defaultValue
+ return <tr
+ key={log.id}
+ className={cn('cursor-pointer border-b border-divider-subtle hover:bg-background-default-hover', currentLog?.id !== log.id ? '' : 'bg-background-default-hover')}
+ onClick={() => {
+ setCurrentLog(log)
+ setShowDrawer(true)
+ }}>
+ <td className='h-4'>
+ {!log.read_at && (
+ <div className='flex items-center p-3 pr-0.5'>
+ <span className='inline-block h-1.5 w-1.5 rounded bg-util-colors-blue-blue-500'></span>
+ </div>
+ )}
+ </td>
+ <td className='w-[160px] p-3 pr-2'>{formatTime(log.created_at, t('appLog.dateTimeFormat') as string)}</td>
+ <td className='p-3 pr-2'>{statusTdRender(log.workflow_run.status)}</td>
+ <td className='p-3 pr-2'>
+ <div className={cn(
+ log.workflow_run.elapsed_time === 0 && 'text-text-quaternary',
+ )}>{`${log.workflow_run.elapsed_time.toFixed(3)}s`}</div>
+ </td>
+ <td className='p-3 pr-2'>{log.workflow_run.total_tokens}</td>
+ <td className='p-3 pr-2'>
+ <div className={cn(endUser === defaultValue ? 'text-text-quaternary' : 'text-text-secondary', 'overflow-hidden text-ellipsis whitespace-nowrap')}>
+ {endUser}
+ </div>
+ </td>
+ </tr>
+ })}
+ </tbody>
+ </table>
+ <Drawer
+ isOpen={showDrawer}
+ onClose={onCloseDrawer}
+ mask={isMobile}
+ footer={null}
+ panelClassName='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[600px] rounded-xl border border-components-panel-border'
+ >
+ <DetailPanel onClose={onCloseDrawer} runID={currentLog?.workflow_run.id || ''} />
+ </Drawer>
+ </div>
+ )
+}
+
+export default WorkflowAppLogList
diff --git a/app/components/base/action-button/index.css b/app/components/base/action-button/index.css
new file mode 100644
index 0000000..3c1a10b
--- /dev/null
+++ b/app/components/base/action-button/index.css
@@ -0,0 +1,45 @@
+@tailwind components;
+
+@layer components {
+ .action-btn {
+ @apply inline-flex justify-center items-center cursor-pointer text-text-tertiary hover:text-text-secondary hover:bg-state-base-hover
+ }
+
+ .action-btn-hover {
+ @apply bg-state-base-hover
+ }
+
+ .action-btn-disabled {
+ @apply cursor-not-allowed
+ }
+
+ .action-btn-xl {
+ @apply p-2 w-9 h-9 rounded-lg
+ }
+
+ .action-btn-l {
+ @apply p-1.5 w-8 h-8 rounded-lg
+ }
+
+ /* m is for the regular button */
+ .action-btn-m {
+ @apply p-0.5 w-6 h-6 rounded-lg
+ }
+
+ .action-btn-xs {
+ @apply p-0 w-4 h-4 rounded
+ }
+
+ .action-btn.action-btn-active {
+ @apply text-text-accent bg-state-accent-active hover:bg-state-accent-active-alt
+ }
+
+ .action-btn.action-btn-disabled {
+ @apply text-text-disabled
+ }
+
+ .action-btn.action-btn-destructive {
+ @apply text-text-destructive bg-state-destructive-hover
+ }
+
+}
diff --git a/app/components/base/action-button/index.tsx b/app/components/base/action-button/index.tsx
new file mode 100644
index 0000000..c90d1a8
--- /dev/null
+++ b/app/components/base/action-button/index.tsx
@@ -0,0 +1,73 @@
+import type { CSSProperties } from 'react'
+import React from 'react'
+import { type VariantProps, cva } from 'class-variance-authority'
+import classNames from '@/utils/classnames'
+
+enum ActionButtonState {
+ Destructive = 'destructive',
+ Active = 'active',
+ Disabled = 'disabled',
+ Default = '',
+ Hover = 'hover',
+}
+
+const actionButtonVariants = cva(
+ 'action-btn',
+ {
+ variants: {
+ size: {
+ xs: 'action-btn-xs',
+ m: 'action-btn-m',
+ l: 'action-btn-l',
+ xl: 'action-btn-xl',
+ },
+ },
+ defaultVariants: {
+ size: 'm',
+ },
+ },
+)
+
+export type ActionButtonProps = {
+ size?: 'xs' | 's' | 'm' | 'l' | 'xl'
+ state?: ActionButtonState
+ styleCss?: CSSProperties
+} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants>
+
+function getActionButtonState(state: ActionButtonState) {
+ switch (state) {
+ case ActionButtonState.Destructive:
+ return 'action-btn-destructive'
+ case ActionButtonState.Active:
+ return 'action-btn-active'
+ case ActionButtonState.Disabled:
+ return 'action-btn-disabled'
+ case ActionButtonState.Hover:
+ return 'action-btn-hover'
+ default:
+ return ''
+ }
+}
+
+const ActionButton = React.forwardRef<HTMLButtonElement, ActionButtonProps>(
+ ({ className, size, state = ActionButtonState.Default, styleCss, children, ...props }, ref) => {
+ return (
+ <button
+ type='button'
+ className={classNames(
+ actionButtonVariants({ className, size }),
+ getActionButtonState(state),
+ )}
+ ref={ref}
+ style={styleCss}
+ {...props}
+ >
+ {children}
+ </button>
+ )
+ },
+)
+ActionButton.displayName = 'ActionButton'
+
+export default ActionButton
+export { ActionButton, ActionButtonState, actionButtonVariants }
diff --git a/app/components/base/agent-log-modal/detail.tsx b/app/components/base/agent-log-modal/detail.tsx
new file mode 100644
index 0000000..148b168
--- /dev/null
+++ b/app/components/base/agent-log-modal/detail.tsx
@@ -0,0 +1,132 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { flatten, uniq } from 'lodash-es'
+import ResultPanel from './result'
+import TracingPanel from './tracing'
+import cn from '@/utils/classnames'
+import { ToastContext } from '@/app/components/base/toast'
+import Loading from '@/app/components/base/loading'
+import { fetchAgentLogDetail } from '@/service/log'
+import type { AgentIteration, AgentLogDetailResponse } from '@/models/log'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import type { IChatItem } from '@/app/components/base/chat/chat/type'
+
+export type AgentLogDetailProps = {
+ activeTab?: 'DETAIL' | 'TRACING'
+ conversationID: string
+ log: IChatItem
+ messageID: string
+}
+
+const AgentLogDetail: FC<AgentLogDetailProps> = ({
+ activeTab = 'DETAIL',
+ conversationID,
+ messageID,
+ log,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const [currentTab, setCurrentTab] = useState<string>(activeTab)
+ const appDetail = useAppStore(s => s.appDetail)
+ const [loading, setLoading] = useState<boolean>(true)
+ const [runDetail, setRunDetail] = useState<AgentLogDetailResponse>()
+ const [list, setList] = useState<AgentIteration[]>([])
+
+ const tools = useMemo(() => {
+ const res = uniq(flatten(runDetail?.iterations.map((iteration) => {
+ return iteration.tool_calls.map((tool: any) => tool.tool_name).filter(Boolean)
+ })).filter(Boolean))
+ return res
+ }, [runDetail])
+
+ const getLogDetail = useCallback(async (appID: string, conversationID: string, messageID: string) => {
+ try {
+ const res = await fetchAgentLogDetail({
+ appID,
+ params: {
+ conversation_id: conversationID,
+ message_id: messageID,
+ },
+ })
+ setRunDetail(res)
+ setList(res.iterations)
+ }
+ catch (err) {
+ notify({
+ type: 'error',
+ message: `${err}`,
+ })
+ }
+ }, [notify])
+
+ const getData = async (appID: string, conversationID: string, messageID: string) => {
+ setLoading(true)
+ await getLogDetail(appID, conversationID, messageID)
+ setLoading(false)
+ }
+
+ const switchTab = async (tab: string) => {
+ setCurrentTab(tab)
+ }
+
+ useEffect(() => {
+ // fetch data
+ if (appDetail)
+ getData(appDetail.id, conversationID, messageID)
+ }, [appDetail, conversationID, messageID])
+
+ return (
+ <div className='relative flex grow flex-col'>
+ {/* tab */}
+ <div className='flex shrink-0 items-center border-b-[0.5px] border-divider-regular px-4'>
+ <div
+ className={cn(
+ 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-text-tertiary',
+ currentTab === 'DETAIL' && '!border-[rgb(21,94,239)] text-text-secondary',
+ )}
+ onClick={() => switchTab('DETAIL')}
+ >{t('runLog.detail')}</div>
+ <div
+ className={cn(
+ 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-text-tertiary',
+ currentTab === 'TRACING' && '!border-[rgb(21,94,239)] text-text-secondary',
+ )}
+ onClick={() => switchTab('TRACING')}
+ >{t('runLog.tracing')}</div>
+ </div>
+ {/* panel detail */}
+ <div className={cn('h-0 grow overflow-y-auto rounded-b-2xl bg-components-panel-bg', currentTab !== 'DETAIL' && '!bg-background-section')}>
+ {loading && (
+ <div className='flex h-full items-center justify-center bg-components-panel-bg'>
+ <Loading />
+ </div>
+ )}
+ {!loading && currentTab === 'DETAIL' && runDetail && (
+ <ResultPanel
+ inputs={log.input}
+ outputs={log.content}
+ status={runDetail.meta.status}
+ error={runDetail.meta.error}
+ elapsed_time={runDetail.meta.elapsed_time}
+ total_tokens={runDetail.meta.total_tokens}
+ created_at={runDetail.meta.start_time}
+ created_by={runDetail.meta.executor}
+ agentMode={runDetail.meta.agent_mode}
+ tools={tools}
+ iterations={runDetail.iterations.length}
+ />
+ )}
+ {!loading && currentTab === 'TRACING' && (
+ <TracingPanel
+ list={list}
+ />
+ )}
+ </div>
+ </div>
+ )
+}
+
+export default AgentLogDetail
diff --git a/app/components/base/agent-log-modal/index.tsx b/app/components/base/agent-log-modal/index.tsx
new file mode 100644
index 0000000..024ea2a
--- /dev/null
+++ b/app/components/base/agent-log-modal/index.tsx
@@ -0,0 +1,61 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import { useEffect, useRef, useState } from 'react'
+import { useClickAway } from 'ahooks'
+import AgentLogDetail from './detail'
+import cn from '@/utils/classnames'
+import type { IChatItem } from '@/app/components/base/chat/chat/type'
+
+type AgentLogModalProps = {
+ currentLogItem?: IChatItem
+ width: number
+ onCancel: () => void
+}
+const AgentLogModal: FC<AgentLogModalProps> = ({
+ currentLogItem,
+ width,
+ onCancel,
+}) => {
+ const { t } = useTranslation()
+ const ref = useRef(null)
+ const [mounted, setMounted] = useState(false)
+
+ useClickAway(() => {
+ if (mounted)
+ onCancel()
+ }, ref)
+
+ useEffect(() => {
+ setMounted(true)
+ }, [])
+
+ if (!currentLogItem || !currentLogItem.conversationId)
+ return null
+
+ return (
+ <div
+ className={cn('relative z-10 flex flex-col rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg py-3 shadow-xl')}
+ style={{
+ width: 480,
+ position: 'fixed',
+ top: 56 + 8,
+ left: 8 + (width - 480),
+ bottom: 16,
+ }}
+ ref={ref}
+ >
+ <h1 className='text-md shrink-0 px-4 py-1 font-semibold text-text-primary'>{t('appLog.runDetail.workflowTitle')}</h1>
+ <span className='absolute right-3 top-4 z-20 cursor-pointer p-1' onClick={onCancel}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </span>
+ <AgentLogDetail
+ conversationID={currentLogItem.conversationId}
+ messageID={currentLogItem.id}
+ log={currentLogItem}
+ />
+ </div>
+ )
+}
+
+export default AgentLogModal
diff --git a/app/components/base/agent-log-modal/iteration.tsx b/app/components/base/agent-log-modal/iteration.tsx
new file mode 100644
index 0000000..d6f8e84
--- /dev/null
+++ b/app/components/base/agent-log-modal/iteration.tsx
@@ -0,0 +1,51 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import type { FC } from 'react'
+import ToolCall from './tool-call'
+import Divider from '@/app/components/base/divider'
+import type { AgentIteration } from '@/models/log'
+import cn from '@/utils/classnames'
+
+type Props = {
+ isFinal: boolean
+ index: number
+ iterationInfo: AgentIteration
+}
+
+const Iteration: FC<Props> = ({ iterationInfo, isFinal, index }) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={cn('px-4 py-2')}>
+ <div className='flex items-center'>
+ {isFinal && (
+ <div className='mr-3 shrink-0 text-xs font-semibold leading-[18px] text-text-tertiary'>{t('appLog.agentLogDetail.finalProcessing')}</div>
+ )}
+ {!isFinal && (
+ <div className='mr-3 shrink-0 text-xs font-semibold leading-[18px] text-text-tertiary'>{`${t('appLog.agentLogDetail.iteration').toUpperCase()} ${index}`}</div>
+ )}
+ <Divider bgStyle='gradient' className='mx-0 h-[1px] grow'/>
+ </div>
+ <ToolCall
+ isLLM
+ isFinal={isFinal}
+ tokens={iterationInfo.tokens}
+ observation={iterationInfo.tool_raw.outputs}
+ finalAnswer={iterationInfo.thought}
+ toolCall={{
+ status: 'success',
+ tool_icon: null,
+ }}
+ />
+ {iterationInfo.tool_calls.map((toolCall, index) => (
+ <ToolCall
+ isLLM={false}
+ key={index}
+ toolCall={toolCall}
+ />
+ ))}
+ </div>
+ )
+}
+
+export default Iteration
diff --git a/app/components/base/agent-log-modal/result.tsx b/app/components/base/agent-log-modal/result.tsx
new file mode 100644
index 0000000..850f457
--- /dev/null
+++ b/app/components/base/agent-log-modal/result.tsx
@@ -0,0 +1,126 @@
+'use client'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import StatusPanel from '@/app/components/workflow/run/status'
+import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
+import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
+import useTimestamp from '@/hooks/use-timestamp'
+
+type ResultPanelProps = {
+ status: string
+ elapsed_time?: number
+ total_tokens?: number
+ error?: string
+ inputs?: any
+ outputs?: any
+ created_by?: string
+ created_at: string
+ agentMode?: string
+ tools?: string[]
+ iterations?: number
+}
+
+const ResultPanel: FC<ResultPanelProps> = ({
+ elapsed_time,
+ total_tokens,
+ error,
+ inputs,
+ outputs,
+ created_by,
+ created_at,
+ agentMode,
+ tools,
+ iterations,
+}) => {
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+
+ return (
+ <div className='bg-components-panel-bg py-2'>
+ <div className='px-4 py-2'>
+ <StatusPanel
+ status='succeeded'
+ time={elapsed_time}
+ tokens={total_tokens}
+ error={error}
+ />
+ </div>
+ <div className='flex flex-col gap-2 px-4 py-2'>
+ <CodeEditor
+ readOnly
+ title={<div>INPUT</div>}
+ language={CodeLanguage.json}
+ value={inputs}
+ isJSONStringifyBeauty
+ />
+ <CodeEditor
+ readOnly
+ title={<div>OUTPUT</div>}
+ language={CodeLanguage.json}
+ value={outputs}
+ isJSONStringifyBeauty
+ />
+ </div>
+ <div className='px-4 py-2'>
+ <div className='h-[0.5px] bg-divider-regular opacity-5' />
+ </div>
+ <div className='px-4 py-2'>
+ <div className='relative'>
+ <div className='h-6 text-xs font-medium leading-6 text-text-tertiary'>{t('runLog.meta.title')}</div>
+ <div className='py-1'>
+ <div className='flex'>
+ <div className='w-[104px] shrink-0 truncate px-2 py-[5px] text-xs leading-[18px] text-text-tertiary'>{t('runLog.meta.status')}</div>
+ <div className='grow px-2 py-[5px] text-xs leading-[18px] text-text-primary'>
+ <span>SUCCESS</span>
+ </div>
+ </div>
+ <div className='flex'>
+ <div className='w-[104px] shrink-0 truncate px-2 py-[5px] text-xs leading-[18px] text-text-tertiary'>{t('runLog.meta.executor')}</div>
+ <div className='grow px-2 py-[5px] text-xs leading-[18px] text-text-primary'>
+ <span>{created_by || 'N/A'}</span>
+ </div>
+ </div>
+ <div className='flex'>
+ <div className='w-[104px] shrink-0 truncate px-2 py-[5px] text-xs leading-[18px] text-text-tertiary'>{t('runLog.meta.startTime')}</div>
+ <div className='grow px-2 py-[5px] text-xs leading-[18px] text-text-primary'>
+ <span>{formatTime(Date.parse(created_at) / 1000, t('appLog.dateTimeFormat') as string)}</span>
+ </div>
+ </div>
+ <div className='flex'>
+ <div className='w-[104px] shrink-0 truncate px-2 py-[5px] text-xs leading-[18px] text-text-tertiary'>{t('runLog.meta.time')}</div>
+ <div className='grow px-2 py-[5px] text-xs leading-[18px] text-text-primary'>
+ <span>{`${elapsed_time?.toFixed(3)}s`}</span>
+ </div>
+ </div>
+ <div className='flex'>
+ <div className='w-[104px] shrink-0 truncate px-2 py-[5px] text-xs leading-[18px] text-text-tertiary'>{t('runLog.meta.tokens')}</div>
+ <div className='grow px-2 py-[5px] text-xs leading-[18px] text-text-primary'>
+ <span>{`${total_tokens || 0} Tokens`}</span>
+ </div>
+ </div>
+ <div className='flex'>
+ <div className='w-[104px] shrink-0 truncate px-2 py-[5px] text-xs leading-[18px] text-text-tertiary'>{t('appLog.agentLogDetail.agentMode')}</div>
+ <div className='grow px-2 py-[5px] text-xs leading-[18px] text-text-primary'>
+ <span>{agentMode === 'function_call' ? t('appDebug.agent.agentModeType.functionCall') : t('appDebug.agent.agentModeType.ReACT')}</span>
+ </div>
+ </div>
+ <div className='flex'>
+ <div className='w-[104px] shrink-0 truncate px-2 py-[5px] text-xs leading-[18px] text-text-tertiary'>{t('appLog.agentLogDetail.toolUsed')}</div>
+ <div className='grow px-2 py-[5px] text-xs leading-[18px] text-text-primary'>
+ <span>{tools?.length ? tools?.join(', ') : 'Null'}</span>
+ </div>
+ </div>
+ <div className='flex'>
+ <div className='w-[104px] shrink-0 truncate px-2 py-[5px] text-xs leading-[18px] text-text-tertiary'>{t('appLog.agentLogDetail.iterations')}</div>
+ <div className='grow px-2 py-[5px] text-xs leading-[18px] text-text-primary'>
+ <span>{iterations}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default ResultPanel
diff --git a/app/components/base/agent-log-modal/tool-call.tsx b/app/components/base/agent-log-modal/tool-call.tsx
new file mode 100644
index 0000000..499a703
--- /dev/null
+++ b/app/components/base/agent-log-modal/tool-call.tsx
@@ -0,0 +1,142 @@
+'use client'
+import type { FC } from 'react'
+import { useState } from 'react'
+import {
+ RiCheckboxCircleLine,
+ RiErrorWarningLine,
+} from '@remixicon/react'
+import { useContext } from 'use-context-selector'
+import cn from '@/utils/classnames'
+import BlockIcon from '@/app/components/workflow/block-icon'
+import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
+import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
+import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows'
+import type { ToolCall } from '@/models/log'
+import { BlockEnum } from '@/app/components/workflow/types'
+import I18n from '@/context/i18n'
+
+type Props = {
+ toolCall: ToolCall
+ isLLM: boolean
+ isFinal?: boolean
+ tokens?: number
+ observation?: any
+ finalAnswer?: any
+}
+
+const ToolCallItem: FC<Props> = ({ toolCall, isLLM = false, isFinal, tokens, observation, finalAnswer }) => {
+ const [collapseState, setCollapseState] = useState<boolean>(true)
+ const { locale } = useContext(I18n)
+ const toolName = isLLM ? 'LLM' : (toolCall.tool_label[locale] || toolCall.tool_label[locale.replaceAll('-', '_')])
+
+ const getTime = (time: number) => {
+ if (time < 1)
+ return `${(time * 1000).toFixed(3)} ms`
+ if (time > 60)
+ return `${Number.parseInt(Math.round(time / 60).toString())} m ${(time % 60).toFixed(3)} s`
+ return `${time.toFixed(3)} s`
+ }
+
+ const getTokenCount = (tokens: number) => {
+ if (tokens < 1000)
+ return tokens
+ if (tokens >= 1000 && tokens < 1000000)
+ return `${Number.parseFloat((tokens / 1000).toFixed(3))}K`
+ if (tokens >= 1000000)
+ return `${Number.parseFloat((tokens / 1000000).toFixed(3))}M`
+ }
+
+ return (
+ <div className={cn('py-1')}>
+ <div className={cn('group rounded-2xl border border-components-panel-border bg-background-default shadow-xs transition-all hover:shadow-md')}>
+ <div
+ className={cn(
+ 'flex cursor-pointer items-center py-3 pl-[6px] pr-3',
+ !collapseState && '!pb-2',
+ )}
+ onClick={() => setCollapseState(!collapseState)}
+ >
+ <ChevronRight
+ className={cn(
+ 'mr-1 h-3 w-3 shrink-0 text-text-quaternary transition-all group-hover:text-text-tertiary',
+ !collapseState && 'rotate-90',
+ )}
+ />
+ <BlockIcon className={cn('mr-2 shrink-0')} type={isLLM ? BlockEnum.LLM : BlockEnum.Tool} toolIcon={toolCall.tool_icon} />
+ <div className={cn(
+ 'grow truncate text-[13px] font-semibold leading-[16px] text-text-secondary',
+ )} title={toolName}>{toolName}</div>
+ <div className='shrink-0 text-xs leading-[18px] text-text-tertiary'>
+ {toolCall.time_cost && (
+ <span>{getTime(toolCall.time_cost || 0)}</span>
+ )}
+ {isLLM && (
+ <span>{`${getTokenCount(tokens || 0)} tokens`}</span>
+ )}
+ </div>
+ {toolCall.status === 'success' && (
+ <RiCheckboxCircleLine className='ml-2 h-3.5 w-3.5 shrink-0 text-[#12B76A]' />
+ )}
+ {toolCall.status === 'error' && (
+ <RiErrorWarningLine className='ml-2 h-3.5 w-3.5 shrink-0 text-[#F04438]' />
+ )}
+ </div>
+ {!collapseState && (
+ <div className='pb-2'>
+ <div className={cn('px-[10px] py-1')}>
+ {toolCall.status === 'error' && (
+ <div className='rounded-lg border-[0.5px] border-[rbga(0,0,0,0.05)] bg-[#fef3f2] px-3 py-[10px] text-xs leading-[18px] text-[#d92d20] shadow-xs'>{toolCall.error}</div>
+ )}
+ </div>
+ {toolCall.tool_input && (
+ <div className={cn('px-[10px] py-1')}>
+ <CodeEditor
+ readOnly
+ title={<div>INPUT</div>}
+ language={CodeLanguage.json}
+ value={toolCall.tool_input}
+ isJSONStringifyBeauty
+ />
+ </div>
+ )}
+ {toolCall.tool_output && (
+ <div className={cn('px-[10px] py-1')}>
+ <CodeEditor
+ readOnly
+ title={<div>OUTPUT</div>}
+ language={CodeLanguage.json}
+ value={toolCall.tool_output}
+ isJSONStringifyBeauty
+ />
+ </div>
+ )}
+ {isLLM && (
+ <div className={cn('px-[10px] py-1')}>
+ <CodeEditor
+ readOnly
+ title={<div>OBSERVATION</div>}
+ language={CodeLanguage.json}
+ value={observation}
+ isJSONStringifyBeauty
+ />
+ </div>
+ )}
+ {isLLM && (
+ <div className={cn('px-[10px] py-1')}>
+ <CodeEditor
+ readOnly
+ title={<div>{isFinal ? 'FINAL ANSWER' : 'THOUGHT'}</div>}
+ language={CodeLanguage.json}
+ value={finalAnswer}
+ isJSONStringifyBeauty
+ />
+ </div>
+ )}
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+
+export default ToolCallItem
diff --git a/app/components/base/agent-log-modal/tracing.tsx b/app/components/base/agent-log-modal/tracing.tsx
new file mode 100644
index 0000000..c390d25
--- /dev/null
+++ b/app/components/base/agent-log-modal/tracing.tsx
@@ -0,0 +1,25 @@
+'use client'
+import type { FC } from 'react'
+import Iteration from './iteration'
+import type { AgentIteration } from '@/models/log'
+
+type TracingPanelProps = {
+ list: AgentIteration[]
+}
+
+const TracingPanel: FC<TracingPanelProps> = ({ list }) => {
+ return (
+ <div className='bg-background-section'>
+ {list.map((iteration, index) => (
+ <Iteration
+ key={index}
+ index={index + 1}
+ isFinal={index + 1 === list.length}
+ iterationInfo={iteration}
+ />
+ ))}
+ </div>
+ )
+}
+
+export default TracingPanel
diff --git a/app/components/base/answer-icon/index.tsx b/app/components/base/answer-icon/index.tsx
new file mode 100644
index 0000000..faad4e5
--- /dev/null
+++ b/app/components/base/answer-icon/index.tsx
@@ -0,0 +1,47 @@
+'use client'
+
+import type { FC } from 'react'
+import { init } from 'emoji-mart'
+import data from '@emoji-mart/data'
+import classNames from '@/utils/classnames'
+import type { AppIconType } from '@/types/app'
+
+init({ data })
+
+export type AnswerIconProps = {
+ iconType?: AppIconType | null
+ icon?: string | null
+ background?: string | null
+ imageUrl?: string | null
+}
+
+const AnswerIcon: FC<AnswerIconProps> = ({
+ iconType,
+ icon,
+ background,
+ imageUrl,
+}) => {
+ const wrapperClassName = classNames(
+ 'flex',
+ 'items-center',
+ 'justify-center',
+ 'w-full',
+ 'h-full',
+ 'rounded-full',
+ 'border-[0.5px]',
+ 'border-black/5',
+ 'text-xl',
+ )
+ const isValidImageIcon = iconType === 'image' && imageUrl
+ return <div
+ className={wrapperClassName}
+ style={{ background: background || '#D5F5F6' }}
+ >
+ {isValidImageIcon
+ ? <img src={imageUrl} className="h-full w-full rounded-full" alt="answer icon" />
+ : (icon && icon !== '') ? <em-emoji id={icon} /> : <em-emoji id='馃' />
+ }
+ </div>
+}
+
+export default AnswerIcon
diff --git a/app/components/base/app-icon-picker/ImageInput.tsx b/app/components/base/app-icon-picker/ImageInput.tsx
new file mode 100644
index 0000000..9c0a95c
--- /dev/null
+++ b/app/components/base/app-icon-picker/ImageInput.tsx
@@ -0,0 +1,126 @@
+'use client'
+
+import type { ChangeEvent, FC } from 'react'
+import { createRef, useEffect, useState } from 'react'
+import Cropper, { type Area, type CropperProps } from 'react-easy-crop'
+import classNames from 'classnames'
+import { useTranslation } from 'react-i18next'
+
+import { ImagePlus } from '../icons/src/vender/line/images'
+import { useDraggableUploader } from './hooks'
+import { checkIsAnimatedImage } from './utils'
+import { ALLOW_FILE_EXTENSIONS } from '@/types/app'
+
+export type OnImageInput = {
+ (isCropped: true, tempUrl: string, croppedAreaPixels: Area, fileName: string): void
+ (isCropped: false, file: File): void
+}
+
+type UploaderProps = {
+ className?: string
+ cropShape?: CropperProps['cropShape']
+ onImageInput?: OnImageInput
+}
+
+const ImageInput: FC<UploaderProps> = ({
+ className,
+ cropShape,
+ onImageInput,
+}) => {
+ const { t } = useTranslation()
+ const [inputImage, setInputImage] = useState<{ file: File; url: string }>()
+ const [isAnimatedImage, setIsAnimatedImage] = useState<boolean>(false)
+ useEffect(() => {
+ return () => {
+ if (inputImage)
+ URL.revokeObjectURL(inputImage.url)
+ }
+ }, [inputImage])
+
+ const [crop, setCrop] = useState({ x: 0, y: 0 })
+ const [zoom, setZoom] = useState(1)
+
+ const onCropComplete = async (_: Area, croppedAreaPixels: Area) => {
+ if (!inputImage)
+ return
+ onImageInput?.(true, inputImage.url, croppedAreaPixels, inputImage.file.name)
+ }
+
+ const handleLocalFileInput = (e: ChangeEvent<HTMLInputElement>) => {
+ const file = e.target.files?.[0]
+ if (file) {
+ setInputImage({ file, url: URL.createObjectURL(file) })
+ checkIsAnimatedImage(file).then((isAnimatedImage) => {
+ setIsAnimatedImage(!!isAnimatedImage)
+ if (isAnimatedImage)
+ onImageInput?.(false, file)
+ })
+ }
+ }
+
+ const {
+ isDragActive,
+ handleDragEnter,
+ handleDragOver,
+ handleDragLeave,
+ handleDrop,
+ } = useDraggableUploader((file: File) => setInputImage({ file, url: URL.createObjectURL(file) }))
+
+ const inputRef = createRef<HTMLInputElement>()
+
+ const handleShowImage = () => {
+ if (isAnimatedImage) {
+ return (
+ <img src={inputImage?.url} alt='' />
+ )
+ }
+
+ return (
+ <Cropper
+ image={inputImage?.url}
+ crop={crop}
+ zoom={zoom}
+ aspect={1}
+ cropShape={cropShape}
+ onCropChange={setCrop}
+ onCropComplete={onCropComplete}
+ onZoomChange={setZoom}
+ />
+ )
+ }
+
+ return (
+ <div className={classNames(className, 'w-full px-3 py-1.5')}>
+ <div
+ className={classNames(
+ isDragActive && 'border-primary-600',
+ 'relative aspect-square bg-gray-50 border-[1.5px] border-gray-200 border-dashed rounded-lg flex flex-col justify-center items-center text-gray-500')}
+ onDragEnter={handleDragEnter}
+ onDragOver={handleDragOver}
+ onDragLeave={handleDragLeave}
+ onDrop={handleDrop}
+ >
+ {
+ !inputImage
+ ? <>
+ <ImagePlus className="pointer-events-none mb-3 h-[30px] w-[30px]" />
+ <div className="mb-[2px] text-sm font-medium">
+ <span className="pointer-events-none">{t('common.imageInput.dropImageHere')} </span>
+ <button className="text-components-button-primary-bg" onClick={() => inputRef.current?.click()}>{t('common.imageInput.browse')}</button>
+ <input
+ ref={inputRef} type="file" className="hidden"
+ onClick={e => ((e.target as HTMLInputElement).value = '')}
+ accept={ALLOW_FILE_EXTENSIONS.map(ext => `.${ext}`).join(',')}
+ onChange={handleLocalFileInput}
+ />
+ </div>
+ <div className="pointer-events-none">{t('common.imageInput.supportedFormats')}</div>
+ </>
+ : handleShowImage()
+ }
+ </div>
+ </div>
+ )
+}
+
+export default ImageInput
diff --git a/app/components/base/app-icon-picker/hooks.tsx b/app/components/base/app-icon-picker/hooks.tsx
new file mode 100644
index 0000000..b3f67c0
--- /dev/null
+++ b/app/components/base/app-icon-picker/hooks.tsx
@@ -0,0 +1,43 @@
+import { useCallback, useState } from 'react'
+
+export const useDraggableUploader = <T extends HTMLElement>(setImageFn: (file: File) => void) => {
+ const [isDragActive, setIsDragActive] = useState(false)
+
+ const handleDragEnter = useCallback((e: React.DragEvent<T>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragActive(true)
+ }, [])
+
+ const handleDragOver = useCallback((e: React.DragEvent<T>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }, [])
+
+ const handleDragLeave = useCallback((e: React.DragEvent<T>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragActive(false)
+ }, [])
+
+ const handleDrop = useCallback((e: React.DragEvent<T>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragActive(false)
+
+ const file = e.dataTransfer.files[0]
+
+ if (!file)
+ return
+
+ setImageFn(file)
+ }, [setImageFn])
+
+ return {
+ handleDragEnter,
+ handleDragOver,
+ handleDragLeave,
+ handleDrop,
+ isDragActive,
+ }
+}
diff --git a/app/components/base/app-icon-picker/index.tsx b/app/components/base/app-icon-picker/index.tsx
new file mode 100644
index 0000000..8304de1
--- /dev/null
+++ b/app/components/base/app-icon-picker/index.tsx
@@ -0,0 +1,150 @@
+import type { FC } from 'react'
+import { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { Area } from 'react-easy-crop'
+import Modal from '../modal'
+import Divider from '../divider'
+import Button from '../button'
+import { ImagePlus } from '../icons/src/vender/line/images'
+import { useLocalFileUploader } from '../image-uploader/hooks'
+import EmojiPickerInner from '../emoji-picker/Inner'
+import type { OnImageInput } from './ImageInput'
+import ImageInput from './ImageInput'
+import s from './style.module.css'
+import getCroppedImg from './utils'
+import type { AppIconType, ImageFile } from '@/types/app'
+import cn from '@/utils/classnames'
+import { DISABLE_UPLOAD_IMAGE_AS_ICON } from '@/config'
+import { noop } from 'lodash-es'
+
+export type AppIconEmojiSelection = {
+ type: 'emoji'
+ icon: string
+ background: string
+}
+
+export type AppIconImageSelection = {
+ type: 'image'
+ fileId: string
+ url: string
+}
+
+export type AppIconSelection = AppIconEmojiSelection | AppIconImageSelection
+
+type AppIconPickerProps = {
+ onSelect?: (payload: AppIconSelection) => void
+ onClose?: () => void
+ className?: string
+}
+
+const AppIconPicker: FC<AppIconPickerProps> = ({
+ onSelect,
+ onClose,
+ className,
+}) => {
+ const { t } = useTranslation()
+
+ const tabs = [
+ { key: 'emoji', label: t('app.iconPicker.emoji'), icon: <span className="text-lg">馃</span> },
+ { key: 'image', label: t('app.iconPicker.image'), icon: <ImagePlus /> },
+ ]
+ const [activeTab, setActiveTab] = useState<AppIconType>('emoji')
+
+ const [emoji, setEmoji] = useState<{ emoji: string; background: string }>()
+ const handleSelectEmoji = useCallback((emoji: string, background: string) => {
+ setEmoji({ emoji, background })
+ }, [setEmoji])
+
+ const [uploading, setUploading] = useState<boolean>()
+
+ const { handleLocalFileUpload } = useLocalFileUploader({
+ limit: 3,
+ disabled: false,
+ onUpload: (imageFile: ImageFile) => {
+ if (imageFile.fileId) {
+ setUploading(false)
+ onSelect?.({
+ type: 'image',
+ fileId: imageFile.fileId,
+ url: imageFile.url,
+ })
+ }
+ },
+ })
+
+ type InputImageInfo = { file: File } | { tempUrl: string; croppedAreaPixels: Area; fileName: string }
+ const [inputImageInfo, setInputImageInfo] = useState<InputImageInfo>()
+
+ const handleImageInput: OnImageInput = async (isCropped: boolean, fileOrTempUrl: string | File, croppedAreaPixels?: Area, fileName?: string) => {
+ setInputImageInfo(
+ isCropped
+ ? { tempUrl: fileOrTempUrl as string, croppedAreaPixels: croppedAreaPixels!, fileName: fileName! }
+ : { file: fileOrTempUrl as File },
+ )
+ }
+
+ const handleSelect = async () => {
+ if (activeTab === 'emoji') {
+ if (emoji) {
+ onSelect?.({
+ type: 'emoji',
+ icon: emoji.emoji,
+ background: emoji.background,
+ })
+ }
+ }
+ else {
+ if (!inputImageInfo)
+ return
+ setUploading(true)
+ if ('file' in inputImageInfo) {
+ handleLocalFileUpload(inputImageInfo.file)
+ return
+ }
+ const blob = await getCroppedImg(inputImageInfo.tempUrl, inputImageInfo.croppedAreaPixels, inputImageInfo.fileName)
+ const file = new File([blob], inputImageInfo.fileName, { type: blob.type })
+ handleLocalFileUpload(file)
+ }
+ }
+
+ return <Modal
+ onClose={noop}
+ isShow
+ closable={false}
+ wrapperClassName={className}
+ className={cn(s.container, '!w-[362px] !p-0')}
+ >
+ {!DISABLE_UPLOAD_IMAGE_AS_ICON && <div className="w-full p-2 pb-0">
+ <div className='flex items-center justify-center gap-2 rounded-xl bg-background-body p-1'>
+ {tabs.map(tab => (
+ <button
+ key={tab.key}
+ className={`
+ flex h-8 flex-1 shrink-0 items-center justify-center rounded-xl p-2 text-sm font-medium
+ ${activeTab === tab.key && 'bg-components-main-nav-nav-button-bg-active shadow-md'}
+ `}
+ onClick={() => setActiveTab(tab.key as AppIconType)}
+ >
+ {tab.icon} {tab.label}
+ </button>
+ ))}
+ </div>
+ </div>}
+
+ <EmojiPickerInner className={cn(activeTab === 'emoji' ? 'block' : 'hidden', 'pt-2')} onSelect={handleSelectEmoji} />
+ <ImageInput className={activeTab === 'image' ? 'block' : 'hidden'} onImageInput={handleImageInput} />
+
+ <Divider className='m-0' />
+ <div className='flex w-full items-center justify-center gap-2 p-3'>
+ <Button className='w-full' onClick={() => onClose?.()}>
+ {t('app.iconPicker.cancel')}
+ </Button>
+
+ <Button variant="primary" className='w-full' disabled={uploading} loading={uploading} onClick={handleSelect}>
+ {t('app.iconPicker.ok')}
+ </Button>
+ </div>
+ </Modal>
+}
+
+export default AppIconPicker
diff --git a/app/components/base/app-icon-picker/style.module.css b/app/components/base/app-icon-picker/style.module.css
new file mode 100644
index 0000000..5facb35
--- /dev/null
+++ b/app/components/base/app-icon-picker/style.module.css
@@ -0,0 +1,12 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ width: 362px;
+ max-height: 552px;
+
+ border: 0.5px solid #EAECF0;
+ box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);
+ border-radius: 12px;
+ background: #fff;
+}
diff --git a/app/components/base/app-icon-picker/utils.ts b/app/components/base/app-icon-picker/utils.ts
new file mode 100644
index 0000000..f63b75e
--- /dev/null
+++ b/app/components/base/app-icon-picker/utils.ts
@@ -0,0 +1,166 @@
+export const createImage = (url: string) =>
+ new Promise<HTMLImageElement>((resolve, reject) => {
+ const image = new Image()
+ image.addEventListener('load', () => resolve(image))
+ image.addEventListener('error', error => reject(error))
+ image.setAttribute('crossOrigin', 'anonymous') // needed to avoid cross-origin issues on CodeSandbox
+ image.src = url
+ })
+
+export function getRadianAngle(degreeValue: number) {
+ return (degreeValue * Math.PI) / 180
+}
+
+export function getMimeType(fileName: string): string {
+ const extension = fileName.split('.').pop()?.toLowerCase()
+ switch (extension) {
+ case 'png':
+ return 'image/png'
+ case 'jpg':
+ case 'jpeg':
+ return 'image/jpeg'
+ case 'gif':
+ return 'image/gif'
+ case 'webp':
+ return 'image/webp'
+ default:
+ return 'image/jpeg'
+ }
+}
+
+/**
+ * Returns the new bounding area of a rotated rectangle.
+ */
+export function rotateSize(width: number, height: number, rotation: number) {
+ const rotRad = getRadianAngle(rotation)
+
+ return {
+ width:
+ Math.abs(Math.cos(rotRad) * width) + Math.abs(Math.sin(rotRad) * height),
+ height:
+ Math.abs(Math.sin(rotRad) * width) + Math.abs(Math.cos(rotRad) * height),
+ }
+}
+
+/**
+ * This function was adapted from the one in the ReadMe of https://github.com/DominicTobias/react-image-crop
+ */
+export default async function getCroppedImg(
+ imageSrc: string,
+ pixelCrop: { x: number; y: number; width: number; height: number },
+ fileName: string,
+ rotation = 0,
+ flip = { horizontal: false, vertical: false },
+): Promise<Blob> {
+ const image = await createImage(imageSrc)
+ const canvas = document.createElement('canvas')
+ const ctx = canvas.getContext('2d')
+ const mimeType = getMimeType(fileName)
+
+ if (!ctx)
+ throw new Error('Could not create a canvas context')
+
+ const rotRad = getRadianAngle(rotation)
+
+ // calculate bounding box of the rotated image
+ const { width: bBoxWidth, height: bBoxHeight } = rotateSize(
+ image.width,
+ image.height,
+ rotation,
+ )
+
+ // set canvas size to match the bounding box
+ canvas.width = bBoxWidth
+ canvas.height = bBoxHeight
+
+ // translate canvas context to a central location to allow rotating and flipping around the center
+ ctx.translate(bBoxWidth / 2, bBoxHeight / 2)
+ ctx.rotate(rotRad)
+ ctx.scale(flip.horizontal ? -1 : 1, flip.vertical ? -1 : 1)
+ ctx.translate(-image.width / 2, -image.height / 2)
+
+ // draw rotated image
+ ctx.drawImage(image, 0, 0)
+
+ const croppedCanvas = document.createElement('canvas')
+
+ const croppedCtx = croppedCanvas.getContext('2d')
+
+ if (!croppedCtx)
+ throw new Error('Could not create a canvas context')
+
+ // Set the size of the cropped canvas
+ croppedCanvas.width = pixelCrop.width
+ croppedCanvas.height = pixelCrop.height
+
+ // Draw the cropped image onto the new canvas
+ croppedCtx.drawImage(
+ canvas,
+ pixelCrop.x,
+ pixelCrop.y,
+ pixelCrop.width,
+ pixelCrop.height,
+ 0,
+ 0,
+ pixelCrop.width,
+ pixelCrop.height,
+ )
+
+ return new Promise((resolve, reject) => {
+ croppedCanvas.toBlob((file) => {
+ if (file)
+ resolve(file)
+ else
+ reject(new Error('Could not create a blob'))
+ }, mimeType)
+ })
+}
+
+export function checkIsAnimatedImage(file: File): Promise<boolean> {
+ return new Promise((resolve, reject) => {
+ const fileReader = new FileReader()
+
+ fileReader.onload = function (e) {
+ const arr = new Uint8Array(e.target?.result as ArrayBuffer)
+
+ // Check file extension
+ const fileName = file.name.toLowerCase()
+ if (fileName.endsWith('.gif')) {
+ // If file is a GIF, assume it's animated
+ resolve(true)
+ }
+ // Check for WebP signature (RIFF and WEBP)
+ else if (isWebP(arr)) {
+ resolve(checkWebPAnimation(arr)) // Check if it's animated
+ }
+ else {
+ resolve(false) // Not a GIF or WebP
+ }
+ }
+
+ fileReader.onerror = function (err) {
+ reject(err) // Reject the promise on error
+ }
+
+ // Read the file as an array buffer
+ fileReader.readAsArrayBuffer(file)
+ })
+}
+
+// Function to check for WebP signature
+function isWebP(arr: Uint8Array) {
+ return (
+ arr[0] === 0x52 && arr[1] === 0x49 && arr[2] === 0x46 && arr[3] === 0x46
+ && arr[8] === 0x57 && arr[9] === 0x45 && arr[10] === 0x42 && arr[11] === 0x50
+ ) // "WEBP"
+}
+
+// Function to check if the WebP is animated (contains ANIM chunk)
+function checkWebPAnimation(arr: Uint8Array) {
+ // Search for the ANIM chunk in WebP to determine if it's animated
+ for (let i = 12; i < arr.length - 4; i++) {
+ if (arr[i] === 0x41 && arr[i + 1] === 0x4E && arr[i + 2] === 0x49 && arr[i + 3] === 0x4D)
+ return true // Found animation
+ }
+ return false // No animation chunk found
+}
diff --git a/app/components/base/app-icon/index.tsx b/app/components/base/app-icon/index.tsx
new file mode 100644
index 0000000..ac17af1
--- /dev/null
+++ b/app/components/base/app-icon/index.tsx
@@ -0,0 +1,71 @@
+'use client'
+
+import type { FC } from 'react'
+import { init } from 'emoji-mart'
+import data from '@emoji-mart/data'
+import { cva } from 'class-variance-authority'
+import type { AppIconType } from '@/types/app'
+import classNames from '@/utils/classnames'
+
+init({ data })
+
+export type AppIconProps = {
+ size?: 'xs' | 'tiny' | 'small' | 'medium' | 'large' | 'xl' | 'xxl'
+ rounded?: boolean
+ iconType?: AppIconType | null
+ icon?: string
+ background?: string | null
+ imageUrl?: string | null
+ className?: string
+ innerIcon?: React.ReactNode
+ onClick?: () => void
+}
+const appIconVariants = cva(
+ 'flex items-center justify-center relative text-lg rounded-lg grow-0 shrink-0 overflow-hidden leading-none',
+ {
+ variants: {
+ size: {
+ xs: 'w-4 h-4 text-xs',
+ tiny: 'w-6 h-6 text-base',
+ small: 'w-8 h-8 text-xl',
+ medium: 'w-9 h-9 text-[22px]',
+ large: 'w-10 h-10 text-[24px]',
+ xl: 'w-12 h-12 text-[28px]',
+ xxl: 'w-14 h-14 text-[32px]',
+ },
+ rounded: {
+ true: 'rounded-full',
+ },
+ },
+ defaultVariants: {
+ size: 'medium',
+ rounded: false,
+ },
+ })
+const AppIcon: FC<AppIconProps> = ({
+ size = 'medium',
+ rounded = false,
+ iconType,
+ icon,
+ background,
+ imageUrl,
+ className,
+ innerIcon,
+ onClick,
+}) => {
+ const isValidImageIcon = iconType === 'image' && imageUrl
+
+ return <span
+ className={classNames(appIconVariants({ size, rounded }), className)}
+ style={{ background: isValidImageIcon ? undefined : (background || '#FFEAD5') }}
+ onClick={onClick}
+ >
+ {isValidImageIcon
+
+ ? <img src={imageUrl} className="h-full w-full" alt="app icon" />
+ : (innerIcon || ((icon && icon !== '') ? <em-emoji id={icon} /> : <em-emoji id='馃' />))
+ }
+ </span>
+}
+
+export default AppIcon
diff --git a/app/components/base/app-icon/style.module.css b/app/components/base/app-icon/style.module.css
new file mode 100644
index 0000000..4ee84fb
--- /dev/null
+++ b/app/components/base/app-icon/style.module.css
@@ -0,0 +1,23 @@
+.appIcon {
+ @apply flex items-center justify-center relative w-9 h-9 text-lg rounded-lg grow-0 shrink-0;
+}
+
+.appIcon.large {
+ @apply w-10 h-10;
+}
+
+.appIcon.small {
+ @apply w-8 h-8;
+}
+
+.appIcon.tiny {
+ @apply w-6 h-6 text-base;
+}
+
+.appIcon.xs {
+ @apply w-5 h-5 text-base;
+}
+
+.appIcon.rounded {
+ @apply rounded-full;
+}
diff --git a/app/components/base/app-unavailable.tsx b/app/components/base/app-unavailable.tsx
new file mode 100644
index 0000000..00abb4c
--- /dev/null
+++ b/app/components/base/app-unavailable.tsx
@@ -0,0 +1,29 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+
+type IAppUnavailableProps = {
+ code?: number
+ isUnknownReason?: boolean
+ unknownReason?: string
+}
+
+const AppUnavailable: FC<IAppUnavailableProps> = ({
+ code = 404,
+ isUnknownReason,
+ unknownReason,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex h-screen w-screen items-center justify-center'>
+ <h1 className='mr-5 h-[50px] pr-5 text-[24px] font-medium leading-[50px]'
+ style={{
+ borderRight: '1px solid rgba(0,0,0,.3)',
+ }}>{code}</h1>
+ <div className='text-sm'>{unknownReason || (isUnknownReason ? t('share.common.appUnknownError') : t('share.common.appUnavailable'))}</div>
+ </div>
+ )
+}
+export default React.memo(AppUnavailable)
diff --git a/app/components/base/audio-btn/audio.player.manager.ts b/app/components/base/audio-btn/audio.player.manager.ts
new file mode 100644
index 0000000..86eb377
--- /dev/null
+++ b/app/components/base/audio-btn/audio.player.manager.ts
@@ -0,0 +1,50 @@
+import AudioPlayer from '@/app/components/base/audio-btn/audio'
+declare global {
+ // eslint-disable-next-line ts/consistent-type-definitions
+ interface AudioPlayerManager {
+ instance: AudioPlayerManager
+ }
+
+}
+
+export class AudioPlayerManager {
+ private static instance: AudioPlayerManager
+ private audioPlayers: AudioPlayer | null = null
+ private msgId: string | undefined
+
+ public static getInstance(): AudioPlayerManager {
+ if (!AudioPlayerManager.instance) {
+ AudioPlayerManager.instance = new AudioPlayerManager()
+ this.instance = AudioPlayerManager.instance
+ }
+
+ return AudioPlayerManager.instance
+ }
+
+ public getAudioPlayer(url: string, isPublic: boolean, id: string | undefined, msgContent: string | null | undefined, voice: string | undefined, callback: ((event: string) => void) | null): AudioPlayer {
+ if (this.msgId && this.msgId === id && this.audioPlayers) {
+ this.audioPlayers.setCallback(callback)
+ return this.audioPlayers
+ }
+ else {
+ if (this.audioPlayers) {
+ try {
+ this.audioPlayers.pauseAudio()
+ this.audioPlayers.cacheBuffers = []
+ this.audioPlayers.sourceBuffer?.abort()
+ }
+ catch {
+ }
+ }
+
+ this.msgId = id
+ this.audioPlayers = new AudioPlayer(url, isPublic, id, msgContent, voice, callback)
+ return this.audioPlayers
+ }
+ }
+
+ public resetMsgId(msgId: string) {
+ this.msgId = msgId
+ this.audioPlayers?.resetMsgId(msgId)
+ }
+}
diff --git a/app/components/base/audio-btn/audio.ts b/app/components/base/audio-btn/audio.ts
new file mode 100644
index 0000000..00797d0
--- /dev/null
+++ b/app/components/base/audio-btn/audio.ts
@@ -0,0 +1,247 @@
+import Toast from '@/app/components/base/toast'
+import { textToAudioStream } from '@/service/share'
+
+declare global {
+ // eslint-disable-next-line ts/consistent-type-definitions
+ interface Window {
+ ManagedMediaSource: any
+ }
+}
+
+export default class AudioPlayer {
+ mediaSource: MediaSource | null
+ audio: HTMLAudioElement
+ audioContext: AudioContext
+ sourceBuffer?: any
+ cacheBuffers: ArrayBuffer[] = []
+ pauseTimer: number | null = null
+ msgId: string | undefined
+ msgContent: string | null | undefined = null
+ voice: string | undefined = undefined
+ isLoadData = false
+ url: string
+ isPublic: boolean
+ callback: ((event: string) => void) | null
+
+ constructor(streamUrl: string, isPublic: boolean, msgId: string | undefined, msgContent: string | null | undefined, voice: string | undefined, callback: ((event: string) => void) | null) {
+ this.audioContext = new AudioContext()
+ this.msgId = msgId
+ this.msgContent = msgContent
+ this.url = streamUrl
+ this.isPublic = isPublic
+ this.voice = voice
+ this.callback = callback
+
+ // Compatible with iphone ios17 ManagedMediaSource
+ const MediaSource = window.ManagedMediaSource || window.MediaSource
+ if (!MediaSource) {
+ Toast.notify({
+ message: 'Your browser does not support audio streaming, if you are using an iPhone, please update to iOS 17.1 or later.',
+ type: 'error',
+ })
+ }
+ this.mediaSource = MediaSource ? new MediaSource() : null
+ this.audio = new Audio()
+ this.setCallback(callback)
+ if (!window.MediaSource) { // if use ManagedMediaSource
+ this.audio.disableRemotePlayback = true
+ this.audio.controls = true
+ }
+ this.audio.src = this.mediaSource ? URL.createObjectURL(this.mediaSource) : ''
+ this.audio.autoplay = true
+
+ const source = this.audioContext.createMediaElementSource(this.audio)
+ source.connect(this.audioContext.destination)
+ this.listenMediaSource('audio/mpeg')
+ }
+
+ public resetMsgId(msgId: string) {
+ this.msgId = msgId
+ }
+
+ private listenMediaSource(contentType: string) {
+ this.mediaSource?.addEventListener('sourceopen', () => {
+ if (this.sourceBuffer)
+ return
+
+ this.sourceBuffer = this.mediaSource?.addSourceBuffer(contentType)
+ })
+ }
+
+ public setCallback(callback: ((event: string) => void) | null) {
+ this.callback = callback
+ if (callback) {
+ this.audio.addEventListener('ended', () => {
+ callback('ended')
+ }, false)
+ this.audio.addEventListener('paused', () => {
+ callback('paused')
+ }, true)
+ this.audio.addEventListener('loaded', () => {
+ callback('loaded')
+ }, true)
+ this.audio.addEventListener('play', () => {
+ callback('play')
+ }, true)
+ this.audio.addEventListener('timeupdate', () => {
+ callback('timeupdate')
+ }, true)
+ this.audio.addEventListener('loadeddate', () => {
+ callback('loadeddate')
+ }, true)
+ this.audio.addEventListener('canplay', () => {
+ callback('canplay')
+ }, true)
+ this.audio.addEventListener('error', () => {
+ callback('error')
+ }, true)
+ }
+ }
+
+ private async loadAudio() {
+ try {
+ const audioResponse: any = await textToAudioStream(this.url, this.isPublic, { content_type: 'audio/mpeg' }, {
+ message_id: this.msgId,
+ streaming: true,
+ voice: this.voice,
+ text: this.msgContent,
+ })
+
+ if (audioResponse.status !== 200) {
+ this.isLoadData = false
+ if (this.callback)
+ this.callback('error')
+ }
+
+ const reader = audioResponse.body.getReader()
+ while (true) {
+ const { value, done } = await reader.read()
+
+ if (done) {
+ this.receiveAudioData(value)
+ break
+ }
+
+ this.receiveAudioData(value)
+ }
+ }
+ catch {
+ this.isLoadData = false
+ this.callback && this.callback('error')
+ }
+ }
+
+ // play audio
+ public playAudio() {
+ if (this.isLoadData) {
+ if (this.audioContext.state === 'suspended') {
+ this.audioContext.resume().then((_) => {
+ this.audio.play()
+ this.callback && this.callback('play')
+ })
+ }
+ else if (this.audio.ended) {
+ this.audio.play()
+ this.callback && this.callback('play')
+ }
+ if (this.callback)
+ this.callback('play')
+ }
+ else {
+ this.isLoadData = true
+ this.loadAudio()
+ }
+ }
+
+ private theEndOfStream() {
+ const endTimer = setInterval(() => {
+ if (!this.sourceBuffer?.updating) {
+ this.mediaSource?.endOfStream()
+ clearInterval(endTimer)
+ }
+ }, 10)
+ }
+
+ private finishStream() {
+ const timer = setInterval(() => {
+ if (!this.cacheBuffers.length) {
+ this.theEndOfStream()
+ clearInterval(timer)
+ }
+
+ if (this.cacheBuffers.length && !this.sourceBuffer?.updating) {
+ const arrayBuffer = this.cacheBuffers.shift()!
+ this.sourceBuffer?.appendBuffer(arrayBuffer)
+ }
+ }, 10)
+ }
+
+ public async playAudioWithAudio(audio: string, play = true) {
+ if (!audio || !audio.length) {
+ this.finishStream()
+ return
+ }
+
+ const audioContent = Buffer.from(audio, 'base64')
+ this.receiveAudioData(new Uint8Array(audioContent))
+ if (play) {
+ this.isLoadData = true
+ if (this.audio.paused) {
+ this.audioContext.resume().then((_) => {
+ this.audio.play()
+ this.callback && this.callback('play')
+ })
+ }
+ else if (this.audio.ended) {
+ this.audio.play()
+ this.callback && this.callback('play')
+ }
+ else if (this.audio.played) { /* empty */ }
+
+ else {
+ this.audio.play()
+ this.callback && this.callback('play')
+ }
+ }
+ }
+
+ public pauseAudio() {
+ this.callback && this.callback('paused')
+ this.audio.pause()
+ this.audioContext.suspend()
+ }
+
+ private receiveAudioData(unit8Array: Uint8Array) {
+ if (!unit8Array) {
+ this.finishStream()
+ return
+ }
+ const audioData = this.byteArrayToArrayBuffer(unit8Array)
+ if (!audioData.byteLength) {
+ if (this.mediaSource?.readyState === 'open')
+ this.finishStream()
+ return
+ }
+
+ if (this.sourceBuffer?.updating) {
+ this.cacheBuffers.push(audioData)
+ }
+ else {
+ if (this.cacheBuffers.length && !this.sourceBuffer?.updating) {
+ this.cacheBuffers.push(audioData)
+ const cacheBuffer = this.cacheBuffers.shift()!
+ this.sourceBuffer?.appendBuffer(cacheBuffer)
+ }
+ else {
+ this.sourceBuffer?.appendBuffer(audioData)
+ }
+ }
+ }
+
+ private byteArrayToArrayBuffer(byteArray: Uint8Array): ArrayBuffer {
+ const arrayBuffer = new ArrayBuffer(byteArray.length)
+ const uint8Array = new Uint8Array(arrayBuffer)
+ uint8Array.set(byteArray)
+ return arrayBuffer
+ }
+}
diff --git a/app/components/base/audio-btn/index.tsx b/app/components/base/audio-btn/index.tsx
new file mode 100644
index 0000000..2a54a8e
--- /dev/null
+++ b/app/components/base/audio-btn/index.tsx
@@ -0,0 +1,110 @@
+'use client'
+import { useState } from 'react'
+import { t } from 'i18next'
+import { useParams, usePathname } from 'next/navigation'
+import s from './style.module.css'
+import Tooltip from '@/app/components/base/tooltip'
+import Loading from '@/app/components/base/loading'
+import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
+
+type AudioBtnProps = {
+ id?: string
+ voice?: string
+ value?: string
+ className?: string
+ isAudition?: boolean
+ noCache?: boolean
+}
+
+type AudioState = 'initial' | 'loading' | 'playing' | 'paused' | 'ended'
+
+const AudioBtn = ({
+ id,
+ voice,
+ value,
+ className,
+ isAudition,
+}: AudioBtnProps) => {
+ const [audioState, setAudioState] = useState<AudioState>('initial')
+
+ const params = useParams()
+ const pathname = usePathname()
+ const audio_finished_call = (event: string): void => {
+ switch (event) {
+ case 'ended':
+ setAudioState('ended')
+ break
+ case 'paused':
+ setAudioState('ended')
+ break
+ case 'loaded':
+ setAudioState('loading')
+ break
+ case 'play':
+ setAudioState('playing')
+ break
+ case 'error':
+ setAudioState('ended')
+ break
+ }
+ }
+ let url = ''
+ let isPublic = false
+
+ if (params.token) {
+ url = '/text-to-audio'
+ isPublic = true
+ }
+ else if (params.appId) {
+ if (pathname.search('explore/installed') > -1)
+ url = `/installed-apps/${params.appId}/text-to-audio`
+ else
+ url = `/apps/${params.appId}/text-to-audio`
+ }
+ const handleToggle = async () => {
+ if (audioState === 'playing' || audioState === 'loading') {
+ setTimeout(() => setAudioState('paused'), 1)
+ AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).pauseAudio()
+ }
+ else {
+ setTimeout(() => setAudioState('loading'), 1)
+ AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).playAudio()
+ }
+ }
+
+ const tooltipContent = {
+ initial: t('appApi.play'),
+ ended: t('appApi.play'),
+ paused: t('appApi.pause'),
+ playing: t('appApi.playing'),
+ loading: t('appApi.loading'),
+ }[audioState]
+
+ return (
+ <div className={`inline-flex items-center justify-center ${(audioState === 'loading' || audioState === 'playing') ? 'mr-1' : className}`}>
+ <Tooltip
+ popupContent={tooltipContent}
+ >
+ <button
+ disabled={audioState === 'loading'}
+ className={`box-border flex h-6 w-6 cursor-pointer items-center justify-center ${isAudition ? 'p-0.5' : 'rounded-md bg-white p-0'}`}
+ onClick={handleToggle}
+ >
+ {audioState === 'loading'
+ ? (
+ <div className='flex h-full w-full items-center justify-center rounded-md'>
+ <Loading />
+ </div>
+ )
+ : (
+ <div className={'flex h-full w-full items-center justify-center rounded-md hover:bg-gray-50'}>
+ <div className={`h-4 w-4 ${(audioState === 'playing') ? s.pauseIcon : s.playIcon}`}></div>
+ </div>
+ )}
+ </button>
+ </Tooltip>
+ </div>
+ )
+}
+
+export default AudioBtn
diff --git a/app/components/base/audio-btn/style.module.css b/app/components/base/audio-btn/style.module.css
new file mode 100644
index 0000000..7e3175a
--- /dev/null
+++ b/app/components/base/audio-btn/style.module.css
@@ -0,0 +1,10 @@
+.playIcon {
+ background-image: url(~@/app/components/develop/secret-key/assets/play.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+.pauseIcon {
+ background-image: url(~@/app/components/develop/secret-key/assets/pause.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
diff --git a/app/components/base/audio-gallery/AudioPlayer.tsx b/app/components/base/audio-gallery/AudioPlayer.tsx
new file mode 100644
index 0000000..67ded63
--- /dev/null
+++ b/app/components/base/audio-gallery/AudioPlayer.tsx
@@ -0,0 +1,319 @@
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import { t } from 'i18next'
+import {
+ RiPauseCircleFill,
+ RiPlayLargeFill,
+} from '@remixicon/react'
+import Toast from '@/app/components/base/toast'
+import useTheme from '@/hooks/use-theme'
+import { Theme } from '@/types/app'
+import cn from '@/utils/classnames'
+
+type AudioPlayerProps = {
+ src: string
+}
+
+const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
+ const [isPlaying, setIsPlaying] = useState(false)
+ const [currentTime, setCurrentTime] = useState(0)
+ const [duration, setDuration] = useState(0)
+ const [waveformData, setWaveformData] = useState<number[]>([])
+ const [bufferedTime, setBufferedTime] = useState(0)
+ const audioRef = useRef<HTMLAudioElement>(null)
+ const canvasRef = useRef<HTMLCanvasElement>(null)
+ const [hasStartedPlaying, setHasStartedPlaying] = useState(false)
+ const [hoverTime, setHoverTime] = useState(0)
+ const [isAudioAvailable, setIsAudioAvailable] = useState(true)
+ const { theme } = useTheme()
+
+ useEffect(() => {
+ const audio = audioRef.current
+ if (!audio)
+ return
+
+ const handleError = () => {
+ setIsAudioAvailable(false)
+ }
+
+ const setAudioData = () => {
+ setDuration(audio.duration)
+ }
+
+ const setAudioTime = () => {
+ setCurrentTime(audio.currentTime)
+ }
+
+ const handleProgress = () => {
+ if (audio.buffered.length > 0)
+ setBufferedTime(audio.buffered.end(audio.buffered.length - 1))
+ }
+
+ const handleEnded = () => {
+ setIsPlaying(false)
+ }
+
+ audio.addEventListener('loadedmetadata', setAudioData)
+ audio.addEventListener('timeupdate', setAudioTime)
+ audio.addEventListener('progress', handleProgress)
+ audio.addEventListener('ended', handleEnded)
+ audio.addEventListener('error', handleError)
+
+ // Preload audio metadata
+ audio.load()
+
+ // Delayed generation of waveform data
+ // eslint-disable-next-line ts/no-use-before-define
+ const timer = setTimeout(() => generateWaveformData(src), 1000)
+
+ return () => {
+ audio.removeEventListener('loadedmetadata', setAudioData)
+ audio.removeEventListener('timeupdate', setAudioTime)
+ audio.removeEventListener('progress', handleProgress)
+ audio.removeEventListener('ended', handleEnded)
+ audio.removeEventListener('error', handleError)
+ clearTimeout(timer)
+ }
+ }, [src])
+
+ const generateWaveformData = async (audioSrc: string) => {
+ if (!window.AudioContext && !(window as any).webkitAudioContext) {
+ setIsAudioAvailable(false)
+ Toast.notify({
+ type: 'error',
+ message: 'Web Audio API is not supported in this browser',
+ })
+ return null
+ }
+
+ const url = new URL(src)
+ const isHttp = url.protocol === 'http:' || url.protocol === 'https:'
+ if (!isHttp) {
+ setIsAudioAvailable(false)
+ return null
+ }
+
+ const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()
+ const samples = 70
+
+ try {
+ const response = await fetch(audioSrc, { mode: 'cors' })
+ if (!response || !response.ok) {
+ setIsAudioAvailable(false)
+ return null
+ }
+
+ const arrayBuffer = await response.arrayBuffer()
+ const audioBuffer = await audioContext.decodeAudioData(arrayBuffer)
+ const channelData = audioBuffer.getChannelData(0)
+ const blockSize = Math.floor(channelData.length / samples)
+ const waveformData: number[] = []
+
+ for (let i = 0; i < samples; i++) {
+ let sum = 0
+ for (let j = 0; j < blockSize; j++)
+ sum += Math.abs(channelData[i * blockSize + j])
+
+ // Apply nonlinear scaling to enhance small amplitudes
+ waveformData.push((sum / blockSize) * 5)
+ }
+
+ // Normalized waveform data
+ const maxAmplitude = Math.max(...waveformData)
+ const normalizedWaveform = waveformData.map(amp => amp / maxAmplitude)
+
+ setWaveformData(normalizedWaveform)
+ setIsAudioAvailable(true)
+ }
+ catch {
+ const waveform: number[] = []
+ let prevValue = Math.random()
+
+ for (let i = 0; i < samples; i++) {
+ const targetValue = Math.random()
+ const interpolatedValue = prevValue + (targetValue - prevValue) * 0.3
+ waveform.push(interpolatedValue)
+ prevValue = interpolatedValue
+ }
+
+ const maxAmplitude = Math.max(...waveform)
+ const randomWaveform = waveform.map(amp => amp / maxAmplitude)
+
+ setWaveformData(randomWaveform)
+ setIsAudioAvailable(true)
+ }
+ finally {
+ await audioContext.close()
+ }
+ }
+
+ const togglePlay = useCallback(() => {
+ const audio = audioRef.current
+ if (audio && isAudioAvailable) {
+ if (isPlaying) {
+ setHasStartedPlaying(false)
+ audio.pause()
+ }
+ else {
+ setHasStartedPlaying(true)
+ audio.play().catch(error => console.error('Error playing audio:', error))
+ }
+
+ setIsPlaying(!isPlaying)
+ }
+ else {
+ Toast.notify({
+ type: 'error',
+ message: 'Audio element not found',
+ })
+ setIsAudioAvailable(false)
+ }
+ }, [isAudioAvailable, isPlaying])
+
+ const handleCanvasInteraction = useCallback((e: React.MouseEvent | React.TouchEvent) => {
+ e.preventDefault()
+
+ const getClientX = (event: React.MouseEvent | React.TouchEvent): number => {
+ if ('touches' in event)
+ return event.touches[0].clientX
+ return event.clientX
+ }
+
+ const updateProgress = (clientX: number) => {
+ const canvas = canvasRef.current
+ const audio = audioRef.current
+ if (!canvas || !audio)
+ return
+
+ const rect = canvas.getBoundingClientRect()
+ const percent = Math.min(Math.max(0, clientX - rect.left), rect.width) / rect.width
+ const newTime = percent * duration
+
+ // Removes the buffer check, allowing drag to any location
+ audio.currentTime = newTime
+ setCurrentTime(newTime)
+
+ if (!isPlaying) {
+ setIsPlaying(true)
+ audio.play().catch((error) => {
+ Toast.notify({
+ type: 'error',
+ message: `Error playing audio: ${error}`,
+ })
+ setIsPlaying(false)
+ })
+ }
+ }
+
+ updateProgress(getClientX(e))
+ }, [duration, isPlaying])
+
+ const formatTime = (time: number) => {
+ const minutes = Math.floor(time / 60)
+ const seconds = Math.floor(time % 60)
+ return `${minutes}:${seconds.toString().padStart(2, '0')}`
+ }
+
+ const drawWaveform = useCallback(() => {
+ const canvas = canvasRef.current
+ if (!canvas)
+ return
+
+ const ctx = canvas.getContext('2d')
+ if (!ctx)
+ return
+
+ const width = canvas.width
+ const height = canvas.height
+ const data = waveformData
+
+ ctx.clearRect(0, 0, width, height)
+
+ const barWidth = width / data.length
+ const playedWidth = (currentTime / duration) * width
+ const cornerRadius = 2
+
+ // Draw waveform bars
+ data.forEach((value, index) => {
+ let color
+
+ if (index * barWidth <= playedWidth)
+ color = theme === Theme.light ? '#296DFF' : '#84ABFF'
+ else if ((index * barWidth / width) * duration <= hoverTime)
+ color = theme === Theme.light ? 'rgba(21,90,239,.40)' : 'rgba(200, 206, 218, 0.28)'
+ else
+ color = theme === Theme.light ? 'rgba(21,90,239,.20)' : 'rgba(200, 206, 218, 0.14)'
+
+ const barHeight = value * height
+ const rectX = index * barWidth
+ const rectY = (height - barHeight) / 2
+ const rectWidth = barWidth * 0.5
+ const rectHeight = barHeight
+
+ ctx.lineWidth = 1
+ ctx.fillStyle = color
+ if (ctx.roundRect) {
+ ctx.beginPath()
+ ctx.roundRect(rectX, rectY, rectWidth, rectHeight, cornerRadius)
+ ctx.fill()
+ }
+ else {
+ ctx.fillRect(rectX, rectY, rectWidth, rectHeight)
+ }
+ })
+ }, [currentTime, duration, hoverTime, theme, waveformData])
+
+ useEffect(() => {
+ drawWaveform()
+ }, [drawWaveform, bufferedTime, hasStartedPlaying])
+
+ const handleMouseMove = useCallback((e: React.MouseEvent) => {
+ const canvas = canvasRef.current
+ const audio = audioRef.current
+ if (!canvas || !audio)
+ return
+
+ const rect = canvas.getBoundingClientRect()
+ const percent = Math.min(Math.max(0, e.clientX - rect.left), rect.width) / rect.width
+ const time = percent * duration
+
+ // Check if the hovered position is within a buffered range before updating hoverTime
+ for (let i = 0; i < audio.buffered.length; i++) {
+ if (time >= audio.buffered.start(i) && time <= audio.buffered.end(i)) {
+ setHoverTime(time)
+ break
+ }
+ }
+ }, [duration])
+
+ return (
+ <div className='flex h-9 min-w-[240px] max-w-[420px] items-end gap-2 rounded-[10px] border border-components-panel-border-subtle bg-components-chat-input-audio-bg-alt p-2 shadow-xs backdrop-blur-sm'>
+ <audio ref={audioRef} src={src} preload="auto"/>
+ <button className='inline-flex shrink-0 cursor-pointer items-center justify-center border-none text-text-accent transition-all hover:text-text-accent-secondary disabled:text-components-button-primary-bg-disabled' onClick={togglePlay} disabled={!isAudioAvailable}>
+ {isPlaying
+ ? (
+ <RiPauseCircleFill className='h-5 w-5' />
+ )
+ : (
+ <RiPlayLargeFill className='h-5 w-5' />
+ )}
+ </button>
+ <div className={cn(isAudioAvailable && 'grow')} hidden={!isAudioAvailable}>
+ <div className='flex h-8 items-center justify-center'>
+ <canvas
+ ref={canvasRef}
+ className='relative flex h-6 w-full grow cursor-pointer items-center justify-center'
+ onClick={handleCanvasInteraction}
+ onMouseMove={handleMouseMove}
+ onMouseDown={handleCanvasInteraction}
+ />
+ <div className='system-xs-medium inline-flex min-w-[50px] items-center justify-center text-text-accent-secondary'>
+ <span className='rounded-[10px] px-0.5 py-1'>{formatTime(duration)}</span>
+ </div>
+ </div>
+ </div>
+ <div className='absolute left-0 top-0 flex h-full w-full items-center justify-center text-text-quaternary' hidden={isAudioAvailable}>{t('common.operation.audioSourceUnavailable')}</div>
+ </div>
+ )
+}
+
+export default AudioPlayer
diff --git a/app/components/base/audio-gallery/index.tsx b/app/components/base/audio-gallery/index.tsx
new file mode 100644
index 0000000..6e11d43
--- /dev/null
+++ b/app/components/base/audio-gallery/index.tsx
@@ -0,0 +1,12 @@
+import React from 'react'
+import AudioPlayer from './AudioPlayer'
+
+type Props = {
+ srcs: string[]
+}
+
+const AudioGallery: React.FC<Props> = ({ srcs }) => {
+ return (<><br/>{srcs.map((src, index) => (<AudioPlayer key={`audio_${index}`} src={src}/>))}</>)
+}
+
+export default React.memo(AudioGallery)
diff --git a/app/components/base/auto-height-textarea/common.tsx b/app/components/base/auto-height-textarea/common.tsx
new file mode 100644
index 0000000..841bfdd
--- /dev/null
+++ b/app/components/base/auto-height-textarea/common.tsx
@@ -0,0 +1,54 @@
+import { useEffect, useRef } from 'react'
+import cn from '@/utils/classnames'
+
+type AutoHeightTextareaProps =
+ & React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>
+ & { outerClassName?: string }
+
+const AutoHeightTextarea = (
+ {
+ ref: outRef,
+ outerClassName,
+ value,
+ className,
+ placeholder,
+ autoFocus,
+ disabled,
+ ...rest
+ }: AutoHeightTextareaProps & {
+ ref: React.RefObject<HTMLTextAreaElement>;
+ },
+) => {
+ const innerRef = useRef<HTMLTextAreaElement>(null)
+ const ref = outRef || innerRef
+
+ useEffect(() => {
+ if (autoFocus && !disabled && value) {
+ if (typeof ref !== 'function') {
+ ref.current?.setSelectionRange(`${value}`.length, `${value}`.length)
+ ref.current?.focus()
+ }
+ }
+ }, [autoFocus, disabled, ref])
+ return (
+ (<div className={outerClassName}>
+ <div className='relative'>
+ <div className={cn(className, 'invisible whitespace-pre-wrap break-all')}>
+ {!value ? placeholder : `${value}`.replace(/\n$/, '\n ')}
+ </div>
+ <textarea
+ ref={ref}
+ placeholder={placeholder}
+ className={cn(className, 'absolute inset-0 h-full w-full resize-none appearance-none border-none outline-none disabled:bg-transparent')}
+ value={value}
+ disabled={disabled}
+ {...rest}
+ />
+ </div>
+ </div>)
+ )
+}
+
+AutoHeightTextarea.displayName = 'AutoHeightTextarea'
+
+export default AutoHeightTextarea
diff --git a/app/components/base/auto-height-textarea/index.tsx b/app/components/base/auto-height-textarea/index.tsx
new file mode 100644
index 0000000..da412a1
--- /dev/null
+++ b/app/components/base/auto-height-textarea/index.tsx
@@ -0,0 +1,96 @@
+import { useEffect, useRef } from 'react'
+import cn from '@/utils/classnames'
+import { sleep } from '@/utils'
+
+type IProps = {
+ placeholder?: string
+ value: string
+ onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void
+ className?: string
+ wrapperClassName?: string
+ minHeight?: number
+ maxHeight?: number
+ autoFocus?: boolean
+ controlFocus?: number
+ onKeyDown?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void
+ onKeyUp?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void
+}
+
+const AutoHeightTextarea = (
+ {
+ ref: outerRef,
+ value,
+ onChange,
+ placeholder,
+ className,
+ wrapperClassName,
+ minHeight = 36,
+ maxHeight = 96,
+ autoFocus,
+ controlFocus,
+ onKeyDown,
+ onKeyUp,
+ }: IProps & {
+ ref: React.RefObject<unknown>;
+ },
+) => {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ const ref = outerRef || useRef<HTMLTextAreaElement>(null)
+
+ const doFocus = () => {
+ if (ref.current) {
+ ref.current.setSelectionRange(value.length, value.length)
+ ref.current.focus()
+ return true
+ }
+ return false
+ }
+
+ const focus = async () => {
+ if (!doFocus()) {
+ let hasFocus = false
+ await sleep(100)
+ hasFocus = doFocus()
+ if (!hasFocus)
+ focus()
+ }
+ }
+
+ useEffect(() => {
+ if (autoFocus)
+ focus()
+ }, [])
+ useEffect(() => {
+ if (controlFocus)
+ focus()
+ }, [controlFocus])
+
+ return (
+ (<div className={`relative ${wrapperClassName}`}>
+ <div className={cn(className, 'invisible overflow-y-auto whitespace-pre-wrap break-all')} style={{
+ minHeight,
+ maxHeight,
+ paddingRight: (value && value.trim().length > 10000) ? 140 : 130,
+ }}>
+ {!value ? placeholder : value.replace(/\n$/, '\n ')}
+ </div>
+ <textarea
+ ref={ref}
+ autoFocus={autoFocus}
+ className={cn(className, 'absolute inset-0 resize-none overflow-auto')}
+ style={{
+ paddingRight: (value && value.trim().length > 10000) ? 140 : 130,
+ }}
+ placeholder={placeholder}
+ onChange={onChange}
+ onKeyDown={onKeyDown}
+ onKeyUp={onKeyUp}
+ value={value}
+ />
+ </div>)
+ )
+}
+
+AutoHeightTextarea.displayName = 'AutoHeightTextarea'
+
+export default AutoHeightTextarea
diff --git a/app/components/base/auto-height-textarea/style.module.scss b/app/components/base/auto-height-textarea/style.module.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/components/base/auto-height-textarea/style.module.scss
diff --git a/app/components/base/avatar/index.tsx b/app/components/base/avatar/index.tsx
new file mode 100644
index 0000000..2a08f75
--- /dev/null
+++ b/app/components/base/avatar/index.tsx
@@ -0,0 +1,54 @@
+'use client'
+import { useState } from 'react'
+import cn from '@/utils/classnames'
+
+export type AvatarProps = {
+ name: string
+ avatar: string | null
+ size?: number
+ className?: string
+ textClassName?: string
+}
+const Avatar = ({
+ name,
+ avatar,
+ size = 30,
+ className,
+ textClassName,
+}: AvatarProps) => {
+ const avatarClassName = 'shrink-0 flex items-center rounded-full bg-primary-600'
+ const style = { width: `${size}px`, height: `${size}px`, fontSize: `${size}px`, lineHeight: `${size}px` }
+ const [imgError, setImgError] = useState(false)
+
+ const handleError = () => {
+ setImgError(true)
+ }
+
+ if (avatar && !imgError) {
+ return (
+ <img
+ className={cn(avatarClassName, className)}
+ style={style}
+ alt={name}
+ src={avatar}
+ onError={handleError}
+ />
+ )
+ }
+
+ return (
+ <div
+ className={cn(avatarClassName, className)}
+ style={style}
+ >
+ <div
+ className={cn(textClassName, 'scale-[0.4] text-center text-white')}
+ style={style}
+ >
+ {name[0].toLocaleUpperCase()}
+ </div>
+ </div>
+ )
+}
+
+export default Avatar
diff --git a/app/components/base/badge.tsx b/app/components/base/badge.tsx
new file mode 100644
index 0000000..0362d8d
--- /dev/null
+++ b/app/components/base/badge.tsx
@@ -0,0 +1,37 @@
+import type { ReactNode } from 'react'
+import { memo } from 'react'
+import cn from '@/utils/classnames'
+
+type BadgeProps = {
+ className?: string
+ text?: ReactNode
+ children?: ReactNode
+ uppercase?: boolean
+ hasRedCornerMark?: boolean
+}
+
+const Badge = ({
+ className,
+ text,
+ children,
+ uppercase = true,
+ hasRedCornerMark,
+}: BadgeProps) => {
+ return (
+ <div
+ className={cn(
+ 'relative inline-flex h-5 items-center rounded-[5px] border border-divider-deep px-[5px] leading-3 text-text-tertiary',
+ uppercase ? 'system-2xs-medium-uppercase' : 'system-xs-medium',
+ className,
+ )}
+ >
+ {hasRedCornerMark && (
+ <div className='absolute right-[-2px] top-[-2px] h-1.5 w-1.5 rounded-[2px] border border-components-badge-status-light-error-border-inner bg-components-badge-status-light-error-bg shadow-sm'>
+ </div>
+ )}
+ {children || text}
+ </div>
+ )
+}
+
+export default memo(Badge)
diff --git a/app/components/base/badge/index.css b/app/components/base/badge/index.css
new file mode 100644
index 0000000..24c62cd
--- /dev/null
+++ b/app/components/base/badge/index.css
@@ -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
+ }
+}
diff --git a/app/components/base/badge/index.tsx b/app/components/base/badge/index.tsx
new file mode 100644
index 0000000..88ba026
--- /dev/null
+++ b/app/components/base/badge/index.tsx
@@ -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 }
diff --git a/app/components/base/block-input/index.tsx b/app/components/base/block-input/index.tsx
new file mode 100644
index 0000000..9b26b52
--- /dev/null
+++ b/app/components/base/block-input/index.tsx
@@ -0,0 +1,146 @@
+'use client'
+
+import type { ChangeEvent, FC } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { varHighlightHTML } from '../../app/configuration/base/var-highlight'
+import Toast from '../toast'
+import classNames from '@/utils/classnames'
+import { checkKeys } from '@/utils/var'
+
+// regex to match the {{}} and replace it with a span
+const regex = /\{\{([^}]+)\}\}/g
+
+export const getInputKeys = (value: string) => {
+ const keys = value.match(regex)?.map((item) => {
+ return item.replace('{{', '').replace('}}', '')
+ }) || []
+ const keyObj: Record<string, boolean> = {}
+ // remove duplicate keys
+ const res: string[] = []
+ keys.forEach((key) => {
+ if (keyObj[key])
+ return
+
+ keyObj[key] = true
+ res.push(key)
+ })
+ return res
+}
+
+export type IBlockInputProps = {
+ value: string
+ className?: string // wrapper class
+ highLightClassName?: string // class for the highlighted text default is text-blue-500
+ readonly?: boolean
+ onConfirm?: (value: string, keys: string[]) => void
+}
+
+const BlockInput: FC<IBlockInputProps> = ({
+ value = '',
+ className,
+ readonly = false,
+ onConfirm,
+}) => {
+ const { t } = useTranslation()
+ // current is used to store the current value of the contentEditable element
+ const [currentValue, setCurrentValue] = useState<string>(value)
+ useEffect(() => {
+ setCurrentValue(value)
+ }, [value])
+
+ const contentEditableRef = useRef<HTMLTextAreaElement>(null)
+ const [isEditing, setIsEditing] = useState<boolean>(false)
+ useEffect(() => {
+ if (isEditing && contentEditableRef.current) {
+ // TODO: Focus at the click position
+ if (currentValue)
+ contentEditableRef.current.setSelectionRange(currentValue.length, currentValue.length)
+
+ contentEditableRef.current.focus()
+ }
+ }, [isEditing])
+
+ const style = classNames({
+ 'block px-4 py-2 w-full h-full text-sm text-gray-900 outline-0 border-0 break-all': true,
+ 'block-input--editing': isEditing,
+ })
+
+ const coloredContent = (currentValue || '')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(regex, varHighlightHTML({ name: '$1' })) // `<span class="${highLightClassName}">{{$1}}</span>`
+ .replace(/\n/g, '<br />')
+
+ // Not use useCallback. That will cause out callback get old data.
+ const handleSubmit = (value: string) => {
+ if (onConfirm) {
+ const keys = getInputKeys(value)
+ const { isValid, errorKey, errorMessageKey } = checkKeys(keys)
+ if (!isValid) {
+ Toast.notify({
+ type: 'error',
+ message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: errorKey }),
+ })
+ return
+ }
+ onConfirm(value, keys)
+ }
+ }
+
+ const onValueChange = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {
+ const value = e.target.value
+ setCurrentValue(value)
+ handleSubmit(value)
+ }, [])
+
+ // Prevent rerendering caused cursor to jump to the start of the contentEditable element
+ const TextAreaContentView = () => {
+ return <div
+ className={classNames(style, className)}
+ dangerouslySetInnerHTML={{ __html: coloredContent }}
+ suppressContentEditableWarning={true}
+ />
+ }
+
+ const placeholder = ''
+ const editAreaClassName = 'focus:outline-none bg-transparent text-sm'
+
+ const textAreaContent = (
+ <div className={classNames(readonly ? 'max-h-[180px] pb-5' : 'h-[180px]', ' overflow-y-auto')} onClick={() => !readonly && setIsEditing(true)}>
+ {isEditing
+ ? <div className='h-full px-4 py-2'>
+ <textarea
+ ref={contentEditableRef}
+ className={classNames(editAreaClassName, 'block w-full h-full resize-none')}
+ placeholder={placeholder}
+ onChange={onValueChange}
+ value={currentValue}
+ onBlur={() => {
+ blur()
+ setIsEditing(false)
+ // click confirm also make blur. Then outer value is change. So below code has problem.
+ // setTimeout(() => {
+ // handleCancel()
+ // }, 1000)
+ }}
+ />
+ </div>
+ : <TextAreaContentView />}
+ </div>)
+
+ return (
+ <div className={classNames('block-input w-full overflow-y-auto bg-white border-none rounded-xl')}>
+ {textAreaContent}
+ {/* footer */}
+ {!readonly && (
+ <div className='flex pb-2 pl-4'>
+ <div className="h-[18px] rounded-md bg-gray-100 px-1 text-xs leading-[18px] text-gray-500">{currentValue?.length}</div>
+ </div>
+ )}
+
+ </div>
+ )
+}
+
+export default React.memo(BlockInput)
diff --git a/app/components/base/button/add-button.tsx b/app/components/base/button/add-button.tsx
new file mode 100644
index 0000000..420b668
--- /dev/null
+++ b/app/components/base/button/add-button.tsx
@@ -0,0 +1,22 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { RiAddLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+
+type Props = {
+ className?: string
+ onClick: () => void
+}
+
+const AddButton: FC<Props> = ({
+ className,
+ onClick,
+}) => {
+ return (
+ <div className={cn(className, 'cursor-pointer select-none rounded-md p-1 hover:bg-state-base-hover')} onClick={onClick}>
+ <RiAddLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ )
+}
+export default React.memo(AddButton)
diff --git a/app/components/base/button/index.css b/app/components/base/button/index.css
new file mode 100644
index 0000000..47e5914
--- /dev/null
+++ b/app/components/base/button/index.css
@@ -0,0 +1,186 @@
+@tailwind components;
+
+@layer components {
+ .btn {
+ @apply inline-flex justify-center items-center cursor-pointer whitespace-nowrap;
+ }
+
+ .btn-disabled {
+ @apply cursor-not-allowed;
+ }
+
+ .btn-small {
+ @apply px-2 h-6 rounded-md text-xs font-medium;
+ }
+
+ .btn-medium {
+ @apply px-3.5 h-8 rounded-lg text-[13px] leading-4 font-medium;
+ }
+
+ .btn-large {
+ @apply px-4 h-9 rounded-[10px] text-sm font-semibold;
+ }
+
+ .btn-primary {
+ @apply
+ shadow
+ bg-components-button-primary-bg
+ border-components-button-primary-border
+ hover:bg-components-button-primary-bg-hover
+ hover:border-components-button-primary-border-hover
+ text-components-button-primary-text;
+ }
+
+ .btn-primary.btn-destructive {
+ @apply
+ bg-components-button-destructive-primary-bg
+ border-components-button-destructive-primary-border
+ hover:bg-components-button-destructive-primary-bg-hover
+ hover:border-components-button-destructive-primary-border-hover
+ text-components-button-destructive-primary-text;
+ }
+
+ .btn-primary.btn-disabled {
+ @apply
+ shadow-none
+ bg-components-button-primary-bg-disabled
+ border-components-button-primary-border-disabled
+ text-components-button-primary-text-disabled;
+ }
+
+ .btn-primary.btn-destructive.btn-disabled {
+ @apply
+ shadow-none
+ bg-components-button-destructive-primary-bg-disabled
+ border-components-button-destructive-primary-border-disabled
+ text-components-button-destructive-primary-text-disabled;
+ }
+
+ .btn-secondary {
+ @apply
+ border-[0.5px]
+ shadow-xs
+ bg-components-button-secondary-bg
+ border-components-button-secondary-border
+ hover:bg-components-button-secondary-bg-hover
+ hover:border-components-button-secondary-border-hover
+ text-components-button-secondary-text;
+ }
+
+ .btn-secondary.btn-disabled {
+ @apply
+ bg-components-button-secondary-bg-disabled
+ border-components-button-secondary-border-disabled
+ text-components-button-secondary-text-disabled;
+ }
+
+ .btn-secondary.btn-destructive {
+ @apply
+ bg-components-button-destructive-secondary-bg
+ border-components-button-destructive-secondary-border
+ hover:bg-components-button-destructive-secondary-bg-hover
+ hover:border-components-button-destructive-secondary-border-hover
+ text-components-button-destructive-secondary-text;
+ }
+
+ .btn-secondary.btn-destructive.btn-disabled {
+ @apply
+ bg-components-button-destructive-secondary-bg-disabled
+ border-components-button-destructive-secondary-border-disabled
+ text-components-button-destructive-secondary-text-disabled;
+ }
+
+
+ .btn-secondary-accent {
+ @apply
+ border-[0.5px]
+ shadow-xs
+ bg-components-button-secondary-bg
+ border-components-button-secondary-border
+ hover:bg-components-button-secondary-bg-hover
+ hover:border-components-button-secondary-border-hover
+ text-components-button-secondary-accent-text;
+ }
+
+ .btn-secondary-accent.btn-disabled {
+ @apply
+ bg-components-button-secondary-bg-disabled
+ border-components-button-secondary-border-disabled
+ text-components-button-secondary-accent-text-disabled;
+ }
+
+ .btn-warning {
+ @apply
+ bg-components-button-destructive-primary-bg
+ border-components-button-destructive-primary-border
+ hover:bg-components-button-destructive-primary-bg-hover
+ hover:border-components-button-destructive-primary-border-hover
+ text-components-button-destructive-primary-text;
+ }
+
+ .btn-warning.btn-disabled {
+ @apply
+ bg-components-button-destructive-primary-bg-disabled
+ border-components-button-destructive-primary-border-disabled
+ text-components-button-destructive-primary-text-disabled;
+ }
+
+ .btn-tertiary {
+ @apply
+ bg-components-button-tertiary-bg
+ hover:bg-components-button-tertiary-bg-hover
+ text-components-button-tertiary-text;
+ }
+
+ .btn-tertiary.btn-disabled {
+ @apply
+ bg-components-button-tertiary-bg-disabled
+ text-components-button-tertiary-text-disabled;
+ }
+
+ .btn-tertiary.btn-destructive {
+ @apply
+ bg-components-button-destructive-tertiary-bg
+ hover:bg-components-button-destructive-tertiary-bg-hover
+ text-components-button-destructive-tertiary-text;
+ }
+
+ .btn-tertiary.btn-destructive.btn-disabled {
+ @apply
+ bg-components-button-destructive-tertiary-bg-disabled
+ text-components-button-destructive-tertiary-text-disabled;
+ }
+
+ .btn-ghost {
+ @apply
+ hover:bg-components-button-ghost-bg-hover
+ text-components-button-ghost-text;
+ }
+
+ .btn-ghost.btn-disabled {
+ @apply
+ text-components-button-ghost-text-disabled;
+ }
+
+ .btn-ghost.btn-destructive {
+ @apply
+ hover:bg-components-button-destructive-ghost-bg-hover
+ text-components-button-destructive-ghost-text;
+ }
+
+ .btn-ghost.btn-destructive.btn-disabled {
+ @apply
+ text-components-button-destructive-ghost-text-disabled;
+ }
+
+ .btn-ghost-accent {
+ @apply
+ hover:bg-state-accent-hover
+ text-components-button-secondary-accent-text;
+ }
+
+ .btn-ghost-accent.btn-disabled {
+ @apply
+ text-components-button-secondary-accent-text-disabled;
+ }
+}
diff --git a/app/components/base/button/index.spec.tsx b/app/components/base/button/index.spec.tsx
new file mode 100644
index 0000000..9da2620
--- /dev/null
+++ b/app/components/base/button/index.spec.tsx
@@ -0,0 +1,110 @@
+import React from 'react'
+import { cleanup, fireEvent, render } from '@testing-library/react'
+import Button from './index'
+
+afterEach(cleanup)
+// https://testing-library.com/docs/queries/about
+describe('Button', () => {
+ describe('Button text', () => {
+ test('Button text should be same as children', async () => {
+ const { getByRole, container } = render(<Button>Click me</Button>)
+ expect(getByRole('button').textContent).toBe('Click me')
+ expect(container.querySelector('button')?.textContent).toBe('Click me')
+ })
+ })
+
+ describe('Button loading', () => {
+ test('Loading button text should include same as children', async () => {
+ const { getByRole } = render(<Button loading>Click me</Button>)
+ expect(getByRole('button').textContent?.includes('Loading')).toBe(true)
+ })
+ test('Not loading button text should include same as children', async () => {
+ const { getByRole } = render(<Button loading={false}>Click me</Button>)
+ expect(getByRole('button').textContent?.includes('Loading')).toBe(false)
+ })
+
+ test('Loading button should have loading classname', async () => {
+ const animClassName = 'anim-breath'
+ const { getByRole } = render(<Button loading spinnerClassName={animClassName}>Click me</Button>)
+ expect(getByRole('button').getElementsByClassName('animate-spin')[0]?.className).toContain(animClassName)
+ })
+ })
+
+ describe('Button style', () => {
+ test('Button should have default variant', async () => {
+ const { getByRole } = render(<Button>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-secondary')
+ })
+
+ test('Button should have primary variant', async () => {
+ const { getByRole } = render(<Button variant='primary'>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-primary')
+ })
+
+ test('Button should have warning variant', async () => {
+ const { getByRole } = render(<Button variant='warning'>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-warning')
+ })
+
+ test('Button should have secondary variant', async () => {
+ const { getByRole } = render(<Button variant='secondary'>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-secondary')
+ })
+
+ test('Button should have secondary-accent variant', async () => {
+ const { getByRole } = render(<Button variant='secondary-accent'>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-secondary-accent')
+ })
+ test('Button should have ghost variant', async () => {
+ const { getByRole } = render(<Button variant='ghost'>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-ghost')
+ })
+ test('Button should have ghost-accent variant', async () => {
+ const { getByRole } = render(<Button variant='ghost-accent'>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-ghost-accent')
+ })
+
+ test('Button disabled should have disabled variant', async () => {
+ const { getByRole } = render(<Button disabled>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-disabled')
+ })
+ })
+
+ describe('Button size', () => {
+ test('Button should have default size', async () => {
+ const { getByRole } = render(<Button>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-medium')
+ })
+
+ test('Button should have small size', async () => {
+ const { getByRole } = render(<Button size='small'>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-small')
+ })
+
+ test('Button should have medium size', async () => {
+ const { getByRole } = render(<Button size='medium'>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-medium')
+ })
+
+ test('Button should have large size', async () => {
+ const { getByRole } = render(<Button size='large'>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-large')
+ })
+ })
+
+ describe('Button destructive', () => {
+ test('Button should have destructive classname', async () => {
+ const { getByRole } = render(<Button destructive>Click me</Button>)
+ expect(getByRole('button').className).toContain('btn-destructive')
+ })
+ })
+
+ describe('Button events', () => {
+ test('onClick should been call after clicked', async () => {
+ const onClick = jest.fn()
+ const { getByRole } = render(<Button onClick={onClick}>Click me</Button>)
+ fireEvent.click(getByRole('button'))
+ expect(onClick).toHaveBeenCalled()
+ })
+ })
+})
diff --git a/app/components/base/button/index.stories.tsx b/app/components/base/button/index.stories.tsx
new file mode 100644
index 0000000..c1b18f1
--- /dev/null
+++ b/app/components/base/button/index.stories.tsx
@@ -0,0 +1,107 @@
+import type { Meta, StoryObj } from '@storybook/react'
+import { fn } from '@storybook/test'
+
+import { RocketLaunchIcon } from '@heroicons/react/20/solid'
+import { Button } from '.'
+
+const meta = {
+ title: 'Base/Button',
+ component: Button,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ argTypes: {
+ loading: { control: 'boolean' },
+ variant: {
+ control: 'select',
+ options: ['primary', 'warning', 'secondary', 'secondary-accent', 'ghost', 'ghost-accent', 'tertiary'],
+ },
+ },
+ args: {
+ variant: 'ghost',
+ onClick: fn(),
+ children: 'adsf',
+ },
+} satisfies Meta<typeof Button>
+
+export default meta
+type Story = StoryObj<typeof meta>
+
+export const Default: Story = {
+ args: {
+ variant: 'primary',
+ loading: false,
+ children: 'Primary Button',
+ },
+}
+
+export const Secondary: Story = {
+ args: {
+ variant: 'secondary',
+ children: 'Secondary Button',
+ },
+}
+
+export const SecondaryAccent: Story = {
+ args: {
+ variant: 'secondary-accent',
+ children: 'Secondary Accent Button',
+ },
+}
+
+export const Ghost: Story = {
+ args: {
+ variant: 'ghost',
+ children: 'Ghost Button',
+ },
+}
+
+export const GhostAccent: Story = {
+ args: {
+ variant: 'ghost-accent',
+ children: 'Ghost Accent Button',
+ },
+}
+
+export const Tertiary: Story = {
+ args: {
+ variant: 'tertiary',
+ children: 'Tertiary Button',
+ },
+}
+
+export const Warning: Story = {
+ args: {
+ variant: 'warning',
+ children: 'Warning Button',
+ },
+}
+
+export const Disabled: Story = {
+ args: {
+ variant: 'primary',
+ disabled: true,
+ children: 'Disabled Button',
+ },
+}
+
+export const Loading: Story = {
+ args: {
+ variant: 'primary',
+ loading: true,
+ children: 'Loading Button',
+ },
+}
+
+export const WithIcon: Story = {
+ args: {
+ variant: 'primary',
+ children: (
+ <>
+ <RocketLaunchIcon className="mr-1.5 h-4 w-4 stroke-[1.8px]" />
+ Launch
+ </>
+ ),
+ },
+}
diff --git a/app/components/base/button/index.tsx b/app/components/base/button/index.tsx
new file mode 100644
index 0000000..b467c49
--- /dev/null
+++ b/app/components/base/button/index.tsx
@@ -0,0 +1,62 @@
+import type { CSSProperties } from 'react'
+import React from 'react'
+import { type VariantProps, cva } from 'class-variance-authority'
+import Spinner from '../spinner'
+import classNames from '@/utils/classnames'
+
+const buttonVariants = cva(
+ 'btn disabled:btn-disabled',
+ {
+ variants: {
+ variant: {
+ 'primary': 'btn-primary',
+ 'warning': 'btn-warning',
+ 'secondary': 'btn-secondary',
+ 'secondary-accent': 'btn-secondary-accent',
+ 'ghost': 'btn-ghost',
+ 'ghost-accent': 'btn-ghost-accent',
+ 'tertiary': 'btn-tertiary',
+ },
+ size: {
+ small: 'btn-small',
+ medium: 'btn-medium',
+ large: 'btn-large',
+ },
+ },
+ defaultVariants: {
+ variant: 'secondary',
+ size: 'medium',
+ },
+ },
+)
+
+export type ButtonProps = {
+ destructive?: boolean
+ loading?: boolean
+ styleCss?: CSSProperties
+ spinnerClassName?: string
+} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants>
+
+const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
+ ({ className, variant, size, destructive, loading, styleCss, children, spinnerClassName, ...props }, ref) => {
+ return (
+ <button
+ type='button'
+ className={classNames(
+ buttonVariants({ variant, size, className }),
+ destructive && 'btn-destructive',
+ )}
+ ref={ref}
+ style={styleCss}
+ {...props}
+ >
+ {children}
+ {loading && <Spinner loading={loading} className={classNames('!text-white !h-3 !w-3 !border-2 !ml-1', spinnerClassName)} />}
+ </button>
+ )
+ },
+)
+Button.displayName = 'Button'
+
+export default Button
+export { Button, buttonVariants }
diff --git a/app/components/base/chat/__tests__/__snapshots__/utils.spec.ts.snap b/app/components/base/chat/__tests__/__snapshots__/utils.spec.ts.snap
new file mode 100644
index 0000000..4ffcfa3
--- /dev/null
+++ b/app/components/base/chat/__tests__/__snapshots__/utils.spec.ts.snap
@@ -0,0 +1,2804 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`build chat item tree and get thread messages should get thread messages from tree6, using specified message as target 1`] = `
+[
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105791,
+ "files": [],
+ "id": "f9d7ff7c-3a3b-4d9a-a289-657817f4caff",
+ "message_id": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "observation": "",
+ "position": 1,
+ "thought": "Sure, I'll play! My number is 57. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105795,
+ "files": [],
+ "id": "f61a3fce-37ac-4f9d-9935-95f97e598dfe",
+ "message_id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "observation": "",
+ "position": 1,
+ "thought": "I choose 83. What's your next number?",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105799,
+ "files": [],
+ "id": "9730d587-9268-4683-9dd9-91a1cab9510b",
+ "message_id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "observation": "",
+ "position": 1,
+ "thought": "I'll go with 112. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "I'll go with 112. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "input": {
+ "inputs": {},
+ "query": "99",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "99",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I'll go with 112. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.49",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "99",
+ "id": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "73bbad14-d915-499d-87bf-0df14d40779d",
+ },
+ ],
+ "content": "I choose 83. What's your next number?",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "input": {
+ "inputs": {},
+ "query": "58",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.33",
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 68,
+ },
+ "parentMessageId": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "58",
+ "id": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ },
+ ],
+ "content": "Sure, I'll play! My number is 57. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "input": {
+ "inputs": {},
+ "query": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.56",
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 49,
+ },
+ "parentMessageId": "question-ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "Let's play a game, I say a number , and you response me with another bigger, yet random-looking number. I'll start first, 38",
+ "id": "question-ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "isAnswer": false,
+ "message_files": [],
+ },
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105791,
+ "files": [],
+ "id": "f9d7ff7c-3a3b-4d9a-a289-657817f4caff",
+ "message_id": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "observation": "",
+ "position": 1,
+ "thought": "Sure, I'll play! My number is 57. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105795,
+ "files": [],
+ "id": "f61a3fce-37ac-4f9d-9935-95f97e598dfe",
+ "message_id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "observation": "",
+ "position": 1,
+ "thought": "I choose 83. What's your next number?",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105799,
+ "files": [],
+ "id": "9730d587-9268-4683-9dd9-91a1cab9510b",
+ "message_id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "observation": "",
+ "position": 1,
+ "thought": "I'll go with 112. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "I'll go with 112. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "input": {
+ "inputs": {},
+ "query": "99",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "99",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I'll go with 112. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.49",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "99",
+ "id": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "73bbad14-d915-499d-87bf-0df14d40779d",
+ },
+ ],
+ "content": "I choose 83. What's your next number?",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "input": {
+ "inputs": {},
+ "query": "58",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.33",
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 68,
+ },
+ "parentMessageId": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "58",
+ "id": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ },
+ ],
+ "content": "Sure, I'll play! My number is 57. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "input": {
+ "inputs": {},
+ "query": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.56",
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 49,
+ },
+ "nextSibling": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "parentMessageId": "question-ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "prevSibling": undefined,
+ "siblingCount": 2,
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105795,
+ "files": [],
+ "id": "f61a3fce-37ac-4f9d-9935-95f97e598dfe",
+ "message_id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "observation": "",
+ "position": 1,
+ "thought": "I choose 83. What's your next number?",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105799,
+ "files": [],
+ "id": "9730d587-9268-4683-9dd9-91a1cab9510b",
+ "message_id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "observation": "",
+ "position": 1,
+ "thought": "I'll go with 112. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "I'll go with 112. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "input": {
+ "inputs": {},
+ "query": "99",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "99",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I'll go with 112. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.49",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "99",
+ "id": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "73bbad14-d915-499d-87bf-0df14d40779d",
+ },
+ ],
+ "content": "I choose 83. What's your next number?",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "input": {
+ "inputs": {},
+ "query": "58",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.33",
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 68,
+ },
+ "parentMessageId": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "58",
+ "id": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ },
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105795,
+ "files": [],
+ "id": "f61a3fce-37ac-4f9d-9935-95f97e598dfe",
+ "message_id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "observation": "",
+ "position": 1,
+ "thought": "I choose 83. What's your next number?",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105799,
+ "files": [],
+ "id": "9730d587-9268-4683-9dd9-91a1cab9510b",
+ "message_id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "observation": "",
+ "position": 1,
+ "thought": "I'll go with 112. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "I'll go with 112. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "input": {
+ "inputs": {},
+ "query": "99",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "99",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I'll go with 112. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.49",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "99",
+ "id": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "73bbad14-d915-499d-87bf-0df14d40779d",
+ },
+ ],
+ "content": "I choose 83. What's your next number?",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "input": {
+ "inputs": {},
+ "query": "58",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.33",
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 68,
+ },
+ "parentMessageId": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "prevSibling": undefined,
+ "siblingCount": 1,
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105799,
+ "files": [],
+ "id": "9730d587-9268-4683-9dd9-91a1cab9510b",
+ "message_id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "observation": "",
+ "position": 1,
+ "thought": "I'll go with 112. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "I'll go with 112. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "input": {
+ "inputs": {},
+ "query": "99",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "99",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I'll go with 112. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.49",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "99",
+ "id": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "73bbad14-d915-499d-87bf-0df14d40779d",
+ },
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105799,
+ "files": [],
+ "id": "9730d587-9268-4683-9dd9-91a1cab9510b",
+ "message_id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "observation": "",
+ "position": 1,
+ "thought": "I'll go with 112. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "I'll go with 112. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "input": {
+ "inputs": {},
+ "query": "99",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "99",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I'll go with 112. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.49",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "prevSibling": undefined,
+ "siblingCount": 1,
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+]
+`;
+
+exports[`build chat item tree and get thread messages should get thread messages from tree6, using the last message as target 1`] = `
+[
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105809,
+ "files": [],
+ "id": "1019cd79-d141-4f9f-880a-fc1441cfd802",
+ "message_id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "observation": "",
+ "position": 1,
+ "thought": "Sure! My number is 54. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105822,
+ "files": [],
+ "id": "0773bec7-b992-4a53-92b2-20ebaeae8798",
+ "message_id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4729. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 4729. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4729. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.30",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 66,
+ },
+ "parentMessageId": "question-324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "3306",
+ "id": "question-324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726107812,
+ "files": [],
+ "id": "5ca650f3-982c-4399-8b95-9ea241c76707",
+ "message_id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4821. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726111024,
+ "files": [],
+ "id": "095cacab-afad-4387-a41d-1662578b8b13",
+ "message_id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 1456. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 1456. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "input": {
+ "inputs": {},
+ "query": "1003",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "1003",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 1456. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.38",
+ "time": "09/11/2024 11:17 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "1003",
+ "id": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ },
+ ],
+ "content": "My number is 4821. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.48",
+ "time": "09/11/2024 10:23 PM",
+ "tokens": 66,
+ },
+ "parentMessageId": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "siblingIndex": 1,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "3306",
+ "id": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ },
+ ],
+ "content": "Sure! My number is 54. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "input": {
+ "inputs": {},
+ "query": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.52",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 46,
+ },
+ "parentMessageId": "question-cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "siblingIndex": 1,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "id": "question-cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "isAnswer": false,
+ "message_files": [],
+ },
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105809,
+ "files": [],
+ "id": "1019cd79-d141-4f9f-880a-fc1441cfd802",
+ "message_id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "observation": "",
+ "position": 1,
+ "thought": "Sure! My number is 54. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105822,
+ "files": [],
+ "id": "0773bec7-b992-4a53-92b2-20ebaeae8798",
+ "message_id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4729. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 4729. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4729. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.30",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 66,
+ },
+ "parentMessageId": "question-324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "3306",
+ "id": "question-324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726107812,
+ "files": [],
+ "id": "5ca650f3-982c-4399-8b95-9ea241c76707",
+ "message_id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4821. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726111024,
+ "files": [],
+ "id": "095cacab-afad-4387-a41d-1662578b8b13",
+ "message_id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 1456. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 1456. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "input": {
+ "inputs": {},
+ "query": "1003",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "1003",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 1456. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.38",
+ "time": "09/11/2024 11:17 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "1003",
+ "id": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ },
+ ],
+ "content": "My number is 4821. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.48",
+ "time": "09/11/2024 10:23 PM",
+ "tokens": 66,
+ },
+ "parentMessageId": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "siblingIndex": 1,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "3306",
+ "id": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ },
+ ],
+ "content": "Sure! My number is 54. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "input": {
+ "inputs": {},
+ "query": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.52",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 46,
+ },
+ "nextSibling": undefined,
+ "parentMessageId": "question-cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "prevSibling": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "siblingCount": 2,
+ "siblingIndex": 1,
+ "workflow_run_id": null,
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726107812,
+ "files": [],
+ "id": "5ca650f3-982c-4399-8b95-9ea241c76707",
+ "message_id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4821. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726111024,
+ "files": [],
+ "id": "095cacab-afad-4387-a41d-1662578b8b13",
+ "message_id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 1456. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 1456. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "input": {
+ "inputs": {},
+ "query": "1003",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "1003",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 1456. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.38",
+ "time": "09/11/2024 11:17 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "1003",
+ "id": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ },
+ ],
+ "content": "My number is 4821. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.48",
+ "time": "09/11/2024 10:23 PM",
+ "tokens": 66,
+ },
+ "parentMessageId": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "siblingIndex": 1,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "3306",
+ "id": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ },
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726107812,
+ "files": [],
+ "id": "5ca650f3-982c-4399-8b95-9ea241c76707",
+ "message_id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4821. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726111024,
+ "files": [],
+ "id": "095cacab-afad-4387-a41d-1662578b8b13",
+ "message_id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 1456. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 1456. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "input": {
+ "inputs": {},
+ "query": "1003",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "1003",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 1456. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.38",
+ "time": "09/11/2024 11:17 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "1003",
+ "id": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ },
+ ],
+ "content": "My number is 4821. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.48",
+ "time": "09/11/2024 10:23 PM",
+ "tokens": 66,
+ },
+ "nextSibling": undefined,
+ "parentMessageId": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "prevSibling": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "siblingCount": 2,
+ "siblingIndex": 1,
+ "workflow_run_id": null,
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726111024,
+ "files": [],
+ "id": "095cacab-afad-4387-a41d-1662578b8b13",
+ "message_id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 1456. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 1456. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "input": {
+ "inputs": {},
+ "query": "1003",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "1003",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 1456. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.38",
+ "time": "09/11/2024 11:17 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "1003",
+ "id": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ },
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726111024,
+ "files": [],
+ "id": "095cacab-afad-4387-a41d-1662578b8b13",
+ "message_id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 1456. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 1456. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "input": {
+ "inputs": {},
+ "query": "1003",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "1003",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 1456. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.38",
+ "time": "09/11/2024 11:17 PM",
+ "tokens": 86,
+ },
+ "nextSibling": undefined,
+ "parentMessageId": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "prevSibling": undefined,
+ "siblingCount": 1,
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+]
+`;
+
+exports[`build chat item tree and get thread messages should work with partial messages 1 1`] = `
+[
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105799,
+ "files": [],
+ "id": "9730d587-9268-4683-9dd9-91a1cab9510b",
+ "message_id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "observation": "",
+ "position": 1,
+ "thought": "I'll go with 112. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "I'll go with 112. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "input": {
+ "inputs": {},
+ "query": "99",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "99",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I'll go with 112. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.49",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "99",
+ "id": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "73bbad14-d915-499d-87bf-0df14d40779d",
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105809,
+ "files": [],
+ "id": "1019cd79-d141-4f9f-880a-fc1441cfd802",
+ "message_id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "observation": "",
+ "position": 1,
+ "thought": "Sure! My number is 54. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105822,
+ "files": [],
+ "id": "0773bec7-b992-4a53-92b2-20ebaeae8798",
+ "message_id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4729. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 4729. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4729. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.30",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 66,
+ },
+ "parentMessageId": "question-324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "3306",
+ "id": "question-324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726107812,
+ "files": [],
+ "id": "5ca650f3-982c-4399-8b95-9ea241c76707",
+ "message_id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4821. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726111024,
+ "files": [],
+ "id": "095cacab-afad-4387-a41d-1662578b8b13",
+ "message_id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 1456. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 1456. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "input": {
+ "inputs": {},
+ "query": "1003",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "1003",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 1456. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.38",
+ "time": "09/11/2024 11:17 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "1003",
+ "id": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ },
+ ],
+ "content": "My number is 4821. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.48",
+ "time": "09/11/2024 10:23 PM",
+ "tokens": 66,
+ },
+ "parentMessageId": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "siblingIndex": 1,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "3306",
+ "id": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ },
+ ],
+ "content": "Sure! My number is 54. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "input": {
+ "inputs": {},
+ "query": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.52",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 46,
+ },
+ "parentMessageId": "question-cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "id": "question-cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "isAnswer": false,
+ "message_files": [],
+ },
+]
+`;
+
+exports[`build chat item tree and get thread messages should work with partial messages 2 1`] = `
+[
+ {
+ "children": [
+ {
+ "children": [],
+ "content": "237.",
+ "id": "ebb73fe2-15de-46dd-aab5-75416d8448eb",
+ "isAnswer": true,
+ "parentMessageId": "question-ebb73fe2-15de-46dd-aab5-75416d8448eb",
+ "siblingIndex": 0,
+ },
+ ],
+ "content": "123",
+ "id": "question-ebb73fe2-15de-46dd-aab5-75416d8448eb",
+ "isAnswer": false,
+ "parentMessageId": "57c989f9-3fa4-4dec-9ee5-c3568dd27418",
+ },
+ {
+ "children": [
+ {
+ "children": [],
+ "content": "My number is 256.",
+ "id": "3553d508-3850-462e-8594-078539f940f9",
+ "isAnswer": true,
+ "parentMessageId": "question-3553d508-3850-462e-8594-078539f940f9",
+ "siblingIndex": 1,
+ },
+ ],
+ "content": "123",
+ "id": "question-3553d508-3850-462e-8594-078539f940f9",
+ "isAnswer": false,
+ "parentMessageId": "57c989f9-3fa4-4dec-9ee5-c3568dd27418",
+ },
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "children": [],
+ "content": "My number is 3e (approximately 8.15).",
+ "id": "9eac3bcc-8d3b-4e56-a12b-44c34cebc719",
+ "isAnswer": true,
+ "parentMessageId": "question-9eac3bcc-8d3b-4e56-a12b-44c34cebc719",
+ "siblingIndex": 0,
+ },
+ ],
+ "content": "e",
+ "id": "question-9eac3bcc-8d3b-4e56-a12b-44c34cebc719",
+ "isAnswer": false,
+ "parentMessageId": "5c56a2b3-f057-42a0-9b2c-52a35713cd8c",
+ },
+ ],
+ "content": "My number is 2蟺 (approximately 6.28).",
+ "id": "5c56a2b3-f057-42a0-9b2c-52a35713cd8c",
+ "isAnswer": true,
+ "parentMessageId": "question-5c56a2b3-f057-42a0-9b2c-52a35713cd8c",
+ "siblingIndex": 0,
+ },
+ ],
+ "content": "蟺",
+ "id": "question-5c56a2b3-f057-42a0-9b2c-52a35713cd8c",
+ "isAnswer": false,
+ "parentMessageId": "46a49bb9-0881-459e-8c6a-24d20ae48d2f",
+ },
+ ],
+ "content": "My number is 145.",
+ "id": "46a49bb9-0881-459e-8c6a-24d20ae48d2f",
+ "isAnswer": true,
+ "parentMessageId": "question-46a49bb9-0881-459e-8c6a-24d20ae48d2f",
+ "siblingIndex": 0,
+ },
+ ],
+ "content": "78",
+ "id": "question-46a49bb9-0881-459e-8c6a-24d20ae48d2f",
+ "isAnswer": false,
+ "parentMessageId": "3cded945-855a-4a24-aab7-43c7dd54664c",
+ },
+ ],
+ "content": "My number is 7.89.",
+ "id": "3cded945-855a-4a24-aab7-43c7dd54664c",
+ "isAnswer": true,
+ "parentMessageId": "question-3cded945-855a-4a24-aab7-43c7dd54664c",
+ "siblingIndex": 0,
+ },
+ ],
+ "content": "3.11",
+ "id": "question-3cded945-855a-4a24-aab7-43c7dd54664c",
+ "isAnswer": false,
+ "parentMessageId": "a956de3d-ef95-4d90-84fe-f7a26ef28cd7",
+ },
+ ],
+ "content": "My number is 22.",
+ "id": "a956de3d-ef95-4d90-84fe-f7a26ef28cd7",
+ "isAnswer": true,
+ "parentMessageId": "question-a956de3d-ef95-4d90-84fe-f7a26ef28cd7",
+ "siblingIndex": 0,
+ },
+ ],
+ "content": "-5",
+ "id": "question-a956de3d-ef95-4d90-84fe-f7a26ef28cd7",
+ "isAnswer": false,
+ "parentMessageId": "93bac05d-1470-4ac9-b090-fe21cd7c3d55",
+ },
+ ],
+ "content": "My number is 4782.",
+ "id": "93bac05d-1470-4ac9-b090-fe21cd7c3d55",
+ "isAnswer": true,
+ "parentMessageId": "question-93bac05d-1470-4ac9-b090-fe21cd7c3d55",
+ "siblingIndex": 0,
+ },
+ ],
+ "content": "3306",
+ "id": "question-93bac05d-1470-4ac9-b090-fe21cd7c3d55",
+ "isAnswer": false,
+ "parentMessageId": "9e51a13b-7780-4565-98dc-f2d8c3b1758f",
+ },
+ ],
+ "content": "My number is 2048.",
+ "id": "9e51a13b-7780-4565-98dc-f2d8c3b1758f",
+ "isAnswer": true,
+ "parentMessageId": "question-9e51a13b-7780-4565-98dc-f2d8c3b1758f",
+ "siblingIndex": 0,
+ },
+ ],
+ "content": "1024",
+ "id": "question-9e51a13b-7780-4565-98dc-f2d8c3b1758f",
+ "isAnswer": false,
+ "parentMessageId": "507f9df9-1f06-4a57-bb38-f00228c42c22",
+ },
+ ],
+ "content": "My number is 259.",
+ "id": "507f9df9-1f06-4a57-bb38-f00228c42c22",
+ "isAnswer": true,
+ "parentMessageId": "question-507f9df9-1f06-4a57-bb38-f00228c42c22",
+ "siblingIndex": 2,
+ },
+ ],
+ "content": "123",
+ "id": "question-507f9df9-1f06-4a57-bb38-f00228c42c22",
+ "isAnswer": false,
+ "parentMessageId": "57c989f9-3fa4-4dec-9ee5-c3568dd27418",
+ },
+]
+`;
+
+exports[`build chat item tree and get thread messages should work with real world messages 1`] = `
+[
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105791,
+ "files": [],
+ "id": "f9d7ff7c-3a3b-4d9a-a289-657817f4caff",
+ "message_id": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "observation": "",
+ "position": 1,
+ "thought": "Sure, I'll play! My number is 57. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105795,
+ "files": [],
+ "id": "f61a3fce-37ac-4f9d-9935-95f97e598dfe",
+ "message_id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "observation": "",
+ "position": 1,
+ "thought": "I choose 83. What's your next number?",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105799,
+ "files": [],
+ "id": "9730d587-9268-4683-9dd9-91a1cab9510b",
+ "message_id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "observation": "",
+ "position": 1,
+ "thought": "I'll go with 112. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "I'll go with 112. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "input": {
+ "inputs": {},
+ "query": "99",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "99",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I'll go with 112. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.49",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "99",
+ "id": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "73bbad14-d915-499d-87bf-0df14d40779d",
+ },
+ ],
+ "content": "I choose 83. What's your next number?",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "input": {
+ "inputs": {},
+ "query": "58",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "58",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.33",
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 68,
+ },
+ "parentMessageId": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "58",
+ "id": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ },
+ ],
+ "content": "Sure, I'll play! My number is 57. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "input": {
+ "inputs": {},
+ "query": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.56",
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 49,
+ },
+ "parentMessageId": "question-ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "Let's play a game, I say a number , and you response me with another bigger, yet random-looking number. I'll start first, 38",
+ "id": "question-ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "isAnswer": false,
+ "message_files": [],
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105809,
+ "files": [],
+ "id": "1019cd79-d141-4f9f-880a-fc1441cfd802",
+ "message_id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "observation": "",
+ "position": 1,
+ "thought": "Sure! My number is 54. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726105822,
+ "files": [],
+ "id": "0773bec7-b992-4a53-92b2-20ebaeae8798",
+ "message_id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4729. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 4729. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4729. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.30",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 66,
+ },
+ "parentMessageId": "question-324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "3306",
+ "id": "question-324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ },
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726107812,
+ "files": [],
+ "id": "5ca650f3-982c-4399-8b95-9ea241c76707",
+ "message_id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 4821. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [
+ {
+ "children": [
+ {
+ "agent_thoughts": [
+ {
+ "chain_id": null,
+ "created_at": 1726111024,
+ "files": [],
+ "id": "095cacab-afad-4387-a41d-1662578b8b13",
+ "message_id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "observation": "",
+ "position": 1,
+ "thought": "My number is 1456. Your turn!",
+ "tool": "",
+ "tool_input": "",
+ "tool_labels": {},
+ },
+ ],
+ "children": [],
+ "content": "My number is 1456. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "input": {
+ "inputs": {},
+ "query": "1003",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "1003",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 1456. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.38",
+ "time": "09/11/2024 11:17 PM",
+ "tokens": 86,
+ },
+ "parentMessageId": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "siblingIndex": 0,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "1003",
+ "id": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ },
+ ],
+ "content": "My number is 4821. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "input": {
+ "inputs": {},
+ "query": "3306",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ {
+ "files": [],
+ "role": "user",
+ "text": "3306",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.48",
+ "time": "09/11/2024 10:23 PM",
+ "tokens": 66,
+ },
+ "parentMessageId": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "siblingIndex": 1,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "3306",
+ "id": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ },
+ ],
+ "content": "Sure! My number is 54. Your turn!",
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "feedbackDisabled": false,
+ "id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "input": {
+ "inputs": {},
+ "query": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ "isAnswer": true,
+ "log": [
+ {
+ "files": [],
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ },
+ {
+ "files": [],
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ },
+ ],
+ "message_files": [],
+ "more": {
+ "latency": "1.52",
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 46,
+ },
+ "parentMessageId": "question-cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "siblingIndex": 1,
+ "workflow_run_id": null,
+ },
+ ],
+ "content": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "id": "question-cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "isAnswer": false,
+ "message_files": [],
+ },
+]
+`;
diff --git a/app/components/base/chat/__tests__/branchedTestMessages.json b/app/components/base/chat/__tests__/branchedTestMessages.json
new file mode 100644
index 0000000..30e0a82
--- /dev/null
+++ b/app/components/base/chat/__tests__/branchedTestMessages.json
@@ -0,0 +1,42 @@
+[
+ {
+ "id": "question-1",
+ "isAnswer": false,
+ "parentMessageId": null
+ },
+ {
+ "id": "1",
+ "isAnswer": true,
+ "parentMessageId": "question-1"
+ },
+ {
+ "id": "question-2",
+ "isAnswer": false,
+ "parentMessageId": "1"
+ },
+ {
+ "id": "2",
+ "isAnswer": true,
+ "parentMessageId": "question-2"
+ },
+ {
+ "id": "question-3",
+ "isAnswer": false,
+ "parentMessageId": "2"
+ },
+ {
+ "id": "3",
+ "isAnswer": true,
+ "parentMessageId": "question-3"
+ },
+ {
+ "id": "question-4",
+ "isAnswer": false,
+ "parentMessageId": "1"
+ },
+ {
+ "id": "4",
+ "isAnswer": true,
+ "parentMessageId": "question-4"
+ }
+]
diff --git a/app/components/base/chat/__tests__/legacyTestMessages.json b/app/components/base/chat/__tests__/legacyTestMessages.json
new file mode 100644
index 0000000..2dab589
--- /dev/null
+++ b/app/components/base/chat/__tests__/legacyTestMessages.json
@@ -0,0 +1,42 @@
+[
+ {
+ "id": "question-1",
+ "isAnswer": false,
+ "parentMessageId": "00000000-0000-0000-0000-000000000000"
+ },
+ {
+ "id": "1",
+ "isAnswer": true,
+ "parentMessageId": "question-1"
+ },
+ {
+ "id": "question-2",
+ "isAnswer": false,
+ "parentMessageId": "00000000-0000-0000-0000-000000000000"
+ },
+ {
+ "id": "2",
+ "isAnswer": true,
+ "parentMessageId": "question-2"
+ },
+ {
+ "id": "question-3",
+ "isAnswer": false,
+ "parentMessageId": "00000000-0000-0000-0000-000000000000"
+ },
+ {
+ "id": "3",
+ "isAnswer": true,
+ "parentMessageId": "question-3"
+ },
+ {
+ "id": "question-4",
+ "isAnswer": false,
+ "parentMessageId": "00000000-0000-0000-0000-000000000000"
+ },
+ {
+ "id": "4",
+ "isAnswer": true,
+ "parentMessageId": "question-4"
+ }
+]
diff --git a/app/components/base/chat/__tests__/mixedTestMessages.json b/app/components/base/chat/__tests__/mixedTestMessages.json
new file mode 100644
index 0000000..14789d9
--- /dev/null
+++ b/app/components/base/chat/__tests__/mixedTestMessages.json
@@ -0,0 +1,42 @@
+[
+ {
+ "id": "question-1",
+ "isAnswer": false,
+ "parentMessageId": "00000000-0000-0000-0000-000000000000"
+ },
+ {
+ "id": "1",
+ "isAnswer": true,
+ "parentMessageId": "question-1"
+ },
+ {
+ "id": "question-2",
+ "isAnswer": false,
+ "parentMessageId": "00000000-0000-0000-0000-000000000000"
+ },
+ {
+ "id": "2",
+ "isAnswer": true,
+ "parentMessageId": "question-2"
+ },
+ {
+ "id": "question-3",
+ "isAnswer": false,
+ "parentMessageId": "2"
+ },
+ {
+ "id": "3",
+ "isAnswer": true,
+ "parentMessageId": "question-3"
+ },
+ {
+ "id": "question-4",
+ "isAnswer": false,
+ "parentMessageId": "1"
+ },
+ {
+ "id": "4",
+ "isAnswer": true,
+ "parentMessageId": "question-4"
+ }
+]
diff --git a/app/components/base/chat/__tests__/multiRootNodesMessages.json b/app/components/base/chat/__tests__/multiRootNodesMessages.json
new file mode 100644
index 0000000..782ccb7
--- /dev/null
+++ b/app/components/base/chat/__tests__/multiRootNodesMessages.json
@@ -0,0 +1,52 @@
+[
+ {
+ "id": "question-1",
+ "isAnswer": false,
+ "parentMessageId": null
+ },
+ {
+ "id": "1",
+ "isAnswer": true,
+ "parentMessageId": "question-1"
+ },
+ {
+ "id": "question-2",
+ "isAnswer": false,
+ "parentMessageId": "1"
+ },
+ {
+ "id": "2",
+ "isAnswer": true,
+ "parentMessageId": "question-2"
+ },
+ {
+ "id": "question-3",
+ "isAnswer": false,
+ "parentMessageId": "2"
+ },
+ {
+ "id": "3",
+ "isAnswer": true,
+ "parentMessageId": "question-3"
+ },
+ {
+ "id": "question-4",
+ "isAnswer": false,
+ "parentMessageId": "1"
+ },
+ {
+ "id": "4",
+ "isAnswer": true,
+ "parentMessageId": "question-4"
+ },
+ {
+ "id": "question-5",
+ "isAnswer": false,
+ "parentMessageId": null
+ },
+ {
+ "id": "5",
+ "isAnswer": true,
+ "parentMessageId": "question-5"
+ }
+]
diff --git a/app/components/base/chat/__tests__/multiRootNodesWithLegacyTestMessages.json b/app/components/base/chat/__tests__/multiRootNodesWithLegacyTestMessages.json
new file mode 100644
index 0000000..5eadc72
--- /dev/null
+++ b/app/components/base/chat/__tests__/multiRootNodesWithLegacyTestMessages.json
@@ -0,0 +1,52 @@
+[
+ {
+ "id": "question-1",
+ "isAnswer": false,
+ "parentMessageId": "00000000-0000-0000-0000-000000000000"
+ },
+ {
+ "id": "1",
+ "isAnswer": true,
+ "parentMessageId": "question-1"
+ },
+ {
+ "id": "question-2",
+ "isAnswer": false,
+ "parentMessageId": "00000000-0000-0000-0000-000000000000"
+ },
+ {
+ "id": "2",
+ "isAnswer": true,
+ "parentMessageId": "question-2"
+ },
+ {
+ "id": "question-3",
+ "isAnswer": false,
+ "parentMessageId": "00000000-0000-0000-0000-000000000000"
+ },
+ {
+ "id": "3",
+ "isAnswer": true,
+ "parentMessageId": "question-3"
+ },
+ {
+ "id": "question-4",
+ "isAnswer": false,
+ "parentMessageId": "1"
+ },
+ {
+ "id": "4",
+ "isAnswer": true,
+ "parentMessageId": "question-4"
+ },
+ {
+ "id": "question-5",
+ "isAnswer": false,
+ "parentMessageId": null
+ },
+ {
+ "id": "5",
+ "isAnswer": true,
+ "parentMessageId": "question-5"
+ }
+]
diff --git a/app/components/base/chat/__tests__/partialMessages.json b/app/components/base/chat/__tests__/partialMessages.json
new file mode 100644
index 0000000..916c6ad
--- /dev/null
+++ b/app/components/base/chat/__tests__/partialMessages.json
@@ -0,0 +1,122 @@
+[
+ {
+ "id": "question-ebb73fe2-15de-46dd-aab5-75416d8448eb",
+ "content": "123",
+ "isAnswer": false,
+ "parentMessageId": "57c989f9-3fa4-4dec-9ee5-c3568dd27418"
+ },
+ {
+ "id": "ebb73fe2-15de-46dd-aab5-75416d8448eb",
+ "content": "237.",
+ "isAnswer": true,
+ "parentMessageId": "question-ebb73fe2-15de-46dd-aab5-75416d8448eb"
+ },
+ {
+ "id": "question-3553d508-3850-462e-8594-078539f940f9",
+ "content": "123",
+ "isAnswer": false,
+ "parentMessageId": "57c989f9-3fa4-4dec-9ee5-c3568dd27418"
+ },
+ {
+ "id": "3553d508-3850-462e-8594-078539f940f9",
+ "content": "My number is 256.",
+ "isAnswer": true,
+ "parentMessageId": "question-3553d508-3850-462e-8594-078539f940f9"
+ },
+ {
+ "id": "question-507f9df9-1f06-4a57-bb38-f00228c42c22",
+ "content": "123",
+ "isAnswer": false,
+ "parentMessageId": "57c989f9-3fa4-4dec-9ee5-c3568dd27418"
+ },
+ {
+ "id": "507f9df9-1f06-4a57-bb38-f00228c42c22",
+ "content": "My number is 259.",
+ "isAnswer": true,
+ "parentMessageId": "question-507f9df9-1f06-4a57-bb38-f00228c42c22"
+ },
+ {
+ "id": "question-9e51a13b-7780-4565-98dc-f2d8c3b1758f",
+ "content": "1024",
+ "isAnswer": false,
+ "parentMessageId": "507f9df9-1f06-4a57-bb38-f00228c42c22"
+ },
+ {
+ "id": "9e51a13b-7780-4565-98dc-f2d8c3b1758f",
+ "content": "My number is 2048.",
+ "isAnswer": true,
+ "parentMessageId": "question-9e51a13b-7780-4565-98dc-f2d8c3b1758f"
+ },
+ {
+ "id": "question-93bac05d-1470-4ac9-b090-fe21cd7c3d55",
+ "content": "3306",
+ "isAnswer": false,
+ "parentMessageId": "9e51a13b-7780-4565-98dc-f2d8c3b1758f"
+ },
+ {
+ "id": "93bac05d-1470-4ac9-b090-fe21cd7c3d55",
+ "content": "My number is 4782.",
+ "isAnswer": true,
+ "parentMessageId": "question-93bac05d-1470-4ac9-b090-fe21cd7c3d55"
+ },
+ {
+ "id": "question-a956de3d-ef95-4d90-84fe-f7a26ef28cd7",
+ "content": "-5",
+ "isAnswer": false,
+ "parentMessageId": "93bac05d-1470-4ac9-b090-fe21cd7c3d55"
+ },
+ {
+ "id": "a956de3d-ef95-4d90-84fe-f7a26ef28cd7",
+ "content": "My number is 22.",
+ "isAnswer": true,
+ "parentMessageId": "question-a956de3d-ef95-4d90-84fe-f7a26ef28cd7"
+ },
+ {
+ "id": "question-3cded945-855a-4a24-aab7-43c7dd54664c",
+ "content": "3.11",
+ "isAnswer": false,
+ "parentMessageId": "a956de3d-ef95-4d90-84fe-f7a26ef28cd7"
+ },
+ {
+ "id": "3cded945-855a-4a24-aab7-43c7dd54664c",
+ "content": "My number is 7.89.",
+ "isAnswer": true,
+ "parentMessageId": "question-3cded945-855a-4a24-aab7-43c7dd54664c"
+ },
+ {
+ "id": "question-46a49bb9-0881-459e-8c6a-24d20ae48d2f",
+ "content": "78",
+ "isAnswer": false,
+ "parentMessageId": "3cded945-855a-4a24-aab7-43c7dd54664c"
+ },
+ {
+ "id": "46a49bb9-0881-459e-8c6a-24d20ae48d2f",
+ "content": "My number is 145.",
+ "isAnswer": true,
+ "parentMessageId": "question-46a49bb9-0881-459e-8c6a-24d20ae48d2f"
+ },
+ {
+ "id": "question-5c56a2b3-f057-42a0-9b2c-52a35713cd8c",
+ "content": "蟺",
+ "isAnswer": false,
+ "parentMessageId": "46a49bb9-0881-459e-8c6a-24d20ae48d2f"
+ },
+ {
+ "id": "5c56a2b3-f057-42a0-9b2c-52a35713cd8c",
+ "content": "My number is 2蟺 (approximately 6.28).",
+ "isAnswer": true,
+ "parentMessageId": "question-5c56a2b3-f057-42a0-9b2c-52a35713cd8c"
+ },
+ {
+ "id": "question-9eac3bcc-8d3b-4e56-a12b-44c34cebc719",
+ "content": "e",
+ "isAnswer": false,
+ "parentMessageId": "5c56a2b3-f057-42a0-9b2c-52a35713cd8c"
+ },
+ {
+ "id": "9eac3bcc-8d3b-4e56-a12b-44c34cebc719",
+ "content": "My number is 3e (approximately 8.15).",
+ "isAnswer": true,
+ "parentMessageId": "question-9eac3bcc-8d3b-4e56-a12b-44c34cebc719"
+ }
+]
diff --git a/app/components/base/chat/__tests__/realWorldMessages.json b/app/components/base/chat/__tests__/realWorldMessages.json
new file mode 100644
index 0000000..858052c
--- /dev/null
+++ b/app/components/base/chat/__tests__/realWorldMessages.json
@@ -0,0 +1,441 @@
+[
+ {
+ "id": "question-ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "content": "Let's play a game, I say a number , and you response me with another bigger, yet random-looking number. I'll start first, 38",
+ "isAnswer": false,
+ "message_files": []
+ },
+ {
+ "id": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "content": "Sure, I'll play! My number is 57. Your turn!",
+ "agent_thoughts": [
+ {
+ "id": "f9d7ff7c-3a3b-4d9a-a289-657817f4caff",
+ "chain_id": null,
+ "message_id": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b",
+ "position": 1,
+ "thought": "Sure, I'll play! My number is 57. Your turn!",
+ "tool": "",
+ "tool_labels": {},
+ "tool_input": "",
+ "created_at": 1726105791,
+ "observation": "",
+ "files": []
+ }
+ ],
+ "feedbackDisabled": false,
+ "isAnswer": true,
+ "message_files": [],
+ "log": [
+ {
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ "files": []
+ }
+ ],
+ "workflow_run_id": null,
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "input": {
+ "inputs": {},
+ "query": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38"
+ },
+ "more": {
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 49,
+ "latency": "1.56"
+ },
+ "parentMessageId": "question-ff4c2b43-48a5-47ad-9dc5-08b34ddba61b"
+ },
+ {
+ "id": "question-73bbad14-d915-499d-87bf-0df14d40779d",
+ "content": "58",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "ff4c2b43-48a5-47ad-9dc5-08b34ddba61b"
+ },
+ {
+ "id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "content": "I choose 83. What's your next number?",
+ "agent_thoughts": [
+ {
+ "id": "f61a3fce-37ac-4f9d-9935-95f97e598dfe",
+ "chain_id": null,
+ "message_id": "73bbad14-d915-499d-87bf-0df14d40779d",
+ "position": 1,
+ "thought": "I choose 83. What's your next number?",
+ "tool": "",
+ "tool_labels": {},
+ "tool_input": "",
+ "created_at": 1726105795,
+ "observation": "",
+ "files": []
+ }
+ ],
+ "feedbackDisabled": false,
+ "isAnswer": true,
+ "message_files": [],
+ "log": [
+ {
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ "files": []
+ },
+ {
+ "role": "user",
+ "text": "58",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ "files": []
+ }
+ ],
+ "workflow_run_id": null,
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "input": {
+ "inputs": {},
+ "query": "58"
+ },
+ "more": {
+ "time": "09/11/2024 09:49 PM",
+ "tokens": 68,
+ "latency": "1.33"
+ },
+ "parentMessageId": "question-73bbad14-d915-499d-87bf-0df14d40779d"
+ },
+ {
+ "id": "question-4c5d0841-1206-463e-95d8-71f812877658",
+ "content": "99",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "73bbad14-d915-499d-87bf-0df14d40779d"
+ },
+ {
+ "id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "content": "I'll go with 112. Your turn!",
+ "agent_thoughts": [
+ {
+ "id": "9730d587-9268-4683-9dd9-91a1cab9510b",
+ "chain_id": null,
+ "message_id": "4c5d0841-1206-463e-95d8-71f812877658",
+ "position": 1,
+ "thought": "I'll go with 112. Your turn!",
+ "tool": "",
+ "tool_labels": {},
+ "tool_input": "",
+ "created_at": 1726105799,
+ "observation": "",
+ "files": []
+ }
+ ],
+ "feedbackDisabled": false,
+ "isAnswer": true,
+ "message_files": [],
+ "log": [
+ {
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "Sure, I'll play! My number is 57. Your turn!",
+ "files": []
+ },
+ {
+ "role": "user",
+ "text": "58",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "I choose 83. What's your next number?",
+ "files": []
+ },
+ {
+ "role": "user",
+ "text": "99",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "I'll go with 112. Your turn!",
+ "files": []
+ }
+ ],
+ "workflow_run_id": null,
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "input": {
+ "inputs": {},
+ "query": "99"
+ },
+ "more": {
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 86,
+ "latency": "1.49"
+ },
+ "parentMessageId": "question-4c5d0841-1206-463e-95d8-71f812877658"
+ },
+ {
+ "id": "question-cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "content": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "isAnswer": false,
+ "message_files": []
+ },
+ {
+ "id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "content": "Sure! My number is 54. Your turn!",
+ "agent_thoughts": [
+ {
+ "id": "1019cd79-d141-4f9f-880a-fc1441cfd802",
+ "chain_id": null,
+ "message_id": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd",
+ "position": 1,
+ "thought": "Sure! My number is 54. Your turn!",
+ "tool": "",
+ "tool_labels": {},
+ "tool_input": "",
+ "created_at": 1726105809,
+ "observation": "",
+ "files": []
+ }
+ ],
+ "feedbackDisabled": false,
+ "isAnswer": true,
+ "message_files": [],
+ "log": [
+ {
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ "files": []
+ }
+ ],
+ "workflow_run_id": null,
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "input": {
+ "inputs": {},
+ "query": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38"
+ },
+ "more": {
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 46,
+ "latency": "1.52"
+ },
+ "parentMessageId": "question-cd5affb0-7bc2-4a6f-be7e-25e74595c9dd"
+ },
+ {
+ "id": "question-324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "content": "3306",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd"
+ },
+ {
+ "id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "content": "My number is 4729. Your turn!",
+ "agent_thoughts": [
+ {
+ "id": "0773bec7-b992-4a53-92b2-20ebaeae8798",
+ "chain_id": null,
+ "message_id": "324bce32-c98c-435d-a66b-bac974ebb5ed",
+ "position": 1,
+ "thought": "My number is 4729. Your turn!",
+ "tool": "",
+ "tool_labels": {},
+ "tool_input": "",
+ "created_at": 1726105822,
+ "observation": "",
+ "files": []
+ }
+ ],
+ "feedbackDisabled": false,
+ "isAnswer": true,
+ "message_files": [],
+ "log": [
+ {
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ "files": []
+ },
+ {
+ "role": "user",
+ "text": "3306",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "My number is 4729. Your turn!",
+ "files": []
+ }
+ ],
+ "workflow_run_id": null,
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "input": {
+ "inputs": {},
+ "query": "3306"
+ },
+ "more": {
+ "time": "09/11/2024 09:50 PM",
+ "tokens": 66,
+ "latency": "1.30"
+ },
+ "parentMessageId": "question-324bce32-c98c-435d-a66b-bac974ebb5ed"
+ },
+ {
+ "id": "question-684b5396-4e91-4043-88e9-aabe48b21acc",
+ "content": "3306",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "cd5affb0-7bc2-4a6f-be7e-25e74595c9dd"
+ },
+ {
+ "id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "content": "My number is 4821. Your turn!",
+ "agent_thoughts": [
+ {
+ "id": "5ca650f3-982c-4399-8b95-9ea241c76707",
+ "chain_id": null,
+ "message_id": "684b5396-4e91-4043-88e9-aabe48b21acc",
+ "position": 1,
+ "thought": "My number is 4821. Your turn!",
+ "tool": "",
+ "tool_labels": {},
+ "tool_input": "",
+ "created_at": 1726107812,
+ "observation": "",
+ "files": []
+ }
+ ],
+ "feedbackDisabled": false,
+ "isAnswer": true,
+ "message_files": [],
+ "log": [
+ {
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ "files": []
+ },
+ {
+ "role": "user",
+ "text": "3306",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ "files": []
+ }
+ ],
+ "workflow_run_id": null,
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "input": {
+ "inputs": {},
+ "query": "3306"
+ },
+ "more": {
+ "time": "09/11/2024 10:23 PM",
+ "tokens": 66,
+ "latency": "1.48"
+ },
+ "parentMessageId": "question-684b5396-4e91-4043-88e9-aabe48b21acc"
+ },
+ {
+ "id": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "content": "1003",
+ "isAnswer": false,
+ "message_files": [],
+ "parentMessageId": "684b5396-4e91-4043-88e9-aabe48b21acc"
+ },
+ {
+ "id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "content": "My number is 1456. Your turn!",
+ "agent_thoughts": [
+ {
+ "id": "095cacab-afad-4387-a41d-1662578b8b13",
+ "chain_id": null,
+ "message_id": "19904a7b-7494-4ed8-b72c-1d18668cea8c",
+ "position": 1,
+ "thought": "My number is 1456. Your turn!",
+ "tool": "",
+ "tool_labels": {},
+ "tool_input": "",
+ "created_at": 1726111024,
+ "observation": "",
+ "files": []
+ }
+ ],
+ "feedbackDisabled": false,
+ "isAnswer": true,
+ "message_files": [],
+ "log": [
+ {
+ "role": "user",
+ "text": "Let's play a game, I say a number , and you response me with another bigger, yet randomly number. I'll start first, 38",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "Sure! My number is 54. Your turn!",
+ "files": []
+ },
+ {
+ "role": "user",
+ "text": "3306",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "My number is 4821. Your turn!",
+ "files": []
+ },
+ {
+ "role": "user",
+ "text": "1003",
+ "files": []
+ },
+ {
+ "role": "assistant",
+ "text": "My number is 1456. Your turn!",
+ "files": []
+ }
+ ],
+ "workflow_run_id": null,
+ "conversationId": "dd6c9cfd-2656-48ec-bd51-2139c1790d80",
+ "input": {
+ "inputs": {},
+ "query": "1003"
+ },
+ "more": {
+ "time": "09/11/2024 11:17 PM",
+ "tokens": 86,
+ "latency": "1.38"
+ },
+ "parentMessageId": "question-19904a7b-7494-4ed8-b72c-1d18668cea8c"
+ }
+]
diff --git a/app/components/base/chat/__tests__/utils.spec.ts b/app/components/base/chat/__tests__/utils.spec.ts
new file mode 100644
index 0000000..3dc484c
--- /dev/null
+++ b/app/components/base/chat/__tests__/utils.spec.ts
@@ -0,0 +1,271 @@
+import { get } from 'lodash-es'
+import { buildChatItemTree, getThreadMessages } from '../utils'
+import type { ChatItemInTree } from '../types'
+import branchedTestMessages from './branchedTestMessages.json'
+import legacyTestMessages from './legacyTestMessages.json'
+import mixedTestMessages from './mixedTestMessages.json'
+import multiRootNodesMessages from './multiRootNodesMessages.json'
+import multiRootNodesWithLegacyTestMessages from './multiRootNodesWithLegacyTestMessages.json'
+import realWorldMessages from './realWorldMessages.json'
+import partialMessages from './partialMessages.json'
+
+function visitNode(tree: ChatItemInTree | ChatItemInTree[], path: string): ChatItemInTree {
+ return get(tree, path)
+}
+
+describe('build chat item tree and get thread messages', () => {
+ const tree1 = buildChatItemTree(branchedTestMessages as ChatItemInTree[])
+
+ it('should build chat item tree1', () => {
+ const a1 = visitNode(tree1, '0.children.0')
+ expect(a1.id).toBe('1')
+ expect(a1.children).toHaveLength(2)
+
+ const a2 = visitNode(a1, 'children.0.children.0')
+ expect(a2.id).toBe('2')
+ expect(a2.siblingIndex).toBe(0)
+
+ const a3 = visitNode(a2, 'children.0.children.0')
+ expect(a3.id).toBe('3')
+
+ const a4 = visitNode(a1, 'children.1.children.0')
+ expect(a4.id).toBe('4')
+ expect(a4.siblingIndex).toBe(1)
+ })
+
+ it('should get thread messages from tree1, using the last message as the target', () => {
+ const threadChatItems1_1 = getThreadMessages(tree1)
+ expect(threadChatItems1_1).toHaveLength(4)
+
+ const q1 = visitNode(threadChatItems1_1, '0')
+ const a1 = visitNode(threadChatItems1_1, '1')
+ const q4 = visitNode(threadChatItems1_1, '2')
+ const a4 = visitNode(threadChatItems1_1, '3')
+
+ expect(q1.id).toBe('question-1')
+ expect(a1.id).toBe('1')
+ expect(q4.id).toBe('question-4')
+ expect(a4.id).toBe('4')
+
+ expect(a4.siblingCount).toBe(2)
+ expect(a4.siblingIndex).toBe(1)
+ })
+
+ it('should get thread messages from tree1, using the message with id 3 as the target', () => {
+ const threadChatItems1_2 = getThreadMessages(tree1, '3')
+ expect(threadChatItems1_2).toHaveLength(6)
+
+ const q1 = visitNode(threadChatItems1_2, '0')
+ const a1 = visitNode(threadChatItems1_2, '1')
+ const q2 = visitNode(threadChatItems1_2, '2')
+ const a2 = visitNode(threadChatItems1_2, '3')
+ const q3 = visitNode(threadChatItems1_2, '4')
+ const a3 = visitNode(threadChatItems1_2, '5')
+
+ expect(q1.id).toBe('question-1')
+ expect(a1.id).toBe('1')
+ expect(q2.id).toBe('question-2')
+ expect(a2.id).toBe('2')
+ expect(q3.id).toBe('question-3')
+ expect(a3.id).toBe('3')
+
+ expect(a2.siblingCount).toBe(2)
+ expect(a2.siblingIndex).toBe(0)
+ })
+
+ const tree2 = buildChatItemTree(legacyTestMessages as ChatItemInTree[])
+ it('should work with legacy chat items', () => {
+ expect(tree2).toHaveLength(1)
+ const q1 = visitNode(tree2, '0')
+ const a1 = visitNode(q1, 'children.0')
+ const q2 = visitNode(a1, 'children.0')
+ const a2 = visitNode(q2, 'children.0')
+ const q3 = visitNode(a2, 'children.0')
+ const a3 = visitNode(q3, 'children.0')
+ const q4 = visitNode(a3, 'children.0')
+ const a4 = visitNode(q4, 'children.0')
+
+ expect(q1.id).toBe('question-1')
+ expect(a1.id).toBe('1')
+ expect(q2.id).toBe('question-2')
+ expect(a2.id).toBe('2')
+ expect(q3.id).toBe('question-3')
+ expect(a3.id).toBe('3')
+ expect(q4.id).toBe('question-4')
+ expect(a4.id).toBe('4')
+ })
+
+ it('should get thread messages from tree2, using the last message as the target', () => {
+ const threadMessages2 = getThreadMessages(tree2)
+ expect(threadMessages2).toHaveLength(8)
+
+ const q1 = visitNode(threadMessages2, '0')
+ const a1 = visitNode(threadMessages2, '1')
+ const q2 = visitNode(threadMessages2, '2')
+ const a2 = visitNode(threadMessages2, '3')
+ const q3 = visitNode(threadMessages2, '4')
+ const a3 = visitNode(threadMessages2, '5')
+ const q4 = visitNode(threadMessages2, '6')
+ const a4 = visitNode(threadMessages2, '7')
+
+ expect(q1.id).toBe('question-1')
+ expect(a1.id).toBe('1')
+ expect(q2.id).toBe('question-2')
+ expect(a2.id).toBe('2')
+ expect(q3.id).toBe('question-3')
+ expect(a3.id).toBe('3')
+ expect(q4.id).toBe('question-4')
+ expect(a4.id).toBe('4')
+
+ expect(a1.siblingCount).toBe(1)
+ expect(a1.siblingIndex).toBe(0)
+ expect(a2.siblingCount).toBe(1)
+ expect(a2.siblingIndex).toBe(0)
+ expect(a3.siblingCount).toBe(1)
+ expect(a3.siblingIndex).toBe(0)
+ expect(a4.siblingCount).toBe(1)
+ expect(a4.siblingIndex).toBe(0)
+ })
+
+ const tree3 = buildChatItemTree(mixedTestMessages as ChatItemInTree[])
+ it('should build mixed chat items tree', () => {
+ expect(tree3).toHaveLength(1)
+
+ const a1 = visitNode(tree3, '0.children.0')
+ expect(a1.id).toBe('1')
+ expect(a1.children).toHaveLength(2)
+
+ const a2 = visitNode(a1, 'children.0.children.0')
+ expect(a2.id).toBe('2')
+ expect(a2.siblingIndex).toBe(0)
+
+ const a3 = visitNode(a2, 'children.0.children.0')
+ expect(a3.id).toBe('3')
+
+ const a4 = visitNode(a1, 'children.1.children.0')
+ expect(a4.id).toBe('4')
+ expect(a4.siblingIndex).toBe(1)
+ })
+
+ it('should get thread messages from tree3, using the last message as the target', () => {
+ const threadMessages3_1 = getThreadMessages(tree3)
+ expect(threadMessages3_1).toHaveLength(4)
+
+ const q1 = visitNode(threadMessages3_1, '0')
+ const a1 = visitNode(threadMessages3_1, '1')
+ const q4 = visitNode(threadMessages3_1, '2')
+ const a4 = visitNode(threadMessages3_1, '3')
+
+ expect(q1.id).toBe('question-1')
+ expect(a1.id).toBe('1')
+ expect(q4.id).toBe('question-4')
+ expect(a4.id).toBe('4')
+
+ expect(a4.siblingCount).toBe(2)
+ expect(a4.siblingIndex).toBe(1)
+ })
+
+ it('should get thread messages from tree3, using the message with id 3 as the target', () => {
+ const threadMessages3_2 = getThreadMessages(tree3, '3')
+ expect(threadMessages3_2).toHaveLength(6)
+
+ const q1 = visitNode(threadMessages3_2, '0')
+ const a1 = visitNode(threadMessages3_2, '1')
+ const q2 = visitNode(threadMessages3_2, '2')
+ const a2 = visitNode(threadMessages3_2, '3')
+ const q3 = visitNode(threadMessages3_2, '4')
+ const a3 = visitNode(threadMessages3_2, '5')
+
+ expect(q1.id).toBe('question-1')
+ expect(a1.id).toBe('1')
+ expect(q2.id).toBe('question-2')
+ expect(a2.id).toBe('2')
+ expect(q3.id).toBe('question-3')
+ expect(a3.id).toBe('3')
+
+ expect(a2.siblingCount).toBe(2)
+ expect(a2.siblingIndex).toBe(0)
+ })
+
+ const tree4 = buildChatItemTree(multiRootNodesMessages as ChatItemInTree[])
+ it('should build multi root nodes chat items tree', () => {
+ expect(tree4).toHaveLength(2)
+
+ const a5 = visitNode(tree4, '1.children.0')
+ expect(a5.id).toBe('5')
+ expect(a5.siblingIndex).toBe(1)
+ })
+
+ it('should get thread messages from tree4, using the last message as the target', () => {
+ const threadMessages4 = getThreadMessages(tree4)
+ expect(threadMessages4).toHaveLength(2)
+
+ const a1 = visitNode(threadMessages4, '0.children.0')
+ expect(a1.id).toBe('5')
+ })
+
+ it('should get thread messages from tree4, using the message with id 2 as the target', () => {
+ const threadMessages4_1 = getThreadMessages(tree4, '2')
+ expect(threadMessages4_1).toHaveLength(6)
+ const a1 = visitNode(threadMessages4_1, '1')
+ expect(a1.id).toBe('1')
+ const a2 = visitNode(threadMessages4_1, '3')
+ expect(a2.id).toBe('2')
+ const a3 = visitNode(threadMessages4_1, '5')
+ expect(a3.id).toBe('3')
+ })
+
+ const tree5 = buildChatItemTree(multiRootNodesWithLegacyTestMessages as ChatItemInTree[])
+ it('should work with multi root nodes chat items with legacy chat items', () => {
+ expect(tree5).toHaveLength(2)
+
+ const q5 = visitNode(tree5, '1')
+ expect(q5.id).toBe('question-5')
+ expect(q5.parentMessageId).toBe(null)
+
+ const a5 = visitNode(q5, 'children.0')
+ expect(a5.id).toBe('5')
+ expect(a5.children).toHaveLength(0)
+ })
+
+ it('should get thread messages from tree5, using the last message as the target', () => {
+ const threadMessages5 = getThreadMessages(tree5)
+ expect(threadMessages5).toHaveLength(2)
+
+ const q5 = visitNode(threadMessages5, '0')
+ const a5 = visitNode(threadMessages5, '1')
+
+ expect(q5.id).toBe('question-5')
+ expect(a5.id).toBe('5')
+
+ expect(a5.siblingCount).toBe(2)
+ expect(a5.siblingIndex).toBe(1)
+ })
+
+ const tree6 = buildChatItemTree(realWorldMessages as ChatItemInTree[])
+ it('should work with real world messages', () => {
+ expect(tree6).toMatchSnapshot()
+ })
+
+ it ('should get thread messages from tree6, using the last message as target', () => {
+ const threadMessages6_1 = getThreadMessages(tree6)
+ expect(threadMessages6_1).toMatchSnapshot()
+ })
+
+ it ('should get thread messages from tree6, using specified message as target', () => {
+ const threadMessages6_2 = getThreadMessages(tree6, 'ff4c2b43-48a5-47ad-9dc5-08b34ddba61b')
+ expect(threadMessages6_2).toMatchSnapshot()
+ })
+
+ const partialMessages1 = (realWorldMessages as ChatItemInTree[]).slice(-10)
+ const tree7 = buildChatItemTree(partialMessages1)
+ it('should work with partial messages 1', () => {
+ expect(tree7).toMatchSnapshot()
+ })
+
+ const partialMessages2 = partialMessages as ChatItemInTree[]
+ const tree8 = buildChatItemTree(partialMessages2)
+ it('should work with partial messages 2', () => {
+ expect(tree8).toMatchSnapshot()
+ })
+})
diff --git a/app/components/base/chat/chat-with-history/chat-wrapper.tsx b/app/components/base/chat/chat-with-history/chat-wrapper.tsx
new file mode 100644
index 0000000..63de135
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/chat-wrapper.tsx
@@ -0,0 +1,270 @@
+import { useCallback, useEffect, useMemo, useState } from 'react'
+import Chat from '../chat'
+import type {
+ ChatConfig,
+ ChatItem,
+ ChatItemInTree,
+ OnSend,
+} from '../types'
+import { useChat } from '../chat/hooks'
+import { getLastAnswer, isValidGeneratedAnswer } from '../utils'
+import { useChatWithHistoryContext } from './context'
+import { InputVarType } from '@/app/components/workflow/types'
+import { TransferMethod } from '@/types/app'
+import InputsForm from '@/app/components/base/chat/chat-with-history/inputs-form'
+import {
+ fetchSuggestedQuestions,
+ getUrl,
+ stopChatMessageResponding,
+} from '@/service/share'
+import AppIcon from '@/app/components/base/app-icon'
+import AnswerIcon from '@/app/components/base/answer-icon'
+import SuggestedQuestions from '@/app/components/base/chat/chat/answer/suggested-questions'
+import { Markdown } from '@/app/components/base/markdown'
+import cn from '@/utils/classnames'
+import type { FileEntity } from '../../file-uploader/types'
+
+const ChatWrapper = () => {
+ const {
+ appParams,
+ appPrevChatTree,
+ currentConversationId,
+ currentConversationItem,
+ currentConversationInputs,
+ inputsForms,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationCompleted,
+ isMobile,
+ isInstalledApp,
+ appId,
+ appMeta,
+ handleFeedback,
+ currentChatInstanceRef,
+ appData,
+ themeBuilder,
+ sidebarCollapseState,
+ clearChatList,
+ setClearChatList,
+ setIsResponding,
+ } = useChatWithHistoryContext()
+ const appConfig = useMemo(() => {
+ const config = appParams || {}
+
+ return {
+ ...config,
+ file_upload: {
+ ...(config as any).file_upload,
+ fileUploadConfig: (config as any).system_parameters,
+ },
+ supportFeedback: true,
+ opening_statement: currentConversationId ? currentConversationItem?.introduction : (config as any).opening_statement,
+ } as ChatConfig
+ }, [appParams, currentConversationItem?.introduction, currentConversationId])
+ const {
+ chatList,
+ setTargetMessageId,
+ handleSend,
+ handleStop,
+ isResponding: respondingState,
+ suggestedQuestions,
+ } = useChat(
+ appConfig,
+ {
+ inputs: (currentConversationId ? currentConversationInputs : newConversationInputs) as any,
+ inputsForm: inputsForms,
+ },
+ appPrevChatTree,
+ taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId),
+ clearChatList,
+ setClearChatList,
+ )
+ const inputsFormValue = currentConversationId ? currentConversationInputs : newConversationInputsRef?.current
+ const inputDisabled = useMemo(() => {
+ let hasEmptyInput = ''
+ let fileIsUploading = false
+ const requiredVars = inputsForms.filter(({ required }) => required)
+ if (requiredVars.length) {
+ requiredVars.forEach(({ variable, label, type }) => {
+ if (hasEmptyInput)
+ return
+
+ if (fileIsUploading)
+ return
+
+ if (!inputsFormValue?.[variable])
+ hasEmptyInput = label as string
+
+ if ((type === InputVarType.singleFile || type === InputVarType.multiFiles) && inputsFormValue?.[variable]) {
+ const files = inputsFormValue[variable]
+ if (Array.isArray(files))
+ fileIsUploading = files.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId)
+ else
+ fileIsUploading = files.transferMethod === TransferMethod.local_file && !files.uploadedId
+ }
+ })
+ }
+ if (hasEmptyInput)
+ return true
+
+ if (fileIsUploading)
+ return true
+ return false
+ }, [inputsFormValue, inputsForms])
+
+ useEffect(() => {
+ if (currentChatInstanceRef.current)
+ currentChatInstanceRef.current.handleStop = handleStop
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+
+ useEffect(() => {
+ setIsResponding(respondingState)
+ }, [respondingState, setIsResponding])
+
+ const doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => {
+ const data: any = {
+ query: message,
+ files,
+ inputs: currentConversationId ? currentConversationInputs : newConversationInputs,
+ conversation_id: currentConversationId,
+ parent_message_id: (isRegenerate ? parentAnswer?.id : getLastAnswer(chatList)?.id) || null,
+ }
+
+ handleSend(
+ getUrl('chat-messages', isInstalledApp, appId || ''),
+ data,
+ {
+ onGetSuggestedQuestions: responseItemId => fetchSuggestedQuestions(responseItemId, isInstalledApp, appId),
+ onConversationComplete: currentConversationId ? undefined : handleNewConversationCompleted,
+ isPublicAPI: !isInstalledApp,
+ },
+ )
+ }, [chatList, handleNewConversationCompleted, handleSend, currentConversationId, currentConversationInputs, newConversationInputs, isInstalledApp, appId])
+
+ const doRegenerate = useCallback((chatItem: ChatItemInTree, editedQuestion?: { message: string, files?: FileEntity[] }) => {
+ const question = editedQuestion ? chatItem : chatList.find(item => item.id === chatItem.parentMessageId)!
+ const parentAnswer = chatList.find(item => item.id === question.parentMessageId)
+ doSend(editedQuestion ? editedQuestion.message : question.content,
+ editedQuestion ? editedQuestion.files : question.message_files,
+ true,
+ isValidGeneratedAnswer(parentAnswer) ? parentAnswer : null,
+ )
+ }, [chatList, doSend])
+
+ const messageList = useMemo(() => {
+ if (currentConversationId)
+ return chatList
+ return chatList.filter(item => !item.isOpeningStatement)
+ }, [chatList, currentConversationId])
+
+ const [collapsed, setCollapsed] = useState(!!currentConversationId)
+
+ const chatNode = useMemo(() => {
+ if (!inputsForms.length)
+ return null
+ if (isMobile) {
+ if (!currentConversationId)
+ return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} />
+ return null
+ }
+ else {
+ return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} />
+ }
+ }, [inputsForms.length, isMobile, currentConversationId, collapsed])
+
+ const welcome = useMemo(() => {
+ const welcomeMessage = chatList.find(item => item.isOpeningStatement)
+ if (respondingState)
+ return null
+ if (currentConversationId)
+ return null
+ if (!welcomeMessage)
+ return null
+ if (!collapsed && inputsForms.length > 0)
+ return null
+ if (welcomeMessage.suggestedQuestions && welcomeMessage.suggestedQuestions?.length > 0) {
+ return (
+ <div className='flex min-h-[50vh] items-center justify-center px-4 py-12'>
+ <div className='flex max-w-[720px] grow gap-4'>
+ <AppIcon
+ size='xl'
+ iconType={appData?.site.icon_type}
+ icon={appData?.site.icon}
+ background={appData?.site.icon_background}
+ imageUrl={appData?.site.icon_url}
+ />
+ <div className='w-0 grow'>
+ <div className='body-lg-regular grow rounded-2xl bg-chat-bubble-bg px-4 py-3 text-text-primary'>
+ <Markdown content={welcomeMessage.content} />
+ <SuggestedQuestions item={welcomeMessage} />
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+ }
+ return (
+ <div className={cn('flex h-[50vh] flex-col items-center justify-center gap-3 py-12')}>
+ <AppIcon
+ size='xl'
+ iconType={appData?.site.icon_type}
+ icon={appData?.site.icon}
+ background={appData?.site.icon_background}
+ imageUrl={appData?.site.icon_url}
+ />
+ <div className='max-w-[768px] px-4'>
+ <Markdown className='!body-2xl-regular !text-text-tertiary' content={welcomeMessage.content} />
+ </div>
+ </div>
+ )
+ }, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length, respondingState])
+
+ const answerIcon = (appData?.site && appData.site.use_icon_as_answer_icon)
+ ? <AnswerIcon
+ iconType={appData.site.icon_type}
+ icon={appData.site.icon}
+ background={appData.site.icon_background}
+ imageUrl={appData.site.icon_url}
+ />
+ : null
+
+ return (
+ <div
+ className='h-full overflow-hidden bg-chatbot-bg'
+ >
+ <Chat
+ appData={appData}
+ config={appConfig}
+ chatList={messageList}
+ isResponding={respondingState}
+ chatContainerInnerClassName={`mx-auto pt-6 w-full max-w-[768px] ${isMobile && 'px-4'}`}
+ chatFooterClassName='pb-4'
+ chatFooterInnerClassName={`mx-auto w-full max-w-[768px] ${isMobile ? 'px-2' : 'px-4'}`}
+ onSend={doSend}
+ inputs={currentConversationId ? currentConversationInputs as any : newConversationInputs}
+ inputsForm={inputsForms}
+ onRegenerate={doRegenerate}
+ onStopResponding={handleStop}
+ chatNode={
+ <>
+ {chatNode}
+ {welcome}
+ </>
+ }
+ allToolIcons={appMeta?.tool_icons || {}}
+ onFeedback={handleFeedback}
+ suggestedQuestions={suggestedQuestions}
+ answerIcon={answerIcon}
+ hideProcessDetail
+ themeBuilder={themeBuilder}
+ switchSibling={siblingMessageId => setTargetMessageId(siblingMessageId)}
+ inputDisabled={inputDisabled}
+ isMobile={isMobile}
+ sidebarCollapseState={sidebarCollapseState}
+ />
+ </div>
+ )
+}
+
+export default ChatWrapper
diff --git a/app/components/base/chat/chat-with-history/context.tsx b/app/components/base/chat/chat-with-history/context.tsx
new file mode 100644
index 0000000..7dd7a78
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/context.tsx
@@ -0,0 +1,94 @@
+'use client'
+
+import type { RefObject } from 'react'
+import { createContext, useContext } from 'use-context-selector'
+import type {
+ Callback,
+ ChatConfig,
+ ChatItemInTree,
+ Feedback,
+} from '../types'
+import type { ThemeBuilder } from '../embedded-chatbot/theme/theme-context'
+import type {
+ AppConversationData,
+ AppData,
+ AppMeta,
+ ConversationItem,
+} from '@/models/share'
+import { noop } from 'lodash-es'
+
+export type ChatWithHistoryContextValue = {
+ appInfoError?: any
+ appInfoLoading?: boolean
+ appMeta?: AppMeta
+ appData?: AppData
+ appParams?: ChatConfig
+ appChatListDataLoading?: boolean
+ currentConversationId: string
+ currentConversationItem?: ConversationItem
+ appPrevChatTree: ChatItemInTree[]
+ pinnedConversationList: AppConversationData['data']
+ conversationList: AppConversationData['data']
+ newConversationInputs: Record<string, any>
+ newConversationInputsRef: RefObject<Record<string, any>>
+ handleNewConversationInputsChange: (v: Record<string, any>) => void
+ inputsForms: any[]
+ handleNewConversation: () => void
+ handleStartChat: (callback?: any) => void
+ handleChangeConversation: (conversationId: string) => void
+ handlePinConversation: (conversationId: string) => void
+ handleUnpinConversation: (conversationId: string) => void
+ handleDeleteConversation: (conversationId: string, callback: Callback) => void
+ conversationRenaming: boolean
+ handleRenameConversation: (conversationId: string, newName: string, callback: Callback) => void
+ handleNewConversationCompleted: (newConversationId: string) => void
+ chatShouldReloadKey: string
+ isMobile: boolean
+ isInstalledApp: boolean
+ appId?: string
+ handleFeedback: (messageId: string, feedback: Feedback) => void
+ currentChatInstanceRef: RefObject<{ handleStop: () => void }>
+ themeBuilder?: ThemeBuilder
+ sidebarCollapseState?: boolean
+ handleSidebarCollapse: (state: boolean) => void
+ clearChatList?: boolean
+ setClearChatList: (state: boolean) => void
+ isResponding?: boolean
+ setIsResponding: (state: boolean) => void,
+ currentConversationInputs: Record<string, any> | null,
+ setCurrentConversationInputs: (v: Record<string, any>) => void,
+}
+
+export const ChatWithHistoryContext = createContext<ChatWithHistoryContextValue>({
+ currentConversationId: '',
+ appPrevChatTree: [],
+ pinnedConversationList: [],
+ conversationList: [],
+ newConversationInputs: {},
+ newConversationInputsRef: { current: {} },
+ handleNewConversationInputsChange: noop,
+ inputsForms: [],
+ handleNewConversation: noop,
+ handleStartChat: noop,
+ handleChangeConversation: noop,
+ handlePinConversation: noop,
+ handleUnpinConversation: noop,
+ handleDeleteConversation: noop,
+ conversationRenaming: false,
+ handleRenameConversation: noop,
+ handleNewConversationCompleted: noop,
+ chatShouldReloadKey: '',
+ isMobile: false,
+ isInstalledApp: false,
+ handleFeedback: noop,
+ currentChatInstanceRef: { current: { handleStop: noop } },
+ sidebarCollapseState: false,
+ handleSidebarCollapse: noop,
+ clearChatList: false,
+ setClearChatList: noop,
+ isResponding: false,
+ setIsResponding: noop,
+ currentConversationInputs: {},
+ setCurrentConversationInputs: noop,
+})
+export const useChatWithHistoryContext = () => useContext(ChatWithHistoryContext)
diff --git a/app/components/base/chat/chat-with-history/header-in-mobile.tsx b/app/components/base/chat/chat-with-history/header-in-mobile.tsx
new file mode 100644
index 0000000..ec8da7b
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/header-in-mobile.tsx
@@ -0,0 +1,152 @@
+import { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiMenuLine,
+} from '@remixicon/react'
+import { useChatWithHistoryContext } from './context'
+import Operation from './header/operation'
+import Sidebar from './sidebar'
+import MobileOperationDropdown from './header/mobile-operation-dropdown'
+import AppIcon from '@/app/components/base/app-icon'
+import ActionButton from '@/app/components/base/action-button'
+import { Message3Fill } from '@/app/components/base/icons/src/public/other'
+import InputsFormContent from '@/app/components/base/chat/chat-with-history/inputs-form/content'
+import Confirm from '@/app/components/base/confirm'
+import RenameModal from '@/app/components/base/chat/chat-with-history/sidebar/rename-modal'
+import type { ConversationItem } from '@/models/share'
+
+const HeaderInMobile = () => {
+ const {
+ appData,
+ currentConversationId,
+ currentConversationItem,
+ pinnedConversationList,
+ handleNewConversation,
+ handlePinConversation,
+ handleUnpinConversation,
+ handleDeleteConversation,
+ handleRenameConversation,
+ conversationRenaming,
+ inputsForms,
+ } = useChatWithHistoryContext()
+ const { t } = useTranslation()
+ const isPin = pinnedConversationList.some(item => item.id === currentConversationId)
+ const [showConfirm, setShowConfirm] = useState<ConversationItem | null>(null)
+ const [showRename, setShowRename] = useState<ConversationItem | null>(null)
+ const handleOperate = useCallback((type: string) => {
+ if (type === 'pin')
+ handlePinConversation(currentConversationId)
+
+ if (type === 'unpin')
+ handleUnpinConversation(currentConversationId)
+
+ if (type === 'delete')
+ setShowConfirm(currentConversationItem as any)
+
+ if (type === 'rename')
+ setShowRename(currentConversationItem as any)
+ }, [currentConversationId, currentConversationItem, handlePinConversation, handleUnpinConversation])
+ const handleCancelConfirm = useCallback(() => {
+ setShowConfirm(null)
+ }, [])
+ const handleDelete = useCallback(() => {
+ if (showConfirm)
+ handleDeleteConversation(showConfirm.id, { onSuccess: handleCancelConfirm })
+ }, [showConfirm, handleDeleteConversation, handleCancelConfirm])
+ const handleCancelRename = useCallback(() => {
+ setShowRename(null)
+ }, [])
+ const handleRename = useCallback((newName: string) => {
+ if (showRename)
+ handleRenameConversation(showRename.id, newName, { onSuccess: handleCancelRename })
+ }, [showRename, handleRenameConversation, handleCancelRename])
+ const [showSidebar, setShowSidebar] = useState(false)
+ const [showChatSettings, setShowChatSettings] = useState(false)
+
+ return (
+ <>
+ <div className='flex shrink-0 items-center gap-1 bg-mask-top2bottom-gray-50-to-transparent px-2 py-3'>
+ <ActionButton size='l' className='shrink-0' onClick={() => setShowSidebar(true)}>
+ <RiMenuLine className='h-[18px] w-[18px]' />
+ </ActionButton>
+ <div className='flex grow items-center justify-center'>
+ {!currentConversationId && (
+ <>
+ <AppIcon
+ className='mr-2'
+ size='tiny'
+ icon={appData?.site.icon}
+ iconType={appData?.site.icon_type}
+ imageUrl={appData?.site.icon_url}
+ background={appData?.site.icon_background}
+ />
+ <div className='system-md-semibold truncate text-text-secondary'>
+ {appData?.site.title}
+ </div>
+ </>
+ )}
+ {currentConversationId && (
+ <Operation
+ title={currentConversationItem?.name || ''}
+ isPinned={!!isPin}
+ togglePin={() => handleOperate(isPin ? 'unpin' : 'pin')}
+ isShowDelete
+ isShowRenameConversation
+ onRenameConversation={() => handleOperate('rename')}
+ onDelete={() => handleOperate('delete')}
+ />
+ )}
+ </div>
+ <MobileOperationDropdown
+ handleResetChat={handleNewConversation}
+ handleViewChatSettings={() => setShowChatSettings(true)}
+ hideViewChatSettings={inputsForms.length < 1}
+ />
+ </div>
+ {showSidebar && (
+ <div className='fixed inset-0 z-50 flex bg-background-overlay p-1'
+ onClick={() => setShowSidebar(false)}
+ >
+ <div className='flex h-full w-[calc(100vw_-_40px)] rounded-xl bg-components-panel-bg shadow-lg backdrop-blur-sm' onClick={e => e.stopPropagation()}>
+ <Sidebar />
+ </div>
+ </div>
+ )}
+ {showChatSettings && (
+ <div className='fixed inset-0 z-50 flex justify-end bg-background-overlay p-1'
+ onClick={() => setShowChatSettings(false)}
+ >
+ <div className='flex h-full w-[calc(100vw_-_40px)] flex-col rounded-xl bg-components-panel-bg shadow-lg backdrop-blur-sm' onClick={e => e.stopPropagation()}>
+ <div className='flex items-center gap-3 rounded-t-2xl border-b border-divider-subtle px-4 py-3'>
+ <Message3Fill className='h-6 w-6 shrink-0' />
+ <div className='system-xl-semibold grow text-text-secondary'>{t('share.chat.chatSettingsTitle')}</div>
+ </div>
+ <div className='p-4'>
+ <InputsFormContent />
+ </div>
+ </div>
+ </div>
+ )}
+ {!!showConfirm && (
+ <Confirm
+ title={t('share.chat.deleteConversation.title')}
+ content={t('share.chat.deleteConversation.content') || ''}
+ isShow
+ onCancel={handleCancelConfirm}
+ onConfirm={handleDelete}
+ />
+ )}
+ {showRename && (
+ <RenameModal
+ isShow
+ onClose={handleCancelRename}
+ saveLoading={conversationRenaming}
+ name={showRename?.name || ''}
+ onSave={handleRename}
+ />
+ )}
+ </>
+ )
+}
+
+export default HeaderInMobile
diff --git a/app/components/base/chat/chat-with-history/header/index.tsx b/app/components/base/chat/chat-with-history/header/index.tsx
new file mode 100644
index 0000000..b5c5bcc
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/header/index.tsx
@@ -0,0 +1,164 @@
+import { useCallback, useState } from 'react'
+import {
+ RiEditBoxLine,
+ RiLayoutRight2Line,
+ RiResetLeftLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import {
+ useChatWithHistoryContext,
+} from '../context'
+import Operation from './operation'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+import AppIcon from '@/app/components/base/app-icon'
+import Tooltip from '@/app/components/base/tooltip'
+import ViewFormDropdown from '@/app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown'
+import Confirm from '@/app/components/base/confirm'
+import RenameModal from '@/app/components/base/chat/chat-with-history/sidebar/rename-modal'
+import type { ConversationItem } from '@/models/share'
+import cn from '@/utils/classnames'
+
+const Header = () => {
+ const {
+ appData,
+ currentConversationId,
+ currentConversationItem,
+ inputsForms,
+ pinnedConversationList,
+ handlePinConversation,
+ handleUnpinConversation,
+ conversationRenaming,
+ handleRenameConversation,
+ handleDeleteConversation,
+ handleNewConversation,
+ sidebarCollapseState,
+ handleSidebarCollapse,
+ isResponding,
+ } = useChatWithHistoryContext()
+ const { t } = useTranslation()
+ const isSidebarCollapsed = sidebarCollapseState
+
+ const isPin = pinnedConversationList.some(item => item.id === currentConversationId)
+
+ const [showConfirm, setShowConfirm] = useState<ConversationItem | null>(null)
+ const [showRename, setShowRename] = useState<ConversationItem | null>(null)
+ const handleOperate = useCallback((type: string) => {
+ if (type === 'pin')
+ handlePinConversation(currentConversationId)
+
+ if (type === 'unpin')
+ handleUnpinConversation(currentConversationId)
+
+ if (type === 'delete')
+ setShowConfirm(currentConversationItem as any)
+
+ if (type === 'rename')
+ setShowRename(currentConversationItem as any)
+ }, [currentConversationId, currentConversationItem, handlePinConversation, handleUnpinConversation])
+ const handleCancelConfirm = useCallback(() => {
+ setShowConfirm(null)
+ }, [])
+ const handleDelete = useCallback(() => {
+ if (showConfirm)
+ handleDeleteConversation(showConfirm.id, { onSuccess: handleCancelConfirm })
+ }, [showConfirm, handleDeleteConversation, handleCancelConfirm])
+ const handleCancelRename = useCallback(() => {
+ setShowRename(null)
+ }, [])
+ const handleRename = useCallback((newName: string) => {
+ if (showRename)
+ handleRenameConversation(showRename.id, newName, { onSuccess: handleCancelRename })
+ }, [showRename, handleRenameConversation, handleCancelRename])
+
+ return (
+ <>
+ <div className='flex h-14 shrink-0 items-center justify-between p-3'>
+ <div className={cn('flex items-center gap-1 transition-all duration-200 ease-in-out', !isSidebarCollapsed && 'user-select-none opacity-0')}>
+ <ActionButton className={cn(!isSidebarCollapsed && 'cursor-default')} size='l' onClick={() => handleSidebarCollapse(false)}>
+ <RiLayoutRight2Line className='h-[18px] w-[18px]' />
+ </ActionButton>
+ <div className='mr-1 shrink-0'>
+ <AppIcon
+ size='large'
+ iconType={appData?.site.icon_type}
+ icon={appData?.site.icon}
+ background={appData?.site.icon_background}
+ imageUrl={appData?.site.icon_url}
+ />
+ </div>
+ {!currentConversationId && (
+ <div className={cn('system-md-semibold grow truncate text-text-secondary')}>{appData?.site.title}</div>
+ )}
+ {currentConversationId && currentConversationItem && isSidebarCollapsed && (
+ <>
+ <div className='p-1 text-divider-deep'>/</div>
+ <Operation
+ title={currentConversationItem?.name || ''}
+ isPinned={!!isPin}
+ togglePin={() => handleOperate(isPin ? 'unpin' : 'pin')}
+ isShowDelete
+ isShowRenameConversation
+ onRenameConversation={() => handleOperate('rename')}
+ onDelete={() => handleOperate('delete')}
+ />
+ </>
+ )}
+ <div className='flex items-center px-1'>
+ <div className='h-[14px] w-px bg-divider-regular'></div>
+ </div>
+ {isSidebarCollapsed && (
+ <Tooltip
+ disabled={!!currentConversationId}
+ popupContent={t('share.chat.newChatTip')}
+ >
+ <div>
+ <ActionButton
+ size='l'
+ state={(!currentConversationId || isResponding) ? ActionButtonState.Disabled : ActionButtonState.Default}
+ disabled={!currentConversationId || isResponding}
+ onClick={handleNewConversation}
+ >
+ <RiEditBoxLine className='h-[18px] w-[18px]' />
+ </ActionButton>
+ </div>
+ </Tooltip>
+ )}
+ </div>
+ <div className='flex items-center gap-1'>
+ {currentConversationId && (
+ <Tooltip
+ popupContent={t('share.chat.resetChat')}
+ >
+ <ActionButton size='l' onClick={handleNewConversation}>
+ <RiResetLeftLine className='h-[18px] w-[18px]' />
+ </ActionButton>
+ </Tooltip>
+ )}
+ {currentConversationId && inputsForms.length > 0 && (
+ <ViewFormDropdown />
+ )}
+ </div>
+ </div>
+ {!!showConfirm && (
+ <Confirm
+ title={t('share.chat.deleteConversation.title')}
+ content={t('share.chat.deleteConversation.content') || ''}
+ isShow
+ onCancel={handleCancelConfirm}
+ onConfirm={handleDelete}
+ />
+ )}
+ {showRename && (
+ <RenameModal
+ isShow
+ onClose={handleCancelRename}
+ saveLoading={conversationRenaming}
+ name={showRename?.name || ''}
+ onSave={handleRename}
+ />
+ )}
+ </>
+ )
+}
+
+export default Header
diff --git a/app/components/base/chat/chat-with-history/header/mobile-operation-dropdown.tsx b/app/components/base/chat/chat-with-history/header/mobile-operation-dropdown.tsx
new file mode 100644
index 0000000..4bb6940
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/header/mobile-operation-dropdown.tsx
@@ -0,0 +1,59 @@
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiMoreFill,
+} from '@remixicon/react'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+
+type Props = {
+ handleResetChat: () => void
+ handleViewChatSettings: () => void
+ hideViewChatSettings?: boolean
+}
+
+const MobileOperationDropdown = ({
+ handleResetChat,
+ handleViewChatSettings,
+ hideViewChatSettings = false,
+}: Props) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 4,
+ crossAxis: -4,
+ }}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ >
+ <ActionButton size='l' state={open ? ActionButtonState.Hover : ActionButtonState.Default}>
+ <RiMoreFill className='h-[18px] w-[18px]' />
+ </ActionButton>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className="z-40">
+ <div
+ className={'min-w-[160px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-sm'}
+ >
+ <div className='system-md-regular flex cursor-pointer items-center space-x-1 rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover' onClick={handleResetChat}>
+ <span className='grow'>{t('share.chat.resetChat')}</span>
+ </div>
+ {!hideViewChatSettings && (
+ <div className='system-md-regular flex cursor-pointer items-center space-x-1 rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover' onClick={handleViewChatSettings}>
+ <span className='grow'>{t('share.chat.viewChatSettings')}</span>
+ </div>
+ )}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+
+ )
+}
+
+export default MobileOperationDropdown
diff --git a/app/components/base/chat/chat-with-history/header/operation.tsx b/app/components/base/chat/chat-with-history/header/operation.tsx
new file mode 100644
index 0000000..0923d71
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/header/operation.tsx
@@ -0,0 +1,73 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import type { Placement } from '@floating-ui/react'
+import {
+ RiArrowDownSLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
+import cn from '@/utils/classnames'
+
+type Props = {
+ title: string
+ isPinned: boolean
+ isShowRenameConversation?: boolean
+ onRenameConversation?: () => void
+ isShowDelete: boolean
+ togglePin: () => void
+ onDelete: () => void
+ placement?: Placement
+}
+
+const Operation: FC<Props> = ({
+ title,
+ isPinned,
+ togglePin,
+ isShowRenameConversation,
+ onRenameConversation,
+ isShowDelete,
+ onDelete,
+ placement = 'bottom-start',
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement={placement}
+ offset={4}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ >
+ <div className={cn('flex cursor-pointer items-center rounded-lg p-1.5 pl-2 text-text-secondary hover:bg-state-base-hover', open && 'bg-state-base-hover')}>
+ <div className='system-md-semibold'>{title}</div>
+ <RiArrowDownSLine className='h-4 w-4 ' />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className="z-50">
+ <div
+ className={'min-w-[120px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-sm'}
+ >
+ <div className={cn('system-md-regular flex cursor-pointer items-center space-x-1 rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover')} onClick={togglePin}>
+ <span className='grow'>{isPinned ? t('explore.sidebar.action.unpin') : t('explore.sidebar.action.pin')}</span>
+ </div>
+ {isShowRenameConversation && (
+ <div className={cn('system-md-regular flex cursor-pointer items-center space-x-1 rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover')} onClick={onRenameConversation}>
+ <span className='grow'>{t('explore.sidebar.action.rename')}</span>
+ </div>
+ )}
+ {isShowDelete && (
+ <div className={cn('system-md-regular group flex cursor-pointer items-center space-x-1 rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-destructive-hover hover:text-text-destructive')} onClick={onDelete} >
+ <span className='grow'>{t('explore.sidebar.action.delete')}</span>
+ </div>
+ )}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(Operation)
diff --git a/app/components/base/chat/chat-with-history/hooks.tsx b/app/components/base/chat/chat-with-history/hooks.tsx
new file mode 100644
index 0000000..91ceaff
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/hooks.tsx
@@ -0,0 +1,495 @@
+import {
+ useCallback,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import { useLocalStorageState } from 'ahooks'
+import produce from 'immer'
+import type {
+ Callback,
+ ChatConfig,
+ ChatItem,
+ Feedback,
+} from '../types'
+import { CONVERSATION_ID_INFO } from '../constants'
+import { buildChatItemTree, getProcessedSystemVariablesFromUrlParams } from '../utils'
+import { addFileInfos, sortAgentSorts } from '../../../tools/utils'
+import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
+import {
+ delConversation,
+ fetchAppInfo,
+ fetchAppMeta,
+ fetchAppParams,
+ fetchChatList,
+ fetchConversations,
+ generationConversationName,
+ pinConversation,
+ renameConversation,
+ unpinConversation,
+ updateFeedback,
+} from '@/service/share'
+import type { InstalledApp } from '@/models/explore'
+import type {
+ AppData,
+ ConversationItem,
+} from '@/models/share'
+import { useToastContext } from '@/app/components/base/toast'
+import { changeLanguage } from '@/i18n/i18next-config'
+import { useAppFavicon } from '@/hooks/use-app-favicon'
+import { InputVarType } from '@/app/components/workflow/types'
+import { TransferMethod } from '@/types/app'
+import { noop } from 'lodash-es'
+
+function getFormattedChatList(messages: any[]) {
+ const newChatList: ChatItem[] = []
+ messages.forEach((item) => {
+ const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || []
+ newChatList.push({
+ id: `question-${item.id}`,
+ content: item.query,
+ isAnswer: false,
+ message_files: getProcessedFilesFromResponse(questionFiles.map((item: any) => ({ ...item, related_id: item.id, upload_file_id: item.upload_file_id }))),
+ parentMessageId: item.parent_message_id || undefined,
+ })
+ const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || []
+ newChatList.push({
+ id: item.id,
+ content: item.answer,
+ agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files),
+ feedback: item.feedback,
+ isAnswer: true,
+ citation: item.retriever_resources,
+ message_files: getProcessedFilesFromResponse(answerFiles.map((item: any) => ({ ...item, related_id: item.id, upload_file_id: item.upload_file_id }))),
+ parentMessageId: `question-${item.id}`,
+ })
+ })
+ return newChatList
+}
+
+export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
+ const isInstalledApp = useMemo(() => !!installedAppInfo, [installedAppInfo])
+ const { data: appInfo, isLoading: appInfoLoading, error: appInfoError } = useSWR(installedAppInfo ? null : 'appInfo', fetchAppInfo)
+
+ useAppFavicon({
+ enable: !installedAppInfo,
+ icon_type: appInfo?.site.icon_type,
+ icon: appInfo?.site.icon,
+ icon_background: appInfo?.site.icon_background,
+ icon_url: appInfo?.site.icon_url,
+ })
+
+ const appData = useMemo(() => {
+ if (isInstalledApp) {
+ const { id, app } = installedAppInfo!
+ return {
+ app_id: id,
+ site: {
+ title: app.name,
+ icon_type: app.icon_type,
+ icon: app.icon,
+ icon_background: app.icon_background,
+ icon_url: app.icon_url,
+ prompt_public: false,
+ copyright: '',
+ show_workflow_steps: true,
+ use_icon_as_answer_icon: app.use_icon_as_answer_icon,
+ },
+ plan: 'basic',
+ } as AppData
+ }
+
+ return appInfo
+ }, [isInstalledApp, installedAppInfo, appInfo])
+ const appId = useMemo(() => appData?.app_id, [appData])
+
+ const [userId, setUserId] = useState<string>()
+ useEffect(() => {
+ getProcessedSystemVariablesFromUrlParams().then(({ user_id }) => {
+ setUserId(user_id)
+ })
+ }, [])
+
+ useEffect(() => {
+ if (appData?.site.default_language)
+ changeLanguage(appData.site.default_language)
+ }, [appData])
+
+ const [sidebarCollapseState, setSidebarCollapseState] = useState<boolean>(false)
+ const handleSidebarCollapse = useCallback((state: boolean) => {
+ if (appId) {
+ setSidebarCollapseState(state)
+ localStorage.setItem('webappSidebarCollapse', state ? 'collapsed' : 'expanded')
+ }
+ }, [appId, setSidebarCollapseState])
+ useEffect(() => {
+ if (appId) {
+ const localState = localStorage.getItem('webappSidebarCollapse')
+ setSidebarCollapseState(localState === 'collapsed')
+ }
+ }, [appId])
+ const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<Record<string, Record<string, string>>>(CONVERSATION_ID_INFO, {
+ defaultValue: {},
+ })
+ const currentConversationId = useMemo(() => conversationIdInfo?.[appId || '']?.[userId || 'DEFAULT'] || '', [appId, conversationIdInfo, userId])
+ const handleConversationIdInfoChange = useCallback((changeConversationId: string) => {
+ if (appId) {
+ let prevValue = conversationIdInfo?.[appId || '']
+ if (typeof prevValue === 'string')
+ prevValue = {}
+ setConversationIdInfo({
+ ...conversationIdInfo,
+ [appId || '']: {
+ ...prevValue,
+ [userId || 'DEFAULT']: changeConversationId,
+ },
+ })
+ }
+ }, [appId, conversationIdInfo, setConversationIdInfo, userId])
+
+ const [newConversationId, setNewConversationId] = useState('')
+ const chatShouldReloadKey = useMemo(() => {
+ if (currentConversationId === newConversationId)
+ return ''
+
+ return currentConversationId
+ }, [currentConversationId, newConversationId])
+
+ const { data: appParams } = useSWR(['appParams', isInstalledApp, appId], () => fetchAppParams(isInstalledApp, appId))
+ const { data: appMeta } = useSWR(['appMeta', isInstalledApp, appId], () => fetchAppMeta(isInstalledApp, appId))
+ const { data: appPinnedConversationData, mutate: mutateAppPinnedConversationData } = useSWR(['appConversationData', isInstalledApp, appId, true], () => fetchConversations(isInstalledApp, appId, undefined, true, 100))
+ const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations(isInstalledApp, appId, undefined, false, 100))
+ const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey, isInstalledApp, appId))
+
+ const [clearChatList, setClearChatList] = useState(false)
+ const [isResponding, setIsResponding] = useState(false)
+ const appPrevChatTree = useMemo(
+ () => (currentConversationId && appChatListData?.data.length)
+ ? buildChatItemTree(getFormattedChatList(appChatListData.data))
+ : [],
+ [appChatListData, currentConversationId],
+ )
+
+ const [showNewConversationItemInList, setShowNewConversationItemInList] = useState(false)
+
+ const pinnedConversationList = useMemo(() => {
+ return appPinnedConversationData?.data || []
+ }, [appPinnedConversationData])
+ const { t } = useTranslation()
+ const newConversationInputsRef = useRef<Record<string, any>>({})
+ const [newConversationInputs, setNewConversationInputs] = useState<Record<string, any>>({})
+ const handleNewConversationInputsChange = useCallback((newInputs: Record<string, any>) => {
+ newConversationInputsRef.current = newInputs
+ setNewConversationInputs(newInputs)
+ }, [])
+ const inputsForms = useMemo(() => {
+ return (appParams?.user_input_form || []).filter((item: any) => !item.external_data_tool).map((item: any) => {
+ if (item.paragraph) {
+ return {
+ ...item.paragraph,
+ type: 'paragraph',
+ }
+ }
+ if (item.number) {
+ return {
+ ...item.number,
+ type: 'number',
+ }
+ }
+ if (item.select) {
+ return {
+ ...item.select,
+ type: 'select',
+ }
+ }
+
+ if (item['file-list']) {
+ return {
+ ...item['file-list'],
+ type: 'file-list',
+ }
+ }
+
+ if (item.file) {
+ return {
+ ...item.file,
+ type: 'file',
+ }
+ }
+
+ return {
+ ...item['text-input'],
+ type: 'text-input',
+ }
+ })
+ }, [appParams])
+ useEffect(() => {
+ const conversationInputs: Record<string, any> = {}
+
+ inputsForms.forEach((item: any) => {
+ conversationInputs[item.variable] = item.default || null
+ })
+ handleNewConversationInputsChange(conversationInputs)
+ }, [handleNewConversationInputsChange, inputsForms])
+
+ const { data: newConversation } = useSWR(newConversationId ? [isInstalledApp, appId, newConversationId] : null, () => generationConversationName(isInstalledApp, appId, newConversationId), { revalidateOnFocus: false })
+ const [originConversationList, setOriginConversationList] = useState<ConversationItem[]>([])
+ useEffect(() => {
+ if (appConversationData?.data && !appConversationDataLoading)
+ setOriginConversationList(appConversationData?.data)
+ }, [appConversationData, appConversationDataLoading])
+ const conversationList = useMemo(() => {
+ const data = originConversationList.slice()
+
+ if (showNewConversationItemInList && data[0]?.id !== '') {
+ data.unshift({
+ id: '',
+ name: t('share.chat.newChatDefaultName'),
+ inputs: {},
+ introduction: '',
+ })
+ }
+ return data
+ }, [originConversationList, showNewConversationItemInList, t])
+
+ useEffect(() => {
+ if (newConversation) {
+ setOriginConversationList(produce((draft) => {
+ const index = draft.findIndex(item => item.id === newConversation.id)
+
+ if (index > -1)
+ draft[index] = newConversation
+ else
+ draft.unshift(newConversation)
+ }))
+ }
+ }, [newConversation])
+
+ const currentConversationItem = useMemo(() => {
+ let conversationItem = conversationList.find(item => item.id === currentConversationId)
+
+ if (!conversationItem && pinnedConversationList.length)
+ conversationItem = pinnedConversationList.find(item => item.id === currentConversationId)
+
+ return conversationItem
+ }, [conversationList, currentConversationId, pinnedConversationList])
+
+ const currentConversationLatestInputs = useMemo(() => {
+ if (!currentConversationId || !appChatListData?.data.length)
+ return newConversationInputsRef.current || {}
+ return appChatListData.data.slice().pop().inputs || {}
+ }, [appChatListData, currentConversationId])
+ const [currentConversationInputs, setCurrentConversationInputs] = useState<Record<string, any>>(currentConversationLatestInputs || {})
+ useEffect(() => {
+ if (currentConversationItem)
+ setCurrentConversationInputs(currentConversationLatestInputs || {})
+ }, [currentConversationItem, currentConversationLatestInputs])
+
+ const { notify } = useToastContext()
+ const checkInputsRequired = useCallback((silent?: boolean) => {
+ let hasEmptyInput = ''
+ let fileIsUploading = false
+ const requiredVars = inputsForms.filter(({ required }) => required)
+ if (requiredVars.length) {
+ requiredVars.forEach(({ variable, label, type }) => {
+ if (hasEmptyInput)
+ return
+
+ if (fileIsUploading)
+ return
+
+ if (!newConversationInputsRef.current[variable] && !silent)
+ hasEmptyInput = label as string
+
+ if ((type === InputVarType.singleFile || type === InputVarType.multiFiles) && newConversationInputsRef.current[variable] && !silent) {
+ const files = newConversationInputsRef.current[variable]
+ if (Array.isArray(files))
+ fileIsUploading = files.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId)
+ else
+ fileIsUploading = files.transferMethod === TransferMethod.local_file && !files.uploadedId
+ }
+ })
+ }
+
+ if (hasEmptyInput) {
+ notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }) })
+ return false
+ }
+
+ if (fileIsUploading) {
+ notify({ type: 'info', message: t('appDebug.errorMessage.waitForFileUpload') })
+ return
+ }
+
+ return true
+ }, [inputsForms, notify, t])
+ const handleStartChat = useCallback((callback: any) => {
+ if (checkInputsRequired()) {
+ setShowNewConversationItemInList(true)
+ callback?.()
+ }
+ }, [setShowNewConversationItemInList, checkInputsRequired])
+ const currentChatInstanceRef = useRef<{ handleStop: () => void }>({ handleStop: noop })
+ const handleChangeConversation = useCallback((conversationId: string) => {
+ currentChatInstanceRef.current.handleStop()
+ setNewConversationId('')
+ handleConversationIdInfoChange(conversationId)
+ if (conversationId)
+ setClearChatList(false)
+ }, [handleConversationIdInfoChange, setClearChatList])
+ const handleNewConversation = useCallback(() => {
+ currentChatInstanceRef.current.handleStop()
+ setShowNewConversationItemInList(true)
+ handleChangeConversation('')
+ handleNewConversationInputsChange({})
+ setClearChatList(true)
+ }, [handleChangeConversation, setShowNewConversationItemInList, handleNewConversationInputsChange, setClearChatList])
+ const handleUpdateConversationList = useCallback(() => {
+ mutateAppConversationData()
+ mutateAppPinnedConversationData()
+ }, [mutateAppConversationData, mutateAppPinnedConversationData])
+
+ const handlePinConversation = useCallback(async (conversationId: string) => {
+ await pinConversation(isInstalledApp, appId, conversationId)
+ notify({ type: 'success', message: t('common.api.success') })
+ handleUpdateConversationList()
+ }, [isInstalledApp, appId, notify, t, handleUpdateConversationList])
+
+ const handleUnpinConversation = useCallback(async (conversationId: string) => {
+ await unpinConversation(isInstalledApp, appId, conversationId)
+ notify({ type: 'success', message: t('common.api.success') })
+ handleUpdateConversationList()
+ }, [isInstalledApp, appId, notify, t, handleUpdateConversationList])
+
+ const [conversationDeleting, setConversationDeleting] = useState(false)
+ const handleDeleteConversation = useCallback(async (
+ conversationId: string,
+ {
+ onSuccess,
+ }: Callback,
+ ) => {
+ if (conversationDeleting)
+ return
+
+ try {
+ setConversationDeleting(true)
+ await delConversation(isInstalledApp, appId, conversationId)
+ notify({ type: 'success', message: t('common.api.success') })
+ onSuccess()
+ }
+ finally {
+ setConversationDeleting(false)
+ }
+
+ if (conversationId === currentConversationId)
+ handleNewConversation()
+
+ handleUpdateConversationList()
+ }, [isInstalledApp, appId, notify, t, handleUpdateConversationList, handleNewConversation, currentConversationId, conversationDeleting])
+
+ const [conversationRenaming, setConversationRenaming] = useState(false)
+ const handleRenameConversation = useCallback(async (
+ conversationId: string,
+ newName: string,
+ {
+ onSuccess,
+ }: Callback,
+ ) => {
+ if (conversationRenaming)
+ return
+
+ if (!newName.trim()) {
+ notify({
+ type: 'error',
+ message: t('common.chat.conversationNameCanNotEmpty'),
+ })
+ return
+ }
+
+ setConversationRenaming(true)
+ try {
+ await renameConversation(isInstalledApp, appId, conversationId, newName)
+
+ notify({
+ type: 'success',
+ message: t('common.actionMsg.modifiedSuccessfully'),
+ })
+ setOriginConversationList(produce((draft) => {
+ const index = originConversationList.findIndex(item => item.id === conversationId)
+ const item = draft[index]
+
+ draft[index] = {
+ ...item,
+ name: newName,
+ }
+ }))
+ onSuccess()
+ }
+ finally {
+ setConversationRenaming(false)
+ }
+ }, [isInstalledApp, appId, notify, t, conversationRenaming, originConversationList])
+
+ const handleNewConversationCompleted = useCallback((newConversationId: string) => {
+ setNewConversationId(newConversationId)
+ handleConversationIdInfoChange(newConversationId)
+ setShowNewConversationItemInList(false)
+ mutateAppConversationData()
+ }, [mutateAppConversationData, handleConversationIdInfoChange])
+
+ const handleFeedback = useCallback(async (messageId: string, feedback: Feedback) => {
+ await updateFeedback({ url: `/messages/${messageId}/feedbacks`, body: { rating: feedback.rating } }, isInstalledApp, appId)
+ notify({ type: 'success', message: t('common.api.success') })
+ }, [isInstalledApp, appId, t, notify])
+
+ return {
+ appInfoError,
+ appInfoLoading,
+ isInstalledApp,
+ appId,
+ currentConversationId,
+ currentConversationItem,
+ handleConversationIdInfoChange,
+ appData,
+ appParams: appParams || {} as ChatConfig,
+ appMeta,
+ appPinnedConversationData,
+ appConversationData,
+ appConversationDataLoading,
+ appChatListData,
+ appChatListDataLoading,
+ appPrevChatTree,
+ pinnedConversationList,
+ conversationList,
+ setShowNewConversationItemInList,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationInputsChange,
+ inputsForms,
+ handleNewConversation,
+ handleStartChat,
+ handleChangeConversation,
+ handlePinConversation,
+ handleUnpinConversation,
+ conversationDeleting,
+ handleDeleteConversation,
+ conversationRenaming,
+ handleRenameConversation,
+ handleNewConversationCompleted,
+ newConversationId,
+ chatShouldReloadKey,
+ handleFeedback,
+ currentChatInstanceRef,
+ sidebarCollapseState,
+ handleSidebarCollapse,
+ clearChatList,
+ setClearChatList,
+ isResponding,
+ setIsResponding,
+ currentConversationInputs,
+ setCurrentConversationInputs,
+ }
+}
diff --git a/app/components/base/chat/chat-with-history/index.tsx b/app/components/base/chat/chat-with-history/index.tsx
new file mode 100644
index 0000000..dfd7bd2
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/index.tsx
@@ -0,0 +1,253 @@
+import type { FC } from 'react'
+import {
+ useEffect,
+ useState,
+} from 'react'
+import { useAsyncEffect } from 'ahooks'
+import { useThemeContext } from '../embedded-chatbot/theme/theme-context'
+import {
+ ChatWithHistoryContext,
+ useChatWithHistoryContext,
+} from './context'
+import { useChatWithHistory } from './hooks'
+import Sidebar from './sidebar'
+import Header from './header'
+import HeaderInMobile from './header-in-mobile'
+import ChatWrapper from './chat-wrapper'
+import type { InstalledApp } from '@/models/explore'
+import Loading from '@/app/components/base/loading'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import { checkOrSetAccessToken } from '@/app/components/share/utils'
+import AppUnavailable from '@/app/components/base/app-unavailable'
+import cn from '@/utils/classnames'
+
+type ChatWithHistoryProps = {
+ className?: string
+}
+const ChatWithHistory: FC<ChatWithHistoryProps> = ({
+ className,
+}) => {
+ const {
+ appInfoError,
+ appData,
+ appInfoLoading,
+ appChatListDataLoading,
+ chatShouldReloadKey,
+ isMobile,
+ themeBuilder,
+ sidebarCollapseState,
+ } = useChatWithHistoryContext()
+ const isSidebarCollapsed = sidebarCollapseState
+ const customConfig = appData?.custom_config
+ const site = appData?.site
+
+ const [showSidePanel, setShowSidePanel] = useState(false)
+
+ useEffect(() => {
+ themeBuilder?.buildTheme(site?.chat_color_theme, site?.chat_color_theme_inverted)
+ if (site) {
+ if (customConfig)
+ document.title = `${site.title}`
+ else
+ document.title = `${site.title} - Powered by Dify`
+ }
+ }, [site, customConfig, themeBuilder])
+
+ if (appInfoLoading) {
+ return (
+ <Loading type='app' />
+ )
+ }
+
+ if (appInfoError) {
+ return (
+ <AppUnavailable />
+ )
+ }
+
+ return (
+ <div className={cn(
+ 'flex h-full bg-background-default-burn',
+ isMobile && 'flex-col',
+ className,
+ )}>
+ {!isMobile && (
+ <div className={cn(
+ 'flex w-[236px] flex-col p-1 pr-0 transition-all duration-200 ease-in-out',
+ isSidebarCollapsed && 'w-0 overflow-hidden !p-0',
+ )}>
+ <Sidebar />
+ </div>
+ )}
+ {isMobile && (
+ <HeaderInMobile />
+ )}
+ <div className={cn('relative grow p-2', isMobile && 'h-[calc(100%_-_56px)] p-0')}>
+ {isSidebarCollapsed && (
+ <div
+ className={cn(
+ 'absolute top-0 z-20 flex h-full w-[256px] flex-col p-2 transition-all duration-500 ease-in-out',
+ showSidePanel ? 'left-0' : 'left-[-248px]',
+ )}
+ onMouseEnter={() => setShowSidePanel(true)}
+ onMouseLeave={() => setShowSidePanel(false)}
+ >
+ <Sidebar isPanel />
+ </div>
+ )}
+ <div className={cn('flex h-full flex-col overflow-hidden border-[0,5px] border-components-panel-border-subtle bg-chatbot-bg', isMobile ? 'rounded-t-2xl' : 'rounded-2xl')}>
+ {!isMobile && <Header />}
+ {appChatListDataLoading && (
+ <Loading type='app' />
+ )}
+ {!appChatListDataLoading && (
+ <ChatWrapper key={chatShouldReloadKey} />
+ )}
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export type ChatWithHistoryWrapProps = {
+ installedAppInfo?: InstalledApp
+ className?: string
+}
+const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
+ installedAppInfo,
+ className,
+}) => {
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+ const themeBuilder = useThemeContext()
+
+ const {
+ appInfoError,
+ appInfoLoading,
+ appData,
+ appParams,
+ appMeta,
+ appChatListDataLoading,
+ currentConversationId,
+ currentConversationItem,
+ appPrevChatTree,
+ pinnedConversationList,
+ conversationList,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationInputsChange,
+ inputsForms,
+ handleNewConversation,
+ handleStartChat,
+ handleChangeConversation,
+ handlePinConversation,
+ handleUnpinConversation,
+ handleDeleteConversation,
+ conversationRenaming,
+ handleRenameConversation,
+ handleNewConversationCompleted,
+ chatShouldReloadKey,
+ isInstalledApp,
+ appId,
+ handleFeedback,
+ currentChatInstanceRef,
+ sidebarCollapseState,
+ handleSidebarCollapse,
+ clearChatList,
+ setClearChatList,
+ isResponding,
+ setIsResponding,
+ currentConversationInputs,
+ setCurrentConversationInputs,
+ } = useChatWithHistory(installedAppInfo)
+
+ return (
+ <ChatWithHistoryContext.Provider value={{
+ appInfoError,
+ appInfoLoading,
+ appData,
+ appParams,
+ appMeta,
+ appChatListDataLoading,
+ currentConversationId,
+ currentConversationItem,
+ appPrevChatTree,
+ pinnedConversationList,
+ conversationList,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationInputsChange,
+ inputsForms,
+ handleNewConversation,
+ handleStartChat,
+ handleChangeConversation,
+ handlePinConversation,
+ handleUnpinConversation,
+ handleDeleteConversation,
+ conversationRenaming,
+ handleRenameConversation,
+ handleNewConversationCompleted,
+ chatShouldReloadKey,
+ isMobile,
+ isInstalledApp,
+ appId,
+ handleFeedback,
+ currentChatInstanceRef,
+ themeBuilder,
+ sidebarCollapseState,
+ handleSidebarCollapse,
+ clearChatList,
+ setClearChatList,
+ isResponding,
+ setIsResponding,
+ currentConversationInputs,
+ setCurrentConversationInputs,
+ }}>
+ <ChatWithHistory className={className} />
+ </ChatWithHistoryContext.Provider>
+ )
+}
+
+const ChatWithHistoryWrapWithCheckToken: FC<ChatWithHistoryWrapProps> = ({
+ installedAppInfo,
+ className,
+}) => {
+ const [initialized, setInitialized] = useState(false)
+ const [appUnavailable, setAppUnavailable] = useState<boolean>(false)
+ const [isUnknownReason, setIsUnknownReason] = useState<boolean>(false)
+
+ useAsyncEffect(async () => {
+ if (!initialized) {
+ if (!installedAppInfo) {
+ try {
+ await checkOrSetAccessToken()
+ }
+ catch (e: any) {
+ if (e.status === 404) {
+ setAppUnavailable(true)
+ }
+ else {
+ setIsUnknownReason(true)
+ setAppUnavailable(true)
+ }
+ }
+ }
+ setInitialized(true)
+ }
+ }, [])
+
+ if (!initialized)
+ return null
+
+ if (appUnavailable)
+ return <AppUnavailable isUnknownReason={isUnknownReason} />
+
+ return (
+ <ChatWithHistoryWrap
+ installedAppInfo={installedAppInfo}
+ className={className}
+ />
+ )
+}
+
+export default ChatWithHistoryWrapWithCheckToken
diff --git a/app/components/base/chat/chat-with-history/inputs-form/content.tsx b/app/components/base/chat/chat-with-history/inputs-form/content.tsx
new file mode 100644
index 0000000..b8d1824
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/inputs-form/content.tsx
@@ -0,0 +1,115 @@
+import React, { memo, useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useChatWithHistoryContext } from '../context'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import { PortalSelect } from '@/app/components/base/select'
+import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader'
+import { InputVarType } from '@/app/components/workflow/types'
+
+type Props = {
+ showTip?: boolean
+}
+
+const InputsFormContent = ({ showTip }: Props) => {
+ const { t } = useTranslation()
+ const {
+ appParams,
+ inputsForms,
+ currentConversationId,
+ currentConversationInputs,
+ setCurrentConversationInputs,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationInputsChange,
+ } = useChatWithHistoryContext()
+ const inputsFormValue = currentConversationId ? currentConversationInputs : newConversationInputs
+
+ const handleFormChange = useCallback((variable: string, value: any) => {
+ setCurrentConversationInputs({
+ ...currentConversationInputs,
+ [variable]: value,
+ })
+ handleNewConversationInputsChange({
+ ...newConversationInputsRef.current,
+ [variable]: value,
+ })
+ }, [newConversationInputsRef, handleNewConversationInputsChange, currentConversationInputs, setCurrentConversationInputs])
+
+ return (
+ <div className='space-y-4'>
+ {inputsForms.map(form => (
+ <div key={form.variable} className='space-y-1'>
+ <div className='flex h-6 items-center gap-1'>
+ <div className='system-md-semibold text-text-secondary'>{form.label}</div>
+ {!form.required && (
+ <div className='system-xs-regular text-text-tertiary'>{t('appDebug.variableTable.optional')}</div>
+ )}
+ </div>
+ {form.type === InputVarType.textInput && (
+ <Input
+ value={inputsFormValue?.[form.variable] || ''}
+ onChange={e => handleFormChange(form.variable, e.target.value)}
+ placeholder={form.label}
+ />
+ )}
+ {form.type === InputVarType.number && (
+ <Input
+ type='number'
+ value={inputsFormValue?.[form.variable] || ''}
+ onChange={e => handleFormChange(form.variable, e.target.value)}
+ placeholder={form.label}
+ />
+ )}
+ {form.type === InputVarType.paragraph && (
+ <Textarea
+ value={inputsFormValue?.[form.variable] || ''}
+ onChange={e => handleFormChange(form.variable, e.target.value)}
+ placeholder={form.label}
+ />
+ )}
+ {form.type === InputVarType.select && (
+ <PortalSelect
+ popupClassName='w-[200px]'
+ value={inputsFormValue?.[form.variable]}
+ items={form.options.map((option: string) => ({ value: option, name: option }))}
+ onSelect={item => handleFormChange(form.variable, item.value as string)}
+ placeholder={form.label}
+ />
+ )}
+ {form.type === InputVarType.singleFile && (
+ <FileUploaderInAttachmentWrapper
+ value={inputsFormValue?.[form.variable] ? [inputsFormValue?.[form.variable]] : []}
+ onChange={files => handleFormChange(form.variable, files[0])}
+ fileConfig={{
+ allowed_file_types: form.allowed_file_types,
+ allowed_file_extensions: form.allowed_file_extensions,
+ allowed_file_upload_methods: form.allowed_file_upload_methods,
+ number_limits: 1,
+ fileUploadConfig: (appParams as any).system_parameters,
+ }}
+ />
+ )}
+ {form.type === InputVarType.multiFiles && (
+ <FileUploaderInAttachmentWrapper
+ value={inputsFormValue?.[form.variable] || []}
+ onChange={files => handleFormChange(form.variable, files)}
+ fileConfig={{
+ allowed_file_types: form.allowed_file_types,
+ allowed_file_extensions: form.allowed_file_extensions,
+ allowed_file_upload_methods: form.allowed_file_upload_methods,
+ number_limits: form.max_length,
+ fileUploadConfig: (appParams as any).system_parameters,
+ }}
+ />
+ )}
+ </div>
+ ))}
+ {showTip && (
+ <div className='system-xs-regular text-text-tertiary'>{t('share.chat.chatFormTip')}</div>
+ )}
+ </div>
+ )
+}
+
+export default memo(InputsFormContent)
diff --git a/app/components/base/chat/chat-with-history/inputs-form/index.tsx b/app/components/base/chat/chat-with-history/inputs-form/index.tsx
new file mode 100644
index 0000000..30ec11c
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/inputs-form/index.tsx
@@ -0,0 +1,79 @@
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { Message3Fill } from '@/app/components/base/icons/src/public/other'
+import Button from '@/app/components/base/button'
+import Divider from '@/app/components/base/divider'
+import InputsFormContent from '@/app/components/base/chat/chat-with-history/inputs-form/content'
+import { useChatWithHistoryContext } from '../context'
+import cn from '@/utils/classnames'
+
+type Props = {
+ collapsed: boolean
+ setCollapsed: (collapsed: boolean) => void
+}
+
+const InputsFormNode = ({
+ collapsed,
+ setCollapsed,
+}: Props) => {
+ const { t } = useTranslation()
+ const {
+ isMobile,
+ currentConversationId,
+ handleStartChat,
+ themeBuilder,
+ } = useChatWithHistoryContext()
+
+ return (
+ <div className={cn('flex flex-col items-center px-4 pt-6', isMobile && 'pt-4')}>
+ <div className={cn(
+ 'w-full max-w-[672px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-md',
+ collapsed && 'border border-components-card-border bg-components-card-bg shadow-none',
+ )}>
+ <div className={cn(
+ 'flex items-center gap-3 rounded-t-2xl px-6 py-4',
+ !collapsed && 'border-b border-divider-subtle',
+ isMobile && 'px-4 py-3',
+ )}>
+ <Message3Fill className='h-6 w-6 shrink-0' />
+ <div className='system-xl-semibold grow text-text-secondary'>{t('share.chat.chatSettingsTitle')}</div>
+ {collapsed && (
+ <Button className='uppercase text-text-tertiary' size='small' variant='ghost' onClick={() => setCollapsed(false)}>{t('common.operation.edit')}</Button>
+ )}
+ {!collapsed && currentConversationId && (
+ <Button className='uppercase text-text-tertiary' size='small' variant='ghost' onClick={() => setCollapsed(true)}>{t('common.operation.close')}</Button>
+ )}
+ </div>
+ {!collapsed && (
+ <div className={cn('p-6', isMobile && 'p-4')}>
+ <InputsFormContent />
+ </div>
+ )}
+ {!collapsed && !currentConversationId && (
+ <div className={cn('p-6', isMobile && 'p-4')}>
+ <Button
+ variant='primary'
+ className='w-full'
+ onClick={() => handleStartChat(() => setCollapsed(true))}
+ style={
+ themeBuilder?.theme
+ ? {
+ backgroundColor: themeBuilder?.theme.primaryColor,
+ }
+ : {}
+ }
+ >{t('share.chat.startChat')}</Button>
+ </div>
+ )}
+ </div>
+ {collapsed && (
+ <div className='flex w-full max-w-[720px] items-center py-4'>
+ <Divider bgStyle='gradient' className='h-px basis-1/2 rotate-180' />
+ <Divider bgStyle='gradient' className='h-px basis-1/2' />
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default InputsFormNode
diff --git a/app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown.tsx b/app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown.tsx
new file mode 100644
index 0000000..43df99c
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown.tsx
@@ -0,0 +1,48 @@
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiChatSettingsLine,
+} from '@remixicon/react'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+import { Message3Fill } from '@/app/components/base/icons/src/public/other'
+import InputsFormContent from '@/app/components/base/chat/chat-with-history/inputs-form/content'
+
+const ViewFormDropdown = () => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 4,
+ crossAxis: 4,
+ }}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ >
+ <ActionButton size='l' state={open ? ActionButtonState.Hover : ActionButtonState.Default}>
+ <RiChatSettingsLine className='h-[18px] w-[18px]' />
+ </ActionButton>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className="z-50">
+ <div className='w-[400px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg backdrop-blur-sm'>
+ <div className='flex items-center gap-3 rounded-t-2xl border-b border-divider-subtle px-6 py-4'>
+ <Message3Fill className='h-6 w-6 shrink-0' />
+ <div className='system-xl-semibold grow text-text-secondary'>{t('share.chat.chatSettingsTitle')}</div>
+ </div>
+ <div className='p-6'>
+ <InputsFormContent />
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+
+ )
+}
+
+export default ViewFormDropdown
diff --git a/app/components/base/chat/chat-with-history/sidebar/index.tsx b/app/components/base/chat/chat-with-history/sidebar/index.tsx
new file mode 100644
index 0000000..dc4e864
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/sidebar/index.tsx
@@ -0,0 +1,179 @@
+import {
+ useCallback,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiEditBoxLine,
+ RiExpandRightLine,
+ RiLayoutLeft2Line,
+} from '@remixicon/react'
+import { useChatWithHistoryContext } from '../context'
+import AppIcon from '@/app/components/base/app-icon'
+import ActionButton from '@/app/components/base/action-button'
+import Button from '@/app/components/base/button'
+import List from '@/app/components/base/chat/chat-with-history/sidebar/list'
+import MenuDropdown from '@/app/components/share/text-generation/menu-dropdown'
+import Confirm from '@/app/components/base/confirm'
+import RenameModal from '@/app/components/base/chat/chat-with-history/sidebar/rename-modal'
+import DifyLogo from '@/app/components/base/logo/dify-logo'
+import type { ConversationItem } from '@/models/share'
+import cn from '@/utils/classnames'
+
+type Props = {
+ isPanel?: boolean
+}
+
+const Sidebar = ({ isPanel }: Props) => {
+ const { t } = useTranslation()
+ const {
+ appData,
+ handleNewConversation,
+ pinnedConversationList,
+ conversationList,
+ currentConversationId,
+ handleChangeConversation,
+ handlePinConversation,
+ handleUnpinConversation,
+ conversationRenaming,
+ handleRenameConversation,
+ handleDeleteConversation,
+ sidebarCollapseState,
+ handleSidebarCollapse,
+ isMobile,
+ isResponding,
+ } = useChatWithHistoryContext()
+ const isSidebarCollapsed = sidebarCollapseState
+
+ const [showConfirm, setShowConfirm] = useState<ConversationItem | null>(null)
+ const [showRename, setShowRename] = useState<ConversationItem | null>(null)
+
+ const handleOperate = useCallback((type: string, item: ConversationItem) => {
+ if (type === 'pin')
+ handlePinConversation(item.id)
+
+ if (type === 'unpin')
+ handleUnpinConversation(item.id)
+
+ if (type === 'delete')
+ setShowConfirm(item)
+
+ if (type === 'rename')
+ setShowRename(item)
+ }, [handlePinConversation, handleUnpinConversation])
+ const handleCancelConfirm = useCallback(() => {
+ setShowConfirm(null)
+ }, [])
+ const handleDelete = useCallback(() => {
+ if (showConfirm)
+ handleDeleteConversation(showConfirm.id, { onSuccess: handleCancelConfirm })
+ }, [showConfirm, handleDeleteConversation, handleCancelConfirm])
+ const handleCancelRename = useCallback(() => {
+ setShowRename(null)
+ }, [])
+ const handleRename = useCallback((newName: string) => {
+ if (showRename)
+ handleRenameConversation(showRename.id, newName, { onSuccess: handleCancelRename })
+ }, [showRename, handleRenameConversation, handleCancelRename])
+
+ return (
+ <div className={cn(
+ 'flex w-full grow flex-col',
+ isPanel && 'rounded-xl border-[0.5px] border-components-panel-border-subtle bg-components-panel-bg shadow-lg',
+ )}>
+ <div className={cn(
+ 'flex shrink-0 items-center gap-3 p-3 pr-2',
+ )}>
+ <div className='shrink-0'>
+ <AppIcon
+ size='large'
+ iconType={appData?.site.icon_type}
+ icon={appData?.site.icon}
+ background={appData?.site.icon_background}
+ imageUrl={appData?.site.icon_url}
+ />
+ </div>
+ <div className={cn('system-md-semibold grow truncate text-text-secondary')}>{appData?.site.title}</div>
+ {!isMobile && isSidebarCollapsed && (
+ <ActionButton size='l' onClick={() => handleSidebarCollapse(false)}>
+ <RiExpandRightLine className='h-[18px] w-[18px]' />
+ </ActionButton>
+ )}
+ {!isMobile && !isSidebarCollapsed && (
+ <ActionButton size='l' onClick={() => handleSidebarCollapse(true)}>
+ <RiLayoutLeft2Line className='h-[18px] w-[18px]' />
+ </ActionButton>
+ )}
+ </div>
+ <div className='shrink-0 px-3 py-4'>
+ <Button variant='secondary-accent' disabled={isResponding} className='w-full justify-center' onClick={handleNewConversation}>
+ <RiEditBoxLine className='mr-1 h-4 w-4' />
+ {t('share.chat.newChat')}
+ </Button>
+ </div>
+ <div className='h-0 grow space-y-2 overflow-y-auto px-3 pt-4'>
+ {/* pinned list */}
+ {!!pinnedConversationList.length && (
+ <div className='mb-4'>
+ <List
+ isPin
+ title={t('share.chat.pinnedTitle') || ''}
+ list={pinnedConversationList}
+ onChangeConversation={handleChangeConversation}
+ onOperate={handleOperate}
+ currentConversationId={currentConversationId}
+ />
+ </div>
+ )}
+ {!!conversationList.length && (
+ <List
+ title={(pinnedConversationList.length && t('share.chat.unpinnedTitle')) || ''}
+ list={conversationList}
+ onChangeConversation={handleChangeConversation}
+ onOperate={handleOperate}
+ currentConversationId={currentConversationId}
+ />
+ )}
+ </div>
+ <div className='flex shrink-0 items-center justify-between p-3'>
+ <MenuDropdown placement='top-start' data={appData?.site} />
+ {/* powered by */}
+ <div className='shrink-0'>
+ {!appData?.custom_config?.remove_webapp_brand && (
+ <div className={cn(
+ 'flex shrink-0 items-center gap-1.5 px-1',
+ )}>
+ <div className='system-2xs-medium-uppercase text-text-tertiary'>{t('share.chat.poweredBy')}</div>
+ {appData?.custom_config?.replace_webapp_logo && (
+ <img src={appData?.custom_config?.replace_webapp_logo} alt='logo' className='block h-5 w-auto' />
+ )}
+ {!appData?.custom_config?.replace_webapp_logo && (
+ <DifyLogo size='small' />
+ )}
+ </div>
+ )}
+ </div>
+ </div>
+ {!!showConfirm && (
+ <Confirm
+ title={t('share.chat.deleteConversation.title')}
+ content={t('share.chat.deleteConversation.content') || ''}
+ isShow
+ onCancel={handleCancelConfirm}
+ onConfirm={handleDelete}
+ />
+ )}
+ {showRename && (
+ <RenameModal
+ isShow
+ onClose={handleCancelRename}
+ saveLoading={conversationRenaming}
+ name={showRename?.name || ''}
+ onSave={handleRename}
+ />
+ )}
+ </div>
+ )
+}
+
+export default Sidebar
diff --git a/app/components/base/chat/chat-with-history/sidebar/item.tsx b/app/components/base/chat/chat-with-history/sidebar/item.tsx
new file mode 100644
index 0000000..ea17f3f
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/sidebar/item.tsx
@@ -0,0 +1,58 @@
+import type { FC } from 'react'
+import {
+ memo,
+ useRef,
+} from 'react'
+import { useHover } from 'ahooks'
+import type { ConversationItem } from '@/models/share'
+import Operation from '@/app/components/base/chat/chat-with-history/sidebar/operation'
+import cn from '@/utils/classnames'
+
+type ItemProps = {
+ isPin?: boolean
+ item: ConversationItem
+ onOperate: (type: string, item: ConversationItem) => void
+ onChangeConversation: (conversationId: string) => void
+ currentConversationId: string
+}
+const Item: FC<ItemProps> = ({
+ isPin,
+ item,
+ onOperate,
+ onChangeConversation,
+ currentConversationId,
+}) => {
+ const ref = useRef(null)
+ const isHovering = useHover(ref)
+ const isSelected = currentConversationId === item.id
+
+ return (
+ <div
+ ref={ref}
+ key={item.id}
+ className={cn(
+ 'system-sm-medium group flex cursor-pointer rounded-lg p-1 pl-3 text-components-menu-item-text hover:bg-state-base-hover',
+ isSelected && 'bg-state-accent-active text-text-accent hover:bg-state-accent-active',
+ )}
+ onClick={() => onChangeConversation(item.id)}
+ >
+ <div className='grow truncate p-1 pl-0' title={item.name}>{item.name}</div>
+ {item.id !== '' && (
+ <div className='shrink-0' onClick={e => e.stopPropagation()}>
+ <Operation
+ isActive={isSelected}
+ isPinned={!!isPin}
+ isItemHovering={isHovering}
+ togglePin={() => onOperate(isPin ? 'unpin' : 'pin', item)}
+ isShowDelete
+ isShowRenameConversation
+ onRenameConversation={() => onOperate('rename', item)}
+ onDelete={() => onOperate('delete', item)}
+ />
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default memo(Item)
diff --git a/app/components/base/chat/chat-with-history/sidebar/list.tsx b/app/components/base/chat/chat-with-history/sidebar/list.tsx
new file mode 100644
index 0000000..4a9c207
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/sidebar/list.tsx
@@ -0,0 +1,40 @@
+import type { FC } from 'react'
+import Item from './item'
+import type { ConversationItem } from '@/models/share'
+
+type ListProps = {
+ isPin?: boolean
+ title?: string
+ list: ConversationItem[]
+ onOperate: (type: string, item: ConversationItem) => void
+ onChangeConversation: (conversationId: string) => void
+ currentConversationId: string
+}
+const List: FC<ListProps> = ({
+ isPin,
+ title,
+ list,
+ onOperate,
+ onChangeConversation,
+ currentConversationId,
+}) => {
+ return (
+ <div className='space-y-0.5'>
+ {title && (
+ <div className='system-xs-medium-uppercase px-3 pb-1 pt-2 text-text-tertiary'>{title}</div>
+ )}
+ {list.map(item => (
+ <Item
+ key={item.id}
+ isPin={isPin}
+ item={item}
+ onOperate={onOperate}
+ onChangeConversation={onChangeConversation}
+ currentConversationId={currentConversationId}
+ />
+ ))}
+ </div>
+ )
+}
+
+export default List
diff --git a/app/components/base/chat/chat-with-history/sidebar/operation.tsx b/app/components/base/chat/chat-with-history/sidebar/operation.tsx
new file mode 100644
index 0000000..19d2aa2
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/sidebar/operation.tsx
@@ -0,0 +1,101 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
+import {
+ RiDeleteBinLine,
+ RiEditLine,
+ RiMoreFill,
+ RiPushpinLine,
+ RiUnpinLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+import cn from '@/utils/classnames'
+
+type Props = {
+ isActive?: boolean
+ isItemHovering?: boolean
+ isPinned: boolean
+ isShowRenameConversation?: boolean
+ onRenameConversation?: () => void
+ isShowDelete: boolean
+ togglePin: () => void
+ onDelete: () => void
+}
+
+const Operation: FC<Props> = ({
+ isActive,
+ isItemHovering,
+ isPinned,
+ togglePin,
+ isShowRenameConversation,
+ onRenameConversation,
+ isShowDelete,
+ onDelete,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const ref = useRef(null)
+ const [isHovering, { setTrue: setIsHovering, setFalse: setNotHovering }] = useBoolean(false)
+ useEffect(() => {
+ if (!isItemHovering && !isHovering)
+ setOpen(false)
+ }, [isItemHovering, isHovering])
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={4}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ >
+ <ActionButton
+ className={cn((isItemHovering || open) ? 'opacity-100' : 'opacity-0')}
+ state={
+ isActive
+ ? ActionButtonState.Active
+ : open
+ ? ActionButtonState.Hover
+ : ActionButtonState.Default
+ }
+ >
+ <RiMoreFill className='h-4 w-4' />
+ </ActionButton>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className="z-50">
+ <div
+ ref={ref}
+ className={'min-w-[120px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-sm'}
+ onMouseEnter={setIsHovering}
+ onMouseLeave={setNotHovering}
+ onClick={(e) => {
+ e.stopPropagation()
+ }}
+ >
+ <div className={cn('system-md-regular flex cursor-pointer items-center space-x-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover')} onClick={togglePin}>
+ {isPinned && <RiUnpinLine className='h-4 w-4 shrink-0 text-text-tertiary' />}
+ {!isPinned && <RiPushpinLine className='h-4 w-4 shrink-0 text-text-tertiary' />}
+ <span className='grow'>{isPinned ? t('explore.sidebar.action.unpin') : t('explore.sidebar.action.pin')}</span>
+ </div>
+ {isShowRenameConversation && (
+ <div className={cn('system-md-regular flex cursor-pointer items-center space-x-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover')} onClick={onRenameConversation}>
+ <RiEditLine className='h-4 w-4 shrink-0 text-text-tertiary' />
+ <span className='grow'>{t('explore.sidebar.action.rename')}</span>
+ </div>
+ )}
+ {isShowDelete && (
+ <div className={cn('system-md-regular group flex cursor-pointer items-center space-x-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-destructive-hover hover:text-text-destructive')} onClick={onDelete} >
+ <RiDeleteBinLine className={cn('h-4 w-4 shrink-0 text-text-tertiary group-hover:text-text-destructive')} />
+ <span className='grow'>{t('explore.sidebar.action.delete')}</span>
+ </div>
+ )}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(Operation)
diff --git a/app/components/base/chat/chat-with-history/sidebar/rename-modal.tsx b/app/components/base/chat/chat-with-history/sidebar/rename-modal.tsx
new file mode 100644
index 0000000..bbd087a
--- /dev/null
+++ b/app/components/base/chat/chat-with-history/sidebar/rename-modal.tsx
@@ -0,0 +1,47 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+
+export type IRenameModalProps = {
+ isShow: boolean
+ saveLoading: boolean
+ name: string
+ onClose: () => void
+ onSave: (name: string) => void
+}
+
+const RenameModal: FC<IRenameModalProps> = ({
+ isShow,
+ saveLoading,
+ name,
+ onClose,
+ onSave,
+}) => {
+ const { t } = useTranslation()
+ const [tempName, setTempName] = useState(name)
+
+ return (
+ <Modal
+ title={t('common.chat.renameConversation')}
+ isShow={isShow}
+ onClose={onClose}
+ >
+ <div className={'mt-6 text-sm font-medium leading-[21px] text-text-primary'}>{t('common.chat.conversationName')}</div>
+ <Input className='mt-2 h-10 w-full'
+ value={tempName}
+ onChange={e => setTempName(e.target.value)}
+ placeholder={t('common.chat.conversationNamePlaceholder') || ''}
+ />
+
+ <div className='mt-10 flex justify-end'>
+ <Button className='mr-2 shrink-0' onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' className='shrink-0' onClick={() => onSave(tempName)} loading={saveLoading}>{t('common.operation.save')}</Button>
+ </div>
+ </Modal>
+ )
+}
+export default React.memo(RenameModal)
diff --git a/app/components/base/chat/chat/answer/__mocks__/markdownContent.ts b/app/components/base/chat/chat/answer/__mocks__/markdownContent.ts
new file mode 100644
index 0000000..a7a25f5
--- /dev/null
+++ b/app/components/base/chat/chat/answer/__mocks__/markdownContent.ts
@@ -0,0 +1,61 @@
+export const markdownContent = `
+# Heading 1
+
+## Heading 2
+
+### Heading 3
+
+#### Heading 4
+
+##### Heading 5
+
+###### Heading 6
+
+# Basic markdown content.
+
+Should support **bold**, *italic*, and ~~strikethrough~~.
+Should support [links](https://www.google.com).
+Should support inline \`code\` blocks.
+
+# Number list
+
+1. First item
+2. Second item
+3. Third item
+
+# Bullet list
+
+- First item
+- Second item
+- Third item
+
+# Link
+
+[Google](https://www.google.com)
+
+# Image
+
+
+
+# Table
+
+| Column 1 | Column 2 | Column 3 |
+| -------- | -------- | -------- |
+| Cell 1 | Cell 2 | Cell 3 |
+| Cell 4 | Cell 5 | Cell 6 |
+| Cell 7 | Cell 8 | Cell 9 |
+
+# Code
+
+\`\`\`JavaScript
+const code = "code"
+\`\`\`
+
+# Blockquote
+
+> This is a blockquote.
+
+# Horizontal rule
+
+---
+`
diff --git a/app/components/base/chat/chat/answer/__mocks__/markdownContentSVG.ts b/app/components/base/chat/chat/answer/__mocks__/markdownContentSVG.ts
new file mode 100644
index 0000000..bcc3ae6
--- /dev/null
+++ b/app/components/base/chat/chat/answer/__mocks__/markdownContentSVG.ts
@@ -0,0 +1,27 @@
+export const markdownContentSVG = `
+\`\`\`svg
+<svg width="400" height="600" xmlns="http://www.w3.org/2000/svg">
+ <rect width="100%" height="100%" fill="#F0F8FF"/>
+
+ <text x="50%" y="60" font-family="妤蜂綋" font-size="32" fill="#4682B4" text-anchor="middle">鍒涙剰Logo璁捐</text>
+
+ <line x1="50" y1="80" x2="350" y2="80" stroke="#B0C4DE" stroke-width="2"/>
+
+ <text x="50%" y="120" font-family="Arial" font-size="24" fill="#708090" text-anchor="middle">绉戠爺</text>
+ <text x="50%" y="150" font-family="MS Mincho" font-size="20" fill="#778899" text-anchor="middle">绉戝鐮旂┒</text>
+
+ <text x="50%" y="200" font-family="姹囨枃鏄庢湞浣�" font-size="18" fill="#696969" text-anchor="middle">
+ <tspan x="50%" dy="25">鎺㈢储鏈煡鐨勭伅濉旓紝</tspan>
+ <tspan x="50%" dy="25">鐓т寒浜虹被鍓嶈繘鐨勯亾璺��</tspan>
+ <tspan x="50%" dy="25">绉戠爺锛屾槸姘镐笉鐔勭伃鐨勫ソ濂囧績锛�</tspan>
+ <tspan x="50%" dy="25">涔熸槸鎺ㄥ姩涓栫晫杩涙鐨勫紩鎿庛��</tspan>
+ </text>
+
+ <circle cx="200" cy="400" r="80" fill="none" stroke="#4169E1" stroke-width="3"/>
+ <line x1="200" y1="320" x2="200" y2="480" stroke="#4169E1" stroke-width="3"/>
+ <line x1="120" y1="400" x2="280" y2="400" stroke="#4169E1" stroke-width="3"/>
+
+ <text x="50%" y="550" font-family="寰蒋闆呴粦" font-size="16" fill="#1E90FF" text-anchor="middle">鎺㈢储 鈥� 鍒涙柊 鈥� 杩涙</text>
+</svg>
+\`\`\`
+`
diff --git a/app/components/base/chat/chat/answer/__mocks__/workflowProcess.ts b/app/components/base/chat/chat/answer/__mocks__/workflowProcess.ts
new file mode 100644
index 0000000..b6bd9a6
--- /dev/null
+++ b/app/components/base/chat/chat/answer/__mocks__/workflowProcess.ts
@@ -0,0 +1,138 @@
+import type { WorkflowProcess } from '@/app/components/base/chat/types'
+import { WorkflowRunningStatus } from '@/app/components/workflow/types'
+
+export const mockedWorkflowProcess = {
+ status: WorkflowRunningStatus.Succeeded,
+ resultText: 'Hello, how can I assist you today?',
+ tracing: [
+ {
+ extras: {},
+ id: 'f6337dc9-e280-4915-965f-10b0552dd917',
+ node_id: '1724232060789',
+ node_type: 'start',
+ title: 'Start',
+ index: 1,
+ predecessor_node_id: null,
+ inputs: {
+ 'sys.query': 'hi',
+ 'sys.files': [],
+ 'sys.conversation_id': '92ce0a3e-8f15-43d1-b31d-32716c4b10a7',
+ 'sys.user_id': 'fbff43f9-d5a4-4e85-b63b-d3a91d806c6f',
+ 'sys.dialogue_count': 1,
+ 'sys.app_id': 'b2e8906a-aad3-43a0-9ace-0e44cc7315e1',
+ 'sys.workflow_id': '70004abe-561f-418b-b9e8-8c957ce55140',
+ 'sys.workflow_run_id': '69db9267-aaee-42e1-9581-dbfb67e8eeb5',
+ },
+ process_data: null,
+ outputs: {
+ 'sys.query': 'hi',
+ 'sys.files': [],
+ 'sys.conversation_id': '92ce0a3e-8f15-43d1-b31d-32716c4b10a7',
+ 'sys.user_id': 'fbff43f9-d5a4-4e85-b63b-d3a91d806c6f',
+ 'sys.dialogue_count': 1,
+ 'sys.app_id': 'b2e8906a-aad3-43a0-9ace-0e44cc7315e1',
+ 'sys.workflow_id': '70004abe-561f-418b-b9e8-8c957ce55140',
+ 'sys.workflow_run_id': '69db9267-aaee-42e1-9581-dbfb67e8eeb5',
+ },
+ status: 'succeeded',
+ error: null,
+ elapsed_time: 0.035744,
+ execution_metadata: null,
+ created_at: 1728980002,
+ finished_at: 1728980002,
+ files: [],
+ parallel_id: null,
+ parallel_start_node_id: null,
+ parent_parallel_id: null,
+ parent_parallel_start_node_id: null,
+ iteration_id: null,
+ loop_id: null,
+ },
+ {
+ extras: {},
+ id: '92204d8d-4198-4c46-aa02-c2754b11dec9',
+ node_id: 'llm',
+ node_type: 'llm',
+ title: 'LLM',
+ index: 2,
+ predecessor_node_id: '1724232060789',
+ inputs: null,
+ process_data: {
+ model_mode: 'chat',
+ prompts: [
+ {
+ role: 'system',
+ text: 'hi',
+ files: [],
+ },
+ {
+ role: 'user',
+ text: 'hi',
+ files: [],
+ },
+ ],
+ model_provider: 'openai',
+ model_name: 'gpt-4o-mini',
+ },
+ outputs: {
+ text: 'Hello! How can I assist you today?',
+ usage: {
+ prompt_tokens: 13,
+ prompt_unit_price: '0.15',
+ prompt_price_unit: '0.000001',
+ prompt_price: '0.0000020',
+ completion_tokens: 9,
+ completion_unit_price: '0.60',
+ completion_price_unit: '0.000001',
+ completion_price: '0.0000054',
+ total_tokens: 22,
+ total_price: '0.0000074',
+ currency: 'USD',
+ latency: 1.8902503330027685,
+ },
+ finish_reason: 'stop',
+ },
+ status: 'succeeded',
+ error: null,
+ elapsed_time: 5.089409,
+ execution_metadata: {
+ total_tokens: 22,
+ total_price: '0.0000074',
+ currency: 'USD',
+ },
+ created_at: 1728980002,
+ finished_at: 1728980007,
+ files: [],
+ parallel_id: null,
+ parallel_start_node_id: null,
+ parent_parallel_id: null,
+ parent_parallel_start_node_id: null,
+ iteration_id: null,
+ loop_id: null,
+ },
+ {
+ extras: {},
+ id: '7149bac6-60f9-4e06-a5ed-1d9d3764c06b',
+ node_id: 'answer',
+ node_type: 'answer',
+ title: 'Answer',
+ index: 3,
+ predecessor_node_id: 'llm',
+ inputs: null,
+ process_data: null,
+ outputs: {
+ answer: 'Hello! How can I assist you today?',
+ },
+ status: 'succeeded',
+ error: null,
+ elapsed_time: 0.015339,
+ execution_metadata: null,
+ created_at: 1728980007,
+ finished_at: 1728980007,
+ parallel_id: null,
+ parallel_start_node_id: null,
+ parent_parallel_id: null,
+ parent_parallel_start_node_id: null,
+ },
+ ],
+} as unknown as WorkflowProcess
diff --git a/app/components/base/chat/chat/answer/agent-content.tsx b/app/components/base/chat/chat/answer/agent-content.tsx
new file mode 100644
index 0000000..c20e38c
--- /dev/null
+++ b/app/components/base/chat/chat/answer/agent-content.tsx
@@ -0,0 +1,61 @@
+import type { FC } from 'react'
+import { memo } from 'react'
+import type {
+ ChatItem,
+} from '../../types'
+import { Markdown } from '@/app/components/base/markdown'
+import Thought from '@/app/components/base/chat/chat/thought'
+import { FileList } from '@/app/components/base/file-uploader'
+import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
+
+type AgentContentProps = {
+ item: ChatItem
+ responding?: boolean
+ content?: string
+}
+const AgentContent: FC<AgentContentProps> = ({
+ item,
+ responding,
+ content,
+}) => {
+ const {
+ annotation,
+ agent_thoughts,
+ } = item
+
+ if (annotation?.logAnnotation)
+ return <Markdown content={annotation?.logAnnotation.content || ''} />
+
+ return (
+ <div>
+ {content ? <Markdown content={content} /> : agent_thoughts?.map((thought, index) => (
+ <div key={index} className='px-2 py-1'>
+ {thought.thought && (
+ <Markdown content={thought.thought} />
+ )}
+ {/* {item.tool} */}
+ {/* perhaps not use tool */}
+ {!!thought.tool && (
+ <Thought
+ thought={thought}
+ isFinished={!!thought.observation || !responding}
+ />
+ )}
+
+ {
+ !!thought.message_files?.length && (
+ <FileList
+ files={getProcessedFilesFromResponse(thought.message_files.map((item: any) => ({ ...item, related_id: item.id })))}
+ showDeleteAction={false}
+ showDownloadAction={true}
+ canPreview={true}
+ />
+ )
+ }
+ </div>
+ ))}
+ </div>
+ )
+}
+
+export default memo(AgentContent)
diff --git a/app/components/base/chat/chat/answer/basic-content.tsx b/app/components/base/chat/chat/answer/basic-content.tsx
new file mode 100644
index 0000000..6c8a44c
--- /dev/null
+++ b/app/components/base/chat/chat/answer/basic-content.tsx
@@ -0,0 +1,31 @@
+import type { FC } from 'react'
+import { memo } from 'react'
+import type { ChatItem } from '../../types'
+import { Markdown } from '@/app/components/base/markdown'
+import cn from '@/utils/classnames'
+
+type BasicContentProps = {
+ item: ChatItem
+}
+const BasicContent: FC<BasicContentProps> = ({
+ item,
+}) => {
+ const {
+ annotation,
+ content,
+ } = item
+
+ if (annotation?.logAnnotation)
+ return <Markdown content={annotation?.logAnnotation.content || ''} />
+
+ return (
+ <Markdown
+ className={cn(
+ item.isError && '!text-[#F04438]',
+ )}
+ content={content}
+ />
+ )
+}
+
+export default memo(BasicContent)
diff --git a/app/components/base/chat/chat/answer/index.stories.tsx b/app/components/base/chat/chat/answer/index.stories.tsx
new file mode 100644
index 0000000..18bc129
--- /dev/null
+++ b/app/components/base/chat/chat/answer/index.stories.tsx
@@ -0,0 +1,96 @@
+import type { Meta, StoryObj } from '@storybook/react'
+
+import type { ChatItem } from '../../types'
+import { mockedWorkflowProcess } from './__mocks__/workflowProcess'
+import { markdownContent } from './__mocks__/markdownContent'
+import { markdownContentSVG } from './__mocks__/markdownContentSVG'
+import Answer from '.'
+
+const meta = {
+ title: 'Base/Chat Answer',
+ component: Answer,
+ parameters: {
+ layout: 'fullscreen',
+ },
+ tags: ['autodocs'],
+ argTypes: {
+ noChatInput: { control: 'boolean', description: 'If set to true, some buttons that are supposed to be shown on hover will not be displayed.' },
+ responding: { control: 'boolean', description: 'Indicates if the answer is being generated.' },
+ showPromptLog: { control: 'boolean', description: 'If set to true, the prompt log button will be shown on hover.' },
+ },
+ args: {
+ noChatInput: false,
+ responding: false,
+ showPromptLog: false,
+ },
+} satisfies Meta<typeof Answer>
+
+export default meta
+type Story = StoryObj<typeof meta>
+
+const mockedBaseChatItem = {
+ id: '1',
+ isAnswer: true,
+ content: 'Hello, how can I assist you today?',
+} satisfies ChatItem
+
+export const Basic: Story = {
+ args: {
+ item: mockedBaseChatItem,
+ question: mockedBaseChatItem.content,
+ index: 0,
+ },
+ render: (args) => {
+ return <div className="w-full px-10 py-5">
+ <Answer {...args} />
+ </div>
+ },
+}
+
+export const WithWorkflowProcess: Story = {
+ args: {
+ item: {
+ ...mockedBaseChatItem,
+ workflowProcess: mockedWorkflowProcess,
+ },
+ question: mockedBaseChatItem.content,
+ index: 0,
+ },
+ render: (args) => {
+ return <div className="w-full px-10 py-5">
+ <Answer {...args} />
+ </div>
+ },
+}
+
+export const WithMarkdownContent: Story = {
+ args: {
+ item: {
+ ...mockedBaseChatItem,
+ content: markdownContent,
+ },
+ question: mockedBaseChatItem.content,
+ index: 0,
+ },
+ render: (args) => {
+ return <div className="w-full px-10 py-5">
+ <Answer {...args} />
+ </div>
+ },
+}
+
+export const WithMarkdownSVG: Story = {
+ args: {
+ item: {
+ ...mockedBaseChatItem,
+ content: markdownContentSVG,
+ },
+ question: mockedBaseChatItem.content,
+ index: 0,
+ },
+ render: (args) => {
+ return <div className="w-full px-10 py-5">
+ <Answer {...args} />
+ </div>
+ },
+}
diff --git a/app/components/base/chat/chat/answer/index.tsx b/app/components/base/chat/chat/answer/index.tsx
new file mode 100644
index 0000000..a0a9323
--- /dev/null
+++ b/app/components/base/chat/chat/answer/index.tsx
@@ -0,0 +1,239 @@
+import type {
+ FC,
+ ReactNode,
+} from 'react'
+import { memo, useCallback, useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import type {
+ ChatConfig,
+ ChatItem,
+} from '../../types'
+import Operation from './operation'
+import AgentContent from './agent-content'
+import BasicContent from './basic-content'
+import SuggestedQuestions from './suggested-questions'
+import More from './more'
+import WorkflowProcessItem from './workflow-process'
+import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
+import Citation from '@/app/components/base/chat/chat/citation'
+import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item'
+import type { AppData } from '@/models/share'
+import AnswerIcon from '@/app/components/base/answer-icon'
+import cn from '@/utils/classnames'
+import { FileList } from '@/app/components/base/file-uploader'
+import ContentSwitch from '../content-switch'
+
+type AnswerProps = {
+ item: ChatItem
+ question: string
+ index: number
+ config?: ChatConfig
+ answerIcon?: ReactNode
+ responding?: boolean
+ showPromptLog?: boolean
+ chatAnswerContainerInner?: string
+ hideProcessDetail?: boolean
+ appData?: AppData
+ noChatInput?: boolean
+ switchSibling?: (siblingMessageId: string) => void
+}
+const Answer: FC<AnswerProps> = ({
+ item,
+ question,
+ index,
+ config,
+ answerIcon,
+ responding,
+ showPromptLog,
+ chatAnswerContainerInner,
+ hideProcessDetail,
+ appData,
+ noChatInput,
+ switchSibling,
+}) => {
+ const { t } = useTranslation()
+ const {
+ content,
+ citation,
+ agent_thoughts,
+ more,
+ annotation,
+ workflowProcess,
+ allFiles,
+ message_files,
+ } = item
+ const hasAgentThoughts = !!agent_thoughts?.length
+
+ const [containerWidth, setContainerWidth] = useState(0)
+ const [contentWidth, setContentWidth] = useState(0)
+ const containerRef = useRef<HTMLDivElement>(null)
+ const contentRef = useRef<HTMLDivElement>(null)
+
+ const getContainerWidth = () => {
+ if (containerRef.current)
+ setContainerWidth(containerRef.current?.clientWidth + 16)
+ }
+ useEffect(() => {
+ getContainerWidth()
+ }, [])
+
+ const getContentWidth = () => {
+ if (contentRef.current)
+ setContentWidth(contentRef.current?.clientWidth)
+ }
+
+ useEffect(() => {
+ if (!responding)
+ getContentWidth()
+ }, [responding])
+
+ // Recalculate contentWidth when content changes (e.g., SVG preview/source toggle)
+ useEffect(() => {
+ if (!containerRef.current)
+ return
+ const resizeObserver = new ResizeObserver(() => {
+ getContentWidth()
+ })
+ resizeObserver.observe(containerRef.current)
+ return () => {
+ resizeObserver.disconnect()
+ }
+ }, [])
+
+ const handleSwitchSibling = useCallback((direction: 'prev' | 'next') => {
+ if (direction === 'prev')
+ item.prevSibling && switchSibling?.(item.prevSibling)
+ else
+ item.nextSibling && switchSibling?.(item.nextSibling)
+ }, [switchSibling, item.prevSibling, item.nextSibling])
+
+ return (
+ <div className='mb-2 flex last:mb-0'>
+ <div className='relative h-10 w-10 shrink-0'>
+ {answerIcon || <AnswerIcon />}
+ {responding && (
+ <div className='absolute left-[-3px] top-[-3px] flex h-4 w-4 items-center rounded-full border-[0.5px] border-divider-subtle bg-background-section-burn pl-[6px] shadow-xs'>
+ <LoadingAnim type='avatar' />
+ </div>
+ )}
+ </div>
+ <div className='chat-answer-container group ml-4 w-0 grow pb-4' ref={containerRef}>
+ <div className={cn('group relative pr-10', chatAnswerContainerInner)}>
+ <div
+ ref={contentRef}
+ className={cn('body-lg-regular relative inline-block max-w-full rounded-2xl bg-chat-bubble-bg px-4 py-3 text-text-primary', workflowProcess && 'w-full')}
+ >
+ {
+ !responding && (
+ <Operation
+ hasWorkflowProcess={!!workflowProcess}
+ maxSize={containerWidth - contentWidth - 4}
+ contentWidth={contentWidth}
+ item={item}
+ question={question}
+ index={index}
+ showPromptLog={showPromptLog}
+ noChatInput={noChatInput}
+ />
+ )
+ }
+ {/** Render the normal steps */}
+ {
+ workflowProcess && !hideProcessDetail && (
+ <WorkflowProcessItem
+ data={workflowProcess}
+ item={item}
+ hideProcessDetail={hideProcessDetail}
+ />
+ )
+ }
+ {/** Hide workflow steps by it's settings in siteInfo */}
+ {
+ workflowProcess && hideProcessDetail && appData && (
+ <WorkflowProcessItem
+ data={workflowProcess}
+ item={item}
+ hideProcessDetail={hideProcessDetail}
+ readonly={!appData.site.show_workflow_steps}
+ />
+ )
+ }
+ {
+ responding && !content && !hasAgentThoughts && (
+ <div className='flex h-5 w-6 items-center justify-center'>
+ <LoadingAnim type='text' />
+ </div>
+ )
+ }
+ {
+ content && !hasAgentThoughts && (
+ <BasicContent item={item} />
+ )
+ }
+ {
+ (hasAgentThoughts) && (
+ <AgentContent
+ item={item}
+ responding={responding}
+ content={content}
+ />
+ )
+ }
+ {
+ !!allFiles?.length && (
+ <FileList
+ className='my-1'
+ files={allFiles}
+ showDeleteAction={false}
+ showDownloadAction
+ canPreview
+ />
+ )
+ }
+ {
+ !!message_files?.length && (
+ <FileList
+ className='my-1'
+ files={message_files}
+ showDeleteAction={false}
+ showDownloadAction
+ canPreview
+ />
+ )
+ }
+ {
+ annotation?.id && annotation.authorName && (
+ <EditTitle
+ className='mt-1'
+ title={t('appAnnotation.editBy', { author: annotation.authorName })}
+ />
+ )
+ }
+ <SuggestedQuestions item={item} />
+ {
+ !!citation?.length && !responding && (
+ <Citation data={citation} showHitInfo={config?.supportCitationHitInfo} />
+ )
+ }
+ {
+ item.siblingCount && item.siblingCount > 1 && item.siblingIndex !== undefined && (
+ <ContentSwitch
+ count={item.siblingCount}
+ currentIndex={item.siblingIndex}
+ prevDisabled={!item.prevSibling}
+ nextDisabled={!item.nextSibling}
+ switchSibling={handleSwitchSibling}
+ />
+ )
+ }
+ </div>
+ </div>
+ <More more={more} />
+ </div>
+ </div>
+ )
+}
+
+export default memo(Answer, (prevProps, nextProps) =>
+ prevProps.responding === false && nextProps.responding === false,
+)
diff --git a/app/components/base/chat/chat/answer/more.tsx b/app/components/base/chat/chat/answer/more.tsx
new file mode 100644
index 0000000..e86011e
--- /dev/null
+++ b/app/components/base/chat/chat/answer/more.tsx
@@ -0,0 +1,46 @@
+import type { FC } from 'react'
+import { memo } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { ChatItem } from '../../types'
+import { formatNumber } from '@/utils/format'
+
+type MoreProps = {
+ more: ChatItem['more']
+}
+const More: FC<MoreProps> = ({
+ more,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='system-xs-regular mt-1 flex items-center text-text-quaternary opacity-0 group-hover:opacity-100'>
+ {
+ more && (
+ <>
+ <div
+ className='mr-2 max-w-[33.3%] shrink-0 truncate'
+ title={`${t('appLog.detail.timeConsuming')} ${more.latency}${t('appLog.detail.second')}`}
+ >
+ {`${t('appLog.detail.timeConsuming')} ${more.latency}${t('appLog.detail.second')}`}
+ </div>
+ <div
+ className='max-w-[33.3%] shrink-0 truncate'
+ title={`${t('appLog.detail.tokenCost')} ${formatNumber(more.tokens)}`}
+ >
+ {`${t('appLog.detail.tokenCost')} ${formatNumber(more.tokens)}`}
+ </div>
+ <div className='mx-2 shrink-0'>路</div>
+ <div
+ className='max-w-[33.3%] shrink-0 truncate'
+ title={more.time}
+ >
+ {more.time}
+ </div>
+ </>
+ )
+ }
+ </div>
+ )
+}
+
+export default memo(More)
diff --git a/app/components/base/chat/chat/answer/operation.tsx b/app/components/base/chat/chat/answer/operation.tsx
new file mode 100644
index 0000000..0fbb7ce
--- /dev/null
+++ b/app/components/base/chat/chat/answer/operation.tsx
@@ -0,0 +1,195 @@
+import type { FC } from 'react'
+import {
+ memo,
+ useMemo,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiClipboardLine,
+ RiResetLeftLine,
+ RiThumbDownLine,
+ RiThumbUpLine,
+} from '@remixicon/react'
+import type { ChatItem } from '../../types'
+import { useChatContext } from '../context'
+import copy from 'copy-to-clipboard'
+import Toast from '@/app/components/base/toast'
+import AnnotationCtrlButton from '@/app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button'
+import EditReplyModal from '@/app/components/app/annotation/edit-annotation-modal'
+import Log from '@/app/components/base/chat/chat/log'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+import NewAudioButton from '@/app/components/base/new-audio-button'
+import cn from '@/utils/classnames'
+
+type OperationProps = {
+ item: ChatItem
+ question: string
+ index: number
+ showPromptLog?: boolean
+ maxSize: number
+ contentWidth: number
+ hasWorkflowProcess: boolean
+ noChatInput?: boolean
+}
+const Operation: FC<OperationProps> = ({
+ item,
+ question,
+ index,
+ showPromptLog,
+ maxSize,
+ contentWidth,
+ hasWorkflowProcess,
+ noChatInput,
+}) => {
+ const { t } = useTranslation()
+ const {
+ config,
+ onAnnotationAdded,
+ onAnnotationEdited,
+ onAnnotationRemoved,
+ onFeedback,
+ onRegenerate,
+ } = useChatContext()
+ const [isShowReplyModal, setIsShowReplyModal] = useState(false)
+ const {
+ id,
+ isOpeningStatement,
+ content: messageContent,
+ annotation,
+ feedback,
+ adminFeedback,
+ agent_thoughts,
+ } = item
+ const [localFeedback, setLocalFeedback] = useState(config?.supportAnnotation ? adminFeedback : feedback)
+
+ const content = useMemo(() => {
+ if (agent_thoughts?.length)
+ return agent_thoughts.reduce((acc, cur) => acc + cur.thought, '')
+
+ return messageContent
+ }, [agent_thoughts, messageContent])
+
+ const handleFeedback = async (rating: 'like' | 'dislike' | null) => {
+ if (!config?.supportFeedback || !onFeedback)
+ return
+
+ await onFeedback?.(id, { rating })
+ setLocalFeedback({ rating })
+ }
+
+ const operationWidth = useMemo(() => {
+ let width = 0
+ if (!isOpeningStatement)
+ width += 26
+ if (!isOpeningStatement && showPromptLog)
+ width += 28 + 8
+ if (!isOpeningStatement && config?.text_to_speech?.enabled)
+ width += 26
+ if (!isOpeningStatement && config?.supportAnnotation && config?.annotation_reply?.enabled)
+ width += 26
+ if (config?.supportFeedback && !localFeedback?.rating && onFeedback && !isOpeningStatement)
+ width += 60 + 8
+ if (config?.supportFeedback && localFeedback?.rating && onFeedback && !isOpeningStatement)
+ width += 28 + 8
+ return width
+ }, [isOpeningStatement, showPromptLog, config?.text_to_speech?.enabled, config?.supportAnnotation, config?.annotation_reply?.enabled, config?.supportFeedback, localFeedback?.rating, onFeedback])
+
+ const positionRight = useMemo(() => operationWidth < maxSize, [operationWidth, maxSize])
+
+ return (
+ <>
+ <div
+ className={cn(
+ 'absolute flex justify-end gap-1',
+ hasWorkflowProcess && '-bottom-4 right-2',
+ !positionRight && '-bottom-4 right-2',
+ !hasWorkflowProcess && positionRight && '!top-[9px]',
+ )}
+ style={(!hasWorkflowProcess && positionRight) ? { left: contentWidth + 8 } : {}}
+ >
+ {showPromptLog && !isOpeningStatement && (
+ <div className='hidden group-hover:block'>
+ <Log logItem={item} />
+ </div>
+ )}
+ {!isOpeningStatement && (
+ <div className='ml-1 hidden items-center gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm group-hover:flex'>
+ {(config?.text_to_speech?.enabled) && (
+ <NewAudioButton
+ id={id}
+ value={content}
+ voice={config?.text_to_speech?.voice}
+ />
+ )}
+ <ActionButton onClick={() => {
+ copy(content)
+ Toast.notify({ type: 'success', message: t('common.actionMsg.copySuccessfully') })
+ }}>
+ <RiClipboardLine className='h-4 w-4' />
+ </ActionButton>
+ {!noChatInput && (
+ <ActionButton onClick={() => onRegenerate?.(item)}>
+ <RiResetLeftLine className='h-4 w-4' />
+ </ActionButton>
+ )}
+ {(config?.supportAnnotation && config.annotation_reply?.enabled) && (
+ <AnnotationCtrlButton
+ appId={config?.appId || ''}
+ messageId={id}
+ cached={!!annotation?.id}
+ query={question}
+ answer={content}
+ onAdded={(id, authorName) => onAnnotationAdded?.(id, authorName, question, content, index)}
+ onEdit={() => setIsShowReplyModal(true)}
+ />
+ )}
+ </div>
+ )}
+ {!isOpeningStatement && config?.supportFeedback && !localFeedback?.rating && onFeedback && (
+ <div className='ml-1 hidden items-center gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm group-hover:flex'>
+ {!localFeedback?.rating && (
+ <>
+ <ActionButton onClick={() => handleFeedback('like')}>
+ <RiThumbUpLine className='h-4 w-4' />
+ </ActionButton>
+ <ActionButton onClick={() => handleFeedback('dislike')}>
+ <RiThumbDownLine className='h-4 w-4' />
+ </ActionButton>
+ </>
+ )}
+ </div>
+ )}
+ {!isOpeningStatement && config?.supportFeedback && localFeedback?.rating && onFeedback && (
+ <div className='ml-1 flex items-center gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm'>
+ {localFeedback?.rating === 'like' && (
+ <ActionButton state={ActionButtonState.Active} onClick={() => handleFeedback(null)}>
+ <RiThumbUpLine className='h-4 w-4' />
+ </ActionButton>
+ )}
+ {localFeedback?.rating === 'dislike' && (
+ <ActionButton state={ActionButtonState.Destructive} onClick={() => handleFeedback(null)}>
+ <RiThumbDownLine className='h-4 w-4' />
+ </ActionButton>
+ )}
+ </div>
+ )}
+ </div>
+ <EditReplyModal
+ isShow={isShowReplyModal}
+ onHide={() => setIsShowReplyModal(false)}
+ query={question}
+ answer={content}
+ onEdited={(editedQuery, editedAnswer) => onAnnotationEdited?.(editedQuery, editedAnswer, index)}
+ onAdded={(annotationId, authorName, editedQuery, editedAnswer) => onAnnotationAdded?.(annotationId, authorName, editedQuery, editedAnswer, index)}
+ appId={config?.appId || ''}
+ messageId={id}
+ annotationId={annotation?.id || ''}
+ createdAt={annotation?.created_at}
+ onRemove={() => onAnnotationRemoved?.(index)}
+ />
+ </>
+ )
+}
+
+export default memo(Operation)
diff --git a/app/components/base/chat/chat/answer/suggested-questions.tsx b/app/components/base/chat/chat/answer/suggested-questions.tsx
new file mode 100644
index 0000000..8b64bff
--- /dev/null
+++ b/app/components/base/chat/chat/answer/suggested-questions.tsx
@@ -0,0 +1,37 @@
+import type { FC } from 'react'
+import { memo } from 'react'
+import type { ChatItem } from '../../types'
+import { useChatContext } from '../context'
+
+type SuggestedQuestionsProps = {
+ item: ChatItem
+}
+const SuggestedQuestions: FC<SuggestedQuestionsProps> = ({
+ item,
+}) => {
+ const { onSend } = useChatContext()
+
+ const {
+ isOpeningStatement,
+ suggestedQuestions,
+ } = item
+
+ if (!isOpeningStatement || !suggestedQuestions?.length)
+ return null
+
+ return (
+ <div className='flex flex-wrap'>
+ {suggestedQuestions.filter(q => !!q && q.trim()).map((question, index) => (
+ <div
+ key={index}
+ className='system-sm-medium mr-1 mt-1 inline-flex max-w-full shrink-0 cursor-pointer flex-wrap rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-3.5 py-2 text-components-button-secondary-accent-text shadow-xs last:mr-0 hover:border-components-button-secondary-border-hover hover:bg-components-button-secondary-bg-hover'
+ onClick={() => onSend?.(question)}
+ >
+ {question}
+ </div>),
+ )}
+ </div>
+ )
+}
+
+export default memo(SuggestedQuestions)
diff --git a/app/components/base/chat/chat/answer/tool-detail.tsx b/app/components/base/chat/chat/answer/tool-detail.tsx
new file mode 100644
index 0000000..26d1b3b
--- /dev/null
+++ b/app/components/base/chat/chat/answer/tool-detail.tsx
@@ -0,0 +1,71 @@
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiArrowDownSLine,
+ RiArrowRightSLine,
+ RiHammerFill,
+ RiLoader2Line,
+} from '@remixicon/react'
+import type { ToolInfoInThought } from '../type'
+import cn from '@/utils/classnames'
+
+type ToolDetailProps = {
+ payload: ToolInfoInThought
+}
+const ToolDetail = ({
+ payload,
+}: ToolDetailProps) => {
+ const { t } = useTranslation()
+ const { name, label, input, isFinished, output } = payload
+ const toolLabel = name.startsWith('dataset_') ? t('dataset.knowledge') : label
+ const [expand, setExpand] = useState(false)
+
+ return (
+ <div
+ className={cn(
+ 'rounded-xl',
+ !expand && 'border-l-[0.25px] border-components-panel-border bg-workflow-process-bg',
+ expand && 'border-[0.5px] border-components-panel-border-subtle bg-background-section-burn',
+ )}
+ >
+ <div
+ className={cn(
+ 'system-xs-medium flex cursor-pointer items-center px-2.5 py-2 text-text-tertiary',
+ expand && 'pb-1.5',
+ )}
+ onClick={() => setExpand(!expand)}
+ >
+ {isFinished && <RiHammerFill className='mr-1 h-3.5 w-3.5' />}
+ {!isFinished && <RiLoader2Line className='mr-1 h-3.5 w-3.5 animate-spin' />}
+ {t(`tools.thought.${isFinished ? 'used' : 'using'}`)}
+ <div className='mx-1 text-text-secondary'>{toolLabel}</div>
+ {!expand && <RiArrowRightSLine className='h-4 w-4' />}
+ {expand && <RiArrowDownSLine className='ml-auto h-4 w-4' />}
+ </div>
+ {
+ expand && (
+ <>
+ <div className='mx-1 mb-0.5 rounded-[10px] bg-components-panel-on-panel-item-bg text-text-secondary'>
+ <div className='system-xs-semibold-uppercase flex h-7 items-center justify-between px-2 pt-1'>
+ {t('tools.thought.requestTitle')}
+ </div>
+ <div className='code-xs-regular break-words px-3 pb-2 pt-1'>
+ {input}
+ </div>
+ </div>
+ <div className='mx-1 mb-1 rounded-[10px] bg-components-panel-on-panel-item-bg text-text-secondary'>
+ <div className='system-xs-semibold-uppercase flex h-7 items-center justify-between px-2 pt-1'>
+ {t('tools.thought.responseTitle')}
+ </div>
+ <div className='code-xs-regular break-words px-3 pb-2 pt-1'>
+ {output}
+ </div>
+ </div>
+ </>
+ )
+ }
+ </div>
+ )
+}
+
+export default ToolDetail
diff --git a/app/components/base/chat/chat/answer/workflow-process.tsx b/app/components/base/chat/chat/answer/workflow-process.tsx
new file mode 100644
index 0000000..4651ff4
--- /dev/null
+++ b/app/components/base/chat/chat/answer/workflow-process.tsx
@@ -0,0 +1,94 @@
+import {
+ useEffect,
+ useState,
+} from 'react'
+import {
+ RiArrowRightSLine,
+ RiErrorWarningFill,
+ RiLoader2Line,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import type { ChatItem, WorkflowProcess } from '../../types'
+import TracingPanel from '@/app/components/workflow/run/tracing-panel'
+import cn from '@/utils/classnames'
+import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/general'
+import { WorkflowRunningStatus } from '@/app/components/workflow/types'
+
+type WorkflowProcessProps = {
+ data: WorkflowProcess
+ item?: ChatItem
+ expand?: boolean
+ hideInfo?: boolean
+ hideProcessDetail?: boolean
+ readonly?: boolean
+}
+const WorkflowProcessItem = ({
+ data,
+ expand = false,
+ hideInfo = false,
+ hideProcessDetail = false,
+ readonly = false,
+}: WorkflowProcessProps) => {
+ const { t } = useTranslation()
+ const [collapse, setCollapse] = useState(!expand)
+ const running = data.status === WorkflowRunningStatus.Running
+ const succeeded = data.status === WorkflowRunningStatus.Succeeded
+ const failed = data.status === WorkflowRunningStatus.Failed || data.status === WorkflowRunningStatus.Stopped
+
+ useEffect(() => {
+ setCollapse(!expand)
+ }, [expand])
+
+ return (
+ <div
+ className={cn(
+ '-mx-1 rounded-xl px-2.5',
+ collapse ? 'border-l-[0.25px] border-components-panel-border py-[7px]' : 'border-[0.5px] border-components-panel-border-subtle px-1 pb-1 pt-[7px]',
+ running && !collapse && 'bg-background-section-burn',
+ succeeded && !collapse && 'bg-state-success-hover',
+ failed && !collapse && 'bg-state-destructive-hover',
+ collapse && 'bg-workflow-process-bg',
+ )}
+ >
+ <div
+ className={cn('flex cursor-pointer items-center', !collapse && 'px-1.5', readonly && 'cursor-default')}
+ onClick={() => !readonly && setCollapse(!collapse)}
+ >
+ {
+ running && (
+ <RiLoader2Line className='mr-1 h-3.5 w-3.5 shrink-0 animate-spin text-text-tertiary' />
+ )
+ }
+ {
+ succeeded && (
+ <CheckCircle className='mr-1 h-3.5 w-3.5 shrink-0 text-text-success' />
+ )
+ }
+ {
+ failed && (
+ <RiErrorWarningFill className='mr-1 h-3.5 w-3.5 shrink-0 text-text-destructive' />
+ )
+ }
+ <div className={cn('system-xs-medium text-text-secondary', !collapse && 'grow')}>
+ {t('workflow.common.workflowProcess')}
+ </div>
+ {!readonly && <RiArrowRightSLine className={cn('ml-1 h-4 w-4 text-text-tertiary', !collapse && 'rotate-90')} />}
+ </div>
+ {
+ !collapse && !readonly && (
+ <div className='mt-1.5'>
+ {
+ <TracingPanel
+ list={data.tracing}
+ hideNodeInfo={hideInfo}
+ hideNodeProcessDetail={hideProcessDetail}
+ />
+ }
+ </div>
+ )
+ }
+ </div>
+ )
+}
+
+export default WorkflowProcessItem
diff --git a/app/components/base/chat/chat/chat-input-area/hooks.ts b/app/components/base/chat/chat/chat-input-area/hooks.ts
new file mode 100644
index 0000000..6b6e801
--- /dev/null
+++ b/app/components/base/chat/chat/chat-input-area/hooks.ts
@@ -0,0 +1,46 @@
+import {
+ useCallback,
+ useRef,
+ useState,
+} from 'react'
+
+export const useTextAreaHeight = () => {
+ const wrapperRef = useRef<HTMLDivElement>(null)
+ const textareaRef = useRef<HTMLTextAreaElement | undefined>(undefined)
+ const textValueRef = useRef<HTMLDivElement>(null)
+ const holdSpaceRef = useRef<HTMLDivElement>(null)
+ const [isMultipleLine, setIsMultipleLine] = useState(false)
+
+ const handleComputeHeight = useCallback(() => {
+ const textareaElement = textareaRef.current
+
+ if (wrapperRef.current && textareaElement && textValueRef.current && holdSpaceRef.current) {
+ const { width: wrapperWidth } = wrapperRef.current.getBoundingClientRect()
+ const { height: textareaHeight } = textareaElement.getBoundingClientRect()
+ const { width: textValueWidth } = textValueRef.current.getBoundingClientRect()
+ const { width: holdSpaceWidth } = holdSpaceRef.current.getBoundingClientRect()
+ if (textareaHeight > 32) {
+ setIsMultipleLine(true)
+ }
+ else {
+ if (textValueWidth + holdSpaceWidth >= wrapperWidth)
+ setIsMultipleLine(true)
+ else
+ setIsMultipleLine(false)
+ }
+ }
+ }, [])
+
+ const handleTextareaResize = useCallback(() => {
+ handleComputeHeight()
+ }, [handleComputeHeight])
+
+ return {
+ wrapperRef,
+ textareaRef,
+ textValueRef,
+ holdSpaceRef,
+ handleTextareaResize,
+ isMultipleLine,
+ }
+}
diff --git a/app/components/base/chat/chat/chat-input-area/index.tsx b/app/components/base/chat/chat/chat-input-area/index.tsx
new file mode 100644
index 0000000..14d8185
--- /dev/null
+++ b/app/components/base/chat/chat/chat-input-area/index.tsx
@@ -0,0 +1,246 @@
+import {
+ useCallback,
+ useRef,
+ useState,
+} from 'react'
+import Textarea from 'react-textarea-autosize'
+import { useTranslation } from 'react-i18next'
+import Recorder from 'js-audio-recorder'
+import type {
+ EnableType,
+ OnSend,
+} from '../../types'
+import type { Theme } from '../../embedded-chatbot/theme/theme-context'
+import type { InputForm } from '../type'
+import { useCheckInputsForms } from '../check-input-forms-hooks'
+import { useTextAreaHeight } from './hooks'
+import Operation from './operation'
+import cn from '@/utils/classnames'
+import { FileListInChatInput } from '@/app/components/base/file-uploader'
+import { useFile } from '@/app/components/base/file-uploader/hooks'
+import {
+ FileContextProvider,
+ useFileStore,
+} from '@/app/components/base/file-uploader/store'
+import VoiceInput from '@/app/components/base/voice-input'
+import { useToastContext } from '@/app/components/base/toast'
+import FeatureBar from '@/app/components/base/features/new-feature-panel/feature-bar'
+import type { FileUpload } from '@/app/components/base/features/types'
+import { TransferMethod } from '@/types/app'
+
+type ChatInputAreaProps = {
+ showFeatureBar?: boolean
+ showFileUpload?: boolean
+ featureBarDisabled?: boolean
+ onFeatureBarClick?: (state: boolean) => void
+ visionConfig?: FileUpload
+ speechToTextConfig?: EnableType
+ onSend?: OnSend
+ inputs?: Record<string, any>
+ inputsForm?: InputForm[]
+ theme?: Theme | null
+ isResponding?: boolean
+ disabled?: boolean
+}
+const ChatInputArea = ({
+ showFeatureBar,
+ showFileUpload,
+ featureBarDisabled,
+ onFeatureBarClick,
+ visionConfig,
+ speechToTextConfig = { enabled: true },
+ onSend,
+ inputs = {},
+ inputsForm = [],
+ theme,
+ isResponding,
+ disabled,
+}: ChatInputAreaProps) => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const {
+ wrapperRef,
+ textareaRef,
+ textValueRef,
+ holdSpaceRef,
+ handleTextareaResize,
+ isMultipleLine,
+ } = useTextAreaHeight()
+ const [query, setQuery] = useState('')
+ const [showVoiceInput, setShowVoiceInput] = useState(false)
+ const filesStore = useFileStore()
+ const {
+ handleDragFileEnter,
+ handleDragFileLeave,
+ handleDragFileOver,
+ handleDropFile,
+ handleClipboardPasteFile,
+ isDragActive,
+ } = useFile(visionConfig!)
+ const { checkInputsForm } = useCheckInputsForms()
+ const historyRef = useRef([''])
+ const [currentIndex, setCurrentIndex] = useState(-1)
+ const isComposingRef = useRef(false)
+ const handleSend = () => {
+ if (isResponding) {
+ notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
+ return
+ }
+
+ if (onSend) {
+ const { files, setFiles } = filesStore.getState()
+ if (files.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId)) {
+ notify({ type: 'info', message: t('appDebug.errorMessage.waitForFileUpload') })
+ return
+ }
+ if (!query || !query.trim()) {
+ notify({ type: 'info', message: t('appAnnotation.errorMessage.queryRequired') })
+ return
+ }
+ if (checkInputsForm(inputs, inputsForm)) {
+ onSend(query, files)
+ setQuery('')
+ setFiles([])
+ }
+ }
+ }
+ const handleCompositionStart = () => {
+ // e: React.CompositionEvent<HTMLTextAreaElement>
+ isComposingRef.current = true
+ }
+ const handleCompositionEnd = () => {
+ // safari or some browsers will trigger compositionend before keydown.
+ // delay 50ms for safari.
+ setTimeout(() => {
+ isComposingRef.current = false
+ }, 50)
+ }
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
+ if (e.key === 'Enter' && !e.shiftKey && !e.nativeEvent.isComposing) {
+ // if isComposing, exit
+ if (isComposingRef.current) return
+ e.preventDefault()
+ setQuery(query.replace(/\n$/, ''))
+ historyRef.current.push(query)
+ setCurrentIndex(historyRef.current.length)
+ handleSend()
+ }
+ else if (e.key === 'ArrowUp' && !e.shiftKey && !e.nativeEvent.isComposing && e.metaKey) {
+ // When the cmd + up key is pressed, output the previous element
+ if (currentIndex > 0) {
+ setCurrentIndex(currentIndex - 1)
+ setQuery(historyRef.current[currentIndex - 1])
+ }
+ }
+ else if (e.key === 'ArrowDown' && !e.shiftKey && !e.nativeEvent.isComposing && e.metaKey) {
+ // When the cmd + down key is pressed, output the next element
+ if (currentIndex < historyRef.current.length - 1) {
+ setCurrentIndex(currentIndex + 1)
+ setQuery(historyRef.current[currentIndex + 1])
+ }
+ else if (currentIndex === historyRef.current.length - 1) {
+ // If it is the last element, clear the input box
+ setCurrentIndex(historyRef.current.length)
+ setQuery('')
+ }
+ }
+ }
+
+ const handleShowVoiceInput = useCallback(() => {
+ (Recorder as any).getPermission().then(() => {
+ setShowVoiceInput(true)
+ }, () => {
+ notify({ type: 'error', message: t('common.voiceInput.notAllow') })
+ })
+ }, [t, notify])
+
+ const operation = (
+ <Operation
+ ref={holdSpaceRef}
+ fileConfig={visionConfig}
+ speechToTextConfig={speechToTextConfig}
+ onShowVoiceInput={handleShowVoiceInput}
+ onSend={handleSend}
+ theme={theme}
+ />
+ )
+
+ return (
+ <>
+ <div
+ className={cn(
+ 'relative z-10 rounded-xl border border-components-chat-input-border bg-components-panel-bg-blur pb-[9px] shadow-md',
+ isDragActive && 'border border-dashed border-components-option-card-option-selected-border',
+ disabled && 'pointer-events-none border-components-panel-border opacity-50 shadow-none',
+ )}
+ >
+ <div className='relative max-h-[158px] overflow-y-auto overflow-x-hidden px-[9px] pt-[9px]'>
+ <FileListInChatInput fileConfig={visionConfig!} />
+ <div
+ ref={wrapperRef}
+ className='flex items-center justify-between'
+ >
+ <div className='relative flex w-full grow items-center'>
+ <div
+ ref={textValueRef}
+ className='body-lg-regular pointer-events-none invisible absolute h-auto w-auto whitespace-pre p-1 leading-6'
+ >
+ {query}
+ </div>
+ <Textarea
+ ref={ref => textareaRef.current = ref as any}
+ className={cn(
+ 'body-lg-regular w-full resize-none bg-transparent p-1 leading-6 text-text-tertiary outline-none',
+ )}
+ placeholder={t('common.chat.inputPlaceholder') || ''}
+ autoFocus
+ minRows={1}
+ onResize={handleTextareaResize}
+ value={query}
+ onChange={(e) => {
+ setQuery(e.target.value)
+ setTimeout(handleTextareaResize, 0)
+ }}
+ onKeyDown={handleKeyDown}
+ onCompositionStart={handleCompositionStart}
+ onCompositionEnd={handleCompositionEnd}
+ onPaste={handleClipboardPasteFile}
+ onDragEnter={handleDragFileEnter}
+ onDragLeave={handleDragFileLeave}
+ onDragOver={handleDragFileOver}
+ onDrop={handleDropFile}
+ />
+ </div>
+ {
+ !isMultipleLine && operation
+ }
+ </div>
+ {
+ showVoiceInput && (
+ <VoiceInput
+ onCancel={() => setShowVoiceInput(false)}
+ onConverted={text => setQuery(text)}
+ />
+ )
+ }
+ </div>
+ {
+ isMultipleLine && (
+ <div className='px-[9px]'>{operation}</div>
+ )
+ }
+ </div>
+ {showFeatureBar && <FeatureBar showFileUpload={showFileUpload} disabled={featureBarDisabled} onFeatureBarClick={onFeatureBarClick} />}
+ </>
+ )
+}
+
+const ChatInputAreaWrapper = (props: ChatInputAreaProps) => {
+ return (
+ <FileContextProvider>
+ <ChatInputArea {...props} />
+ </FileContextProvider>
+ )
+}
+
+export default ChatInputAreaWrapper
diff --git a/app/components/base/chat/chat/chat-input-area/operation.tsx b/app/components/base/chat/chat/chat-input-area/operation.tsx
new file mode 100644
index 0000000..122dfcb
--- /dev/null
+++ b/app/components/base/chat/chat/chat-input-area/operation.tsx
@@ -0,0 +1,78 @@
+import { memo } from 'react'
+import {
+ RiMicLine,
+ RiSendPlane2Fill,
+} from '@remixicon/react'
+import type {
+ EnableType,
+} from '../../types'
+import type { Theme } from '../../embedded-chatbot/theme/theme-context'
+import Button from '@/app/components/base/button'
+import ActionButton from '@/app/components/base/action-button'
+import { FileUploaderInChatInput } from '@/app/components/base/file-uploader'
+import type { FileUpload } from '@/app/components/base/features/types'
+import cn from '@/utils/classnames'
+
+type OperationProps = {
+ fileConfig?: FileUpload
+ speechToTextConfig?: EnableType
+ onShowVoiceInput?: () => void
+ onSend: () => void
+ theme?: Theme | null
+}
+const Operation = (
+ {
+ ref,
+ fileConfig,
+ speechToTextConfig,
+ onShowVoiceInput,
+ onSend,
+ theme,
+ }: OperationProps & {
+ ref: React.RefObject<HTMLDivElement>;
+ },
+) => {
+ return (
+ <div
+ className={cn(
+ 'flex shrink-0 items-center justify-end',
+ )}
+ >
+ <div
+ className='flex items-center pl-1'
+ ref={ref}
+ >
+ <div className='flex items-center space-x-1'>
+ {fileConfig?.enabled && <FileUploaderInChatInput fileConfig={fileConfig} />}
+ {
+ speechToTextConfig?.enabled && (
+ <ActionButton
+ size='l'
+ onClick={onShowVoiceInput}
+ >
+ <RiMicLine className='h-5 w-5' />
+ </ActionButton>
+ )
+ }
+ </div>
+ <Button
+ className='ml-3 w-8 px-0'
+ variant='primary'
+ onClick={onSend}
+ style={
+ theme
+ ? {
+ backgroundColor: theme.primaryColor,
+ }
+ : {}
+ }
+ >
+ <RiSendPlane2Fill className='h-4 w-4' />
+ </Button>
+ </div>
+ </div>
+ )
+}
+Operation.displayName = 'Operation'
+
+export default memo(Operation)
diff --git a/app/components/base/chat/chat/check-input-forms-hooks.ts b/app/components/base/chat/chat/check-input-forms-hooks.ts
new file mode 100644
index 0000000..62c59a0
--- /dev/null
+++ b/app/components/base/chat/chat/check-input-forms-hooks.ts
@@ -0,0 +1,54 @@
+import { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { InputForm } from './type'
+import { useToastContext } from '@/app/components/base/toast'
+import { InputVarType } from '@/app/components/workflow/types'
+import { TransferMethod } from '@/types/app'
+
+export const useCheckInputsForms = () => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+
+ const checkInputsForm = useCallback((inputs: Record<string, any>, inputsForm: InputForm[]) => {
+ let hasEmptyInput = ''
+ let fileIsUploading = false
+ const requiredVars = inputsForm.filter(({ required }) => required)
+
+ if (requiredVars?.length) {
+ requiredVars.forEach(({ variable, label, type }) => {
+ if (hasEmptyInput)
+ return
+
+ if (fileIsUploading)
+ return
+
+ if (!inputs[variable])
+ hasEmptyInput = label as string
+
+ if ((type === InputVarType.singleFile || type === InputVarType.multiFiles) && inputs[variable]) {
+ const files = inputs[variable]
+ if (Array.isArray(files))
+ fileIsUploading = files.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId)
+ else
+ fileIsUploading = files.transferMethod === TransferMethod.local_file && !files.uploadedId
+ }
+ })
+ }
+
+ if (hasEmptyInput) {
+ notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }) })
+ return false
+ }
+
+ if (fileIsUploading) {
+ notify({ type: 'info', message: t('appDebug.errorMessage.waitForFileUpload') })
+ return
+ }
+
+ return true
+ }, [notify, t])
+
+ return {
+ checkInputsForm,
+ }
+}
diff --git a/app/components/base/chat/chat/citation/index.tsx b/app/components/base/chat/chat/citation/index.tsx
new file mode 100644
index 0000000..9552492
--- /dev/null
+++ b/app/components/base/chat/chat/citation/index.tsx
@@ -0,0 +1,125 @@
+import { useEffect, useMemo, useRef, useState } from 'react'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowDownSLine } from '@remixicon/react'
+import type { CitationItem } from '../type'
+import Popup from './popup'
+
+export type Resources = {
+ documentId: string
+ documentName: string
+ dataSourceType: string
+ sources: CitationItem[]
+}
+
+type CitationProps = {
+ data: CitationItem[]
+ showHitInfo?: boolean
+ containerClassName?: string
+}
+const Citation: FC<CitationProps> = ({
+ data,
+ showHitInfo,
+ containerClassName = 'chat-answer-container',
+}) => {
+ const { t } = useTranslation()
+ const elesRef = useRef<HTMLDivElement[]>([])
+ const [limitNumberInOneLine, setLimitNumberInOneLine] = useState(0)
+ const [showMore, setShowMore] = useState(false)
+ const resources = useMemo(() => data.reduce((prev: Resources[], next) => {
+ const documentId = next.document_id
+ const documentName = next.document_name
+ const dataSourceType = next.data_source_type
+ const documentIndex = prev.findIndex(i => i.documentId === documentId)
+
+ if (documentIndex > -1) {
+ prev[documentIndex].sources.push(next)
+ }
+ else {
+ prev.push({
+ documentId,
+ documentName,
+ dataSourceType,
+ sources: [next],
+ })
+ }
+
+ return prev
+ }, []), [data])
+
+ const handleAdjustResourcesLayout = () => {
+ const containerWidth = document.querySelector(`.${containerClassName}`)!.clientWidth - 40
+ let totalWidth = 0
+ for (let i = 0; i < resources.length; i++) {
+ totalWidth += elesRef.current[i].clientWidth
+
+ if (totalWidth + i * 4 > containerWidth!) {
+ totalWidth -= elesRef.current[i].clientWidth
+
+ if (totalWidth + 34 > containerWidth!)
+ setLimitNumberInOneLine(i - 1)
+ else
+ setLimitNumberInOneLine(i)
+
+ break
+ }
+ else {
+ setLimitNumberInOneLine(i + 1)
+ }
+ }
+ }
+
+ useEffect(() => {
+ handleAdjustResourcesLayout()
+ }, [])
+
+ const resourcesLength = resources.length
+
+ return (
+ <div className='-mb-1 mt-3'>
+ <div className='system-xs-medium mb-2 flex items-center text-text-tertiary'>
+ {t('common.chat.citation.title')}
+ <div className='ml-2 h-[1px] grow bg-divider-regular' />
+ </div>
+ <div className='relative flex flex-wrap'>
+ {
+ resources.map((res, index) => (
+ <div
+ key={index}
+ className='absolute left-0 top-0 -z-10 mb-1 mr-1 h-7 w-auto max-w-[240px] whitespace-nowrap pl-7 pr-2 text-xs opacity-0'
+ ref={(ele: any) => (elesRef.current[index] = ele!)}
+ >
+ {res.documentName}
+ </div>
+ ))
+ }
+ {
+ resources.slice(0, showMore ? resourcesLength : limitNumberInOneLine).map((res, index) => (
+ <div key={index} className='mb-1 mr-1 cursor-pointer'>
+ <Popup
+ data={res}
+ showHitInfo={showHitInfo}
+ />
+ </div>
+ ))
+ }
+ {
+ limitNumberInOneLine < resourcesLength && (
+ <div
+ className='system-xs-medium flex h-7 cursor-pointer items-center rounded-lg bg-components-panel-bg px-2 text-text-tertiary'
+ onClick={() => setShowMore(v => !v)}
+ >
+ {
+ !showMore
+ ? `+ ${resourcesLength - limitNumberInOneLine}`
+ : <RiArrowDownSLine className='h-4 w-4 rotate-180 text-text-tertiary' />
+ }
+ </div>
+ )
+ }
+ </div>
+ </div>
+ )
+}
+
+export default Citation
diff --git a/app/components/base/chat/chat/citation/popup.tsx b/app/components/base/chat/chat/citation/popup.tsx
new file mode 100644
index 0000000..c26f427
--- /dev/null
+++ b/app/components/base/chat/chat/citation/popup.tsx
@@ -0,0 +1,131 @@
+import { Fragment, useState } from 'react'
+import type { FC } from 'react'
+import Link from 'next/link'
+import { useTranslation } from 'react-i18next'
+import Tooltip from './tooltip'
+import ProgressTooltip from './progress-tooltip'
+import type { Resources } from './index'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import FileIcon from '@/app/components/base/file-icon'
+import {
+ Hash02,
+ Target04,
+} from '@/app/components/base/icons/src/vender/line/general'
+import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows'
+import {
+ BezierCurve03,
+ TypeSquare,
+} from '@/app/components/base/icons/src/vender/line/editor'
+
+type PopupProps = {
+ data: Resources
+ showHitInfo?: boolean
+}
+
+const Popup: FC<PopupProps> = ({
+ data,
+ showHitInfo = false,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const fileType = data.dataSourceType !== 'notion'
+ ? (/\.([^.]*)$/g.exec(data.documentName)?.[1] || '')
+ : 'notion'
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='top-start'
+ offset={{
+ mainAxis: 8,
+ crossAxis: -2,
+ }}
+ >
+ <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
+ <div className='flex h-7 max-w-[240px] items-center rounded-lg bg-components-button-secondary-bg px-2'>
+ <FileIcon type={fileType} className='mr-1 h-4 w-4 shrink-0' />
+ <div className='truncate text-xs text-text-tertiary'>{data.documentName}</div>
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 1000 }}>
+ <div className='max-w-[360px] rounded-xl bg-background-section-burn shadow-lg'>
+ <div className='px-4 pb-2 pt-3'>
+ <div className='flex h-[18px] items-center'>
+ <FileIcon type={fileType} className='mr-1 h-4 w-4 shrink-0' />
+ <div className='system-xs-medium truncate text-text-tertiary'>{data.documentName}</div>
+ </div>
+ </div>
+ <div className='max-h-[450px] overflow-y-auto rounded-lg bg-components-panel-bg px-4 py-0.5'>
+ <div className='w-full'>
+ {
+ data.sources.map((source, index) => (
+ <Fragment key={index}>
+ <div className='group py-3'>
+ <div className='mb-2 flex items-center justify-between'>
+ <div className='flex h-5 items-center rounded-md border border-divider-subtle px-1.5'>
+ <Hash02 className='mr-0.5 h-3 w-3 text-text-quaternary' />
+ <div className='text-[11px] font-medium text-text-tertiary'>
+ {source.segment_position || index + 1}
+ </div>
+ </div>
+ {
+ showHitInfo && (
+ <Link
+ href={`/datasets/${source.dataset_id}/documents/${source.document_id}`}
+ className='hidden h-[18px] items-center text-xs text-text-accent group-hover:flex'>
+ {t('common.chat.citation.linkToDataset')}
+ <ArrowUpRight className='ml-1 h-3 w-3' />
+ </Link>
+ )
+ }
+ </div>
+ <div className='break-words text-[13px] text-text-secondary'>{source.content}</div>
+ {
+ showHitInfo && (
+ <div className='system-xs-medium mt-2 flex flex-wrap items-center text-text-quaternary'>
+ <Tooltip
+ text={t('common.chat.citation.characters')}
+ data={source.word_count}
+ icon={<TypeSquare className='mr-1 h-3 w-3' />}
+ />
+ <Tooltip
+ text={t('common.chat.citation.hitCount')}
+ data={source.hit_count}
+ icon={<Target04 className='mr-1 h-3 w-3' />}
+ />
+ <Tooltip
+ text={t('common.chat.citation.vectorHash')}
+ data={source.index_node_hash?.substring(0, 7)}
+ icon={<BezierCurve03 className='mr-1 h-3 w-3' />}
+ />
+ {
+ source.score && (
+ <ProgressTooltip data={Number(source.score.toFixed(2))} />
+ )
+ }
+ </div>
+ )
+ }
+ </div>
+ {
+ index !== data.sources.length - 1 && (
+ <div className='my-1 h-[1px] bg-divider-regular' />
+ )
+ }
+ </Fragment>
+ ))
+ }
+ </div>
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default Popup
diff --git a/app/components/base/chat/chat/citation/progress-tooltip.tsx b/app/components/base/chat/chat/citation/progress-tooltip.tsx
new file mode 100644
index 0000000..e1f2404
--- /dev/null
+++ b/app/components/base/chat/chat/citation/progress-tooltip.tsx
@@ -0,0 +1,46 @@
+import { useState } from 'react'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+
+type ProgressTooltipProps = {
+ data: number
+}
+
+const ProgressTooltip: FC<ProgressTooltipProps> = ({
+ data,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='top-start'
+ >
+ <PortalToFollowElemTrigger
+ onMouseEnter={() => setOpen(true)}
+ onMouseLeave={() => setOpen(false)}
+ >
+ <div className='flex grow items-center'>
+ <div className='mr-1 h-1.5 w-16 overflow-hidden rounded-[3px] border border-components-progress-gray-border'>
+ <div className='h-full bg-components-progress-gray-progress' style={{ width: `${data * 100}%` }}></div>
+ </div>
+ {data}
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 1001 }}>
+ <div className='system-xs-medium rounded-lg bg-components-tooltip-bg p-3 text-text-quaternary shadow-lg'>
+ {t('common.chat.citation.hitScore')} {data}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default ProgressTooltip
diff --git a/app/components/base/chat/chat/citation/tooltip.tsx b/app/components/base/chat/chat/citation/tooltip.tsx
new file mode 100644
index 0000000..8d58e9a
--- /dev/null
+++ b/app/components/base/chat/chat/citation/tooltip.tsx
@@ -0,0 +1,46 @@
+import React, { useState } from 'react'
+import type { FC } from 'react'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+
+type TooltipProps = {
+ data: number | string
+ text: string
+ icon: React.ReactNode
+}
+
+const Tooltip: FC<TooltipProps> = ({
+ data,
+ text,
+ icon,
+}) => {
+ const [open, setOpen] = useState(false)
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='top-start'
+ >
+ <PortalToFollowElemTrigger
+ onMouseEnter={() => setOpen(true)}
+ onMouseLeave={() => setOpen(false)}
+ >
+ <div className='mr-6 flex items-center'>
+ {icon}
+ {data}
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 1001 }}>
+ <div className='system-xs-medium rounded-lg bg-components-tooltip-bg p-3 text-text-quaternary shadow-lg'>
+ {text} {data}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default Tooltip
diff --git a/app/components/base/chat/chat/content-switch.tsx b/app/components/base/chat/chat/content-switch.tsx
new file mode 100644
index 0000000..cf428f4
--- /dev/null
+++ b/app/components/base/chat/chat/content-switch.tsx
@@ -0,0 +1,39 @@
+import { ChevronRight } from '../../icons/src/vender/line/arrows'
+
+export default function ContentSwitch({
+ count,
+ currentIndex,
+ prevDisabled,
+ nextDisabled,
+ switchSibling,
+}: {
+ count?: number
+ currentIndex?: number
+ prevDisabled: boolean
+ nextDisabled: boolean
+ switchSibling: (direction: 'prev' | 'next') => void
+}) {
+ return (
+ count && count > 1 && currentIndex !== undefined && (
+ <div className="flex items-center justify-center pt-3.5 text-sm">
+ <button
+ className={`${prevDisabled ? 'opacity-30' : 'opacity-100'}`}
+ disabled={prevDisabled}
+ onClick={() => !prevDisabled && switchSibling('prev')}
+ >
+ <ChevronRight className="h-[14px] w-[14px] rotate-180 text-text-primary" />
+ </button>
+ <span className="px-2 text-xs text-text-primary">
+ {currentIndex + 1} / {count}
+ </span>
+ <button
+ className={`${nextDisabled ? 'opacity-30' : 'opacity-100'}`}
+ disabled={nextDisabled}
+ onClick={() => !nextDisabled && switchSibling('next')}
+ >
+ <ChevronRight className="h-[14px] w-[14px] text-text-primary" />
+ </button>
+ </div>
+ )
+ )
+}
diff --git a/app/components/base/chat/chat/context.tsx b/app/components/base/chat/chat/context.tsx
new file mode 100644
index 0000000..8c69884
--- /dev/null
+++ b/app/components/base/chat/chat/context.tsx
@@ -0,0 +1,66 @@
+'use client'
+
+import type { ReactNode } from 'react'
+import { createContext, useContext } from 'use-context-selector'
+import type { ChatProps } from './index'
+
+export type ChatContextValue = Pick<ChatProps, 'config'
+ | 'isResponding'
+ | 'chatList'
+ | 'showPromptLog'
+ | 'questionIcon'
+ | 'answerIcon'
+ | 'onSend'
+ | 'onRegenerate'
+ | 'onAnnotationEdited'
+ | 'onAnnotationAdded'
+ | 'onAnnotationRemoved'
+ | 'onFeedback'
+>
+
+const ChatContext = createContext<ChatContextValue>({
+ chatList: [],
+})
+
+type ChatContextProviderProps = {
+ children: ReactNode
+} & ChatContextValue
+
+export const ChatContextProvider = ({
+ children,
+ config,
+ isResponding,
+ chatList,
+ showPromptLog,
+ questionIcon,
+ answerIcon,
+ onSend,
+ onRegenerate,
+ onAnnotationEdited,
+ onAnnotationAdded,
+ onAnnotationRemoved,
+ onFeedback,
+}: ChatContextProviderProps) => {
+ return (
+ <ChatContext.Provider value={{
+ config,
+ isResponding,
+ chatList: chatList || [],
+ showPromptLog,
+ questionIcon,
+ answerIcon,
+ onSend,
+ onRegenerate,
+ onAnnotationEdited,
+ onAnnotationAdded,
+ onAnnotationRemoved,
+ onFeedback,
+ }}>
+ {children}
+ </ChatContext.Provider>
+ )
+}
+
+export const useChatContext = () => useContext(ChatContext)
+
+export default ChatContext
diff --git a/app/components/base/chat/chat/hooks.ts b/app/components/base/chat/chat/hooks.ts
new file mode 100644
index 0000000..fde4674
--- /dev/null
+++ b/app/components/base/chat/chat/hooks.ts
@@ -0,0 +1,710 @@
+import {
+ useCallback,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import { produce, setAutoFreeze } from 'immer'
+import { uniqBy } from 'lodash-es'
+import { useParams, usePathname } from 'next/navigation'
+import { v4 as uuidV4 } from 'uuid'
+import type {
+ ChatConfig,
+ ChatItem,
+ ChatItemInTree,
+ Inputs,
+} from '../types'
+import { getThreadMessages } from '../utils'
+import type { InputForm } from './type'
+import {
+ getProcessedInputs,
+ processOpeningStatement,
+} from './utils'
+import { TransferMethod } from '@/types/app'
+import { useToastContext } from '@/app/components/base/toast'
+import { ssePost } from '@/service/base'
+import type { Annotation } from '@/models/log'
+import { WorkflowRunningStatus } from '@/app/components/workflow/types'
+import useTimestamp from '@/hooks/use-timestamp'
+import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
+import type { FileEntity } from '@/app/components/base/file-uploader/types'
+import {
+ getProcessedFiles,
+ getProcessedFilesFromResponse,
+} from '@/app/components/base/file-uploader/utils'
+import { noop } from 'lodash-es'
+
+type GetAbortController = (abortController: AbortController) => void
+type SendCallback = {
+ onGetConversationMessages?: (conversationId: string, getAbortController: GetAbortController) => Promise<any>
+ onGetSuggestedQuestions?: (responseItemId: string, getAbortController: GetAbortController) => Promise<any>
+ onConversationComplete?: (conversationId: string) => void
+ isPublicAPI?: boolean
+}
+
+export const useChat = (
+ config?: ChatConfig,
+ formSettings?: {
+ inputs: Inputs
+ inputsForm: InputForm[]
+ },
+ prevChatTree?: ChatItemInTree[],
+ stopChat?: (taskId: string) => void,
+ clearChatList?: boolean,
+ clearChatListCallback?: (state: boolean) => void,
+) => {
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+ const { notify } = useToastContext()
+ const conversationId = useRef('')
+ const hasStopResponded = useRef(false)
+ const [isResponding, setIsResponding] = useState(false)
+ const isRespondingRef = useRef(false)
+ const taskIdRef = useRef('')
+ const [suggestedQuestions, setSuggestQuestions] = useState<string[]>([])
+ const conversationMessagesAbortControllerRef = useRef<AbortController | null>(null)
+ const suggestedQuestionsAbortControllerRef = useRef<AbortController | null>(null)
+ const params = useParams()
+ const pathname = usePathname()
+
+ const [chatTree, setChatTree] = useState<ChatItemInTree[]>(prevChatTree || [])
+ const chatTreeRef = useRef<ChatItemInTree[]>(chatTree)
+ const [targetMessageId, setTargetMessageId] = useState<string>()
+ const threadMessages = useMemo(() => getThreadMessages(chatTree, targetMessageId), [chatTree, targetMessageId])
+
+ const getIntroduction = useCallback((str: string) => {
+ return processOpeningStatement(str, formSettings?.inputs || {}, formSettings?.inputsForm || [])
+ }, [formSettings?.inputs, formSettings?.inputsForm])
+
+ /** Final chat list that will be rendered */
+ const chatList = useMemo(() => {
+ const ret = [...threadMessages]
+ if (config?.opening_statement) {
+ const index = threadMessages.findIndex(item => item.isOpeningStatement)
+
+ if (index > -1) {
+ ret[index] = {
+ ...ret[index],
+ content: getIntroduction(config.opening_statement),
+ suggestedQuestions: config.suggested_questions,
+ }
+ }
+ else {
+ ret.unshift({
+ id: 'opening-statement',
+ content: getIntroduction(config.opening_statement),
+ isAnswer: true,
+ isOpeningStatement: true,
+ suggestedQuestions: config.suggested_questions,
+ })
+ }
+ }
+ return ret
+ }, [threadMessages, config?.opening_statement, getIntroduction, config?.suggested_questions])
+
+ useEffect(() => {
+ setAutoFreeze(false)
+ return () => {
+ setAutoFreeze(true)
+ }
+ }, [])
+
+ /** Find the target node by bfs and then operate on it */
+ const produceChatTreeNode = useCallback((targetId: string, operation: (node: ChatItemInTree) => void) => {
+ return produce(chatTreeRef.current, (draft) => {
+ const queue: ChatItemInTree[] = [...draft]
+ while (queue.length > 0) {
+ const current = queue.shift()!
+ if (current.id === targetId) {
+ operation(current)
+ break
+ }
+ if (current.children)
+ queue.push(...current.children)
+ }
+ })
+ }, [])
+
+ type UpdateChatTreeNode = {
+ (id: string, fields: Partial<ChatItemInTree>): void
+ (id: string, update: (node: ChatItemInTree) => void): void
+ }
+
+ const updateChatTreeNode: UpdateChatTreeNode = useCallback((
+ id: string,
+ fieldsOrUpdate: Partial<ChatItemInTree> | ((node: ChatItemInTree) => void),
+ ) => {
+ const nextState = produceChatTreeNode(id, (node) => {
+ if (typeof fieldsOrUpdate === 'function') {
+ fieldsOrUpdate(node)
+ }
+ else {
+ Object.keys(fieldsOrUpdate).forEach((key) => {
+ (node as any)[key] = (fieldsOrUpdate as any)[key]
+ })
+ }
+ })
+ setChatTree(nextState)
+ chatTreeRef.current = nextState
+ }, [produceChatTreeNode])
+
+ const handleResponding = useCallback((isResponding: boolean) => {
+ setIsResponding(isResponding)
+ isRespondingRef.current = isResponding
+ }, [])
+
+ const handleStop = useCallback(() => {
+ hasStopResponded.current = true
+ handleResponding(false)
+ if (stopChat && taskIdRef.current)
+ stopChat(taskIdRef.current)
+ if (conversationMessagesAbortControllerRef.current)
+ conversationMessagesAbortControllerRef.current.abort()
+ if (suggestedQuestionsAbortControllerRef.current)
+ suggestedQuestionsAbortControllerRef.current.abort()
+ }, [stopChat, handleResponding])
+
+ const handleRestart = useCallback((cb?: any) => {
+ conversationId.current = ''
+ taskIdRef.current = ''
+ handleStop()
+ setChatTree([])
+ setSuggestQuestions([])
+ cb?.()
+ }, [handleStop])
+
+ const updateCurrentQAOnTree = useCallback(({
+ parentId,
+ responseItem,
+ placeholderQuestionId,
+ questionItem,
+ }: {
+ parentId?: string
+ responseItem: ChatItem
+ placeholderQuestionId: string
+ questionItem: ChatItem
+ }) => {
+ let nextState: ChatItemInTree[]
+ const currentQA = { ...questionItem, children: [{ ...responseItem, children: [] }] }
+ if (!parentId && !chatTree.some(item => [placeholderQuestionId, questionItem.id].includes(item.id))) {
+ // QA whose parent is not provided is considered as a first message of the conversation,
+ // and it should be a root node of the chat tree
+ nextState = produce(chatTree, (draft) => {
+ draft.push(currentQA)
+ })
+ }
+ else {
+ // find the target QA in the tree and update it; if not found, insert it to its parent node
+ nextState = produceChatTreeNode(parentId!, (parentNode) => {
+ const questionNodeIndex = parentNode.children!.findIndex(item => [placeholderQuestionId, questionItem.id].includes(item.id))
+ if (questionNodeIndex === -1)
+ parentNode.children!.push(currentQA)
+ else
+ parentNode.children![questionNodeIndex] = currentQA
+ })
+ }
+ setChatTree(nextState)
+ chatTreeRef.current = nextState
+ }, [chatTree, produceChatTreeNode])
+
+ const handleSend = useCallback(async (
+ url: string,
+ data: {
+ query: string
+ files?: FileEntity[]
+ parent_message_id?: string
+ [key: string]: any
+ },
+ {
+ onGetConversationMessages,
+ onGetSuggestedQuestions,
+ onConversationComplete,
+ isPublicAPI,
+ }: SendCallback,
+ ) => {
+ setSuggestQuestions([])
+
+ if (isRespondingRef.current) {
+ notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
+ return false
+ }
+
+ const parentMessage = threadMessages.find(item => item.id === data.parent_message_id)
+
+ const placeholderQuestionId = `question-${Date.now()}`
+ const questionItem = {
+ id: placeholderQuestionId,
+ content: data.query,
+ isAnswer: false,
+ message_files: data.files,
+ parentMessageId: data.parent_message_id,
+ }
+
+ const placeholderAnswerId = `answer-placeholder-${Date.now()}`
+ const placeholderAnswerItem = {
+ id: placeholderAnswerId,
+ content: '',
+ isAnswer: true,
+ parentMessageId: questionItem.id,
+ siblingIndex: parentMessage?.children?.length ?? chatTree.length,
+ }
+
+ setTargetMessageId(parentMessage?.id)
+ updateCurrentQAOnTree({
+ parentId: data.parent_message_id,
+ responseItem: placeholderAnswerItem,
+ placeholderQuestionId,
+ questionItem,
+ })
+
+ // answer
+ const responseItem: ChatItemInTree = {
+ id: placeholderAnswerId,
+ content: '',
+ agent_thoughts: [],
+ message_files: [],
+ isAnswer: true,
+ parentMessageId: questionItem.id,
+ siblingIndex: parentMessage?.children?.length ?? chatTree.length,
+ }
+
+ handleResponding(true)
+ hasStopResponded.current = false
+
+ const { query, files, inputs, ...restData } = data
+ const bodyParams = {
+ response_mode: 'streaming',
+ conversation_id: conversationId.current,
+ files: getProcessedFiles(files || []),
+ query,
+ inputs: getProcessedInputs(inputs || {}, formSettings?.inputsForm || []),
+ ...restData,
+ }
+ if (bodyParams?.files?.length) {
+ bodyParams.files = bodyParams.files.map((item) => {
+ if (item.transfer_method === TransferMethod.local_file) {
+ return {
+ ...item,
+ url: '',
+ }
+ }
+ return item
+ })
+ }
+
+ let isAgentMode = false
+ let hasSetResponseId = false
+
+ let ttsUrl = ''
+ let ttsIsPublic = false
+ if (params.token) {
+ ttsUrl = '/text-to-audio'
+ ttsIsPublic = true
+ }
+ else if (params.appId) {
+ if (pathname.search('explore/installed') > -1)
+ ttsUrl = `/installed-apps/${params.appId}/text-to-audio`
+ else
+ ttsUrl = `/apps/${params.appId}/text-to-audio`
+ }
+ const player = AudioPlayerManager.getInstance().getAudioPlayer(ttsUrl, ttsIsPublic, uuidV4(), 'none', 'none', noop)
+ ssePost(
+ url,
+ {
+ body: bodyParams,
+ },
+ {
+ isPublicAPI,
+ onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => {
+ if (!isAgentMode) {
+ responseItem.content = responseItem.content + message
+ }
+ else {
+ const lastThought = responseItem.agent_thoughts?.[responseItem.agent_thoughts?.length - 1]
+ if (lastThought)
+ lastThought.thought = lastThought.thought + message // need immer setAutoFreeze
+ }
+
+ if (messageId && !hasSetResponseId) {
+ questionItem.id = `question-${messageId}`
+ responseItem.id = messageId
+ responseItem.parentMessageId = questionItem.id
+ hasSetResponseId = true
+ }
+
+ if (isFirstMessage && newConversationId)
+ conversationId.current = newConversationId
+
+ taskIdRef.current = taskId
+ if (messageId)
+ responseItem.id = messageId
+
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ async onCompleted(hasError?: boolean) {
+ handleResponding(false)
+
+ if (hasError)
+ return
+
+ if (onConversationComplete)
+ onConversationComplete(conversationId.current)
+
+ if (conversationId.current && !hasStopResponded.current && onGetConversationMessages) {
+ const { data }: any = await onGetConversationMessages(
+ conversationId.current,
+ newAbortController => conversationMessagesAbortControllerRef.current = newAbortController,
+ )
+ const newResponseItem = data.find((item: any) => item.id === responseItem.id)
+ if (!newResponseItem)
+ return
+
+ updateChatTreeNode(responseItem.id, {
+ content: newResponseItem.answer,
+ log: [
+ ...newResponseItem.message,
+ ...(newResponseItem.message[newResponseItem.message.length - 1].role !== 'assistant'
+ ? [
+ {
+ role: 'assistant',
+ text: newResponseItem.answer,
+ files: newResponseItem.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [],
+ },
+ ]
+ : []),
+ ],
+ more: {
+ time: formatTime(newResponseItem.created_at, 'hh:mm A'),
+ tokens: newResponseItem.answer_tokens + newResponseItem.message_tokens,
+ latency: newResponseItem.provider_response_latency.toFixed(2),
+ },
+ // for agent log
+ conversationId: conversationId.current,
+ input: {
+ inputs: newResponseItem.inputs,
+ query: newResponseItem.query,
+ },
+ })
+ }
+ if (config?.suggested_questions_after_answer?.enabled && !hasStopResponded.current && onGetSuggestedQuestions) {
+ try {
+ const { data }: any = await onGetSuggestedQuestions(
+ responseItem.id,
+ newAbortController => suggestedQuestionsAbortControllerRef.current = newAbortController,
+ )
+ setSuggestQuestions(data)
+ }
+ // eslint-disable-next-line unused-imports/no-unused-vars
+ catch (e) {
+ setSuggestQuestions([])
+ }
+ }
+ },
+ onFile(file) {
+ const lastThought = responseItem.agent_thoughts?.[responseItem.agent_thoughts?.length - 1]
+ if (lastThought)
+ responseItem.agent_thoughts![responseItem.agent_thoughts!.length - 1].message_files = [...(lastThought as any).message_files, file]
+
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onThought(thought) {
+ isAgentMode = true
+ const response = responseItem as any
+ if (thought.message_id && !hasSetResponseId)
+ response.id = thought.message_id
+ if (thought.conversation_id)
+ response.conversationId = thought.conversation_id
+
+ if (response.agent_thoughts.length === 0) {
+ response.agent_thoughts.push(thought)
+ }
+ else {
+ const lastThought = response.agent_thoughts[response.agent_thoughts.length - 1]
+ // thought changed but still the same thought, so update.
+ if (lastThought.id === thought.id) {
+ thought.thought = lastThought.thought
+ thought.message_files = lastThought.message_files
+ responseItem.agent_thoughts![response.agent_thoughts.length - 1] = thought
+ }
+ else {
+ responseItem.agent_thoughts!.push(thought)
+ }
+ }
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onMessageEnd: (messageEnd) => {
+ if (messageEnd.metadata?.annotation_reply) {
+ responseItem.id = messageEnd.id
+ responseItem.annotation = ({
+ id: messageEnd.metadata.annotation_reply.id,
+ authorName: messageEnd.metadata.annotation_reply.account.name,
+ })
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ return
+ }
+ responseItem.citation = messageEnd.metadata?.retriever_resources || []
+ const processedFilesFromResponse = getProcessedFilesFromResponse(messageEnd.files || [])
+ responseItem.allFiles = uniqBy([...(responseItem.allFiles || []), ...(processedFilesFromResponse || [])], 'id')
+
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onMessageReplace: (messageReplace) => {
+ responseItem.content = messageReplace.answer
+ },
+ onError() {
+ handleResponding(false)
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onWorkflowStarted: ({ workflow_run_id, task_id }) => {
+ taskIdRef.current = task_id
+ responseItem.workflow_run_id = workflow_run_id
+ responseItem.workflowProcess = {
+ status: WorkflowRunningStatus.Running,
+ tracing: [],
+ }
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onWorkflowFinished: ({ data: workflowFinishedData }) => {
+ responseItem.workflowProcess!.status = workflowFinishedData.status as WorkflowRunningStatus
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onIterationStart: ({ data: iterationStartedData }) => {
+ responseItem.workflowProcess!.tracing!.push({
+ ...iterationStartedData,
+ status: WorkflowRunningStatus.Running,
+ })
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onIterationFinish: ({ data: iterationFinishedData }) => {
+ const tracing = responseItem.workflowProcess!.tracing!
+ const iterationIndex = tracing.findIndex(item => item.node_id === iterationFinishedData.node_id
+ && (item.execution_metadata?.parallel_id === iterationFinishedData.execution_metadata?.parallel_id || item.parallel_id === iterationFinishedData.execution_metadata?.parallel_id))!
+ tracing[iterationIndex] = {
+ ...tracing[iterationIndex],
+ ...iterationFinishedData,
+ status: WorkflowRunningStatus.Succeeded,
+ }
+
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onNodeStarted: ({ data: nodeStartedData }) => {
+ if (nodeStartedData.iteration_id)
+ return
+
+ if (data.loop_id)
+ return
+
+ responseItem.workflowProcess!.tracing!.push({
+ ...nodeStartedData,
+ status: WorkflowRunningStatus.Running,
+ })
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onNodeFinished: ({ data: nodeFinishedData }) => {
+ if (nodeFinishedData.iteration_id)
+ return
+
+ if (data.loop_id)
+ return
+
+ const currentIndex = responseItem.workflowProcess!.tracing!.findIndex((item) => {
+ if (!item.execution_metadata?.parallel_id)
+ return item.node_id === nodeFinishedData.node_id
+
+ return item.node_id === nodeFinishedData.node_id && (item.execution_metadata?.parallel_id === nodeFinishedData.execution_metadata?.parallel_id)
+ })
+ responseItem.workflowProcess!.tracing[currentIndex] = nodeFinishedData as any
+
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onTTSChunk: (messageId: string, audio: string) => {
+ if (!audio || audio === '')
+ return
+ player.playAudioWithAudio(audio, true)
+ AudioPlayerManager.getInstance().resetMsgId(messageId)
+ },
+ onTTSEnd: (messageId: string, audio: string) => {
+ player.playAudioWithAudio(audio, false)
+ },
+ onLoopStart: ({ data: loopStartedData }) => {
+ responseItem.workflowProcess!.tracing!.push({
+ ...loopStartedData,
+ status: WorkflowRunningStatus.Running,
+ })
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ onLoopFinish: ({ data: loopFinishedData }) => {
+ const tracing = responseItem.workflowProcess!.tracing!
+ const loopIndex = tracing.findIndex(item => item.node_id === loopFinishedData.node_id
+ && (item.execution_metadata?.parallel_id === loopFinishedData.execution_metadata?.parallel_id || item.parallel_id === loopFinishedData.execution_metadata?.parallel_id))!
+ tracing[loopIndex] = {
+ ...tracing[loopIndex],
+ ...loopFinishedData,
+ status: WorkflowRunningStatus.Succeeded,
+ }
+
+ updateCurrentQAOnTree({
+ placeholderQuestionId,
+ questionItem,
+ responseItem,
+ parentId: data.parent_message_id,
+ })
+ },
+ })
+ return true
+ }, [
+ t,
+ chatTree.length,
+ threadMessages,
+ config?.suggested_questions_after_answer,
+ updateCurrentQAOnTree,
+ updateChatTreeNode,
+ notify,
+ handleResponding,
+ formatTime,
+ params.token,
+ params.appId,
+ pathname,
+ formSettings,
+ ])
+
+ const handleAnnotationEdited = useCallback((query: string, answer: string, index: number) => {
+ const targetQuestionId = chatList[index - 1].id
+ const targetAnswerId = chatList[index].id
+
+ updateChatTreeNode(targetQuestionId, {
+ content: query,
+ })
+ updateChatTreeNode(targetAnswerId, {
+ content: answer,
+ annotation: {
+ ...chatList[index].annotation,
+ logAnnotation: undefined,
+ } as any,
+ })
+ }, [chatList, updateChatTreeNode])
+
+ const handleAnnotationAdded = useCallback((annotationId: string, authorName: string, query: string, answer: string, index: number) => {
+ const targetQuestionId = chatList[index - 1].id
+ const targetAnswerId = chatList[index].id
+
+ updateChatTreeNode(targetQuestionId, {
+ content: query,
+ })
+
+ updateChatTreeNode(targetAnswerId, {
+ content: chatList[index].content,
+ annotation: {
+ id: annotationId,
+ authorName,
+ logAnnotation: {
+ content: answer,
+ account: {
+ id: '',
+ name: authorName,
+ email: '',
+ },
+ },
+ } as Annotation,
+ })
+ }, [chatList, updateChatTreeNode])
+
+ const handleAnnotationRemoved = useCallback((index: number) => {
+ const targetAnswerId = chatList[index].id
+
+ updateChatTreeNode(targetAnswerId, {
+ content: chatList[index].content,
+ annotation: {
+ ...(chatList[index].annotation || {}),
+ id: '',
+ } as Annotation,
+ })
+ }, [chatList, updateChatTreeNode])
+
+ useEffect(() => {
+ if (clearChatList)
+ handleRestart(() => clearChatListCallback?.(false))
+ }, [clearChatList, clearChatListCallback, handleRestart])
+
+ return {
+ chatList,
+ setTargetMessageId,
+ conversationId: conversationId.current,
+ isResponding,
+ setIsResponding,
+ handleSend,
+ suggestedQuestions,
+ handleRestart,
+ handleStop,
+ handleAnnotationEdited,
+ handleAnnotationAdded,
+ handleAnnotationRemoved,
+ }
+}
diff --git a/app/components/base/chat/chat/index.tsx b/app/components/base/chat/chat/index.tsx
new file mode 100644
index 0000000..7c8eb23
--- /dev/null
+++ b/app/components/base/chat/chat/index.tsx
@@ -0,0 +1,348 @@
+import type {
+ FC,
+ ReactNode,
+} from 'react'
+import {
+ memo,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import { debounce } from 'lodash-es'
+import { useShallow } from 'zustand/react/shallow'
+import type {
+ ChatConfig,
+ ChatItem,
+ Feedback,
+ OnRegenerate,
+ OnSend,
+} from '../types'
+import type { ThemeBuilder } from '../embedded-chatbot/theme/theme-context'
+import Question from './question'
+import Answer from './answer'
+import ChatInputArea from './chat-input-area'
+import TryToAsk from './try-to-ask'
+import { ChatContextProvider } from './context'
+import type { InputForm } from './type'
+import cn from '@/utils/classnames'
+import type { Emoji } from '@/app/components/tools/types'
+import Button from '@/app/components/base/button'
+import { StopCircle } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
+import AgentLogModal from '@/app/components/base/agent-log-modal'
+import PromptLogModal from '@/app/components/base/prompt-log-modal'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import type { AppData } from '@/models/share'
+
+export type ChatProps = {
+ appData?: AppData
+ chatList: ChatItem[]
+ config?: ChatConfig
+ isResponding?: boolean
+ noStopResponding?: boolean
+ onStopResponding?: () => void
+ noChatInput?: boolean
+ onSend?: OnSend
+ inputs?: Record<string, any>
+ inputsForm?: InputForm[]
+ onRegenerate?: OnRegenerate
+ chatContainerClassName?: string
+ chatContainerInnerClassName?: string
+ chatFooterClassName?: string
+ chatFooterInnerClassName?: string
+ suggestedQuestions?: string[]
+ showPromptLog?: boolean
+ questionIcon?: ReactNode
+ answerIcon?: ReactNode
+ allToolIcons?: Record<string, string | Emoji>
+ onAnnotationEdited?: (question: string, answer: string, index: number) => void
+ onAnnotationAdded?: (annotationId: string, authorName: string, question: string, answer: string, index: number) => void
+ onAnnotationRemoved?: (index: number) => void
+ chatNode?: ReactNode
+ onFeedback?: (messageId: string, feedback: Feedback) => void
+ chatAnswerContainerInner?: string
+ hideProcessDetail?: boolean
+ hideLogModal?: boolean
+ themeBuilder?: ThemeBuilder
+ switchSibling?: (siblingMessageId: string) => void
+ showFeatureBar?: boolean
+ showFileUpload?: boolean
+ onFeatureBarClick?: (state: boolean) => void
+ noSpacing?: boolean
+ inputDisabled?: boolean
+ isMobile?: boolean
+ sidebarCollapseState?: boolean
+}
+
+const Chat: FC<ChatProps> = ({
+ appData,
+ config,
+ onSend,
+ inputs,
+ inputsForm,
+ onRegenerate,
+ chatList,
+ isResponding,
+ noStopResponding,
+ onStopResponding,
+ noChatInput,
+ chatContainerClassName,
+ chatContainerInnerClassName,
+ chatFooterClassName,
+ chatFooterInnerClassName,
+ suggestedQuestions,
+ showPromptLog,
+ questionIcon,
+ answerIcon,
+ onAnnotationAdded,
+ onAnnotationEdited,
+ onAnnotationRemoved,
+ chatNode,
+ onFeedback,
+ chatAnswerContainerInner,
+ hideProcessDetail,
+ hideLogModal,
+ themeBuilder,
+ switchSibling,
+ showFeatureBar,
+ showFileUpload,
+ onFeatureBarClick,
+ noSpacing,
+ inputDisabled,
+ isMobile,
+ sidebarCollapseState,
+}) => {
+ const { t } = useTranslation()
+ const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore(useShallow(state => ({
+ currentLogItem: state.currentLogItem,
+ setCurrentLogItem: state.setCurrentLogItem,
+ showPromptLogModal: state.showPromptLogModal,
+ setShowPromptLogModal: state.setShowPromptLogModal,
+ showAgentLogModal: state.showAgentLogModal,
+ setShowAgentLogModal: state.setShowAgentLogModal,
+ })))
+ const [width, setWidth] = useState(0)
+ const chatContainerRef = useRef<HTMLDivElement>(null)
+ const chatContainerInnerRef = useRef<HTMLDivElement>(null)
+ const chatFooterRef = useRef<HTMLDivElement>(null)
+ const chatFooterInnerRef = useRef<HTMLDivElement>(null)
+ const userScrolledRef = useRef(false)
+
+ const handleScrollToBottom = useCallback(() => {
+ if (chatList.length > 1 && chatContainerRef.current && !userScrolledRef.current)
+ chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight
+ }, [chatList.length])
+
+ const handleWindowResize = useCallback(() => {
+ if (chatContainerRef.current)
+ setWidth(document.body.clientWidth - (chatContainerRef.current?.clientWidth + 16) - 8)
+
+ if (chatContainerRef.current && chatFooterRef.current)
+ chatFooterRef.current.style.width = `${chatContainerRef.current.clientWidth}px`
+
+ if (chatContainerInnerRef.current && chatFooterInnerRef.current)
+ chatFooterInnerRef.current.style.width = `${chatContainerInnerRef.current.clientWidth}px`
+ }, [])
+
+ useEffect(() => {
+ handleScrollToBottom()
+ handleWindowResize()
+ }, [handleScrollToBottom, handleWindowResize])
+
+ useEffect(() => {
+ if (chatContainerRef.current) {
+ requestAnimationFrame(() => {
+ handleScrollToBottom()
+ handleWindowResize()
+ })
+ }
+ })
+
+ useEffect(() => {
+ window.addEventListener('resize', debounce(handleWindowResize))
+ return () => window.removeEventListener('resize', handleWindowResize)
+ }, [handleWindowResize])
+
+ useEffect(() => {
+ if (chatFooterRef.current && chatContainerRef.current) {
+ // container padding bottom
+ const resizeContainerObserver = new ResizeObserver((entries) => {
+ for (const entry of entries) {
+ const { blockSize } = entry.borderBoxSize[0]
+ chatContainerRef.current!.style.paddingBottom = `${blockSize}px`
+ handleScrollToBottom()
+ }
+ })
+ resizeContainerObserver.observe(chatFooterRef.current)
+
+ // footer width
+ const resizeFooterObserver = new ResizeObserver((entries) => {
+ for (const entry of entries) {
+ const { inlineSize } = entry.borderBoxSize[0]
+ chatFooterRef.current!.style.width = `${inlineSize}px`
+ }
+ })
+ resizeFooterObserver.observe(chatContainerRef.current)
+
+ return () => {
+ resizeContainerObserver.disconnect()
+ resizeFooterObserver.disconnect()
+ }
+ }
+ }, [handleScrollToBottom])
+
+ useEffect(() => {
+ const chatContainer = chatContainerRef.current
+ if (chatContainer) {
+ const setUserScrolled = () => {
+ // eslint-disable-next-line sonarjs/no-gratuitous-expressions
+ if (chatContainer) // its in event callback, chatContainer may be null
+ userScrolledRef.current = chatContainer.scrollHeight - chatContainer.scrollTop > chatContainer.clientHeight
+ }
+ chatContainer.addEventListener('scroll', setUserScrolled)
+ return () => chatContainer.removeEventListener('scroll', setUserScrolled)
+ }
+ }, [])
+
+ useEffect(() => {
+ if (!sidebarCollapseState)
+ setTimeout(() => handleWindowResize(), 200)
+ }, [handleWindowResize, sidebarCollapseState])
+
+ const hasTryToAsk = config?.suggested_questions_after_answer?.enabled && !!suggestedQuestions?.length && onSend
+
+ return (
+ <ChatContextProvider
+ config={config}
+ chatList={chatList}
+ isResponding={isResponding}
+ showPromptLog={showPromptLog}
+ questionIcon={questionIcon}
+ answerIcon={answerIcon}
+ onSend={onSend}
+ onRegenerate={onRegenerate}
+ onAnnotationAdded={onAnnotationAdded}
+ onAnnotationEdited={onAnnotationEdited}
+ onAnnotationRemoved={onAnnotationRemoved}
+ onFeedback={onFeedback}
+ >
+ <div className='relative h-full'>
+ <div
+ ref={chatContainerRef}
+ className={cn('relative h-full overflow-y-auto overflow-x-hidden', chatContainerClassName)}
+ >
+ {chatNode}
+ <div
+ ref={chatContainerInnerRef}
+ className={cn('w-full', !noSpacing && 'px-8', chatContainerInnerClassName)}
+ >
+ {
+ chatList.map((item, index) => {
+ if (item.isAnswer) {
+ const isLast = item.id === chatList[chatList.length - 1]?.id
+ return (
+ <Answer
+ appData={appData}
+ key={item.id}
+ item={item}
+ question={chatList[index - 1]?.content}
+ index={index}
+ config={config}
+ answerIcon={answerIcon}
+ responding={isLast && isResponding}
+ showPromptLog={showPromptLog}
+ chatAnswerContainerInner={chatAnswerContainerInner}
+ hideProcessDetail={hideProcessDetail}
+ noChatInput={noChatInput}
+ switchSibling={switchSibling}
+ />
+ )
+ }
+ return (
+ <Question
+ key={item.id}
+ item={item}
+ questionIcon={questionIcon}
+ theme={themeBuilder?.theme}
+ enableEdit={config?.questionEditEnable}
+ switchSibling={switchSibling}
+ />
+ )
+ })
+ }
+ </div>
+ </div>
+ <div
+ className={`absolute bottom-0 flex justify-center bg-chat-input-mask ${(hasTryToAsk || !noChatInput || !noStopResponding) && chatFooterClassName}`}
+ ref={chatFooterRef}
+ >
+ <div
+ ref={chatFooterInnerRef}
+ className={cn('relative', chatFooterInnerClassName)}
+ >
+ {
+ !noStopResponding && isResponding && (
+ <div className='mb-2 flex justify-center'>
+ <Button onClick={onStopResponding}>
+ <StopCircle className='mr-[5px] h-3.5 w-3.5 text-gray-500' />
+ <span className='text-xs font-normal text-gray-500'>{t('appDebug.operation.stopResponding')}</span>
+ </Button>
+ </div>
+ )
+ }
+ {
+ hasTryToAsk && (
+ <TryToAsk
+ suggestedQuestions={suggestedQuestions}
+ onSend={onSend}
+ isMobile={isMobile}
+ />
+ )
+ }
+ {
+ !noChatInput && (
+ <ChatInputArea
+ disabled={inputDisabled}
+ showFeatureBar={showFeatureBar}
+ showFileUpload={showFileUpload}
+ featureBarDisabled={isResponding}
+ onFeatureBarClick={onFeatureBarClick}
+ visionConfig={config?.file_upload}
+ speechToTextConfig={config?.speech_to_text}
+ onSend={onSend}
+ inputs={inputs}
+ inputsForm={inputsForm}
+ theme={themeBuilder?.theme}
+ isResponding={isResponding}
+ />
+ )
+ }
+ </div>
+ </div>
+ {showPromptLogModal && !hideLogModal && (
+ <PromptLogModal
+ width={width}
+ currentLogItem={currentLogItem}
+ onCancel={() => {
+ setCurrentLogItem()
+ setShowPromptLogModal(false)
+ }}
+ />
+ )}
+ {showAgentLogModal && !hideLogModal && (
+ <AgentLogModal
+ width={width}
+ currentLogItem={currentLogItem}
+ onCancel={() => {
+ setCurrentLogItem()
+ setShowAgentLogModal(false)
+ }}
+ />
+ )}
+ </div>
+ </ChatContextProvider>
+ )
+}
+
+export default memo(Chat)
diff --git a/app/components/base/chat/chat/loading-anim/index.tsx b/app/components/base/chat/chat/loading-anim/index.tsx
new file mode 100644
index 0000000..dd43ef9
--- /dev/null
+++ b/app/components/base/chat/chat/loading-anim/index.tsx
@@ -0,0 +1,17 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import s from './style.module.css'
+
+export type ILoadingAnimProps = {
+ type: 'text' | 'avatar'
+}
+
+const LoadingAnim: FC<ILoadingAnimProps> = ({
+ type,
+}) => {
+ return (
+ <div className={`${s['dot-flashing']} ${s[type]}`}></div>
+ )
+}
+export default React.memo(LoadingAnim)
diff --git a/app/components/base/chat/chat/loading-anim/style.module.css b/app/components/base/chat/chat/loading-anim/style.module.css
new file mode 100644
index 0000000..b1371ec
--- /dev/null
+++ b/app/components/base/chat/chat/loading-anim/style.module.css
@@ -0,0 +1,82 @@
+.dot-flashing {
+ position: relative;
+ animation: 1s infinite linear alternate;
+ animation-delay: 0.5s;
+}
+
+.dot-flashing::before,
+.dot-flashing::after {
+ content: "";
+ display: inline-block;
+ position: absolute;
+ top: 0;
+ animation: 1s infinite linear alternate;
+}
+
+.dot-flashing::before {
+ animation-delay: 0s;
+}
+
+.dot-flashing::after {
+ animation-delay: 1s;
+}
+
+@keyframes dot-flashing {
+ 0% {
+ background-color: #667085;
+ }
+
+ 50%,
+ 100% {
+ background-color: rgba(102, 112, 133, 0.3);
+ }
+}
+
+@keyframes dot-flashing-avatar {
+ 0% {
+ background-color: #155EEF;
+ }
+
+ 50%,
+ 100% {
+ background-color: rgba(21, 94, 239, 0.3);
+ }
+}
+
+.text,
+.text::before,
+.text::after {
+ width: 4px;
+ height: 4px;
+ border-radius: 50%;
+ background-color: #667085;
+ color: #667085;
+ animation-name: dot-flashing;
+}
+
+.text::before {
+ left: -7px;
+}
+
+.text::after {
+ left: 7px;
+}
+
+.avatar,
+.avatar::before,
+.avatar::after {
+ width: 2px;
+ height: 2px;
+ border-radius: 50%;
+ background-color: #155EEF;
+ color: #155EEF;
+ animation-name: dot-flashing-avatar;
+}
+
+.avatar::before {
+ left: -5px;
+}
+
+.avatar::after {
+ left: 5px;
+}
diff --git a/app/components/base/chat/chat/log/index.tsx b/app/components/base/chat/chat/log/index.tsx
new file mode 100644
index 0000000..5963e12
--- /dev/null
+++ b/app/components/base/chat/chat/log/index.tsx
@@ -0,0 +1,42 @@
+import type { FC } from 'react'
+import { RiFileList3Line } from '@remixicon/react'
+import type { IChatItem } from '@/app/components/base/chat/chat/type'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import ActionButton from '@/app/components/base/action-button'
+
+type LogProps = {
+ logItem: IChatItem
+}
+const Log: FC<LogProps> = ({
+ logItem,
+}) => {
+ const setCurrentLogItem = useAppStore(s => s.setCurrentLogItem)
+ const setShowPromptLogModal = useAppStore(s => s.setShowPromptLogModal)
+ const setShowAgentLogModal = useAppStore(s => s.setShowAgentLogModal)
+ const setShowMessageLogModal = useAppStore(s => s.setShowMessageLogModal)
+ const { workflow_run_id: runID, agent_thoughts } = logItem
+ const isAgent = agent_thoughts && agent_thoughts.length > 0
+
+ return (
+ <div
+ className='ml-1 flex items-center gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm'
+ onClick={(e) => {
+ e.stopPropagation()
+ e.nativeEvent.stopImmediatePropagation()
+ setCurrentLogItem(logItem)
+ if (runID)
+ setShowMessageLogModal(true)
+ else if (isAgent)
+ setShowAgentLogModal(true)
+ else
+ setShowPromptLogModal(true)
+ }}
+ >
+ <ActionButton>
+ <RiFileList3Line className='h-4 w-4' />
+ </ActionButton>
+ </div>
+ )
+}
+
+export default Log
diff --git a/app/components/base/chat/chat/question.stories.tsx b/app/components/base/chat/chat/question.stories.tsx
new file mode 100644
index 0000000..9c0eb8c
--- /dev/null
+++ b/app/components/base/chat/chat/question.stories.tsx
@@ -0,0 +1,33 @@
+import type { Meta, StoryObj } from '@storybook/react'
+
+import type { ChatItem } from '../types'
+import Question from './question'
+import { User } from '@/app/components/base/icons/src/public/avatar'
+
+const meta = {
+ title: 'Base/Chat Question',
+ component: Question,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ argTypes: {},
+ args: {},
+} satisfies Meta<typeof Question>
+
+export default meta
+type Story = StoryObj<typeof meta>
+
+export const Default: Story = {
+ args: {
+ item: {
+ id: '1',
+ isAnswer: false,
+ content: 'You are a helpful assistant.',
+ } satisfies ChatItem,
+ theme: undefined,
+ questionIcon: <div className='h-full w-full rounded-full border-[0.5px] border-black/5'>
+ <User className='h-full w-full' />
+ </div>,
+ },
+}
diff --git a/app/components/base/chat/chat/question.tsx b/app/components/base/chat/chat/question.tsx
new file mode 100644
index 0000000..8fc49d1
--- /dev/null
+++ b/app/components/base/chat/chat/question.tsx
@@ -0,0 +1,178 @@
+import type {
+ FC,
+ ReactNode,
+} from 'react'
+import {
+ memo,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from 'react'
+import type { ChatItem } from '../types'
+import type { Theme } from '../embedded-chatbot/theme/theme-context'
+import { CssTransform } from '../embedded-chatbot/theme/utils'
+import ContentSwitch from './content-switch'
+import { User } from '@/app/components/base/icons/src/public/avatar'
+import { Markdown } from '@/app/components/base/markdown'
+import { FileList } from '@/app/components/base/file-uploader'
+import ActionButton from '../../action-button'
+import { RiClipboardLine, RiEditLine } from '@remixicon/react'
+import Toast from '../../toast'
+import copy from 'copy-to-clipboard'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+import Textarea from 'react-textarea-autosize'
+import Button from '../../button'
+import { useChatContext } from './context'
+
+type QuestionProps = {
+ item: ChatItem
+ questionIcon?: ReactNode
+ theme: Theme | null | undefined
+ enableEdit?: boolean
+ switchSibling?: (siblingMessageId: string) => void
+}
+
+const Question: FC<QuestionProps> = ({
+ item,
+ questionIcon,
+ theme,
+ enableEdit = true,
+ switchSibling,
+}) => {
+ const { t } = useTranslation()
+
+ const {
+ content,
+ message_files,
+ } = item
+
+ const {
+ onRegenerate,
+ } = useChatContext()
+
+ const [isEditing, setIsEditing] = useState(false)
+ const [editedContent, setEditedContent] = useState(content)
+ const [contentWidth, setContentWidth] = useState(0)
+ const contentRef = useRef<HTMLDivElement>(null)
+
+ const handleEdit = useCallback(() => {
+ setIsEditing(true)
+ setEditedContent(content)
+ }, [content])
+
+ const handleResend = useCallback(() => {
+ setIsEditing(false)
+ onRegenerate?.(item, { message: editedContent, files: message_files })
+ }, [editedContent, message_files, item, onRegenerate])
+
+ const handleCancelEditing = useCallback(() => {
+ setIsEditing(false)
+ setEditedContent(content)
+ }, [content])
+
+ const handleSwitchSibling = useCallback((direction: 'prev' | 'next') => {
+ if (direction === 'prev')
+ item.prevSibling && switchSibling?.(item.prevSibling)
+ else
+ item.nextSibling && switchSibling?.(item.nextSibling)
+ }, [switchSibling, item.prevSibling, item.nextSibling])
+
+ const getContentWidth = () => {
+ if (contentRef.current)
+ setContentWidth(contentRef.current?.clientWidth)
+ }
+
+ useEffect(() => {
+ if (!contentRef.current)
+ return
+ const resizeObserver = new ResizeObserver(() => {
+ getContentWidth()
+ })
+ resizeObserver.observe(contentRef.current)
+ return () => {
+ resizeObserver.disconnect()
+ }
+ }, [])
+
+ return (
+ <div className='mb-2 flex justify-end last:mb-0'>
+ <div className={cn('group relative mr-4 flex max-w-full items-start pl-14', isEditing && 'flex-1')}>
+ <div className={cn('mr-2 gap-1', isEditing ? 'hidden' : 'flex')}>
+ <div
+ className="absolute hidden gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm group-hover:flex"
+ style={{ right: contentWidth + 8 }}
+ >
+ <ActionButton onClick={() => {
+ copy(content)
+ Toast.notify({ type: 'success', message: t('common.actionMsg.copySuccessfully') })
+ }}>
+ <RiClipboardLine className='h-4 w-4' />
+ </ActionButton>
+ {enableEdit && <ActionButton onClick={handleEdit}>
+ <RiEditLine className='h-4 w-4' />
+ </ActionButton>}
+ </div>
+ </div>
+ <div
+ ref={contentRef}
+ className='w-full rounded-2xl bg-[#D1E9FF]/50 px-4 py-3 text-sm text-gray-900'
+ style={theme?.chatBubbleColorStyle ? CssTransform(theme.chatBubbleColorStyle) : {}}
+ >
+ {
+ !!message_files?.length && (
+ <FileList
+ className='mb-2'
+ files={message_files}
+ showDeleteAction={false}
+ showDownloadAction={true}
+ />
+ )
+ }
+ { !isEditing
+ ? <Markdown content={content} />
+ : <div className="
+ flex flex-col gap-2 rounded-xl
+ border border-components-chat-input-border bg-components-panel-bg-blur p-[9px] shadow-md
+ ">
+ <div className="max-h-[158px] overflow-y-auto overflow-x-hidden">
+ <Textarea
+ className={cn(
+ 'body-lg-regular w-full p-1 leading-6 text-text-tertiary outline-none',
+ )}
+ autoFocus
+ minRows={1}
+ value={editedContent}
+ onChange={e => setEditedContent(e.target.value)}
+ />
+ </div>
+ <div className="flex justify-end gap-2">
+ <Button variant='ghost' onClick={handleCancelEditing}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' onClick={handleResend}>{t('common.chat.resend')}</Button>
+ </div>
+ </div> }
+ { !isEditing && <ContentSwitch
+ count={item.siblingCount}
+ currentIndex={item.siblingIndex}
+ prevDisabled={!item.prevSibling}
+ nextDisabled={!item.nextSibling}
+ switchSibling={handleSwitchSibling}
+ />}
+ </div>
+ <div className='mt-1 h-[18px]' />
+ </div>
+ <div className='h-10 w-10 shrink-0'>
+ {
+ questionIcon || (
+ <div className='h-full w-full rounded-full border-[0.5px] border-black/5'>
+ <User className='h-full w-full' />
+ </div>
+ )
+ }
+ </div>
+ </div>
+ )
+}
+
+export default memo(Question)
diff --git a/app/components/base/chat/chat/thought/index.tsx b/app/components/base/chat/chat/thought/index.tsx
new file mode 100644
index 0000000..36f7e65
--- /dev/null
+++ b/app/components/base/chat/chat/thought/index.tsx
@@ -0,0 +1,58 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import type { ThoughtItem, ToolInfoInThought } from '../type'
+import ToolDetail from '@/app/components/base/chat/chat/answer/tool-detail'
+
+export type IThoughtProps = {
+ thought: ThoughtItem
+ isFinished: boolean
+}
+
+function getValue(value: string, isValueArray: boolean, index: number) {
+ if (isValueArray) {
+ try {
+ return JSON.parse(value)[index]
+ }
+ catch {
+ }
+ }
+ return value
+}
+
+const Thought: FC<IThoughtProps> = ({
+ thought,
+ isFinished,
+}) => {
+ const [toolNames, isValueArray]: [string[], boolean] = (() => {
+ try {
+ if (Array.isArray(JSON.parse(thought.tool)))
+ return [JSON.parse(thought.tool), true]
+ }
+ catch {
+ }
+ return [[thought.tool], false]
+ })()
+
+ const toolThoughtList = toolNames.map((toolName, index) => {
+ return {
+ name: toolName,
+ label: thought.tool_labels?.toolName?.language ?? toolName,
+ input: getValue(thought.tool_input, isValueArray, index),
+ output: getValue(thought.observation, isValueArray, index),
+ isFinished,
+ }
+ })
+
+ return (
+ <div className='my-2 space-y-2'>
+ {toolThoughtList.map((item: ToolInfoInThought, index) => (
+ <ToolDetail
+ key={index}
+ payload={item}
+ />
+ ))}
+ </div>
+ )
+}
+export default React.memo(Thought)
diff --git a/app/components/base/chat/chat/thought/panel.tsx b/app/components/base/chat/chat/thought/panel.tsx
new file mode 100644
index 0000000..541818c
--- /dev/null
+++ b/app/components/base/chat/chat/thought/panel.tsx
@@ -0,0 +1,28 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+
+type Props = {
+ isRequest: boolean
+ toolName: string
+ content: string
+}
+
+const Panel: FC<Props> = ({
+ isRequest,
+ toolName,
+ content,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='overflow-hidden rounded-md border border-black/5 bg-gray-100'>
+ <div className='flex items-center bg-gray-50 px-2 py-1 text-xs font-medium uppercase leading-[18px] text-gray-500'>
+ {t(`tools.thought.${isRequest ? 'requestTitle' : 'responseTitle'}`)} {toolName}
+ </div>
+ <div className='border-t border-black/5 p-2 text-xs leading-4 text-gray-700'>{content}</div>
+ </div>
+ )
+}
+export default React.memo(Panel)
diff --git a/app/components/base/chat/chat/thought/tool.tsx b/app/components/base/chat/chat/thought/tool.tsx
new file mode 100644
index 0000000..d0a3c52
--- /dev/null
+++ b/app/components/base/chat/chat/thought/tool.tsx
@@ -0,0 +1,106 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+
+import {
+ RiArrowDownSLine,
+ RiLoader2Line,
+} from '@remixicon/react'
+import type { ToolInfoInThought } from '../type'
+import Panel from './panel'
+import cn from '@/utils/classnames'
+import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/general'
+import { DataSet as DataSetIcon } from '@/app/components/base/icons/src/public/thought'
+import type { Emoji } from '@/app/components/tools/types'
+import AppIcon from '@/app/components/base/app-icon'
+
+type Props = {
+ payload: ToolInfoInThought
+ allToolIcons?: Record<string, string | Emoji>
+}
+
+const getIcon = (toolName: string, allToolIcons: Record<string, string | Emoji>) => {
+ if (toolName.startsWith('dataset_'))
+ return <DataSetIcon className='shrink-0'></DataSetIcon>
+ const icon = allToolIcons[toolName]
+ if (!icon)
+ return null
+ return (
+ typeof icon === 'string'
+ ? (
+ <div
+ className='h-3 w-3 shrink-0 rounded-[3px] bg-cover bg-center'
+ style={{
+ backgroundImage: `url(${icon})`,
+ }}
+ ></div>
+ )
+ : (
+ <AppIcon
+ className='shrink-0 rounded-[3px]'
+ size='xs'
+ icon={icon?.content}
+ background={icon?.background}
+ />
+ ))
+}
+
+const Tool: FC<Props> = ({
+ payload,
+ allToolIcons = {},
+}) => {
+ const { t } = useTranslation()
+ const { name, label, input, isFinished, output } = payload
+ const toolName = name.startsWith('dataset_') ? t('dataset.knowledge') : name
+ const toolLabel = name.startsWith('dataset_') ? t('dataset.knowledge') : label
+ const [isShowDetail, setIsShowDetail] = useState(false)
+ const icon = getIcon(name, allToolIcons) as any
+ return (
+ <div>
+ <div className={cn(!isShowDetail && 'shadow-sm', !isShowDetail && 'inline-block', 'max-w-full overflow-x-auto rounded-md bg-white')}>
+ <div
+ className={cn('flex h-7 cursor-pointer items-center px-2')}
+ onClick={() => setIsShowDetail(!isShowDetail)}
+ >
+ {!isFinished && (
+ <RiLoader2Line className='h-3 w-3 shrink-0 animate-spin text-gray-500' />
+ )}
+ {isFinished && !isShowDetail && (
+ <CheckCircle className='h-3 w-3 shrink-0 text-[#12B76A]' />
+ )}
+ {isFinished && isShowDetail && (
+ icon
+ )}
+ <span className='mx-1 shrink-0 text-xs font-medium text-gray-500'>
+ {t(`tools.thought.${isFinished ? 'used' : 'using'}`)}
+ </span>
+ <span
+ className='truncate text-xs font-medium text-gray-700'
+ title={toolLabel}
+ >
+ {toolLabel}
+ </span>
+ <RiArrowDownSLine
+ className={cn(isShowDetail && 'rotate-180', 'ml-1 h-3 w-3 shrink-0 cursor-pointer select-none text-gray-500')}
+ />
+ </div>
+ {isShowDetail && (
+ <div className='space-y-2 border-t border-black/5 p-2 '>
+ <Panel
+ isRequest={true}
+ toolName={toolName}
+ content={input} />
+ {output && (
+ <Panel
+ isRequest={false}
+ toolName={toolName}
+ content={output as string} />
+ )}
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+export default React.memo(Tool)
diff --git a/app/components/base/chat/chat/try-to-ask.tsx b/app/components/base/chat/chat/try-to-ask.tsx
new file mode 100644
index 0000000..7e3dcc9
--- /dev/null
+++ b/app/components/base/chat/chat/try-to-ask.tsx
@@ -0,0 +1,47 @@
+import type { FC } from 'react'
+import { memo } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { OnSend } from '../types'
+import Button from '@/app/components/base/button'
+import Divider from '@/app/components/base/divider'
+import cn from '@/utils/classnames'
+
+type TryToAskProps = {
+ suggestedQuestions: string[]
+ onSend: OnSend
+ isMobile?: boolean
+}
+const TryToAsk: FC<TryToAskProps> = ({
+ suggestedQuestions,
+ onSend,
+ isMobile,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='mb-2 py-2'>
+ <div className={cn('mb-2.5 flex items-center justify-between gap-2', isMobile && 'justify-end')}>
+ <Divider bgStyle='gradient' className='h-px grow rotate-180' />
+ <div className='system-xs-medium-uppercase shrink-0 text-text-tertiary'>{t('appDebug.feature.suggestedQuestionsAfterAnswer.tryToAsk')}</div>
+ {!isMobile && <Divider bgStyle='gradient' className='h-px grow' />}
+ </div>
+ <div className={cn('flex flex-wrap justify-center', isMobile && 'justify-end')}>
+ {
+ suggestedQuestions.map((suggestQuestion, index) => (
+ <Button
+ size='small'
+ key={index}
+ variant='secondary-accent'
+ className='mb-1 mr-1 last:mr-0'
+ onClick={() => onSend(suggestQuestion)}
+ >
+ {suggestQuestion}
+ </Button>
+ ))
+ }
+ </div>
+ </div>
+ )
+}
+
+export default memo(TryToAsk)
diff --git a/app/components/base/chat/chat/type.ts b/app/components/base/chat/chat/type.ts
new file mode 100644
index 0000000..b37151f
--- /dev/null
+++ b/app/components/base/chat/chat/type.ts
@@ -0,0 +1,147 @@
+import type { TypeWithI18N } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import type { Annotation, MessageRating } from '@/models/log'
+import type { FileEntity } from '@/app/components/base/file-uploader/types'
+import type { InputVarType } from '@/app/components/workflow/types'
+import type { FileResponse } from '@/types/workflow'
+
+export type MessageMore = {
+ time: string
+ tokens: number
+ latency: number | string
+}
+
+export type FeedbackType = {
+ rating: MessageRating
+ content?: string | null
+}
+
+export type FeedbackFunc = (
+ messageId: string,
+ feedback: FeedbackType
+) => Promise<any>
+export type SubmitAnnotationFunc = (
+ messageId: string,
+ content: string
+) => Promise<any>
+
+export type DisplayScene = 'web' | 'console'
+
+export type ToolInfoInThought = {
+ name: string
+ label: string
+ input: string
+ output: string
+ isFinished: boolean
+}
+
+export type ThoughtItem = {
+ id: string
+ tool: string // plugin or dataset. May has multi.
+ thought: string
+ tool_input: string
+ tool_labels?: { [key: string]: TypeWithI18N }
+ message_id: string
+ conversation_id: string
+ observation: string
+ position: number
+ files?: string[]
+ message_files?: FileEntity[]
+}
+
+export type CitationItem = {
+ content: string
+ data_source_type: string
+ dataset_name: string
+ dataset_id: string
+ document_id: string
+ document_name: string
+ hit_count: number
+ index_node_hash: string
+ segment_id: string
+ segment_position: number
+ score: number
+ word_count: number
+}
+
+export type IChatItem = {
+ id: string
+ content: string
+ citation?: CitationItem[]
+ /**
+ * Specific message type
+ */
+ isAnswer: boolean
+ /**
+ * The user feedback result of this message
+ */
+ feedback?: FeedbackType
+ /**
+ * The admin feedback result of this message
+ */
+ adminFeedback?: FeedbackType
+ /**
+ * Whether to hide the feedback area
+ */
+ feedbackDisabled?: boolean
+ /**
+ * More information about this message
+ */
+ more?: MessageMore
+ annotation?: Annotation
+ useCurrentUserAvatar?: boolean
+ isOpeningStatement?: boolean
+ suggestedQuestions?: string[]
+ log?: { role: string; text: string; files?: FileEntity[] }[]
+ agent_thoughts?: ThoughtItem[]
+ message_files?: FileEntity[]
+ workflow_run_id?: string
+ // for agent log
+ conversationId?: string
+ input?: any
+ parentMessageId?: string | null
+ siblingCount?: number
+ siblingIndex?: number
+ prevSibling?: string
+ nextSibling?: string
+}
+
+export type Metadata = {
+ retriever_resources?: CitationItem[]
+ annotation_reply: {
+ id: string
+ account: {
+ id: string
+ name: string
+ }
+ }
+}
+
+export type MessageEnd = {
+ id: string
+ metadata: Metadata
+ files?: FileResponse[]
+}
+
+export type MessageReplace = {
+ id: string
+ task_id: string
+ answer: string
+ conversation_id: string
+}
+
+export type AnnotationReply = {
+ id: string
+ task_id: string
+ answer: string
+ conversation_id: string
+ annotation_id: string
+ annotation_author_name: string
+}
+
+export type InputForm = {
+ type: InputVarType
+ label: string
+ variable: any
+ required: boolean
+ [key: string]: any
+}
diff --git a/app/components/base/chat/chat/utils.ts b/app/components/base/chat/chat/utils.ts
new file mode 100644
index 0000000..69bc680
--- /dev/null
+++ b/app/components/base/chat/chat/utils.ts
@@ -0,0 +1,52 @@
+import type { InputForm } from './type'
+import { InputVarType } from '@/app/components/workflow/types'
+import { getProcessedFiles } from '@/app/components/base/file-uploader/utils'
+
+export const processOpeningStatement = (openingStatement: string, inputs: Record<string, any>, inputsForm: InputForm[]) => {
+ if (!openingStatement)
+ return openingStatement
+
+ return openingStatement.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
+ const name = inputs[key]
+ if (name) { // has set value
+ return name
+ }
+
+ const valueObj = inputsForm.find(v => v.variable === key)
+ return valueObj ? `{{${valueObj.label}}}` : match
+ })
+}
+
+export const processInputFileFromServer = (fileItem: Record<string, any>) => {
+ return {
+ type: fileItem.type,
+ transfer_method: fileItem.transfer_method,
+ url: fileItem.remote_url,
+ upload_file_id: fileItem.related_id,
+ }
+}
+
+export const getProcessedInputs = (inputs: Record<string, any>, inputsForm: InputForm[]) => {
+ const processedInputs = { ...inputs }
+
+ inputsForm.forEach((item) => {
+ const inputValue = inputs[item.variable]
+ if (!inputValue)
+ return
+
+ if (item.type === InputVarType.singleFile) {
+ if ('transfer_method' in inputValue)
+ processedInputs[item.variable] = processInputFileFromServer(inputValue)
+ else
+ processedInputs[item.variable] = getProcessedFiles([inputValue])[0]
+ }
+ else if (item.type === InputVarType.multiFiles) {
+ if ('transfer_method' in inputValue[0])
+ processedInputs[item.variable] = inputValue.map(processInputFileFromServer)
+ else
+ processedInputs[item.variable] = getProcessedFiles(inputValue)
+ }
+ })
+
+ return processedInputs
+}
diff --git a/app/components/base/chat/constants.ts b/app/components/base/chat/constants.ts
new file mode 100644
index 0000000..309f0f0
--- /dev/null
+++ b/app/components/base/chat/constants.ts
@@ -0,0 +1,2 @@
+export const CONVERSATION_ID_INFO = 'conversationIdInfo'
+export const UUID_NIL = '00000000-0000-0000-0000-000000000000'
diff --git a/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx b/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx
new file mode 100644
index 0000000..a06930c
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx
@@ -0,0 +1,264 @@
+import { useCallback, useEffect, useMemo, useState } from 'react'
+import Chat from '../chat'
+import type {
+ ChatConfig,
+ ChatItem,
+ ChatItemInTree,
+ OnSend,
+} from '../types'
+import { useChat } from '../chat/hooks'
+import { getLastAnswer, isValidGeneratedAnswer } from '../utils'
+import { useEmbeddedChatbotContext } from './context'
+import { isDify } from './utils'
+import { InputVarType } from '@/app/components/workflow/types'
+import { TransferMethod } from '@/types/app'
+import InputsForm from '@/app/components/base/chat/embedded-chatbot/inputs-form'
+import {
+ fetchSuggestedQuestions,
+ getUrl,
+ stopChatMessageResponding,
+} from '@/service/share'
+import AppIcon from '@/app/components/base/app-icon'
+import LogoAvatar from '@/app/components/base/logo/logo-embedded-chat-avatar'
+import AnswerIcon from '@/app/components/base/answer-icon'
+import SuggestedQuestions from '@/app/components/base/chat/chat/answer/suggested-questions'
+import { Markdown } from '@/app/components/base/markdown'
+import cn from '@/utils/classnames'
+import type { FileEntity } from '../../file-uploader/types'
+
+const ChatWrapper = () => {
+ const {
+ appData,
+ appParams,
+ appPrevChatList,
+ currentConversationId,
+ currentConversationItem,
+ currentConversationInputs,
+ inputsForms,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationCompleted,
+ isMobile,
+ isInstalledApp,
+ appId,
+ appMeta,
+ handleFeedback,
+ currentChatInstanceRef,
+ themeBuilder,
+ clearChatList,
+ setClearChatList,
+ setIsResponding,
+ } = useEmbeddedChatbotContext()
+ const appConfig = useMemo(() => {
+ const config = appParams || {}
+
+ return {
+ ...config,
+ file_upload: {
+ ...(config as any).file_upload,
+ fileUploadConfig: (config as any).system_parameters,
+ },
+ supportFeedback: true,
+ opening_statement: currentConversationId ? currentConversationItem?.introduction : (config as any).opening_statement,
+ } as ChatConfig
+ }, [appParams, currentConversationItem?.introduction, currentConversationId])
+ const {
+ chatList,
+ setTargetMessageId,
+ handleSend,
+ handleStop,
+ isResponding: respondingState,
+ suggestedQuestions,
+ } = useChat(
+ appConfig,
+ {
+ inputs: (currentConversationId ? currentConversationInputs : newConversationInputs) as any,
+ inputsForm: inputsForms,
+ },
+ appPrevChatList,
+ taskId => stopChatMessageResponding('', taskId, isInstalledApp, appId),
+ clearChatList,
+ setClearChatList,
+ )
+ const inputsFormValue = currentConversationId ? currentConversationInputs : newConversationInputsRef?.current
+ const inputDisabled = useMemo(() => {
+ let hasEmptyInput = ''
+ let fileIsUploading = false
+ const requiredVars = inputsForms.filter(({ required }) => required)
+ if (requiredVars.length) {
+ requiredVars.forEach(({ variable, label, type }) => {
+ if (hasEmptyInput)
+ return
+
+ if (fileIsUploading)
+ return
+
+ if (!inputsFormValue?.[variable])
+ hasEmptyInput = label as string
+
+ if ((type === InputVarType.singleFile || type === InputVarType.multiFiles) && inputsFormValue?.[variable]) {
+ const files = inputsFormValue[variable]
+ if (Array.isArray(files))
+ fileIsUploading = files.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId)
+ else
+ fileIsUploading = files.transferMethod === TransferMethod.local_file && !files.uploadedId
+ }
+ })
+ }
+ if (hasEmptyInput)
+ return true
+
+ if (fileIsUploading)
+ return true
+ return false
+ }, [inputsFormValue, inputsForms])
+
+ useEffect(() => {
+ if (currentChatInstanceRef.current)
+ currentChatInstanceRef.current.handleStop = handleStop
+ }, [currentChatInstanceRef, handleStop])
+ useEffect(() => {
+ setIsResponding(respondingState)
+ }, [respondingState, setIsResponding])
+
+ const doSend: OnSend = useCallback((message, files, isRegenerate = false, parentAnswer: ChatItem | null = null) => {
+ const data: any = {
+ query: message,
+ files,
+ inputs: currentConversationId ? currentConversationInputs : newConversationInputs,
+ conversation_id: currentConversationId,
+ parent_message_id: (isRegenerate ? parentAnswer?.id : getLastAnswer(chatList)?.id) || null,
+ }
+
+ handleSend(
+ getUrl('chat-messages', isInstalledApp, appId || ''),
+ data,
+ {
+ onGetSuggestedQuestions: responseItemId => fetchSuggestedQuestions(responseItemId, isInstalledApp, appId),
+ onConversationComplete: currentConversationId ? undefined : handleNewConversationCompleted,
+ isPublicAPI: !isInstalledApp,
+ },
+ )
+ }, [currentConversationId, currentConversationInputs, newConversationInputs, chatList, handleSend, isInstalledApp, appId, handleNewConversationCompleted])
+
+ const doRegenerate = useCallback((chatItem: ChatItemInTree, editedQuestion?: { message: string, files?: FileEntity[] }) => {
+ const question = editedQuestion ? chatItem : chatList.find(item => item.id === chatItem.parentMessageId)!
+ const parentAnswer = chatList.find(item => item.id === question.parentMessageId)
+ doSend(editedQuestion ? editedQuestion.message : question.content,
+ editedQuestion ? editedQuestion.files : question.message_files,
+ true,
+ isValidGeneratedAnswer(parentAnswer) ? parentAnswer : null,
+ )
+ }, [chatList, doSend])
+
+ const messageList = useMemo(() => {
+ if (currentConversationId)
+ return chatList
+ return chatList.filter(item => !item.isOpeningStatement)
+ }, [chatList, currentConversationId])
+
+ const [collapsed, setCollapsed] = useState(!!currentConversationId)
+
+ const chatNode = useMemo(() => {
+ if (!inputsForms.length)
+ return null
+ if (isMobile) {
+ if (!currentConversationId)
+ return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} />
+ return <div className='mb-4'></div>
+ }
+ else {
+ return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} />
+ }
+ }, [inputsForms.length, isMobile, currentConversationId, collapsed])
+
+ const welcome = useMemo(() => {
+ const welcomeMessage = chatList.find(item => item.isOpeningStatement)
+ if (respondingState)
+ return null
+ if (currentConversationId)
+ return null
+ if (!welcomeMessage)
+ return null
+ if (!collapsed && inputsForms.length > 0)
+ return null
+ if (welcomeMessage.suggestedQuestions && welcomeMessage.suggestedQuestions?.length > 0) {
+ return (
+ <div className={cn('flex items-center justify-center px-4 py-12', isMobile ? 'min-h-[30vh] py-0' : 'h-[50vh]')}>
+ <div className='flex max-w-[720px] grow gap-4'>
+ <AppIcon
+ size='xl'
+ iconType={appData?.site.icon_type}
+ icon={appData?.site.icon}
+ background={appData?.site.icon_background}
+ imageUrl={appData?.site.icon_url}
+ />
+ <div className='body-lg-regular grow rounded-2xl bg-chat-bubble-bg px-4 py-3 text-text-primary'>
+ <Markdown content={welcomeMessage.content} />
+ <SuggestedQuestions item={welcomeMessage} />
+ </div>
+ </div>
+ </div>
+ )
+ }
+ return (
+ <div className={cn('flex h-[50vh] flex-col items-center justify-center gap-3 py-12', isMobile ? 'min-h-[30vh] py-0' : 'h-[50vh]')}>
+ <AppIcon
+ size='xl'
+ iconType={appData?.site.icon_type}
+ icon={appData?.site.icon}
+ background={appData?.site.icon_background}
+ imageUrl={appData?.site.icon_url}
+ />
+ <div className='max-w-[768px] px-4'>
+ <Markdown className='!body-2xl-regular !text-text-tertiary' content={welcomeMessage.content} />
+ </div>
+ </div>
+ )
+ }, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length, respondingState])
+
+ const answerIcon = isDify()
+ ? <LogoAvatar className='relative shrink-0' />
+ : (appData?.site && appData.site.use_icon_as_answer_icon)
+ ? <AnswerIcon
+ iconType={appData.site.icon_type}
+ icon={appData.site.icon}
+ background={appData.site.icon_background}
+ imageUrl={appData.site.icon_url}
+ />
+ : null
+
+ return (
+ <Chat
+ appData={appData}
+ config={appConfig}
+ chatList={messageList}
+ isResponding={respondingState}
+ chatContainerInnerClassName={cn('mx-auto w-full max-w-full pt-4 tablet:px-4', isMobile && 'px-4')}
+ chatFooterClassName={cn('pb-4', !isMobile && 'rounded-b-2xl')}
+ chatFooterInnerClassName={cn('mx-auto w-full max-w-full px-4', isMobile && 'px-2')}
+ onSend={doSend}
+ inputs={currentConversationId ? currentConversationInputs as any : newConversationInputs}
+ inputsForm={inputsForms}
+ onRegenerate={doRegenerate}
+ onStopResponding={handleStop}
+ chatNode={
+ <>
+ {chatNode}
+ {welcome}
+ </>
+ }
+ allToolIcons={appMeta?.tool_icons || {}}
+ onFeedback={handleFeedback}
+ suggestedQuestions={suggestedQuestions}
+ answerIcon={answerIcon}
+ hideProcessDetail
+ themeBuilder={themeBuilder}
+ switchSibling={siblingMessageId => setTargetMessageId(siblingMessageId)}
+ inputDisabled={inputDisabled}
+ isMobile={isMobile}
+ />
+ )
+}
+
+export default ChatWrapper
diff --git a/app/components/base/chat/embedded-chatbot/context.tsx b/app/components/base/chat/embedded-chatbot/context.tsx
new file mode 100644
index 0000000..fb00dbd
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/context.tsx
@@ -0,0 +1,81 @@
+'use client'
+
+import type { RefObject } from 'react'
+import { createContext, useContext } from 'use-context-selector'
+import type {
+ ChatConfig,
+ ChatItem,
+ Feedback,
+} from '../types'
+import type { ThemeBuilder } from './theme/theme-context'
+import type {
+ AppConversationData,
+ AppData,
+ AppMeta,
+ ConversationItem,
+} from '@/models/share'
+import { noop } from 'lodash-es'
+
+export type EmbeddedChatbotContextValue = {
+ appInfoError?: any
+ appInfoLoading?: boolean
+ appMeta?: AppMeta
+ appData?: AppData
+ appParams?: ChatConfig
+ appChatListDataLoading?: boolean
+ currentConversationId: string
+ currentConversationItem?: ConversationItem
+ appPrevChatList: ChatItem[]
+ pinnedConversationList: AppConversationData['data']
+ conversationList: AppConversationData['data']
+ newConversationInputs: Record<string, any>
+ newConversationInputsRef: RefObject<Record<string, any>>
+ handleNewConversationInputsChange: (v: Record<string, any>) => void
+ inputsForms: any[]
+ handleNewConversation: () => void
+ handleStartChat: (callback?: any) => void
+ handleChangeConversation: (conversationId: string) => void
+ handleNewConversationCompleted: (newConversationId: string) => void
+ chatShouldReloadKey: string
+ isMobile: boolean
+ isInstalledApp: boolean
+ allowResetChat: boolean
+ appId?: string
+ handleFeedback: (messageId: string, feedback: Feedback) => void
+ currentChatInstanceRef: RefObject<{ handleStop: () => void }>
+ themeBuilder?: ThemeBuilder
+ clearChatList?: boolean
+ setClearChatList: (state: boolean) => void
+ isResponding?: boolean
+ setIsResponding: (state: boolean) => void,
+ currentConversationInputs: Record<string, any> | null,
+ setCurrentConversationInputs: (v: Record<string, any>) => void,
+}
+
+export const EmbeddedChatbotContext = createContext<EmbeddedChatbotContextValue>({
+ currentConversationId: '',
+ appPrevChatList: [],
+ pinnedConversationList: [],
+ conversationList: [],
+ newConversationInputs: {},
+ newConversationInputsRef: { current: {} },
+ handleNewConversationInputsChange: noop,
+ inputsForms: [],
+ handleNewConversation: noop,
+ handleStartChat: noop,
+ handleChangeConversation: noop,
+ handleNewConversationCompleted: noop,
+ chatShouldReloadKey: '',
+ isMobile: false,
+ isInstalledApp: false,
+ allowResetChat: true,
+ handleFeedback: noop,
+ currentChatInstanceRef: { current: { handleStop: noop } },
+ clearChatList: false,
+ setClearChatList: noop,
+ isResponding: false,
+ setIsResponding: noop,
+ currentConversationInputs: {},
+ setCurrentConversationInputs: noop,
+})
+export const useEmbeddedChatbotContext = () => useContext(EmbeddedChatbotContext)
diff --git a/app/components/base/chat/embedded-chatbot/header/index.tsx b/app/components/base/chat/embedded-chatbot/header/index.tsx
new file mode 100644
index 0000000..c6c02a4
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/header/index.tsx
@@ -0,0 +1,179 @@
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import { RiCollapseDiagonal2Line, RiExpandDiagonal2Line, RiResetLeftLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import type { Theme } from '../theme/theme-context'
+import { CssTransform } from '../theme/utils'
+import {
+ useEmbeddedChatbotContext,
+} from '../context'
+import Tooltip from '@/app/components/base/tooltip'
+import ActionButton from '@/app/components/base/action-button'
+import Divider from '@/app/components/base/divider'
+import ViewFormDropdown from '@/app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown'
+import DifyLogo from '@/app/components/base/logo/dify-logo'
+import cn from '@/utils/classnames'
+
+export type IHeaderProps = {
+ isMobile?: boolean
+ allowResetChat?: boolean
+ customerIcon?: React.ReactNode
+ title: string
+ theme?: Theme
+ onCreateNewChat?: () => void
+}
+const Header: FC<IHeaderProps> = ({
+ isMobile,
+ allowResetChat,
+ customerIcon,
+ title,
+ theme,
+ onCreateNewChat,
+}) => {
+ const { t } = useTranslation()
+ const {
+ appData,
+ currentConversationId,
+ inputsForms,
+ } = useEmbeddedChatbotContext()
+
+ const isClient = typeof window !== 'undefined'
+ const isIframe = isClient ? window.self !== window.top : false
+ const [parentOrigin, setParentOrigin] = useState('')
+ const [showToggleExpandButton, setShowToggleExpandButton] = useState(false)
+ const [expanded, setExpanded] = useState(false)
+
+ const handleMessageReceived = useCallback((event: MessageEvent) => {
+ let currentParentOrigin = parentOrigin
+ if (!currentParentOrigin && event.data.type === 'dify-chatbot-config') {
+ currentParentOrigin = event.origin
+ setParentOrigin(event.origin)
+ }
+ if (event.origin !== currentParentOrigin)
+ return
+ if (event.data.type === 'dify-chatbot-config')
+ setShowToggleExpandButton(event.data.payload.isToggledByButton && !event.data.payload.isDraggable)
+ }, [parentOrigin])
+
+ useEffect(() => {
+ if (!isIframe) return
+
+ const listener = (event: MessageEvent) => handleMessageReceived(event)
+ window.addEventListener('message', listener)
+
+ window.parent.postMessage({ type: 'dify-chatbot-iframe-ready' }, '*')
+
+ return () => window.removeEventListener('message', listener)
+ }, [isIframe, handleMessageReceived])
+
+ const handleToggleExpand = useCallback(() => {
+ if (!isIframe || !showToggleExpandButton) return
+ setExpanded(!expanded)
+ window.parent.postMessage({
+ type: 'dify-chatbot-expand-change',
+ }, parentOrigin)
+ }, [isIframe, parentOrigin, showToggleExpandButton, expanded])
+
+ if (!isMobile) {
+ return (
+ <div className='flex h-14 shrink-0 items-center justify-end p-3'>
+ <div className='flex items-center gap-1'>
+ {/* powered by */}
+ <div className='shrink-0'>
+ {!appData?.custom_config?.remove_webapp_brand && (
+ <div className={cn(
+ 'flex shrink-0 items-center gap-1.5 px-2',
+ )}>
+ <div className='system-2xs-medium-uppercase text-text-tertiary'>{t('share.chat.poweredBy')}</div>
+ {appData?.custom_config?.replace_webapp_logo && (
+ <img src={appData?.custom_config?.replace_webapp_logo} alt='logo' className='block h-5 w-auto' />
+ )}
+ {!appData?.custom_config?.replace_webapp_logo && (
+ <DifyLogo size='small' />
+ )}
+ </div>
+ )}
+ </div>
+ {currentConversationId && (
+ <Divider type='vertical' className='h-3.5' />
+ )}
+ {
+ showToggleExpandButton && (
+ <Tooltip
+ popupContent={expanded ? t('share.chat.collapse') : t('share.chat.expand')}
+ >
+ <ActionButton size='l' onClick={handleToggleExpand}>
+ {
+ expanded
+ ? <RiCollapseDiagonal2Line className='h-[18px] w-[18px]' />
+ : <RiExpandDiagonal2Line className='h-[18px] w-[18px]' />
+ }
+ </ActionButton>
+ </Tooltip>
+ )
+ }
+ {currentConversationId && allowResetChat && (
+ <Tooltip
+ popupContent={t('share.chat.resetChat')}
+ >
+ <ActionButton size='l' onClick={onCreateNewChat}>
+ <RiResetLeftLine className='h-[18px] w-[18px]' />
+ </ActionButton>
+ </Tooltip>
+ )}
+ {currentConversationId && inputsForms.length > 0 && (
+ <ViewFormDropdown />
+ )}
+ </div>
+ </div>
+ )
+ }
+
+ return (
+ <div
+ className={cn('flex h-14 shrink-0 items-center justify-between rounded-t-2xl px-3')}
+ style={Object.assign({}, CssTransform(theme?.backgroundHeaderColorStyle ?? ''), CssTransform(theme?.headerBorderBottomStyle ?? ''))}
+ >
+ <div className="flex grow items-center space-x-3">
+ {customerIcon}
+ <div
+ className='system-md-semibold truncate'
+ style={CssTransform(theme?.colorFontOnHeaderStyle ?? '')}
+ >
+ {title}
+ </div>
+ </div>
+ <div className='flex items-center gap-1'>
+ {
+ showToggleExpandButton && (
+ <Tooltip
+ popupContent={expanded ? t('share.chat.collapse') : t('share.chat.expand')}
+ >
+ <ActionButton size='l' onClick={handleToggleExpand}>
+ {
+ expanded
+ ? <RiCollapseDiagonal2Line className={cn('h-[18px] w-[18px]', theme?.colorPathOnHeader)} />
+ : <RiExpandDiagonal2Line className={cn('h-[18px] w-[18px]', theme?.colorPathOnHeader)} />
+ }
+ </ActionButton>
+ </Tooltip>
+ )
+ }
+ {currentConversationId && allowResetChat && (
+ <Tooltip
+ popupContent={t('share.chat.resetChat')}
+ >
+ <ActionButton size='l' onClick={onCreateNewChat}>
+ <RiResetLeftLine className={cn('h-[18px] w-[18px]', theme?.colorPathOnHeader)} />
+ </ActionButton>
+ </Tooltip>
+ )}
+ {currentConversationId && inputsForms.length > 0 && (
+ <ViewFormDropdown iconColor={theme?.colorPathOnHeader} />
+ )}
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(Header)
diff --git a/app/components/base/chat/embedded-chatbot/hooks.tsx b/app/components/base/chat/embedded-chatbot/hooks.tsx
new file mode 100644
index 0000000..7efbc95
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/hooks.tsx
@@ -0,0 +1,405 @@
+import {
+ useCallback,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import { useLocalStorageState } from 'ahooks'
+import produce from 'immer'
+import type {
+ ChatConfig,
+ ChatItem,
+ Feedback,
+} from '../types'
+import { CONVERSATION_ID_INFO } from '../constants'
+import { buildChatItemTree, getProcessedInputsFromUrlParams, getProcessedSystemVariablesFromUrlParams } from '../utils'
+import { getProcessedFilesFromResponse } from '../../file-uploader/utils'
+import {
+ fetchAppInfo,
+ fetchAppMeta,
+ fetchAppParams,
+ fetchChatList,
+ fetchConversations,
+ generationConversationName,
+ updateFeedback,
+} from '@/service/share'
+import type {
+ // AppData,
+ ConversationItem,
+} from '@/models/share'
+import { useToastContext } from '@/app/components/base/toast'
+import { changeLanguage } from '@/i18n/i18next-config'
+import { InputVarType } from '@/app/components/workflow/types'
+import { TransferMethod } from '@/types/app'
+import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
+import { noop } from 'lodash-es'
+
+function getFormattedChatList(messages: any[]) {
+ const newChatList: ChatItem[] = []
+ messages.forEach((item) => {
+ const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || []
+ newChatList.push({
+ id: `question-${item.id}`,
+ content: item.query,
+ isAnswer: false,
+ message_files: getProcessedFilesFromResponse(questionFiles.map((item: any) => ({ ...item, related_id: item.id }))),
+ parentMessageId: item.parent_message_id || undefined,
+ })
+ const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || []
+ newChatList.push({
+ id: item.id,
+ content: item.answer,
+ agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files),
+ feedback: item.feedback,
+ isAnswer: true,
+ citation: item.retriever_resources,
+ message_files: getProcessedFilesFromResponse(answerFiles.map((item: any) => ({ ...item, related_id: item.id }))),
+ parentMessageId: `question-${item.id}`,
+ })
+ })
+ return newChatList
+}
+
+export const useEmbeddedChatbot = () => {
+ const isInstalledApp = false
+ const { data: appInfo, isLoading: appInfoLoading, error: appInfoError } = useSWR('appInfo', fetchAppInfo)
+
+ const appData = useMemo(() => {
+ return appInfo
+ }, [appInfo])
+ const appId = useMemo(() => appData?.app_id, [appData])
+
+ const [userId, setUserId] = useState<string>()
+ const [conversationId, setConversationId] = useState<string>()
+ useEffect(() => {
+ getProcessedSystemVariablesFromUrlParams().then(({ user_id, conversation_id }) => {
+ setUserId(user_id)
+ setConversationId(conversation_id)
+ })
+ }, [])
+
+ useEffect(() => {
+ const setLanguageFromParams = async () => {
+ // Check URL parameters for language override
+ const urlParams = new URLSearchParams(window.location.search)
+ const localeParam = urlParams.get('locale')
+
+ // Check for encoded system variables
+ const systemVariables = await getProcessedSystemVariablesFromUrlParams()
+ const localeFromSysVar = systemVariables.locale
+
+ if (localeParam) {
+ // If locale parameter exists in URL, use it instead of default
+ changeLanguage(localeParam)
+ }
+ else if (localeFromSysVar) {
+ // If locale is set as a system variable, use that
+ changeLanguage(localeFromSysVar)
+ }
+ else if (appInfo?.site.default_language) {
+ // Otherwise use the default from app config
+ changeLanguage(appInfo.site.default_language)
+ }
+ }
+
+ setLanguageFromParams()
+ }, [appInfo])
+
+ const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState<Record<string, Record<string, string>>>(CONVERSATION_ID_INFO, {
+ defaultValue: {},
+ })
+ const allowResetChat = !conversationId
+ const currentConversationId = useMemo(() => conversationIdInfo?.[appId || '']?.[userId || 'DEFAULT'] || conversationId || '',
+ [appId, conversationIdInfo, userId, conversationId])
+ const handleConversationIdInfoChange = useCallback((changeConversationId: string) => {
+ if (appId) {
+ let prevValue = conversationIdInfo?.[appId || '']
+ if (typeof prevValue === 'string')
+ prevValue = {}
+ setConversationIdInfo({
+ ...conversationIdInfo,
+ [appId || '']: {
+ ...prevValue,
+ [userId || 'DEFAULT']: changeConversationId,
+ },
+ })
+ }
+ }, [appId, conversationIdInfo, setConversationIdInfo, userId])
+
+ const [newConversationId, setNewConversationId] = useState('')
+ const chatShouldReloadKey = useMemo(() => {
+ if (currentConversationId === newConversationId)
+ return ''
+
+ return currentConversationId
+ }, [currentConversationId, newConversationId])
+
+ const { data: appParams } = useSWR(['appParams', isInstalledApp, appId], () => fetchAppParams(isInstalledApp, appId))
+ const { data: appMeta } = useSWR(['appMeta', isInstalledApp, appId], () => fetchAppMeta(isInstalledApp, appId))
+ const { data: appPinnedConversationData } = useSWR(['appConversationData', isInstalledApp, appId, true], () => fetchConversations(isInstalledApp, appId, undefined, true, 100))
+ const { data: appConversationData, isLoading: appConversationDataLoading, mutate: mutateAppConversationData } = useSWR(['appConversationData', isInstalledApp, appId, false], () => fetchConversations(isInstalledApp, appId, undefined, false, 100))
+ const { data: appChatListData, isLoading: appChatListDataLoading } = useSWR(chatShouldReloadKey ? ['appChatList', chatShouldReloadKey, isInstalledApp, appId] : null, () => fetchChatList(chatShouldReloadKey, isInstalledApp, appId))
+
+ const [clearChatList, setClearChatList] = useState(false)
+ const [isResponding, setIsResponding] = useState(false)
+ const appPrevChatList = useMemo(
+ () => (currentConversationId && appChatListData?.data.length)
+ ? buildChatItemTree(getFormattedChatList(appChatListData.data))
+ : [],
+ [appChatListData, currentConversationId],
+ )
+
+ const [showNewConversationItemInList, setShowNewConversationItemInList] = useState(false)
+
+ const pinnedConversationList = useMemo(() => {
+ return appPinnedConversationData?.data || []
+ }, [appPinnedConversationData])
+ const { t } = useTranslation()
+ const newConversationInputsRef = useRef<Record<string, any>>({})
+ const [newConversationInputs, setNewConversationInputs] = useState<Record<string, any>>({})
+ const [initInputs, setInitInputs] = useState<Record<string, any>>({})
+ const handleNewConversationInputsChange = useCallback((newInputs: Record<string, any>) => {
+ newConversationInputsRef.current = newInputs
+ setNewConversationInputs(newInputs)
+ }, [])
+ const inputsForms = useMemo(() => {
+ return (appParams?.user_input_form || []).filter((item: any) => !item.external_data_tool).map((item: any) => {
+ if (item.paragraph) {
+ let value = initInputs[item.paragraph.variable]
+ if (value && item.paragraph.max_length && value.length > item.paragraph.max_length)
+ value = value.slice(0, item.paragraph.max_length)
+
+ return {
+ ...item.paragraph,
+ default: value || item.default,
+ type: 'paragraph',
+ }
+ }
+ if (item.number) {
+ const convertedNumber = Number(initInputs[item.number.variable]) ?? undefined
+ return {
+ ...item.number,
+ default: convertedNumber || item.default,
+ type: 'number',
+ }
+ }
+ if (item.select) {
+ const isInputInOptions = item.select.options.includes(initInputs[item.select.variable])
+ return {
+ ...item.select,
+ default: (isInputInOptions ? initInputs[item.select.variable] : undefined) || item.default,
+ type: 'select',
+ }
+ }
+
+ if (item['file-list']) {
+ return {
+ ...item['file-list'],
+ type: 'file-list',
+ }
+ }
+
+ if (item.file) {
+ return {
+ ...item.file,
+ type: 'file',
+ }
+ }
+
+ let value = initInputs[item['text-input'].variable]
+ if (value && item['text-input'].max_length && value.length > item['text-input'].max_length)
+ value = value.slice(0, item['text-input'].max_length)
+
+ return {
+ ...item['text-input'],
+ default: value || item.default,
+ type: 'text-input',
+ }
+ })
+ }, [initInputs, appParams])
+
+ useEffect(() => {
+ // init inputs from url params
+ (async () => {
+ const inputs = await getProcessedInputsFromUrlParams()
+ setInitInputs(inputs)
+ })()
+ }, [])
+ useEffect(() => {
+ const conversationInputs: Record<string, any> = {}
+
+ inputsForms.forEach((item: any) => {
+ conversationInputs[item.variable] = item.default || null
+ })
+ handleNewConversationInputsChange(conversationInputs)
+ }, [handleNewConversationInputsChange, inputsForms])
+
+ const { data: newConversation } = useSWR(newConversationId ? [isInstalledApp, appId, newConversationId] : null, () => generationConversationName(isInstalledApp, appId, newConversationId), { revalidateOnFocus: false })
+ const [originConversationList, setOriginConversationList] = useState<ConversationItem[]>([])
+ useEffect(() => {
+ if (appConversationData?.data && !appConversationDataLoading)
+ setOriginConversationList(appConversationData?.data)
+ }, [appConversationData, appConversationDataLoading])
+ const conversationList = useMemo(() => {
+ const data = originConversationList.slice()
+
+ if (showNewConversationItemInList && data[0]?.id !== '') {
+ data.unshift({
+ id: '',
+ name: t('share.chat.newChatDefaultName'),
+ inputs: {},
+ introduction: '',
+ })
+ }
+ return data
+ }, [originConversationList, showNewConversationItemInList, t])
+
+ useEffect(() => {
+ if (newConversation) {
+ setOriginConversationList(produce((draft) => {
+ const index = draft.findIndex(item => item.id === newConversation.id)
+
+ if (index > -1)
+ draft[index] = newConversation
+ else
+ draft.unshift(newConversation)
+ }))
+ }
+ }, [newConversation])
+
+ const currentConversationItem = useMemo(() => {
+ let conversationItem = conversationList.find(item => item.id === currentConversationId)
+
+ if (!conversationItem && pinnedConversationList.length)
+ conversationItem = pinnedConversationList.find(item => item.id === currentConversationId)
+
+ return conversationItem
+ }, [conversationList, currentConversationId, pinnedConversationList])
+
+ const currentConversationLatestInputs = useMemo(() => {
+ if (!currentConversationId || !appChatListData?.data.length)
+ return newConversationInputsRef.current || {}
+ return appChatListData.data.slice().pop().inputs || {}
+ }, [appChatListData, currentConversationId])
+ const [currentConversationInputs, setCurrentConversationInputs] = useState<Record<string, any>>(currentConversationLatestInputs || {})
+ useEffect(() => {
+ if (currentConversationItem)
+ setCurrentConversationInputs(currentConversationLatestInputs || {})
+ }, [currentConversationItem, currentConversationLatestInputs])
+
+ const { notify } = useToastContext()
+ const checkInputsRequired = useCallback((silent?: boolean) => {
+ let hasEmptyInput = ''
+ let fileIsUploading = false
+ const requiredVars = inputsForms.filter(({ required }) => required)
+ if (requiredVars.length) {
+ requiredVars.forEach(({ variable, label, type }) => {
+ if (hasEmptyInput)
+ return
+
+ if (fileIsUploading)
+ return
+
+ if (!newConversationInputsRef.current[variable] && !silent)
+ hasEmptyInput = label as string
+
+ if ((type === InputVarType.singleFile || type === InputVarType.multiFiles) && newConversationInputsRef.current[variable] && !silent) {
+ const files = newConversationInputsRef.current[variable]
+ if (Array.isArray(files))
+ fileIsUploading = files.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId)
+ else
+ fileIsUploading = files.transferMethod === TransferMethod.local_file && !files.uploadedId
+ }
+ })
+ }
+
+ if (hasEmptyInput) {
+ notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }) })
+ return false
+ }
+
+ if (fileIsUploading) {
+ notify({ type: 'info', message: t('appDebug.errorMessage.waitForFileUpload') })
+ return
+ }
+
+ return true
+ }, [inputsForms, notify, t])
+ const handleStartChat = useCallback((callback?: any) => {
+ if (checkInputsRequired()) {
+ setShowNewConversationItemInList(true)
+ callback?.()
+ }
+ }, [setShowNewConversationItemInList, checkInputsRequired])
+ const currentChatInstanceRef = useRef<{ handleStop: () => void }>({ handleStop: noop })
+ const handleChangeConversation = useCallback((conversationId: string) => {
+ currentChatInstanceRef.current.handleStop()
+ setNewConversationId('')
+ handleConversationIdInfoChange(conversationId)
+ if (conversationId)
+ setClearChatList(false)
+ }, [handleConversationIdInfoChange, setClearChatList])
+ const handleNewConversation = useCallback(async () => {
+ currentChatInstanceRef.current.handleStop()
+ setShowNewConversationItemInList(true)
+ handleChangeConversation('')
+ handleNewConversationInputsChange(await getProcessedInputsFromUrlParams())
+ setClearChatList(true)
+ }, [handleChangeConversation, setShowNewConversationItemInList, handleNewConversationInputsChange, setClearChatList])
+
+ const handleNewConversationCompleted = useCallback((newConversationId: string) => {
+ setNewConversationId(newConversationId)
+ handleConversationIdInfoChange(newConversationId)
+ setShowNewConversationItemInList(false)
+ mutateAppConversationData()
+ }, [mutateAppConversationData, handleConversationIdInfoChange])
+
+ const handleFeedback = useCallback(async (messageId: string, feedback: Feedback) => {
+ await updateFeedback({ url: `/messages/${messageId}/feedbacks`, body: { rating: feedback.rating } }, isInstalledApp, appId)
+ notify({ type: 'success', message: t('common.api.success') })
+ }, [isInstalledApp, appId, t, notify])
+
+ return {
+ appInfoError,
+ appInfoLoading,
+ isInstalledApp,
+ allowResetChat,
+ appId,
+ currentConversationId,
+ currentConversationItem,
+ handleConversationIdInfoChange,
+ appData,
+ appParams: appParams || {} as ChatConfig,
+ appMeta,
+ appPinnedConversationData,
+ appConversationData,
+ appConversationDataLoading,
+ appChatListData,
+ appChatListDataLoading,
+ appPrevChatList,
+ pinnedConversationList,
+ conversationList,
+ setShowNewConversationItemInList,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationInputsChange,
+ inputsForms,
+ handleNewConversation,
+ handleStartChat,
+ handleChangeConversation,
+ handleNewConversationCompleted,
+ newConversationId,
+ chatShouldReloadKey,
+ handleFeedback,
+ currentChatInstanceRef,
+ clearChatList,
+ setClearChatList,
+ isResponding,
+ setIsResponding,
+ currentConversationInputs,
+ setCurrentConversationInputs,
+ }
+}
diff --git a/app/components/base/chat/embedded-chatbot/index.tsx b/app/components/base/chat/embedded-chatbot/index.tsx
new file mode 100644
index 0000000..59c358a
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/index.tsx
@@ -0,0 +1,241 @@
+import {
+ useEffect,
+ useState,
+} from 'react'
+import { useAsyncEffect } from 'ahooks'
+import { useTranslation } from 'react-i18next'
+import {
+ EmbeddedChatbotContext,
+ useEmbeddedChatbotContext,
+} from './context'
+import { useEmbeddedChatbot } from './hooks'
+import { isDify } from './utils'
+import { useThemeContext } from './theme/theme-context'
+import { CssTransform } from './theme/utils'
+import { checkOrSetAccessToken } from '@/app/components/share/utils'
+import AppUnavailable from '@/app/components/base/app-unavailable'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import Loading from '@/app/components/base/loading'
+import LogoHeader from '@/app/components/base/logo/logo-embedded-chat-header'
+import Header from '@/app/components/base/chat/embedded-chatbot/header'
+import ChatWrapper from '@/app/components/base/chat/embedded-chatbot/chat-wrapper'
+import DifyLogo from '@/app/components/base/logo/dify-logo'
+import cn from '@/utils/classnames'
+
+const Chatbot = () => {
+ const {
+ isMobile,
+ allowResetChat,
+ appInfoError,
+ appInfoLoading,
+ appData,
+ appChatListDataLoading,
+ chatShouldReloadKey,
+ handleNewConversation,
+ themeBuilder,
+ } = useEmbeddedChatbotContext()
+ const { t } = useTranslation()
+
+ const customConfig = appData?.custom_config
+ const site = appData?.site
+
+ const difyIcon = <LogoHeader />
+
+ useEffect(() => {
+ themeBuilder?.buildTheme(site?.chat_color_theme, site?.chat_color_theme_inverted)
+ if (site) {
+ if (customConfig)
+ document.title = `${site.title}`
+ else
+ document.title = `${site.title} - Powered by Dify`
+ }
+ }, [site, customConfig, themeBuilder])
+
+ if (appInfoLoading) {
+ return (
+ <>
+ {!isMobile && <Loading type='app' />}
+ {isMobile && (
+ <div className={cn('relative')}>
+ <div className={cn('flex h-[calc(100vh_-_60px)] flex-col rounded-2xl border-[0.5px] border-components-panel-border shadow-xs')}>
+ <Loading type='app' />
+ </div>
+ </div>
+ )}
+ </>
+ )
+ }
+
+ if (appInfoError) {
+ return (
+ <>
+ {!isMobile && <AppUnavailable />}
+ {isMobile && (
+ <div className={cn('relative')}>
+ <div className={cn('flex h-[calc(100vh_-_60px)] flex-col rounded-2xl border-[0.5px] border-components-panel-border shadow-xs')}>
+ <AppUnavailable />
+ </div>
+ </div>
+ )}
+ </>
+ )
+ }
+ return (
+ <div className='relative'>
+ <div
+ className={cn(
+ 'flex flex-col rounded-2xl border border-components-panel-border-subtle',
+ isMobile ? 'h-[calc(100vh_-_60px)] border-[0.5px] border-components-panel-border shadow-xs' : 'h-[100vh] bg-chatbot-bg',
+ )}
+ style={isMobile ? Object.assign({}, CssTransform(themeBuilder?.theme?.backgroundHeaderColorStyle ?? '')) : {}}
+ >
+ <Header
+ isMobile={isMobile}
+ allowResetChat={allowResetChat}
+ title={site?.title || ''}
+ customerIcon={isDify() ? difyIcon : ''}
+ theme={themeBuilder?.theme}
+ onCreateNewChat={handleNewConversation}
+ />
+ <div className={cn('flex grow flex-col overflow-y-auto', isMobile && '!h-[calc(100vh_-_3rem)] rounded-2xl bg-chatbot-bg')}>
+ {appChatListDataLoading && (
+ <Loading type='app' />
+ )}
+ {!appChatListDataLoading && (
+ <ChatWrapper key={chatShouldReloadKey} />
+ )}
+ </div>
+ </div>
+ {/* powered by */}
+ {isMobile && (
+ <div className='flex h-[60px] shrink-0 items-center pl-2'>
+ {!appData?.custom_config?.remove_webapp_brand && (
+ <div className={cn(
+ 'flex shrink-0 items-center gap-1.5 px-2',
+ )}>
+ <div className='system-2xs-medium-uppercase text-text-tertiary'>{t('share.chat.poweredBy')}</div>
+ {appData?.custom_config?.replace_webapp_logo && (
+ <img src={appData?.custom_config?.replace_webapp_logo} alt='logo' className='block h-5 w-auto' />
+ )}
+ {!appData?.custom_config?.replace_webapp_logo && (
+ <DifyLogo size='small' />
+ )}
+ </div>
+ )}
+ </div>
+ )}
+ </div>
+ )
+}
+
+const EmbeddedChatbotWrapper = () => {
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+ const themeBuilder = useThemeContext()
+
+ const {
+ appInfoError,
+ appInfoLoading,
+ appData,
+ appParams,
+ appMeta,
+ appChatListDataLoading,
+ currentConversationId,
+ currentConversationItem,
+ appPrevChatList,
+ pinnedConversationList,
+ conversationList,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationInputsChange,
+ inputsForms,
+ handleNewConversation,
+ handleStartChat,
+ handleChangeConversation,
+ handleNewConversationCompleted,
+ chatShouldReloadKey,
+ isInstalledApp,
+ allowResetChat,
+ appId,
+ handleFeedback,
+ currentChatInstanceRef,
+ clearChatList,
+ setClearChatList,
+ isResponding,
+ setIsResponding,
+ currentConversationInputs,
+ setCurrentConversationInputs,
+ } = useEmbeddedChatbot()
+
+ return <EmbeddedChatbotContext.Provider value={{
+ appInfoError,
+ appInfoLoading,
+ appData,
+ appParams,
+ appMeta,
+ appChatListDataLoading,
+ currentConversationId,
+ currentConversationItem,
+ appPrevChatList,
+ pinnedConversationList,
+ conversationList,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationInputsChange,
+ inputsForms,
+ handleNewConversation,
+ handleStartChat,
+ handleChangeConversation,
+ handleNewConversationCompleted,
+ chatShouldReloadKey,
+ isMobile,
+ isInstalledApp,
+ allowResetChat,
+ appId,
+ handleFeedback,
+ currentChatInstanceRef,
+ themeBuilder,
+ clearChatList,
+ setClearChatList,
+ isResponding,
+ setIsResponding,
+ currentConversationInputs,
+ setCurrentConversationInputs,
+ }}>
+ <Chatbot />
+ </EmbeddedChatbotContext.Provider>
+}
+
+const EmbeddedChatbot = () => {
+ const [initialized, setInitialized] = useState(false)
+ const [appUnavailable, setAppUnavailable] = useState<boolean>(false)
+ const [isUnknownReason, setIsUnknownReason] = useState<boolean>(false)
+
+ useAsyncEffect(async () => {
+ if (!initialized) {
+ try {
+ await checkOrSetAccessToken()
+ }
+ catch (e: any) {
+ if (e.status === 404) {
+ setAppUnavailable(true)
+ }
+ else {
+ setIsUnknownReason(true)
+ setAppUnavailable(true)
+ }
+ }
+ setInitialized(true)
+ }
+ }, [])
+
+ if (!initialized)
+ return null
+
+ if (appUnavailable)
+ return <AppUnavailable isUnknownReason={isUnknownReason} />
+
+ return <EmbeddedChatbotWrapper />
+}
+
+export default EmbeddedChatbot
diff --git a/app/components/base/chat/embedded-chatbot/inputs-form/content.tsx b/app/components/base/chat/embedded-chatbot/inputs-form/content.tsx
new file mode 100644
index 0000000..e56520d
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/inputs-form/content.tsx
@@ -0,0 +1,115 @@
+import React, { memo, useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useEmbeddedChatbotContext } from '../context'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import { PortalSelect } from '@/app/components/base/select'
+import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader'
+import { InputVarType } from '@/app/components/workflow/types'
+
+type Props = {
+ showTip?: boolean
+}
+
+const InputsFormContent = ({ showTip }: Props) => {
+ const { t } = useTranslation()
+ const {
+ appParams,
+ inputsForms,
+ currentConversationId,
+ currentConversationInputs,
+ setCurrentConversationInputs,
+ newConversationInputs,
+ newConversationInputsRef,
+ handleNewConversationInputsChange,
+ } = useEmbeddedChatbotContext()
+ const inputsFormValue = currentConversationId ? currentConversationInputs : newConversationInputs
+
+ const handleFormChange = useCallback((variable: string, value: any) => {
+ setCurrentConversationInputs({
+ ...currentConversationInputs,
+ [variable]: value,
+ })
+ handleNewConversationInputsChange({
+ ...newConversationInputsRef.current,
+ [variable]: value,
+ })
+ }, [newConversationInputsRef, handleNewConversationInputsChange, currentConversationInputs, setCurrentConversationInputs])
+
+ return (
+ <div className='space-y-4'>
+ {inputsForms.map(form => (
+ <div key={form.variable} className='space-y-1'>
+ <div className='flex h-6 items-center gap-1'>
+ <div className='system-md-semibold text-text-secondary'>{form.label}</div>
+ {!form.required && (
+ <div className='system-xs-regular text-text-tertiary'>{t('appDebug.variableTable.optional')}</div>
+ )}
+ </div>
+ {form.type === InputVarType.textInput && (
+ <Input
+ value={inputsFormValue?.[form.variable] || ''}
+ onChange={e => handleFormChange(form.variable, e.target.value)}
+ placeholder={form.label}
+ />
+ )}
+ {form.type === InputVarType.number && (
+ <Input
+ type='number'
+ value={inputsFormValue?.[form.variable] || ''}
+ onChange={e => handleFormChange(form.variable, e.target.value)}
+ placeholder={form.label}
+ />
+ )}
+ {form.type === InputVarType.paragraph && (
+ <Textarea
+ value={inputsFormValue?.[form.variable] || ''}
+ onChange={e => handleFormChange(form.variable, e.target.value)}
+ placeholder={form.label}
+ />
+ )}
+ {form.type === InputVarType.select && (
+ <PortalSelect
+ popupClassName='w-[200px]'
+ value={inputsFormValue?.[form.variable]}
+ items={form.options.map((option: string) => ({ value: option, name: option }))}
+ onSelect={item => handleFormChange(form.variable, item.value as string)}
+ placeholder={form.label}
+ />
+ )}
+ {form.type === InputVarType.singleFile && (
+ <FileUploaderInAttachmentWrapper
+ value={inputsFormValue?.[form.variable] ? [inputsFormValue?.[form.variable]] : []}
+ onChange={files => handleFormChange(form.variable, files[0])}
+ fileConfig={{
+ allowed_file_types: form.allowed_file_types,
+ allowed_file_extensions: form.allowed_file_extensions,
+ allowed_file_upload_methods: form.allowed_file_upload_methods,
+ number_limits: 1,
+ fileUploadConfig: (appParams as any).system_parameters,
+ }}
+ />
+ )}
+ {form.type === InputVarType.multiFiles && (
+ <FileUploaderInAttachmentWrapper
+ value={inputsFormValue?.[form.variable] || []}
+ onChange={files => handleFormChange(form.variable, files)}
+ fileConfig={{
+ allowed_file_types: form.allowed_file_types,
+ allowed_file_extensions: form.allowed_file_extensions,
+ allowed_file_upload_methods: form.allowed_file_upload_methods,
+ number_limits: form.max_length,
+ fileUploadConfig: (appParams as any).system_parameters,
+ }}
+ />
+ )}
+ </div>
+ ))}
+ {showTip && (
+ <div className='system-xs-regular text-text-tertiary'>{t('share.chat.chatFormTip')}</div>
+ )}
+ </div>
+ )
+}
+
+export default memo(InputsFormContent)
diff --git a/app/components/base/chat/embedded-chatbot/inputs-form/index.tsx b/app/components/base/chat/embedded-chatbot/inputs-form/index.tsx
new file mode 100644
index 0000000..4ac4aaa
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/inputs-form/index.tsx
@@ -0,0 +1,79 @@
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { Message3Fill } from '@/app/components/base/icons/src/public/other'
+import Button from '@/app/components/base/button'
+import Divider from '@/app/components/base/divider'
+import InputsFormContent from '@/app/components/base/chat/embedded-chatbot/inputs-form/content'
+import { useEmbeddedChatbotContext } from '../context'
+import cn from '@/utils/classnames'
+
+type Props = {
+ collapsed: boolean
+ setCollapsed: (collapsed: boolean) => void
+}
+
+const InputsFormNode = ({
+ collapsed,
+ setCollapsed,
+}: Props) => {
+ const { t } = useTranslation()
+ const {
+ isMobile,
+ currentConversationId,
+ themeBuilder,
+ handleStartChat,
+ } = useEmbeddedChatbotContext()
+
+ return (
+ <div className={cn('mb-6 flex flex-col items-center px-4 pt-6', isMobile && 'mb-4 pt-4')}>
+ <div className={cn(
+ 'w-full max-w-[672px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-md',
+ collapsed && 'border border-components-card-border bg-components-card-bg shadow-none',
+ )}>
+ <div className={cn(
+ 'flex items-center gap-3 rounded-t-2xl px-6 py-4',
+ !collapsed && 'border-b border-divider-subtle',
+ isMobile && 'px-4 py-3',
+ )}>
+ <Message3Fill className='h-6 w-6 shrink-0' />
+ <div className='system-xl-semibold grow text-text-secondary'>{t('share.chat.chatSettingsTitle')}</div>
+ {collapsed && (
+ <Button className='uppercase text-text-tertiary' size='small' variant='ghost' onClick={() => setCollapsed(false)}>{t('common.operation.edit')}</Button>
+ )}
+ {!collapsed && currentConversationId && (
+ <Button className='uppercase text-text-tertiary' size='small' variant='ghost' onClick={() => setCollapsed(true)}>{t('common.operation.close')}</Button>
+ )}
+ </div>
+ {!collapsed && (
+ <div className={cn('p-6', isMobile && 'p-4')}>
+ <InputsFormContent />
+ </div>
+ )}
+ {!collapsed && !currentConversationId && (
+ <div className={cn('p-6', isMobile && 'p-4')}>
+ <Button
+ variant='primary'
+ className='w-full'
+ onClick={() => handleStartChat(() => setCollapsed(true))}
+ style={
+ themeBuilder?.theme
+ ? {
+ backgroundColor: themeBuilder?.theme.primaryColor,
+ }
+ : {}
+ }
+ >{t('share.chat.startChat')}</Button>
+ </div>
+ )}
+ </div>
+ {collapsed && (
+ <div className='flex w-full max-w-[720px] items-center py-4'>
+ <Divider bgStyle='gradient' className='h-px basis-1/2 rotate-180' />
+ <Divider bgStyle='gradient' className='h-px basis-1/2' />
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default InputsFormNode
diff --git a/app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown.tsx b/app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown.tsx
new file mode 100644
index 0000000..d6c8986
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown.tsx
@@ -0,0 +1,52 @@
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiChatSettingsLine,
+} from '@remixicon/react'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+import { Message3Fill } from '@/app/components/base/icons/src/public/other'
+import InputsFormContent from '@/app/components/base/chat/embedded-chatbot/inputs-form/content'
+import cn from '@/utils/classnames'
+
+type Props = {
+ iconColor?: string
+}
+const ViewFormDropdown = ({ iconColor }: Props) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 4,
+ crossAxis: 4,
+ }}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ >
+ <ActionButton size='l' state={open ? ActionButtonState.Hover : ActionButtonState.Default}>
+ <RiChatSettingsLine className={cn('h-[18px] w-[18px]', iconColor)} />
+ </ActionButton>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className="z-50">
+ <div className='w-[400px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg backdrop-blur-sm'>
+ <div className='flex items-center gap-3 rounded-t-2xl border-b border-divider-subtle px-6 py-4'>
+ <Message3Fill className='h-6 w-6 shrink-0' />
+ <div className='system-xl-semibold grow text-text-secondary'>{t('share.chat.chatSettingsTitle')}</div>
+ </div>
+ <div className='p-6'>
+ <InputsFormContent />
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+
+ )
+}
+
+export default ViewFormDropdown
diff --git a/app/components/base/chat/embedded-chatbot/theme/theme-context.ts b/app/components/base/chat/embedded-chatbot/theme/theme-context.ts
new file mode 100644
index 0000000..d4d617d
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/theme/theme-context.ts
@@ -0,0 +1,75 @@
+import { createContext, useContext } from 'use-context-selector'
+import { hexToRGBA } from './utils'
+
+export class Theme {
+ public chatColorTheme: string | null
+ public chatColorThemeInverted: boolean
+
+ public primaryColor = '#1C64F2'
+ public backgroundHeaderColorStyle = 'backgroundImage: linear-gradient(to right, #2563eb, #0ea5e9)'
+ public headerBorderBottomStyle = ''
+ public colorFontOnHeaderStyle = 'color: white'
+ public colorPathOnHeader = 'text-text-primary-on-surface'
+ public backgroundButtonDefaultColorStyle = 'backgroundColor: #1C64F2'
+ public roundedBackgroundColorStyle = 'backgroundColor: rgb(245 248 255)'
+ public chatBubbleColorStyle = 'backgroundColor: rgb(225 239 254)'
+ public chatBubbleColor = 'rgb(225 239 254)'
+
+ constructor(chatColorTheme: string | null = null, chatColorThemeInverted = false) {
+ this.chatColorTheme = chatColorTheme
+ this.chatColorThemeInverted = chatColorThemeInverted
+ this.configCustomColor()
+ this.configInvertedColor()
+ }
+
+ private configCustomColor() {
+ if (this.chatColorTheme !== null && this.chatColorTheme !== '') {
+ this.primaryColor = this.chatColorTheme ?? '#1C64F2'
+ this.backgroundHeaderColorStyle = `backgroundColor: ${this.primaryColor}`
+ this.backgroundButtonDefaultColorStyle = `backgroundColor: ${this.primaryColor}; color: ${this.colorFontOnHeaderStyle};`
+ this.roundedBackgroundColorStyle = `backgroundColor: ${hexToRGBA(this.primaryColor, 0.05)}`
+ this.chatBubbleColorStyle = `backgroundColor: ${hexToRGBA(this.primaryColor, 0.15)}`
+ this.chatBubbleColor = `${hexToRGBA(this.primaryColor, 0.15)}`
+ }
+ }
+
+ private configInvertedColor() {
+ if (this.chatColorThemeInverted) {
+ this.backgroundHeaderColorStyle = 'backgroundColor: #ffffff'
+ this.colorFontOnHeaderStyle = `color: ${this.primaryColor}`
+ this.headerBorderBottomStyle = 'borderBottom: 1px solid #ccc'
+ this.colorPathOnHeader = this.primaryColor
+ }
+ }
+}
+
+export class ThemeBuilder {
+ private _theme?: Theme
+ private buildChecker = false
+
+ public get theme() {
+ if (this._theme === undefined) {
+ this._theme = new Theme()
+ return this._theme
+ }
+ else {
+ return this._theme
+ }
+ }
+
+ public buildTheme(chatColorTheme: string | null = null, chatColorThemeInverted = false) {
+ if (!this.buildChecker) {
+ this._theme = new Theme(chatColorTheme, chatColorThemeInverted)
+ this.buildChecker = true
+ }
+ else {
+ if (this.theme?.chatColorTheme !== chatColorTheme || this.theme?.chatColorThemeInverted !== chatColorThemeInverted) {
+ this._theme = new Theme(chatColorTheme, chatColorThemeInverted)
+ this.buildChecker = true
+ }
+ }
+ }
+}
+
+const ThemeContext = createContext<ThemeBuilder>(new ThemeBuilder())
+export const useThemeContext = () => useContext(ThemeContext)
diff --git a/app/components/base/chat/embedded-chatbot/theme/utils.ts b/app/components/base/chat/embedded-chatbot/theme/utils.ts
new file mode 100644
index 0000000..812b928
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/theme/utils.ts
@@ -0,0 +1,29 @@
+export function hexToRGBA(hex: string, opacity: number): string {
+ hex = hex.replace('#', '')
+
+ const r = Number.parseInt(hex.slice(0, 2), 16)
+ const g = Number.parseInt(hex.slice(2, 4), 16)
+ const b = Number.parseInt(hex.slice(4, 6), 16)
+
+ // Returning an RGB color object
+ return `rgba(${r},${g},${b},${opacity.toString()})`
+}
+
+/**
+ * Since strings cannot be directly assigned to the 'style' attribute in JSX,
+ * this method transforms the string into an object representation of the styles.
+ */
+export function CssTransform(cssString: string): object {
+ if (cssString.length === 0)
+ return {}
+
+ const style: object = {}
+ const propertyValuePairs = cssString.split(';')
+ for (const pair of propertyValuePairs) {
+ if (pair.trim().length > 0) {
+ const [property, value] = pair.split(':')
+ Object.assign(style, { [property.trim()]: value.trim() })
+ }
+ }
+ return style
+}
diff --git a/app/components/base/chat/embedded-chatbot/utils.ts b/app/components/base/chat/embedded-chatbot/utils.ts
new file mode 100644
index 0000000..a3fa68e
--- /dev/null
+++ b/app/components/base/chat/embedded-chatbot/utils.ts
@@ -0,0 +1,3 @@
+export const isDify = () => {
+ return document.referrer.includes('dify.ai')
+}
diff --git a/app/components/base/chat/types.ts b/app/components/base/chat/types.ts
new file mode 100644
index 0000000..91f9bc9
--- /dev/null
+++ b/app/components/base/chat/types.ts
@@ -0,0 +1,86 @@
+import type {
+ ModelConfig,
+ VisionSettings,
+} from '@/types/app'
+import type { IChatItem } from '@/app/components/base/chat/chat/type'
+import type { NodeTracing } from '@/types/workflow'
+import type { WorkflowRunningStatus } from '@/app/components/workflow/types'
+import type { FileEntity } from '@/app/components/base/file-uploader/types'
+
+export type { VisionFile } from '@/types/app'
+export { TransferMethod } from '@/types/app'
+export type {
+ Inputs,
+ PromptVariable,
+} from '@/models/debug'
+
+export type UserInputForm = {
+ default: string
+ label: string
+ required: boolean
+ variable: string
+}
+
+export type UserInputFormTextInput = {
+ 'text-input': UserInputForm & {
+ max_length: number
+ }
+}
+
+export type UserInputFormSelect = {
+ select: UserInputForm & {
+ options: string[]
+ }
+}
+
+export type UserInputFormParagraph = {
+ paragraph: UserInputForm
+}
+
+export type VisionConfig = VisionSettings
+
+export type EnableType = {
+ enabled: boolean
+}
+
+export type ChatConfig = Omit<ModelConfig, 'model'> & {
+ supportAnnotation?: boolean
+ appId?: string
+ questionEditEnable?: boolean
+ supportFeedback?: boolean
+ supportCitationHitInfo?: boolean
+}
+
+export type WorkflowProcess = {
+ status: WorkflowRunningStatus
+ tracing: NodeTracing[]
+ expand?: boolean // for UI
+ resultText?: string
+ files?: FileEntity[]
+}
+
+export type ChatItem = IChatItem & {
+ isError?: boolean
+ workflowProcess?: WorkflowProcess
+ conversationId?: string
+ allFiles?: FileEntity[]
+}
+
+export type ChatItemInTree = {
+ children?: ChatItemInTree[]
+} & ChatItem
+
+export type OnSend = {
+ (message: string, files?: FileEntity[]): void
+ (message: string, files: FileEntity[] | undefined, isRegenerate: boolean, lastAnswer?: ChatItem | null): void
+}
+
+export type OnRegenerate = (chatItem: ChatItem) => void
+
+export type Callback = {
+ onSuccess: () => void
+}
+
+export type Feedback = {
+ rating: 'like' | 'dislike' | null
+}
diff --git a/app/components/base/chat/utils.ts b/app/components/base/chat/utils.ts
new file mode 100644
index 0000000..bdac599
--- /dev/null
+++ b/app/components/base/chat/utils.ts
@@ -0,0 +1,193 @@
+import { UUID_NIL } from './constants'
+import type { IChatItem } from './chat/type'
+import type { ChatItem, ChatItemInTree } from './types'
+
+async function decodeBase64AndDecompress(base64String: string) {
+ try {
+ const binaryString = atob(base64String)
+ const compressedUint8Array = Uint8Array.from(binaryString, char => char.charCodeAt(0))
+ const decompressedStream = new Response(compressedUint8Array).body?.pipeThrough(new DecompressionStream('gzip'))
+ const decompressedArrayBuffer = await new Response(decompressedStream).arrayBuffer()
+ return new TextDecoder().decode(decompressedArrayBuffer)
+ }
+ catch {
+ return undefined
+ }
+}
+
+async function getProcessedInputsFromUrlParams(): Promise<Record<string, any>> {
+ const urlParams = new URLSearchParams(window.location.search)
+ const inputs: Record<string, any> = {}
+ const entriesArray = Array.from(urlParams.entries())
+ await Promise.all(
+ entriesArray.map(async ([key, value]) => {
+ if (!key.startsWith('sys.'))
+ inputs[key] = await decodeBase64AndDecompress(decodeURIComponent(value))
+ }),
+ )
+ return inputs
+}
+
+async function getProcessedSystemVariablesFromUrlParams(): Promise<Record<string, any>> {
+ const urlParams = new URLSearchParams(window.location.search)
+ const systemVariables: Record<string, any> = {}
+ const entriesArray = Array.from(urlParams.entries())
+ await Promise.all(
+ entriesArray.map(async ([key, value]) => {
+ if (key.startsWith('sys.'))
+ systemVariables[key.slice(4)] = await decodeBase64AndDecompress(decodeURIComponent(value))
+ }),
+ )
+ return systemVariables
+}
+
+function isValidGeneratedAnswer(item?: ChatItem | ChatItemInTree): boolean {
+ return !!item && item.isAnswer && !item.id.startsWith('answer-placeholder-') && !item.isOpeningStatement
+}
+
+function getLastAnswer<T extends ChatItem | ChatItemInTree>(chatList: T[]): T | null {
+ for (let i = chatList.length - 1; i >= 0; i--) {
+ const item = chatList[i]
+ if (isValidGeneratedAnswer(item))
+ return item
+ }
+ return null
+}
+
+/**
+ * Build a chat item tree from a chat list
+ * @param allMessages - The chat list, sorted from oldest to newest
+ * @returns The chat item tree
+ */
+function buildChatItemTree(allMessages: IChatItem[]): ChatItemInTree[] {
+ const map: Record<string, ChatItemInTree> = {}
+ const rootNodes: ChatItemInTree[] = []
+ const childrenCount: Record<string, number> = {}
+
+ let lastAppendedLegacyAnswer: ChatItemInTree | null = null
+ for (let i = 0; i < allMessages.length; i += 2) {
+ const question = allMessages[i]!
+ const answer = allMessages[i + 1]!
+
+ const isLegacy = question.parentMessageId === UUID_NIL
+ const parentMessageId = isLegacy
+ ? (lastAppendedLegacyAnswer?.id || '')
+ : (question.parentMessageId || '')
+
+ // Process question
+ childrenCount[parentMessageId] = (childrenCount[parentMessageId] || 0) + 1
+ const questionNode: ChatItemInTree = {
+ ...question,
+ children: [],
+ }
+ map[question.id] = questionNode
+
+ // Process answer
+ childrenCount[question.id] = 1
+ const answerNode: ChatItemInTree = {
+ ...answer,
+ children: [],
+ siblingIndex: isLegacy ? 0 : childrenCount[parentMessageId] - 1,
+ }
+ map[answer.id] = answerNode
+
+ // Connect question and answer
+ questionNode.children!.push(answerNode)
+
+ // Append to parent or add to root
+ if (isLegacy) {
+ if (!lastAppendedLegacyAnswer)
+ rootNodes.push(questionNode)
+ else
+ lastAppendedLegacyAnswer.children!.push(questionNode)
+
+ lastAppendedLegacyAnswer = answerNode
+ }
+ else {
+ if (
+ !parentMessageId
+ || !allMessages.some(item => item.id === parentMessageId) // parent message might not be fetched yet, in this case we will append the question to the root nodes
+ )
+ rootNodes.push(questionNode)
+ else
+ map[parentMessageId]?.children!.push(questionNode)
+ }
+ }
+
+ return rootNodes
+}
+
+function getThreadMessages(tree: ChatItemInTree[], targetMessageId?: string): ChatItemInTree[] {
+ let ret: ChatItemInTree[] = []
+ let targetNode: ChatItemInTree | undefined
+
+ // find path to the target message
+ const stack = tree.slice().reverse().map(rootNode => ({
+ node: rootNode,
+ path: [rootNode],
+ }))
+ while (stack.length > 0) {
+ const { node, path } = stack.pop()!
+ if (
+ node.id === targetMessageId
+ || (!targetMessageId && !node.children?.length && !stack.length) // if targetMessageId is not provided, we use the last message in the tree as the target
+ ) {
+ targetNode = node
+ ret = path.map((item, index) => {
+ if (!item.isAnswer)
+ return item
+
+ const parentAnswer = path[index - 2]
+ const siblingCount = !parentAnswer ? tree.length : parentAnswer.children!.length
+ const prevSibling = !parentAnswer ? tree[item.siblingIndex! - 1]?.children?.[0]?.id : parentAnswer.children![item.siblingIndex! - 1]?.children?.[0].id
+ const nextSibling = !parentAnswer ? tree[item.siblingIndex! + 1]?.children?.[0]?.id : parentAnswer.children![item.siblingIndex! + 1]?.children?.[0].id
+
+ return { ...item, siblingCount, prevSibling, nextSibling }
+ })
+ break
+ }
+ if (node.children) {
+ for (let i = node.children.length - 1; i >= 0; i--) {
+ stack.push({
+ node: node.children[i],
+ path: [...path, node.children[i]],
+ })
+ }
+ }
+ }
+
+ // append all descendant messages to the path
+ if (targetNode) {
+ const stack = [targetNode]
+ while (stack.length > 0) {
+ const node = stack.pop()!
+ if (node !== targetNode)
+ ret.push(node)
+ if (node.children?.length) {
+ const lastChild = node.children.at(-1)!
+
+ if (!lastChild.isAnswer) {
+ stack.push(lastChild)
+ continue
+ }
+
+ const parentAnswer = ret.at(-2)
+ const siblingCount = parentAnswer?.children?.length
+ const prevSibling = parentAnswer?.children?.at(-2)?.children?.[0]?.id
+
+ stack.push({ ...lastChild, siblingCount, prevSibling })
+ }
+ }
+ }
+
+ return ret
+}
+
+export {
+ getProcessedInputsFromUrlParams,
+ getProcessedSystemVariablesFromUrlParams,
+ isValidGeneratedAnswer,
+ getLastAnswer,
+ buildChatItemTree,
+ getThreadMessages,
+}
diff --git a/app/components/base/checkbox/assets/indeterminate-icon.tsx b/app/components/base/checkbox/assets/indeterminate-icon.tsx
new file mode 100644
index 0000000..56df8db
--- /dev/null
+++ b/app/components/base/checkbox/assets/indeterminate-icon.tsx
@@ -0,0 +1,11 @@
+const IndeterminateIcon = () => {
+ return (
+ <div data-testid='indeterminate-icon'>
+ <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
+ <path d="M2.5 6H9.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/>
+ </svg>
+ </div>
+ )
+}
+
+export default IndeterminateIcon
diff --git a/app/components/base/checkbox/index.spec.tsx b/app/components/base/checkbox/index.spec.tsx
new file mode 100644
index 0000000..7ef901a
--- /dev/null
+++ b/app/components/base/checkbox/index.spec.tsx
@@ -0,0 +1,67 @@
+import { fireEvent, render, screen } from '@testing-library/react'
+import Checkbox from './index'
+
+describe('Checkbox Component', () => {
+ const mockProps = {
+ id: 'test',
+ }
+
+ it('renders unchecked checkbox by default', () => {
+ render(<Checkbox {...mockProps} />)
+ const checkbox = screen.getByTestId('checkbox-test')
+ expect(checkbox).toBeInTheDocument()
+ expect(checkbox).not.toHaveClass('bg-components-checkbox-bg')
+ })
+
+ it('renders checked checkbox when checked prop is true', () => {
+ render(<Checkbox {...mockProps} checked />)
+ const checkbox = screen.getByTestId('checkbox-test')
+ expect(checkbox).toHaveClass('bg-components-checkbox-bg')
+ expect(screen.getByTestId('check-icon-test')).toBeInTheDocument()
+ })
+
+ it('renders indeterminate state correctly', () => {
+ render(<Checkbox {...mockProps} indeterminate />)
+ expect(screen.getByTestId('indeterminate-icon')).toBeInTheDocument()
+ })
+
+ it('handles click events when not disabled', () => {
+ const onCheck = jest.fn()
+ render(<Checkbox {...mockProps} onCheck={onCheck} />)
+ const checkbox = screen.getByTestId('checkbox-test')
+
+ fireEvent.click(checkbox)
+ expect(onCheck).toHaveBeenCalledTimes(1)
+ })
+
+ it('does not handle click events when disabled', () => {
+ const onCheck = jest.fn()
+ render(<Checkbox {...mockProps} disabled onCheck={onCheck} />)
+ const checkbox = screen.getByTestId('checkbox-test')
+
+ fireEvent.click(checkbox)
+ expect(onCheck).not.toHaveBeenCalled()
+ expect(checkbox).toHaveClass('cursor-not-allowed')
+ })
+
+ it('applies custom className when provided', () => {
+ const customClass = 'custom-class'
+ render(<Checkbox {...mockProps} className={customClass} />)
+ const checkbox = screen.getByTestId('checkbox-test')
+ expect(checkbox).toHaveClass(customClass)
+ })
+
+ it('applies correct styles for disabled checked state', () => {
+ render(<Checkbox {...mockProps} checked disabled />)
+ const checkbox = screen.getByTestId('checkbox-test')
+ expect(checkbox).toHaveClass('bg-components-checkbox-bg-disabled-checked')
+ expect(checkbox).toHaveClass('cursor-not-allowed')
+ })
+
+ it('applies correct styles for disabled unchecked state', () => {
+ render(<Checkbox {...mockProps} disabled />)
+ const checkbox = screen.getByTestId('checkbox-test')
+ expect(checkbox).toHaveClass('bg-components-checkbox-bg-disabled')
+ expect(checkbox).toHaveClass('cursor-not-allowed')
+ })
+})
diff --git a/app/components/base/checkbox/index.tsx b/app/components/base/checkbox/index.tsx
new file mode 100644
index 0000000..3e47967
--- /dev/null
+++ b/app/components/base/checkbox/index.tsx
@@ -0,0 +1,51 @@
+import { RiCheckLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import IndeterminateIcon from './assets/indeterminate-icon'
+
+type CheckboxProps = {
+ id?: string
+ checked?: boolean
+ onCheck?: () => void
+ className?: string
+ disabled?: boolean
+ indeterminate?: boolean
+}
+
+const Checkbox = ({
+ id,
+ checked,
+ onCheck,
+ className,
+ disabled,
+ indeterminate,
+}: CheckboxProps) => {
+ const checkClassName = (checked || indeterminate)
+ ? 'bg-components-checkbox-bg text-components-checkbox-icon hover:bg-components-checkbox-bg-hover'
+ : 'border border-components-checkbox-border bg-components-checkbox-bg-unchecked hover:bg-components-checkbox-bg-unchecked-hover hover:border-components-checkbox-border-hover'
+ const disabledClassName = (checked || indeterminate)
+ ? 'cursor-not-allowed bg-components-checkbox-bg-disabled-checked text-components-checkbox-icon-disabled hover:bg-components-checkbox-bg-disabled-checked'
+ : 'cursor-not-allowed border-components-checkbox-border-disabled bg-components-checkbox-bg-disabled hover:border-components-checkbox-border-disabled hover:bg-components-checkbox-bg-disabled'
+
+ return (
+ <div
+ id={id}
+ className={cn(
+ 'flex h-4 w-4 cursor-pointer items-center justify-center rounded-[4px] shadow-xs shadow-shadow-shadow-3',
+ checkClassName,
+ disabled && disabledClassName,
+ className,
+ )}
+ onClick={() => {
+ if (disabled)
+ return
+ onCheck?.()
+ }}
+ data-testid={`checkbox-${id}`}
+ >
+ {!checked && indeterminate && <IndeterminateIcon />}
+ {checked && <RiCheckLine className='h-3 w-3' data-testid={`check-icon-${id}`} />}
+ </div>
+ )
+}
+
+export default Checkbox
diff --git a/app/components/base/chip/index.tsx b/app/components/base/chip/index.tsx
new file mode 100644
index 0000000..eeaf2b1
--- /dev/null
+++ b/app/components/base/chip/index.tsx
@@ -0,0 +1,109 @@
+import type { FC } from 'react'
+import { useMemo, useState } from 'react'
+import { RiArrowDownSLine, RiCheckLine, RiCloseCircleFill, RiFilter3Line } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+
+export type Item = {
+ value: number | string
+ name: string
+} & Record<string, any>
+
+type Props = {
+ className?: string
+ panelClassName?: string
+ showLeftIcon?: boolean
+ leftIcon?: any
+ value: number | string
+ items: Item[]
+ onSelect: (item: any) => void
+ onClear: () => void
+}
+const Chip: FC<Props> = ({
+ className,
+ panelClassName,
+ showLeftIcon = true,
+ leftIcon,
+ value,
+ items,
+ onSelect,
+ onClear,
+}) => {
+ const [open, setOpen] = useState(false)
+
+ const triggerContent = useMemo(() => {
+ return items.find(item => item.value === value)?.name || ''
+ }, [items, value])
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <div className='relative'>
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ className='block'
+ >
+ <div className={cn(
+ 'flex min-h-8 cursor-pointer items-center rounded-lg border-[0.5px] border-transparent bg-components-input-bg-normal px-2 py-1 hover:bg-state-base-hover-alt',
+ open && !value && '!bg-state-base-hover-alt hover:bg-state-base-hover-alt',
+ !open && !!value && '!border-components-button-secondary-border !bg-components-button-secondary-bg shadow-xs hover:border-components-button-secondary-border-hover hover:!bg-components-button-secondary-bg-hover',
+ open && !!value && '!border-components-button-secondary-border-hover !bg-components-button-secondary-bg-hover shadow-xs hover:border-components-button-secondary-border-hover hover:!bg-components-button-secondary-bg-hover',
+ className,
+ )}>
+ {showLeftIcon && (
+ <div className='p-0.5'>
+ {leftIcon || (
+ <RiFilter3Line className={cn('h-4 w-4 text-text-tertiary', !!value && 'text-text-secondary')} />
+ )}
+ </div>
+ )}
+ <div className='flex grow items-center gap-0.5 first-line:p-1'>
+ <div className={cn('system-sm-regular text-text-tertiary', !!value && 'text-text-secondary')}>
+ {triggerContent}
+ </div>
+ </div>
+ {!value && <RiArrowDownSLine className='h-4 w-4 text-text-tertiary' />}
+ {!!value && (
+ <div className='group/clear cursor-pointer p-[1px]' onClick={(e) => {
+ e.stopPropagation()
+ onClear()
+ }}>
+ <RiCloseCircleFill className='h-3.5 w-3.5 text-text-quaternary group-hover/clear:text-text-tertiary' />
+ </div>
+ )}
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1002]'>
+ <div className={cn('relative w-[240px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg', panelClassName)}>
+ <div className='max-h-72 overflow-auto p-1'>
+ {items.map(item => (
+ <div
+ key={item.value}
+ className='flex cursor-pointer items-center gap-2 rounded-lg px-2 py-[6px] pl-3 hover:bg-state-base-hover'
+ onClick={() => {
+ onSelect(item)
+ setOpen(false)
+ }}
+ >
+ <div title={item.name} className='system-sm-medium grow truncate text-text-secondary'>{item.name}</div>
+ {value === item.value && <RiCheckLine className='h-4 w-4 shrink-0 text-util-colors-blue-light-blue-light-600' />}
+ </div>
+ ))}
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </div>
+ </PortalToFollowElem>
+
+ )
+}
+
+export default Chip
diff --git a/app/components/base/confirm/index.tsx b/app/components/base/confirm/index.tsx
new file mode 100644
index 0000000..8cb1c8b
--- /dev/null
+++ b/app/components/base/confirm/index.tsx
@@ -0,0 +1,108 @@
+import React, { useEffect, useRef, useState } from 'react'
+import { createPortal } from 'react-dom'
+import { useTranslation } from 'react-i18next'
+import Button from '../button'
+
+export type IConfirm = {
+ className?: string
+ isShow: boolean
+ type?: 'info' | 'warning'
+ title: string
+ content?: React.ReactNode
+ confirmText?: string | null
+ onConfirm: () => void
+ cancelText?: string
+ onCancel: () => void
+ isLoading?: boolean
+ isDisabled?: boolean
+ showConfirm?: boolean
+ showCancel?: boolean
+ maskClosable?: boolean
+}
+
+function Confirm({
+ isShow,
+ type = 'warning',
+ title,
+ content,
+ confirmText,
+ cancelText,
+ onConfirm,
+ onCancel,
+ showConfirm = true,
+ showCancel = true,
+ isLoading = false,
+ isDisabled = false,
+ maskClosable = true,
+}: IConfirm) {
+ const { t } = useTranslation()
+ const dialogRef = useRef<HTMLDivElement>(null)
+ const [isVisible, setIsVisible] = useState(isShow)
+
+ const confirmTxt = confirmText || `${t('common.operation.confirm')}`
+ const cancelTxt = cancelText || `${t('common.operation.cancel')}`
+
+ useEffect(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === 'Escape')
+ onCancel()
+ if (event.key === 'Enter' && isShow) {
+ event.preventDefault()
+ onConfirm()
+ }
+ }
+
+ document.addEventListener('keydown', handleKeyDown)
+ return () => {
+ document.removeEventListener('keydown', handleKeyDown)
+ }
+ }, [onCancel, onConfirm, isShow])
+
+ const handleClickOutside = (event: MouseEvent) => {
+ if (maskClosable && dialogRef.current && !dialogRef.current.contains(event.target as Node))
+ onCancel()
+ }
+
+ useEffect(() => {
+ document.addEventListener('mousedown', handleClickOutside)
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside)
+ }
+ }, [maskClosable])
+
+ useEffect(() => {
+ if (isShow) {
+ setIsVisible(true)
+ }
+ else {
+ const timer = setTimeout(() => setIsVisible(false), 200)
+ return () => clearTimeout(timer)
+ }
+ }, [isShow])
+
+ if (!isVisible)
+ return null
+
+ return createPortal(
+ <div className={'fixed inset-0 z-[10000000] flex items-center justify-center bg-background-overlay'}
+ onClick={(e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }}>
+ <div ref={dialogRef} className={'relative w-full max-w-[480px] overflow-hidden'}>
+ <div className='shadows-shadow-lg flex max-w-full flex-col items-start rounded-2xl border-[0.5px] border-solid border-components-panel-border bg-components-panel-bg'>
+ <div className='flex flex-col items-start gap-2 self-stretch pb-4 pl-6 pr-6 pt-6'>
+ <div className='title-2xl-semi-bold text-text-primary'>{title}</div>
+ <div className='system-md-regular w-full text-text-tertiary'>{content}</div>
+ </div>
+ <div className='flex items-start justify-end gap-2 self-stretch p-6'>
+ {showCancel && <Button onClick={onCancel}>{cancelTxt}</Button>}
+ {showConfirm && <Button variant={'primary'} destructive={type !== 'info'} loading={isLoading} disabled={isDisabled} onClick={onConfirm}>{confirmTxt}</Button>}
+ </div>
+ </div>
+ </div>
+ </div>, document.body,
+ )
+}
+
+export default React.memo(Confirm)
diff --git a/app/components/base/content-dialog/index.tsx b/app/components/base/content-dialog/index.tsx
new file mode 100644
index 0000000..861a36f
--- /dev/null
+++ b/app/components/base/content-dialog/index.tsx
@@ -0,0 +1,51 @@
+import type { ReactNode } from 'react'
+import { Transition, TransitionChild } from '@headlessui/react'
+import classNames from '@/utils/classnames'
+
+type ContentDialogProps = {
+ className?: string
+ show: boolean
+ onClose?: () => void
+ children: ReactNode
+}
+
+const ContentDialog = ({
+ className,
+ show,
+ onClose,
+ children,
+}: ContentDialogProps) => {
+ return (
+ <Transition
+ show={show}
+ as="div"
+ className="absolute left-0 top-0 z-20 box-border h-full w-full p-2"
+ >
+ <TransitionChild>
+ <div
+ className={classNames(
+ 'absolute left-0 inset-0 w-full bg-app-detail-overlay-bg',
+ 'duration-300 ease-in data-[closed]:opacity-0',
+ 'data-[enter]:opacity-100',
+ 'data-[leave]:opacity-0',
+ )}
+ onClick={onClose}
+ />
+ </TransitionChild>
+
+ <TransitionChild>
+ <div className={classNames(
+ 'absolute left-0 w-full bg-app-detail-bg border-r border-divider-burn',
+ 'duration-100 ease-in data-[closed]:-translate-x-full',
+ 'data-[enter]:ease-out data-[enter]:duration-300 data-[enter]:translate-x-0',
+ 'data-[leave]:ease-in data-[leave]:duration-200 data-[leave]:-translate-x-full',
+ className,
+ )}>
+ {children}
+ </div>
+ </TransitionChild>
+ </Transition>
+ )
+}
+
+export default ContentDialog
diff --git a/app/components/base/copy-btn/index.tsx b/app/components/base/copy-btn/index.tsx
new file mode 100644
index 0000000..88c8ba6
--- /dev/null
+++ b/app/components/base/copy-btn/index.tsx
@@ -0,0 +1,54 @@
+'use client'
+import { useState } from 'react'
+import { t } from 'i18next'
+import { debounce } from 'lodash-es'
+import copy from 'copy-to-clipboard'
+import s from './style.module.css'
+import Tooltip from '@/app/components/base/tooltip'
+
+type ICopyBtnProps = {
+ value: string
+ className?: string
+ isPlain?: boolean
+}
+
+const CopyBtn = ({
+ value,
+ className,
+ isPlain,
+}: ICopyBtnProps) => {
+ const [isCopied, setIsCopied] = useState(false)
+
+ const onClickCopy = debounce(() => {
+ copy(value)
+ setIsCopied(true)
+ }, 100)
+
+ const onMouseLeave = debounce(() => {
+ setIsCopied(false)
+ }, 100)
+
+ return (
+ <div className={`${className}`}>
+ <Tooltip
+ popupContent={(isCopied ? t('appApi.copied') : t('appApi.copy'))}
+ asChild={false}
+ >
+ <div
+ onMouseLeave={onMouseLeave}
+ className={'box-border flex cursor-pointer items-center justify-center rounded-md bg-components-button-secondary-bg p-0.5'}
+ style={!isPlain
+ ? {
+ boxShadow: '0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)',
+ }
+ : {}}
+ onClick={onClickCopy}
+ >
+ <div className={`h-6 w-6 rounded-md hover:bg-components-button-secondary-bg-hover ${s.copyIcon} ${isCopied ? s.copied : ''}`}></div>
+ </div>
+ </Tooltip>
+ </div>
+ )
+}
+
+export default CopyBtn
diff --git a/app/components/base/copy-btn/style.module.css b/app/components/base/copy-btn/style.module.css
new file mode 100644
index 0000000..83625d6
--- /dev/null
+++ b/app/components/base/copy-btn/style.module.css
@@ -0,0 +1,15 @@
+.copyIcon {
+ background-image: url(~@/app/components/develop/secret-key/assets/copy.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.copyIcon:hover {
+ background-image: url(~@/app/components/develop/secret-key/assets/copy-hover.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.copyIcon.copied {
+ background-image: url(~@/app/components/develop/secret-key/assets/copied.svg);
+}
diff --git a/app/components/base/copy-feedback/index.tsx b/app/components/base/copy-feedback/index.tsx
new file mode 100644
index 0000000..18ebe03
--- /dev/null
+++ b/app/components/base/copy-feedback/index.tsx
@@ -0,0 +1,91 @@
+'use client'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiClipboardFill,
+ RiClipboardLine,
+} from '@remixicon/react'
+import { debounce } from 'lodash-es'
+import copy from 'copy-to-clipboard'
+import copyStyle from './style.module.css'
+import Tooltip from '@/app/components/base/tooltip'
+import ActionButton from '@/app/components/base/action-button'
+
+type Props = {
+ content: string
+ className?: string
+}
+
+const prefixEmbedded = 'appOverview.overview.appInfo.embedded'
+
+const CopyFeedback = ({ content }: Props) => {
+ const { t } = useTranslation()
+ const [isCopied, setIsCopied] = useState<boolean>(false)
+
+ const onClickCopy = debounce(() => {
+ copy(content)
+ setIsCopied(true)
+ }, 100)
+
+ const onMouseLeave = debounce(() => {
+ setIsCopied(false)
+ }, 100)
+
+ return (
+ <Tooltip
+ popupContent={
+ (isCopied
+ ? t(`${prefixEmbedded}.copied`)
+ : t(`${prefixEmbedded}.copy`)) || ''
+ }
+ >
+ <ActionButton>
+ <div
+ onClick={onClickCopy}
+ onMouseLeave={onMouseLeave}
+ >
+ {isCopied && <RiClipboardFill className='h-4 w-4' />}
+ {!isCopied && <RiClipboardLine className='h-4 w-4' />}
+ </div>
+ </ActionButton>
+ </Tooltip>
+ )
+}
+
+export default CopyFeedback
+
+export const CopyFeedbackNew = ({ content, className }: Pick<Props, 'className' | 'content'>) => {
+ const { t } = useTranslation()
+ const [isCopied, setIsCopied] = useState<boolean>(false)
+
+ const onClickCopy = debounce(() => {
+ copy(content)
+ setIsCopied(true)
+ }, 100)
+
+ const onMouseLeave = debounce(() => {
+ setIsCopied(false)
+ }, 100)
+
+ return (
+ <Tooltip
+ popupContent={
+ (isCopied
+ ? t(`${prefixEmbedded}.copied`)
+ : t(`${prefixEmbedded}.copy`)) || ''
+ }
+ >
+ <div
+ className={`h-8 w-8 cursor-pointer rounded-lg hover:bg-components-button-ghost-bg-hover ${className ?? ''
+ }`}
+ >
+ <div
+ onClick={onClickCopy}
+ onMouseLeave={onMouseLeave}
+ className={`h-full w-full ${copyStyle.copyIcon} ${isCopied ? copyStyle.copied : ''
+ }`}
+ ></div>
+ </div>
+ </Tooltip>
+ )
+}
diff --git a/app/components/base/copy-feedback/style.module.css b/app/components/base/copy-feedback/style.module.css
new file mode 100644
index 0000000..83625d6
--- /dev/null
+++ b/app/components/base/copy-feedback/style.module.css
@@ -0,0 +1,15 @@
+.copyIcon {
+ background-image: url(~@/app/components/develop/secret-key/assets/copy.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.copyIcon:hover {
+ background-image: url(~@/app/components/develop/secret-key/assets/copy-hover.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.copyIcon.copied {
+ background-image: url(~@/app/components/develop/secret-key/assets/copied.svg);
+}
diff --git a/app/components/base/copy-icon/index.tsx b/app/components/base/copy-icon/index.tsx
new file mode 100644
index 0000000..c9e8a5a
--- /dev/null
+++ b/app/components/base/copy-icon/index.tsx
@@ -0,0 +1,53 @@
+'use client'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { debounce } from 'lodash-es'
+import copy from 'copy-to-clipboard'
+import Tooltip from '../tooltip'
+import {
+ Clipboard,
+ ClipboardCheck,
+} from '@/app/components/base/icons/src/vender/line/files'
+
+type Props = {
+ content: string
+}
+
+const prefixEmbedded = 'appOverview.overview.appInfo.embedded'
+
+export const CopyIcon = ({ content }: Props) => {
+ const { t } = useTranslation()
+ const [isCopied, setIsCopied] = useState<boolean>(false)
+
+ const onClickCopy = debounce(() => {
+ copy(content)
+ setIsCopied(true)
+ }, 100)
+
+ const onMouseLeave = debounce(() => {
+ setIsCopied(false)
+ }, 100)
+
+ return (
+ <Tooltip
+ popupContent={
+ (isCopied
+ ? t(`${prefixEmbedded}.copied`)
+ : t(`${prefixEmbedded}.copy`)) || ''
+ }
+ >
+ <div onMouseLeave={onMouseLeave}>
+ {!isCopied
+ ? (
+ <Clipboard className='mx-1 h-3.5 w-3.5 cursor-pointer text-text-tertiary' onClick={onClickCopy} />
+ )
+ : (
+ <ClipboardCheck className='mx-1 h-3.5 w-3.5 text-text-tertiary' />
+ )
+ }
+ </div>
+ </Tooltip>
+ )
+}
+
+export default CopyIcon
diff --git a/app/components/base/corner-label/index.tsx b/app/components/base/corner-label/index.tsx
new file mode 100644
index 0000000..9e192ed
--- /dev/null
+++ b/app/components/base/corner-label/index.tsx
@@ -0,0 +1,21 @@
+import { Corner } from '../icons/src/vender/solid/shapes'
+import cn from '@/utils/classnames'
+
+type CornerLabelProps = {
+ label: string
+ className?: string
+ labelClassName?: string
+}
+
+const CornerLabel: React.FC<CornerLabelProps> = ({ label, className, labelClassName }) => {
+ return (
+ <div className={cn('group/corner-label inline-flex items-start', className)}>
+ <Corner className='h-5 w-[13px] text-background-section group-hover/corner-label:text-background-section-burn' />
+ <div className={cn('flex items-center gap-0.5 bg-background-section py-1 pr-2 group-hover/corner-label:bg-background-section-burn', labelClassName)}>
+ <div className='system-2xs-medium-uppercase text-text-tertiary'>{label}</div>
+ </div>
+ </div>
+ )
+}
+
+export default CornerLabel
diff --git a/app/components/base/custom-icon/index.tsx b/app/components/base/custom-icon/index.tsx
new file mode 100644
index 0000000..c3afee9
--- /dev/null
+++ b/app/components/base/custom-icon/index.tsx
@@ -0,0 +1,16 @@
+import type { FC } from 'react'
+import React from 'react'
+
+type IconProps = {
+ icon: any
+ className?: string
+ [key: string]: any
+}
+
+const Icon: FC<IconProps> = ({ icon, className, ...other }) => {
+ return (
+ <img src={icon} className={`h-3 w-3 ${className}`} {...other} alt="icon" />
+ )
+}
+
+export default Icon
diff --git a/app/components/base/date-and-time-picker/calendar/days-of-week.tsx b/app/components/base/date-and-time-picker/calendar/days-of-week.tsx
new file mode 100644
index 0000000..f7a59f2
--- /dev/null
+++ b/app/components/base/date-and-time-picker/calendar/days-of-week.tsx
@@ -0,0 +1,21 @@
+import React from 'react'
+import { useDaysOfWeek } from '../hooks'
+
+export const DaysOfWeek = () => {
+ const daysOfWeek = useDaysOfWeek()
+
+ return (
+ <div className='grid grid-cols-7 gap-x-0.5 border-b-[0.5px] border-divider-regular p-2'>
+ {daysOfWeek.map(day => (
+ <div
+ key={day}
+ className='system-2xs-medium flex items-center justify-center text-text-tertiary'
+ >
+ {day}
+ </div>
+ ))}
+ </div>
+ )
+}
+
+export default React.memo(DaysOfWeek)
diff --git a/app/components/base/date-and-time-picker/calendar/index.tsx b/app/components/base/date-and-time-picker/calendar/index.tsx
new file mode 100644
index 0000000..00612fc
--- /dev/null
+++ b/app/components/base/date-and-time-picker/calendar/index.tsx
@@ -0,0 +1,27 @@
+import type { FC } from 'react'
+import type { CalendarProps } from '../types'
+import { DaysOfWeek } from './days-of-week'
+import CalendarItem from './item'
+
+const Calendar: FC<CalendarProps> = ({
+ days,
+ selectedDate,
+ onDateClick,
+ wrapperClassName,
+}) => {
+ return <div className={wrapperClassName}>
+ <DaysOfWeek/>
+ <div className='grid grid-cols-7 gap-0.5 p-2'>
+ {
+ days.map(day => <CalendarItem
+ key={day.date.format('YYYY-MM-DD')}
+ day={day}
+ selectedDate={selectedDate}
+ onClick={onDateClick}
+ />)
+ }
+ </div>
+ </div>
+}
+
+export default Calendar
diff --git a/app/components/base/date-and-time-picker/calendar/item.tsx b/app/components/base/date-and-time-picker/calendar/item.tsx
new file mode 100644
index 0000000..20e0b84
--- /dev/null
+++ b/app/components/base/date-and-time-picker/calendar/item.tsx
@@ -0,0 +1,30 @@
+import React, { type FC } from 'react'
+import type { CalendarItemProps } from '../types'
+import cn from '@/utils/classnames'
+import dayjs from '../utils/dayjs'
+
+const Item: FC<CalendarItemProps> = ({
+ day,
+ selectedDate,
+ onClick,
+}) => {
+ const { date, isCurrentMonth } = day
+ const isSelected = selectedDate?.isSame(date, 'date')
+ const isToday = date.isSame(dayjs(), 'date')
+
+ return (
+ <button
+ onClick={() => onClick(date)}
+ className={cn(
+ 'system-sm-medium relative flex items-center justify-center rounded-lg px-1 py-2',
+ isCurrentMonth ? 'text-text-secondary' : 'text-text-quaternary hover:text-text-secondary',
+ isSelected ? 'system-sm-medium bg-components-button-primary-bg text-components-button-primary-text' : 'hover:bg-state-base-hover',
+ )}
+ >
+ {date.date()}
+ {isToday && <div className='absolute bottom-1 mx-auto h-1 w-1 rounded-full bg-components-button-primary-bg' />}
+ </button>
+ )
+}
+
+export default React.memo(Item)
diff --git a/app/components/base/date-and-time-picker/common/option-list-item.tsx b/app/components/base/date-and-time-picker/common/option-list-item.tsx
new file mode 100644
index 0000000..d11a6e9
--- /dev/null
+++ b/app/components/base/date-and-time-picker/common/option-list-item.tsx
@@ -0,0 +1,38 @@
+import React, { type FC, useEffect, useRef } from 'react'
+import cn from '@/utils/classnames'
+
+type OptionListItemProps = {
+ isSelected: boolean
+ onClick: () => void
+} & React.LiHTMLAttributes<HTMLLIElement>
+
+const OptionListItem: FC<OptionListItemProps> = ({
+ isSelected,
+ onClick,
+ children,
+}) => {
+ const listItemRef = useRef<HTMLLIElement>(null)
+
+ useEffect(() => {
+ if (isSelected)
+ listItemRef.current?.scrollIntoView({ behavior: 'instant' })
+ }, [])
+
+ return (
+ <li
+ ref={listItemRef}
+ className={cn(
+ 'system-xs-medium flex cursor-pointer items-center justify-center rounded-md px-1.5 py-1 text-components-button-ghost-text',
+ isSelected ? 'bg-components-button-ghost-bg-hover' : 'hover:bg-components-button-ghost-bg-hover',
+ )}
+ onClick={() => {
+ listItemRef.current?.scrollIntoView({ behavior: 'smooth' })
+ onClick()
+ }}
+ >
+ {children}
+ </li>
+ )
+}
+
+export default React.memo(OptionListItem)
diff --git a/app/components/base/date-and-time-picker/date-picker/footer.tsx b/app/components/base/date-and-time-picker/date-picker/footer.tsx
new file mode 100644
index 0000000..6351a82
--- /dev/null
+++ b/app/components/base/date-and-time-picker/date-picker/footer.tsx
@@ -0,0 +1,59 @@
+import React, { type FC } from 'react'
+import Button from '../../button'
+import { type DatePickerFooterProps, ViewType } from '../types'
+import { RiTimeLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { useTranslation } from 'react-i18next'
+
+const Footer: FC<DatePickerFooterProps> = ({
+ needTimePicker,
+ displayTime,
+ view,
+ handleClickTimePicker,
+ handleSelectCurrentDate,
+ handleConfirmDate,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={cn(
+ 'flex items-center justify-between border-t-[0.5px] border-divider-regular p-2',
+ !needTimePicker && 'justify-end',
+ )}>
+ {/* Time Picker */}
+ {needTimePicker && (
+ <button
+ type='button'
+ className='system-xs-medium flex items-center gap-x-[1px] rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-1.5
+ py-1 text-components-button-secondary-accent-text shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px]'
+ onClick={handleClickTimePicker}
+ >
+ <RiTimeLine className='h-3.5 w-3.5' />
+ {view === ViewType.date && <span>{displayTime}</span>}
+ {view === ViewType.time && <span>{t('time.operation.pickDate')}</span>}
+ </button>
+ )}
+ <div className='flex items-center gap-x-1'>
+ {/* Now */}
+ <button
+ type='button'
+ className='system-xs-medium flex items-center justify-center px-1.5 py-1 text-components-button-secondary-accent-text'
+ onClick={handleSelectCurrentDate}
+ >
+ <span className='px-[3px]'>{t('time.operation.now')}</span>
+ </button>
+ {/* Confirm Button */}
+ <Button
+ variant='primary'
+ size='small'
+ className='w-16 px-1.5 py-1'
+ onClick={handleConfirmDate}
+ >
+ {t('time.operation.ok')}
+ </Button>
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(Footer)
diff --git a/app/components/base/date-and-time-picker/date-picker/header.tsx b/app/components/base/date-and-time-picker/date-picker/header.tsx
new file mode 100644
index 0000000..2631cdb
--- /dev/null
+++ b/app/components/base/date-and-time-picker/date-picker/header.tsx
@@ -0,0 +1,41 @@
+import React, { type FC } from 'react'
+import { RiArrowDownSLine, RiArrowUpSLine } from '@remixicon/react'
+import type { DatePickerHeaderProps } from '../types'
+import { useMonths } from '../hooks'
+
+const Header: FC<DatePickerHeaderProps> = ({
+ handleOpenYearMonthPicker,
+ currentDate,
+ onClickNextMonth,
+ onClickPrevMonth,
+}) => {
+ const months = useMonths()
+
+ return (
+ <div className='mx-2 mt-2 flex items-center'>
+ <div className='flex-1'>
+ <button
+ onClick={handleOpenYearMonthPicker}
+ className='system-md-semibold flex items-center gap-x-0.5 rounded-lg px-2 py-1.5 text-text-primary hover:bg-state-base-hover'
+ >
+ <span>{`${months[currentDate.month()]} ${currentDate.year()}`}</span>
+ <RiArrowDownSLine className='h-4 w-4 text-text-tertiary' />
+ </button>
+ </div>
+ <button
+ onClick={onClickPrevMonth}
+ className='rounded-lg p-1.5 hover:bg-state-base-hover'
+ >
+ <RiArrowUpSLine className='h-[18px] w-[18px] text-text-secondary' />
+ </button>
+ <button
+ onClick={onClickNextMonth}
+ className='rounded-lg p-1.5 hover:bg-state-base-hover'
+ >
+ <RiArrowDownSLine className='h-[18px] w-[18px] text-text-secondary' />
+ </button>
+ </div>
+ )
+}
+
+export default React.memo(Header)
diff --git a/app/components/base/date-and-time-picker/date-picker/index.tsx b/app/components/base/date-and-time-picker/date-picker/index.tsx
new file mode 100644
index 0000000..f4fc861
--- /dev/null
+++ b/app/components/base/date-and-time-picker/date-picker/index.tsx
@@ -0,0 +1,309 @@
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { RiCalendarLine, RiCloseCircleFill } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import type { DatePickerProps, Period } from '../types'
+import { ViewType } from '../types'
+import type { Dayjs } from 'dayjs'
+import dayjs, {
+ clearMonthMapCache,
+ cloneTime,
+ getDateWithTimezone,
+ getDaysInMonth,
+ getHourIn12Hour,
+} from '../utils/dayjs'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import DatePickerHeader from './header'
+import Calendar from '../calendar'
+import DatePickerFooter from './footer'
+import YearAndMonthPickerHeader from '../year-and-month-picker/header'
+import YearAndMonthPickerOptions from '../year-and-month-picker/options'
+import YearAndMonthPickerFooter from '../year-and-month-picker/footer'
+import TimePickerHeader from '../time-picker/header'
+import TimePickerOptions from '../time-picker/options'
+import { useTranslation } from 'react-i18next'
+
+const DatePicker = ({
+ value,
+ timezone,
+ onChange,
+ onClear,
+ placeholder,
+ needTimePicker = true,
+ renderTrigger,
+ triggerWrapClassName,
+ popupZIndexClassname = 'z-[11]',
+}: DatePickerProps) => {
+ const { t } = useTranslation()
+ const [isOpen, setIsOpen] = useState(false)
+ const [view, setView] = useState(ViewType.date)
+ const containerRef = useRef<HTMLDivElement>(null)
+ const isInitial = useRef(true)
+ const inputValue = useRef(value ? value.tz(timezone) : undefined).current
+ const defaultValue = useRef(getDateWithTimezone({ timezone })).current
+
+ const [currentDate, setCurrentDate] = useState(inputValue || defaultValue)
+ const [selectedDate, setSelectedDate] = useState(inputValue)
+
+ const [selectedMonth, setSelectedMonth] = useState((inputValue || defaultValue).month())
+ const [selectedYear, setSelectedYear] = useState((inputValue || defaultValue).year())
+
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
+ setIsOpen(false)
+ setView(ViewType.date)
+ }
+ }
+ document.addEventListener('mousedown', handleClickOutside)
+ return () => document.removeEventListener('mousedown', handleClickOutside)
+ }, [])
+
+ useEffect(() => {
+ if (isInitial.current) {
+ isInitial.current = false
+ return
+ }
+ clearMonthMapCache()
+ if (value) {
+ const newValue = getDateWithTimezone({ date: value, timezone })
+ setCurrentDate(newValue)
+ setSelectedDate(newValue)
+ onChange(newValue)
+ }
+ else {
+ setCurrentDate(prev => getDateWithTimezone({ date: prev, timezone }))
+ setSelectedDate(prev => prev ? getDateWithTimezone({ date: prev, timezone }) : undefined)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [timezone])
+
+ const handleClickTrigger = (e: React.MouseEvent) => {
+ e.stopPropagation()
+ if (isOpen) {
+ setIsOpen(false)
+ return
+ }
+ setView(ViewType.date)
+ setIsOpen(true)
+ if (value) {
+ setCurrentDate(value)
+ setSelectedDate(value)
+ }
+ }
+
+ const handleClear = (e: React.MouseEvent) => {
+ e.stopPropagation()
+ setSelectedDate(undefined)
+ if (!isOpen)
+ onClear()
+ }
+
+ const days = useMemo(() => {
+ return getDaysInMonth(currentDate)
+ }, [currentDate])
+
+ const handleClickNextMonth = useCallback(() => {
+ setCurrentDate(currentDate.clone().add(1, 'month'))
+ }, [currentDate])
+
+ const handleClickPrevMonth = useCallback(() => {
+ setCurrentDate(currentDate.clone().subtract(1, 'month'))
+ }, [currentDate])
+
+ const handleDateSelect = useCallback((day: Dayjs) => {
+ const newDate = cloneTime(day, selectedDate || getDateWithTimezone({ timezone }))
+ setCurrentDate(newDate)
+ setSelectedDate(newDate)
+ }, [selectedDate, timezone])
+
+ const handleSelectCurrentDate = () => {
+ const newDate = getDateWithTimezone({ timezone })
+ setCurrentDate(newDate)
+ setSelectedDate(newDate)
+ onChange(newDate)
+ setIsOpen(false)
+ }
+
+ const handleConfirmDate = () => {
+ // debugger
+ onChange(selectedDate ? selectedDate.tz(timezone) : undefined)
+ setIsOpen(false)
+ }
+
+ const handleClickTimePicker = () => {
+ if (view === ViewType.date) {
+ setView(ViewType.time)
+ return
+ }
+ if (view === ViewType.time)
+ setView(ViewType.date)
+ }
+
+ const handleTimeSelect = (hour: string, minute: string, period: Period) => {
+ const newTime = cloneTime(dayjs(), dayjs(`1/1/2000 ${hour}:${minute} ${period}`))
+ setSelectedDate((prev) => {
+ return prev ? cloneTime(prev, newTime) : newTime
+ })
+ }
+
+ const handleSelectHour = useCallback((hour: string) => {
+ const selectedTime = selectedDate || getDateWithTimezone({ timezone })
+ handleTimeSelect(hour, selectedTime.minute().toString().padStart(2, '0'), selectedTime.format('A') as Period)
+ }, [selectedDate, timezone])
+
+ const handleSelectMinute = useCallback((minute: string) => {
+ const selectedTime = selectedDate || getDateWithTimezone({ timezone })
+ handleTimeSelect(getHourIn12Hour(selectedTime).toString().padStart(2, '0'), minute, selectedTime.format('A') as Period)
+ }, [selectedDate, timezone])
+
+ const handleSelectPeriod = useCallback((period: Period) => {
+ const selectedTime = selectedDate || getDateWithTimezone({ timezone })
+ handleTimeSelect(getHourIn12Hour(selectedTime).toString().padStart(2, '0'), selectedTime.minute().toString().padStart(2, '0'), period)
+ }, [selectedDate, timezone])
+
+ const handleOpenYearMonthPicker = () => {
+ setSelectedMonth(currentDate.month())
+ setSelectedYear(currentDate.year())
+ setView(ViewType.yearMonth)
+ }
+
+ const handleCloseYearMonthPicker = useCallback(() => {
+ setView(ViewType.date)
+ }, [])
+
+ const handleMonthSelect = useCallback((month: number) => {
+ setSelectedMonth(month)
+ }, [])
+
+ const handleYearSelect = useCallback((year: number) => {
+ setSelectedYear(year)
+ }, [])
+
+ const handleYearMonthCancel = useCallback(() => {
+ setView(ViewType.date)
+ }, [])
+
+ const handleYearMonthConfirm = () => {
+ setCurrentDate(prev => prev.clone().month(selectedMonth).year(selectedYear))
+ setView(ViewType.date)
+ }
+
+ const timeFormat = needTimePicker ? 'MMMM D, YYYY hh:mm A' : 'MMMM D, YYYY'
+ const displayValue = value?.format(timeFormat) || ''
+ const displayTime = selectedDate?.format('hh:mm A') || '--:-- --'
+ const placeholderDate = isOpen && selectedDate ? selectedDate.format(timeFormat) : (placeholder || t('time.defaultPlaceholder'))
+
+ return (
+ <PortalToFollowElem
+ open={isOpen}
+ onOpenChange={setIsOpen}
+ placement='bottom-end'
+ >
+ <PortalToFollowElemTrigger className={triggerWrapClassName}>
+ {renderTrigger ? (renderTrigger({
+ value,
+ selectedDate,
+ isOpen,
+ handleClear,
+ handleClickTrigger,
+ })) : (
+ <div
+ className='group flex w-[252px] cursor-pointer items-center gap-x-0.5 rounded-lg bg-components-input-bg-normal px-2 py-1 hover:bg-state-base-hover-alt'
+ onClick={handleClickTrigger}
+ >
+ <input
+ className='system-xs-regular flex-1 cursor-pointer appearance-none truncate bg-transparent p-1
+ text-components-input-text-filled outline-none placeholder:text-components-input-text-placeholder'
+ readOnly
+ value={isOpen ? '' : displayValue}
+ placeholder={placeholderDate}
+ />
+ <RiCalendarLine className={cn(
+ 'h-4 w-4 shrink-0 text-text-quaternary',
+ isOpen ? 'text-text-secondary' : 'group-hover:text-text-secondary',
+ (displayValue || (isOpen && selectedDate)) && 'group-hover:hidden',
+ )} />
+ <RiCloseCircleFill
+ className={cn(
+ 'hidden h-4 w-4 shrink-0 text-text-quaternary',
+ (displayValue || (isOpen && selectedDate)) && 'hover:text-text-secondary group-hover:inline-block',
+ )}
+ onClick={handleClear}
+ />
+ </div>
+ )}
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className={popupZIndexClassname}>
+ <div className='mt-1 w-[252px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg shadow-shadow-shadow-5'>
+ {/* Header */}
+ {view === ViewType.date ? (
+ <DatePickerHeader
+ handleOpenYearMonthPicker={handleOpenYearMonthPicker}
+ currentDate={currentDate}
+ onClickNextMonth={handleClickNextMonth}
+ onClickPrevMonth={handleClickPrevMonth}
+ />
+ ) : view === ViewType.yearMonth ? (
+ <YearAndMonthPickerHeader
+ selectedYear={selectedYear}
+ selectedMonth={selectedMonth}
+ onClick={handleCloseYearMonthPicker}
+ />
+ ) : (
+ <TimePickerHeader />
+ )}
+
+ {/* Content */}
+ {
+ view === ViewType.date ? (
+ <Calendar
+ days={days}
+ selectedDate={selectedDate}
+ onDateClick={handleDateSelect}
+ />
+ ) : view === ViewType.yearMonth ? (
+ <YearAndMonthPickerOptions
+ selectedMonth={selectedMonth}
+ selectedYear={selectedYear}
+ handleMonthSelect={handleMonthSelect}
+ handleYearSelect={handleYearSelect}
+ />
+ ) : (
+ <TimePickerOptions
+ selectedTime={selectedDate}
+ handleSelectHour={handleSelectHour}
+ handleSelectMinute={handleSelectMinute}
+ handleSelectPeriod={handleSelectPeriod}
+ />
+ )
+ }
+
+ {/* Footer */}
+ {
+ [ViewType.date, ViewType.time].includes(view) ? (
+ <DatePickerFooter
+ needTimePicker={needTimePicker}
+ displayTime={displayTime}
+ view={view}
+ handleClickTimePicker={handleClickTimePicker}
+ handleSelectCurrentDate={handleSelectCurrentDate}
+ handleConfirmDate={handleConfirmDate}
+ />
+ ) : (
+ <YearAndMonthPickerFooter
+ handleYearMonthCancel={handleYearMonthCancel}
+ handleYearMonthConfirm={handleYearMonthConfirm}
+ />
+ )
+ }
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default DatePicker
diff --git a/app/components/base/date-and-time-picker/hooks.ts b/app/components/base/date-and-time-picker/hooks.ts
new file mode 100644
index 0000000..b92a8e2
--- /dev/null
+++ b/app/components/base/date-and-time-picker/hooks.ts
@@ -0,0 +1,49 @@
+import dayjs from './utils/dayjs'
+import { Period } from './types'
+import { useTranslation } from 'react-i18next'
+
+const YEAR_RANGE = 100
+
+export const useDaysOfWeek = () => {
+ const { t } = useTranslation()
+ const daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => t(`time.daysInWeek.${day}`))
+
+ return daysOfWeek
+}
+
+export const useMonths = () => {
+ const { t } = useTranslation()
+ const months = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December',
+ ].map(month => t(`time.months.${month}`))
+
+ return months
+}
+
+export const useYearOptions = () => {
+ const yearOptions = Array.from({ length: 200 }, (_, i) => dayjs().year() - YEAR_RANGE / 2 + i)
+ return yearOptions
+}
+
+export const useTimeOptions = () => {
+ const hourOptions = Array.from({ length: 12 }, (_, i) => (i + 1).toString().padStart(2, '0'))
+ const minuteOptions = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0'))
+ const periodOptions = [Period.AM, Period.PM]
+
+ return {
+ hourOptions,
+ minuteOptions,
+ periodOptions,
+ }
+}
diff --git a/app/components/base/date-and-time-picker/time-picker/footer.tsx b/app/components/base/date-and-time-picker/time-picker/footer.tsx
new file mode 100644
index 0000000..47dd8b1
--- /dev/null
+++ b/app/components/base/date-and-time-picker/time-picker/footer.tsx
@@ -0,0 +1,37 @@
+import React, { type FC } from 'react'
+import type { TimePickerFooterProps } from '../types'
+import Button from '../../button'
+import { useTranslation } from 'react-i18next'
+
+const Footer: FC<TimePickerFooterProps> = ({
+ handleSelectCurrentTime,
+ handleConfirm,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex items-center justify-end border-t-[0.5px] border-divider-regular p-2'>
+ <div className='flex items-center gap-x-1'>
+ {/* Now */}
+ <button
+ type='button'
+ className='system-xs-medium flex items-center justify-center px-1.5 py-1 text-components-button-secondary-accent-text'
+ onClick={handleSelectCurrentTime}
+ >
+ <span className='px-[3px]'>{t('time.operation.now')}</span>
+ </button>
+ {/* Confirm Button */}
+ <Button
+ variant='primary'
+ size='small'
+ className='w-16 px-1.5 py-1'
+ onClick={handleConfirm.bind(null)}
+ >
+ {t('time.operation.ok')}
+ </Button>
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(Footer)
diff --git a/app/components/base/date-and-time-picker/time-picker/header.tsx b/app/components/base/date-and-time-picker/time-picker/header.tsx
new file mode 100644
index 0000000..3d85b2e
--- /dev/null
+++ b/app/components/base/date-and-time-picker/time-picker/header.tsx
@@ -0,0 +1,16 @@
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+
+const Header = () => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex flex-col border-b-[0.5px] border-divider-regular'>
+ <div className='system-md-semibold flex items-center px-2 py-1.5 text-text-primary'>
+ {t('time.title.pickTime')}
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(Header)
diff --git a/app/components/base/date-and-time-picker/time-picker/index.tsx b/app/components/base/date-and-time-picker/time-picker/index.tsx
new file mode 100644
index 0000000..a5e666d
--- /dev/null
+++ b/app/components/base/date-and-time-picker/time-picker/index.tsx
@@ -0,0 +1,170 @@
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import type { Period, TimePickerProps } from '../types'
+import dayjs, { cloneTime, getDateWithTimezone, getHourIn12Hour } from '../utils/dayjs'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import Footer from './footer'
+import Options from './options'
+import Header from './header'
+import { useTranslation } from 'react-i18next'
+import { RiCloseCircleFill, RiTimeLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+
+const TimePicker = ({
+ value,
+ timezone,
+ placeholder,
+ onChange,
+ onClear,
+ renderTrigger,
+}: TimePickerProps) => {
+ const { t } = useTranslation()
+ const [isOpen, setIsOpen] = useState(false)
+ const containerRef = useRef<HTMLDivElement>(null)
+ const isInitial = useRef(true)
+ const [selectedTime, setSelectedTime] = useState(value ? getDateWithTimezone({ timezone, date: value }) : undefined)
+
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (containerRef.current && !containerRef.current.contains(event.target as Node))
+ setIsOpen(false)
+ }
+ document.addEventListener('mousedown', handleClickOutside)
+ return () => document.removeEventListener('mousedown', handleClickOutside)
+ }, [])
+
+ useEffect(() => {
+ if (isInitial.current) {
+ isInitial.current = false
+ return
+ }
+ if (value) {
+ const newValue = getDateWithTimezone({ date: value, timezone })
+ setSelectedTime(newValue)
+ onChange(newValue)
+ }
+ else {
+ setSelectedTime(prev => prev ? getDateWithTimezone({ date: prev, timezone }) : undefined)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [timezone])
+
+ const handleClickTrigger = (e: React.MouseEvent) => {
+ e.stopPropagation()
+ if (isOpen) {
+ setIsOpen(false)
+ return
+ }
+ setIsOpen(true)
+ if (value)
+ setSelectedTime(value)
+ }
+
+ const handleClear = (e: React.MouseEvent) => {
+ e.stopPropagation()
+ setSelectedTime(undefined)
+ if (!isOpen)
+ onClear()
+ }
+
+ const handleTimeSelect = (hour: string, minute: string, period: Period) => {
+ const newTime = cloneTime(dayjs(), dayjs(`1/1/2000 ${hour}:${minute} ${period}`))
+ setSelectedTime((prev) => {
+ return prev ? cloneTime(prev, newTime) : newTime
+ })
+ }
+
+ const handleSelectHour = useCallback((hour: string) => {
+ const time = selectedTime || dayjs().startOf('day')
+ handleTimeSelect(hour, time.minute().toString().padStart(2, '0'), time.format('A') as Period)
+ }, [selectedTime])
+
+ const handleSelectMinute = useCallback((minute: string) => {
+ const time = selectedTime || dayjs().startOf('day')
+ handleTimeSelect(getHourIn12Hour(time).toString().padStart(2, '0'), minute, time.format('A') as Period)
+ }, [selectedTime])
+
+ const handleSelectPeriod = useCallback((period: Period) => {
+ const time = selectedTime || dayjs().startOf('day')
+ handleTimeSelect(getHourIn12Hour(time).toString().padStart(2, '0'), time.minute().toString().padStart(2, '0'), period)
+ }, [selectedTime])
+
+ const handleSelectCurrentTime = useCallback(() => {
+ const newDate = getDateWithTimezone({ timezone })
+ setSelectedTime(newDate)
+ onChange(newDate)
+ setIsOpen(false)
+ }, [onChange, timezone])
+
+ const handleConfirm = useCallback(() => {
+ onChange(selectedTime)
+ setIsOpen(false)
+ }, [onChange, selectedTime])
+
+ const timeFormat = 'hh:mm A'
+ const displayValue = value?.format(timeFormat) || ''
+ const placeholderDate = isOpen && selectedTime ? selectedTime.format(timeFormat) : (placeholder || t('time.defaultPlaceholder'))
+
+ return (
+ <PortalToFollowElem
+ open={isOpen}
+ onOpenChange={setIsOpen}
+ placement='bottom-end'
+ >
+ <PortalToFollowElemTrigger>
+ {renderTrigger ? (renderTrigger()) : (
+ <div
+ className='group flex w-[252px] cursor-pointer items-center gap-x-0.5 rounded-lg bg-components-input-bg-normal px-2 py-1 hover:bg-state-base-hover-alt'
+ onClick={handleClickTrigger}
+ >
+ <input
+ className='system-xs-regular flex-1 cursor-pointer appearance-none truncate bg-transparent p-1
+ text-components-input-text-filled outline-none placeholder:text-components-input-text-placeholder'
+ readOnly
+ value={isOpen ? '' : displayValue}
+ placeholder={placeholderDate}
+ />
+ <RiTimeLine className={cn(
+ 'h-4 w-4 shrink-0 text-text-quaternary',
+ isOpen ? 'text-text-secondary' : 'group-hover:text-text-secondary',
+ (displayValue || (isOpen && selectedTime)) && 'group-hover:hidden',
+ )} />
+ <RiCloseCircleFill
+ className={cn(
+ 'hidden h-4 w-4 shrink-0 text-text-quaternary',
+ (displayValue || (isOpen && selectedTime)) && 'hover:text-text-secondary group-hover:inline-block',
+ )}
+ onClick={handleClear}
+ />
+ </div>
+ )}
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-50'>
+ <div className='mt-1 w-[252px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg shadow-shadow-shadow-5'>
+ {/* Header */}
+ <Header />
+
+ {/* Time Options */}
+ <Options
+ selectedTime={selectedTime}
+ handleSelectHour={handleSelectHour}
+ handleSelectMinute={handleSelectMinute}
+ handleSelectPeriod={handleSelectPeriod}
+ />
+
+ {/* Footer */}
+ <Footer
+ handleSelectCurrentTime={handleSelectCurrentTime}
+ handleConfirm={handleConfirm}
+ />
+
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default TimePicker
diff --git a/app/components/base/date-and-time-picker/time-picker/options.tsx b/app/components/base/date-and-time-picker/time-picker/options.tsx
new file mode 100644
index 0000000..887f6f4
--- /dev/null
+++ b/app/components/base/date-and-time-picker/time-picker/options.tsx
@@ -0,0 +1,71 @@
+import React, { type FC } from 'react'
+import { useTimeOptions } from '../hooks'
+import type { TimeOptionsProps } from '../types'
+import OptionListItem from '../common/option-list-item'
+
+const Options: FC<TimeOptionsProps> = ({
+ selectedTime,
+ handleSelectHour,
+ handleSelectMinute,
+ handleSelectPeriod,
+}) => {
+ const { hourOptions, minuteOptions, periodOptions } = useTimeOptions()
+
+ return (
+ <div className='grid grid-cols-3 gap-x-1 p-2'>
+ {/* Hour */}
+ <ul className='no-scrollbar flex h-[208px] flex-col gap-y-0.5 overflow-y-auto pb-[184px]'>
+ {
+ hourOptions.map((hour) => {
+ const isSelected = selectedTime?.format('hh') === hour
+ return (
+ <OptionListItem
+ key={hour}
+ isSelected={isSelected}
+ onClick={handleSelectHour.bind(null, hour)}
+ >
+ {hour}
+ </OptionListItem>
+ )
+ })
+ }
+ </ul>
+ {/* Minute */}
+ <ul className='no-scrollbar flex h-[208px] flex-col gap-y-0.5 overflow-y-auto pb-[184px]'>
+ {
+ minuteOptions.map((minute) => {
+ const isSelected = selectedTime?.format('mm') === minute
+ return (
+ <OptionListItem
+ key={minute}
+ isSelected={isSelected}
+ onClick={handleSelectMinute.bind(null, minute)}
+ >
+ {minute}
+ </OptionListItem>
+ )
+ })
+ }
+ </ul>
+ {/* Period */}
+ <ul className='no-scrollbar flex h-[208px] flex-col gap-y-0.5 overflow-y-auto pb-[184px]'>
+ {
+ periodOptions.map((period) => {
+ const isSelected = selectedTime?.format('A') === period
+ return (
+ <OptionListItem
+ key={period}
+ isSelected={isSelected}
+ onClick={handleSelectPeriod.bind(null, period)}
+ >
+ {period}
+ </OptionListItem>
+ )
+ })
+ }
+ </ul>
+ </div>
+ )
+}
+
+export default React.memo(Options)
diff --git a/app/components/base/date-and-time-picker/types.ts b/app/components/base/date-and-time-picker/types.ts
new file mode 100644
index 0000000..214c0f0
--- /dev/null
+++ b/app/components/base/date-and-time-picker/types.ts
@@ -0,0 +1,105 @@
+import type { Dayjs } from 'dayjs'
+
+export enum ViewType {
+ date = 'date',
+ yearMonth = 'yearMonth',
+ time = 'time',
+}
+
+export enum Period {
+ AM = 'AM',
+ PM = 'PM',
+}
+
+export type TriggerProps = {
+ value: Dayjs | undefined
+ selectedDate: Dayjs | undefined
+ isOpen: boolean
+ handleClear: (e: React.MouseEvent) => void
+ handleClickTrigger: (e: React.MouseEvent) => void
+}
+
+export type DatePickerProps = {
+ value: Dayjs | undefined
+ timezone?: string
+ placeholder?: string
+ needTimePicker?: boolean
+ onChange: (date: Dayjs | undefined) => void
+ onClear: () => void
+ triggerWrapClassName?: string
+ renderTrigger?: (props: TriggerProps) => React.ReactNode
+ popupZIndexClassname?: string
+}
+
+export type DatePickerHeaderProps = {
+ handleOpenYearMonthPicker: () => void
+ currentDate: Dayjs
+ onClickNextMonth: () => void
+ onClickPrevMonth: () => void
+}
+
+export type DatePickerFooterProps = {
+ needTimePicker: boolean
+ displayTime: string
+ view: ViewType
+ handleClickTimePicker: () => void
+ handleSelectCurrentDate: () => void
+ handleConfirmDate: () => void
+}
+
+export type TimePickerProps = {
+ value: Dayjs | undefined
+ timezone?: string
+ placeholder?: string
+ onChange: (date: Dayjs | undefined) => void
+ onClear: () => void
+ renderTrigger?: () => React.ReactNode
+}
+
+export type TimePickerFooterProps = {
+ handleSelectCurrentTime: () => void
+ handleConfirm: () => void
+}
+
+export type Day = {
+ date: Dayjs
+ isCurrentMonth: boolean
+}
+
+export type CalendarProps = {
+ days: Day[]
+ selectedDate: Dayjs | undefined
+ onDateClick: (date: Dayjs) => void
+ wrapperClassName?: string
+}
+
+export type CalendarItemProps = {
+ day: Day
+ selectedDate: Dayjs | undefined
+ onClick: (date: Dayjs) => void
+}
+
+export type TimeOptionsProps = {
+ selectedTime: Dayjs | undefined
+ handleSelectHour: (hour: string) => void
+ handleSelectMinute: (minute: string) => void
+ handleSelectPeriod: (period: Period) => void
+}
+
+export type YearAndMonthPickerHeaderProps = {
+ selectedYear: number
+ selectedMonth: number
+ onClick: () => void
+}
+
+export type YearAndMonthPickerOptionsProps = {
+ selectedYear: number
+ selectedMonth: number
+ handleYearSelect: (year: number) => void
+ handleMonthSelect: (month: number) => void
+}
+
+export type YearAndMonthPickerFooterProps = {
+ handleYearMonthCancel: () => void
+ handleYearMonthConfirm: () => void
+}
diff --git a/app/components/base/date-and-time-picker/utils/dayjs.ts b/app/components/base/date-and-time-picker/utils/dayjs.ts
new file mode 100644
index 0000000..0928fa5
--- /dev/null
+++ b/app/components/base/date-and-time-picker/utils/dayjs.ts
@@ -0,0 +1,80 @@
+import dayjs, { type Dayjs } from 'dayjs'
+import type { Day } from '../types'
+import utc from 'dayjs/plugin/utc'
+import timezone from 'dayjs/plugin/timezone'
+
+dayjs.extend(utc)
+dayjs.extend(timezone)
+
+export default dayjs
+
+const monthMaps: Record<string, Day[]> = {}
+
+export const cloneTime = (targetDate: Dayjs, sourceDate: Dayjs) => {
+ return targetDate.clone()
+ .set('hour', sourceDate.hour())
+ .set('minute', sourceDate.minute())
+}
+
+export const getDaysInMonth = (currentDate: Dayjs) => {
+ const key = currentDate.format('YYYY-MM')
+ // return the cached days
+ if (monthMaps[key])
+ return monthMaps[key]
+
+ const daysInCurrentMonth = currentDate.daysInMonth()
+ const firstDay = currentDate.startOf('month').day()
+ const lastDay = currentDate.endOf('month').day()
+ const lastDayInLastMonth = currentDate.clone().subtract(1, 'month').endOf('month')
+ const firstDayInNextMonth = currentDate.clone().add(1, 'month').startOf('month')
+ const days: Day[] = []
+ const daysInOneWeek = 7
+ const totalLines = 6
+
+ // Add cells for days before the first day of the month
+ for (let i = firstDay - 1; i >= 0; i--) {
+ const date = cloneTime(lastDayInLastMonth.subtract(i, 'day'), currentDate)
+ days.push({
+ date,
+ isCurrentMonth: false,
+ })
+ }
+
+ // Add days of the month
+ for (let i = 1; i <= daysInCurrentMonth; i++) {
+ const date = cloneTime(currentDate.startOf('month').add(i - 1, 'day'), currentDate)
+ days.push({
+ date,
+ isCurrentMonth: true,
+ })
+ }
+
+ // Add cells for days after the last day of the month
+ const totalLinesOfCurrentMonth = Math.ceil((daysInCurrentMonth - ((daysInOneWeek - firstDay) + lastDay + 1)) / 7) + 2
+ const needAdditionalLine = totalLinesOfCurrentMonth < totalLines
+ for (let i = 0; lastDay + i < (needAdditionalLine ? 2 * daysInOneWeek - 1 : daysInOneWeek - 1); i++) {
+ const date = cloneTime(firstDayInNextMonth.add(i, 'day'), currentDate)
+ days.push({
+ date,
+ isCurrentMonth: false,
+ })
+ }
+
+ // cache the days
+ monthMaps[key] = days
+ return days
+}
+
+export const clearMonthMapCache = () => {
+ for (const key in monthMaps)
+ delete monthMaps[key]
+}
+
+export const getHourIn12Hour = (date: Dayjs) => {
+ const hour = date.hour()
+ return hour === 0 ? 12 : hour >= 12 ? hour - 12 : hour
+}
+
+export const getDateWithTimezone = (props: { date?: Dayjs, timezone?: string }) => {
+ return props.date ? dayjs.tz(props.date, props.timezone) : dayjs().tz(props.timezone)
+}
diff --git a/app/components/base/date-and-time-picker/year-and-month-picker/footer.tsx b/app/components/base/date-and-time-picker/year-and-month-picker/footer.tsx
new file mode 100644
index 0000000..8e0566a
--- /dev/null
+++ b/app/components/base/date-and-time-picker/year-and-month-picker/footer.tsx
@@ -0,0 +1,25 @@
+import type { FC } from 'react'
+import React from 'react'
+import Button from '../../button'
+import type { YearAndMonthPickerFooterProps } from '../types'
+import { useTranslation } from 'react-i18next'
+
+const Footer: FC<YearAndMonthPickerFooterProps> = ({
+ handleYearMonthCancel,
+ handleYearMonthConfirm,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='grid grid-cols-2 gap-x-1 p-2'>
+ <Button size='small' onClick={handleYearMonthCancel}>
+ {t('time.operation.cancel')}
+ </Button>
+ <Button variant='primary' size='small' onClick={handleYearMonthConfirm}>
+ {t('time.operation.ok')}
+ </Button>
+ </div>
+ )
+}
+
+export default React.memo(Footer)
diff --git a/app/components/base/date-and-time-picker/year-and-month-picker/header.tsx b/app/components/base/date-and-time-picker/year-and-month-picker/header.tsx
new file mode 100644
index 0000000..63923e6
--- /dev/null
+++ b/app/components/base/date-and-time-picker/year-and-month-picker/header.tsx
@@ -0,0 +1,27 @@
+import React, { type FC } from 'react'
+import type { YearAndMonthPickerHeaderProps } from '../types'
+import { useMonths } from '../hooks'
+import { RiArrowUpSLine } from '@remixicon/react'
+
+const Header: FC<YearAndMonthPickerHeaderProps> = ({
+ selectedYear,
+ selectedMonth,
+ onClick,
+}) => {
+ const months = useMonths()
+
+ return (
+ <div className='flex border-b-[0.5px] border-divider-regular p-2 pb-1'>
+ {/* Year and Month */}
+ <button
+ onClick={onClick}
+ className='system-md-semibold flex items-center gap-x-0.5 rounded-lg px-2 py-1.5 text-text-primary hover:bg-state-base-hover'
+ >
+ <span>{`${months[selectedMonth]} ${selectedYear}`}</span>
+ <RiArrowUpSLine className='h-4 w-4 text-text-tertiary' />
+ </button>
+ </div>
+ )
+}
+
+export default React.memo(Header)
diff --git a/app/components/base/date-and-time-picker/year-and-month-picker/options.tsx b/app/components/base/date-and-time-picker/year-and-month-picker/options.tsx
new file mode 100644
index 0000000..684db79
--- /dev/null
+++ b/app/components/base/date-and-time-picker/year-and-month-picker/options.tsx
@@ -0,0 +1,55 @@
+import React, { type FC } from 'react'
+import type { YearAndMonthPickerOptionsProps } from '../types'
+import { useMonths, useYearOptions } from '../hooks'
+import OptionListItem from '../common/option-list-item'
+
+const Options: FC<YearAndMonthPickerOptionsProps> = ({
+ selectedMonth,
+ selectedYear,
+ handleMonthSelect,
+ handleYearSelect,
+}) => {
+ const months = useMonths()
+ const yearOptions = useYearOptions()
+
+ return (
+ <div className='grid grid-cols-2 gap-x-1 p-2'>
+ {/* Month Picker */}
+ <ul className='no-scrollbar flex h-[208px] flex-col gap-y-0.5 overflow-y-auto pb-[184px]'>
+ {
+ months.map((month, index) => {
+ const isSelected = selectedMonth === index
+ return (
+ <OptionListItem
+ key={month}
+ isSelected={isSelected}
+ onClick={handleMonthSelect.bind(null, index)}
+ >
+ {month}
+ </OptionListItem>
+ )
+ })
+ }
+ </ul>
+ {/* Year Picker */}
+ <ul className='no-scrollbar flex h-[208px] flex-col gap-y-0.5 overflow-y-auto pb-[184px]'>
+ {
+ yearOptions.map((year) => {
+ const isSelected = selectedYear === year
+ return (
+ <OptionListItem
+ key={year}
+ isSelected={isSelected}
+ onClick={handleYearSelect.bind(null, year)}
+ >
+ {year}
+ </OptionListItem>
+ )
+ })
+ }
+ </ul>
+ </div>
+ )
+}
+
+export default React.memo(Options)
diff --git a/app/components/base/dialog/index.tsx b/app/components/base/dialog/index.tsx
new file mode 100644
index 0000000..6eae3bc
--- /dev/null
+++ b/app/components/base/dialog/index.tsx
@@ -0,0 +1,81 @@
+import { Fragment, useCallback } from 'react'
+import type { ElementType, ReactNode } from 'react'
+import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react'
+import classNames from '@/utils/classnames'
+
+// https://headlessui.com/react/dialog
+
+type DialogProps = {
+ className?: string
+ titleClassName?: string
+ bodyClassName?: string
+ footerClassName?: string
+ titleAs?: ElementType
+ title?: ReactNode
+ children: ReactNode
+ footer?: ReactNode
+ show: boolean
+ onClose?: () => void
+}
+
+const CustomDialog = ({
+ className,
+ titleClassName,
+ bodyClassName,
+ footerClassName,
+ titleAs,
+ title,
+ children,
+ footer,
+ show,
+ onClose,
+}: DialogProps) => {
+ const close = useCallback(() => onClose?.(), [onClose])
+ return (
+ <Transition appear show={show} as={Fragment}>
+ <Dialog as="div" className="relative z-40" onClose={close}>
+ <TransitionChild>
+ <div className={classNames(
+ 'fixed inset-0 bg-background-overlay-backdrop backdrop-blur-[6px]',
+ 'duration-300 ease-in data-[closed]:opacity-0',
+ 'data-[enter]:opacity-100',
+ 'data-[leave]:opacity-0',
+ )} />
+ </TransitionChild>
+
+ <div className="fixed inset-0 overflow-y-auto">
+ <div className="flex min-h-full items-center justify-center">
+ <TransitionChild>
+ <DialogPanel className={classNames(
+ 'w-full max-w-[800px] p-6 overflow-hidden transition-all transform bg-components-panel-bg border-[0.5px] border-components-panel-border shadow-xl rounded-2xl',
+ 'duration-100 ease-in data-[closed]:opacity-0 data-[closed]:scale-95',
+ 'data-[enter]:opacity-100 data-[enter]:scale-100',
+ 'data-[leave]:opacity-0 data-[enter]:scale-95',
+ className,
+ )}>
+ {Boolean(title) && (
+ <DialogTitle
+ as={titleAs || 'h3'}
+ className={classNames('pr-8 pb-3 title-2xl-semi-bold text-text-primary', titleClassName)}
+ >
+ {title}
+ </DialogTitle>
+ )}
+ <div className={classNames(bodyClassName)}>
+ {children}
+ </div>
+ {Boolean(footer) && (
+ <div className={classNames('flex items-center justify-end gap-2 px-6 pb-6 pt-3', footerClassName)}>
+ {footer}
+ </div>
+ )}
+ </DialogPanel>
+ </TransitionChild>
+ </div>
+ </div>
+ </Dialog>
+ </Transition >
+ )
+}
+
+export default CustomDialog
diff --git a/app/components/base/divider/index.spec.tsx b/app/components/base/divider/index.spec.tsx
new file mode 100644
index 0000000..d33bfeb
--- /dev/null
+++ b/app/components/base/divider/index.spec.tsx
@@ -0,0 +1,55 @@
+import { render } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import Divider from './index'
+
+describe('Divider', () => {
+ it('renders with default props', () => {
+ const { container } = render(<Divider />)
+ const divider = container.firstChild as HTMLElement
+ expect(divider).toHaveClass('w-full h-[0.5px] my-2')
+ expect(divider).toHaveClass('bg-divider-regular')
+ })
+
+ it('renders horizontal solid divider correctly', () => {
+ const { container } = render(<Divider type="horizontal" bgStyle="solid" />)
+ const divider = container.firstChild as HTMLElement
+ expect(divider).toHaveClass('w-full h-[0.5px] my-2')
+ expect(divider).toHaveClass('bg-divider-regular')
+ })
+
+ it('renders vertical solid divider correctly', () => {
+ const { container } = render(<Divider type="vertical" bgStyle="solid" />)
+ const divider = container.firstChild as HTMLElement
+ expect(divider).toHaveClass('w-[1px] h-full mx-2')
+ expect(divider).toHaveClass('bg-divider-regular')
+ })
+
+ it('renders horizontal gradient divider correctly', () => {
+ const { container } = render(<Divider type="horizontal" bgStyle="gradient" />)
+ const divider = container.firstChild as HTMLElement
+ expect(divider).toHaveClass('w-full h-[0.5px] my-2')
+ expect(divider).toHaveClass('bg-gradient-to-r from-divider-regular to-background-gradient-mask-transparent')
+ })
+
+ it('renders vertical gradient divider correctly', () => {
+ const { container } = render(<Divider type="vertical" bgStyle="gradient" />)
+ const divider = container.firstChild as HTMLElement
+ expect(divider).toHaveClass('w-[1px] h-full mx-2')
+ expect(divider).toHaveClass('bg-gradient-to-r from-divider-regular to-background-gradient-mask-transparent')
+ })
+
+ it('applies custom className correctly', () => {
+ const customClass = 'test-custom-class'
+ const { container } = render(<Divider className={customClass} />)
+ const divider = container.firstChild as HTMLElement
+ expect(divider).toHaveClass(customClass)
+ expect(divider).toHaveClass('w-full h-[0.5px] my-2')
+ })
+
+ it('applies custom style correctly', () => {
+ const customStyle = { margin: '10px' }
+ const { container } = render(<Divider style={customStyle} />)
+ const divider = container.firstChild as HTMLElement
+ expect(divider).toHaveStyle('margin: 10px')
+ })
+})
diff --git a/app/components/base/divider/index.tsx b/app/components/base/divider/index.tsx
new file mode 100644
index 0000000..6fe16b9
--- /dev/null
+++ b/app/components/base/divider/index.tsx
@@ -0,0 +1,36 @@
+import type { CSSProperties, FC } from 'react'
+import React from 'react'
+import { type VariantProps, cva } from 'class-variance-authority'
+import classNames from '@/utils/classnames'
+
+const dividerVariants = cva('',
+ {
+ variants: {
+ type: {
+ horizontal: 'w-full h-[0.5px] my-2 ',
+ vertical: 'w-[1px] h-full mx-2',
+ },
+ bgStyle: {
+ gradient: 'bg-gradient-to-r from-divider-regular to-background-gradient-mask-transparent',
+ solid: 'bg-divider-regular',
+ },
+ },
+ defaultVariants: {
+ type: 'horizontal',
+ bgStyle: 'solid',
+ },
+ },
+)
+
+export type DividerProps = {
+ className?: string
+ style?: CSSProperties
+} & VariantProps<typeof dividerVariants>
+
+const Divider: FC<DividerProps> = ({ type, bgStyle, className = '', style }) => {
+ return (
+ <div className={classNames(dividerVariants({ type, bgStyle }), className)} style={style}></div>
+ )
+}
+
+export default Divider
diff --git a/app/components/base/divider/with-label.tsx b/app/components/base/divider/with-label.tsx
new file mode 100644
index 0000000..0cd9796
--- /dev/null
+++ b/app/components/base/divider/with-label.tsx
@@ -0,0 +1,23 @@
+import type { FC } from 'react'
+import type { DividerProps } from '.'
+import Divider from '.'
+import classNames from '@/utils/classnames'
+
+export type DividerWithLabelProps = DividerProps & {
+ label: string
+}
+
+export const DividerWithLabel: FC<DividerWithLabelProps> = (props) => {
+ const { label, className, ...rest } = props
+ return <div
+ className="my-2 flex items-center gap-2"
+ >
+ <Divider {...rest} className={classNames('flex-1', className)} />
+ <span className="text-xs text-text-tertiary">
+ {label}
+ </span>
+ <Divider {...rest} className={classNames('flex-1', className)} />
+ </div>
+}
+
+export default DividerWithLabel
diff --git a/app/components/base/drawer-plus/index.tsx b/app/components/base/drawer-plus/index.tsx
new file mode 100644
index 0000000..33a1948
--- /dev/null
+++ b/app/components/base/drawer-plus/index.tsx
@@ -0,0 +1,105 @@
+'use client'
+import type { FC } from 'react'
+import React, { useRef } from 'react'
+import { RiCloseLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import Drawer from '@/app/components/base/drawer'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+
+type Props = {
+ isShow: boolean
+ onHide: () => void
+ dialogClassName?: string
+ dialogBackdropClassName?: string
+ panelClassName?: string
+ maxWidthClassName?: string
+ contentClassName?: string
+ headerClassName?: string
+ height?: number | string
+ title: string | React.JSX.Element
+ titleDescription?: string | React.JSX.Element
+ body: React.JSX.Element
+ foot?: React.JSX.Element
+ isShowMask?: boolean
+ clickOutsideNotOpen?: boolean
+ positionCenter?: boolean
+}
+
+const DrawerPlus: FC<Props> = ({
+ isShow,
+ onHide,
+ dialogClassName = '',
+ dialogBackdropClassName = '',
+ panelClassName = '',
+ maxWidthClassName = '!max-w-[640px]',
+ height = 'calc(100vh - 72px)',
+ contentClassName,
+ headerClassName,
+ title,
+ titleDescription,
+ body,
+ foot,
+ isShowMask,
+ clickOutsideNotOpen = true,
+ positionCenter,
+}) => {
+ const ref = useRef(null)
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ if (!isShow)
+ return null
+
+ return (
+ // clickOutsideNotOpen to fix confirm modal click cause drawer close
+ <Drawer
+ isOpen={isShow}
+ clickOutsideNotOpen={clickOutsideNotOpen}
+ onClose={onHide}
+ footer={null}
+ mask={isMobile || isShowMask}
+ positionCenter={positionCenter}
+ dialogClassName={dialogClassName}
+ dialogBackdropClassName={dialogBackdropClassName}
+ panelClassName={cn('mx-2 mb-3 mt-16 rounded-xl !p-0 sm:mr-2', panelClassName, maxWidthClassName)}
+ >
+ <div
+ className={cn(contentClassName, 'flex w-full flex-col rounded-xl border-[0.5px] border-divider-subtle bg-components-panel-bg shadow-xl')}
+ style={{
+ height,
+ }}
+ ref={ref}
+ >
+ <div className={cn(headerClassName, 'shrink-0 border-b border-divider-subtle py-4')}>
+ <div className='flex h-6 items-center justify-between pl-6 pr-5'>
+ <div className='system-xl-semibold text-text-primary'>
+ {title}
+ </div>
+ <div className='flex items-center'>
+ <div
+ onClick={onHide}
+ className='flex h-6 w-6 cursor-pointer items-center justify-center'
+ >
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ {titleDescription && (
+ <div className='system-xs-regular pl-6 pr-10 text-text-tertiary'>
+ {titleDescription}
+ </div>
+ )}
+ </div>
+ <div className='grow overflow-y-auto'>
+ {body}
+ </div>
+ {foot && (
+ <div className='shrink-0'>
+ {foot}
+ </div>
+ )}
+ </div>
+ </Drawer>
+ )
+}
+export default React.memo(DrawerPlus)
diff --git a/app/components/base/drawer/index.tsx b/app/components/base/drawer/index.tsx
new file mode 100644
index 0000000..8217caa
--- /dev/null
+++ b/app/components/base/drawer/index.tsx
@@ -0,0 +1,94 @@
+'use client'
+import { Dialog, DialogBackdrop, DialogTitle } from '@headlessui/react'
+import { useTranslation } from 'react-i18next'
+import { XMarkIcon } from '@heroicons/react/24/outline'
+import Button from '../button'
+import cn from '@/utils/classnames'
+
+export type IDrawerProps = {
+ title?: string
+ description?: string
+ dialogClassName?: string
+ dialogBackdropClassName?: string
+ panelClassName?: string
+ children: React.ReactNode
+ footer?: React.ReactNode
+ mask?: boolean
+ positionCenter?: boolean
+ isOpen: boolean
+ showClose?: boolean
+ clickOutsideNotOpen?: boolean
+ onClose: () => void
+ onCancel?: () => void
+ onOk?: () => void
+ unmount?: boolean
+}
+
+export default function Drawer({
+ title = '',
+ description = '',
+ dialogClassName = '',
+ dialogBackdropClassName = '',
+ panelClassName = '',
+ children,
+ footer,
+ mask = true,
+ positionCenter,
+ showClose = false,
+ isOpen,
+ clickOutsideNotOpen,
+ onClose,
+ onCancel,
+ onOk,
+ unmount = false,
+}: IDrawerProps) {
+ const { t } = useTranslation()
+ return (
+ <Dialog
+ unmount={unmount}
+ open={isOpen}
+ onClose={() => !clickOutsideNotOpen && onClose()}
+ className={cn('fixed inset-0 z-[30] overflow-y-auto', dialogClassName)}
+ >
+ <div className={cn('flex h-screen w-screen justify-end', positionCenter && '!justify-center')}>
+ {/* mask */}
+ <DialogBackdrop
+ className={cn('fixed inset-0 z-[40]', mask && 'bg-black/30', dialogBackdropClassName)}
+ onClick={() => {
+ !clickOutsideNotOpen && onClose()
+ }}
+ />
+ <div className={cn('relative z-[50] flex w-full max-w-sm flex-col justify-between overflow-hidden bg-components-panel-bg p-6 text-left align-middle shadow-xl', panelClassName)}>
+ <>
+ <div className='flex justify-between'>
+ {title && <DialogTitle
+ as="h3"
+ className="text-lg font-medium leading-6 text-text-primary"
+ >
+ {title}
+ </DialogTitle>}
+ {showClose && <DialogTitle className="mb-4 flex cursor-pointer items-center" as="div">
+ <XMarkIcon className='h-4 w-4 text-text-tertiary' onClick={onClose} />
+ </DialogTitle>}
+ </div>
+ {description && <div className='mt-2 text-xs font-normal text-text-tertiary'>{description}</div>}
+ {children}
+ </>
+ {footer || (footer === null
+ ? null
+ : <div className="mt-10 flex flex-row justify-end">
+ <Button
+ className='mr-2'
+ onClick={() => {
+ onCancel && onCancel()
+ }}>{t('common.operation.cancel')}</Button>
+ <Button
+ onClick={() => {
+ onOk && onOk()
+ }}>{t('common.operation.save')}</Button>
+ </div>)}
+ </div>
+ </div>
+ </Dialog>
+ )
+}
diff --git a/app/components/base/dropdown/index.tsx b/app/components/base/dropdown/index.tsx
new file mode 100644
index 0000000..cdee153
--- /dev/null
+++ b/app/components/base/dropdown/index.tsx
@@ -0,0 +1,106 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import {
+ RiMoreFill,
+} from '@remixicon/react'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+
+export type Item = {
+ value: string | number
+ text: string | React.JSX.Element
+}
+type DropdownProps = {
+ items: Item[]
+ secondItems?: Item[]
+ onSelect: (item: Item) => void
+ renderTrigger?: (open: boolean) => React.ReactNode
+ popupClassName?: string
+}
+const Dropdown: FC<DropdownProps> = ({
+ items,
+ onSelect,
+ secondItems,
+ renderTrigger,
+ popupClassName,
+}) => {
+ const [open, setOpen] = useState(false)
+
+ const handleSelect = (item: Item) => {
+ setOpen(false)
+ onSelect(item)
+ }
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ >
+ <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
+ {
+ renderTrigger
+ ? renderTrigger(open)
+ : (
+ <div
+ className={`
+ flex h-6 w-6 cursor-pointer items-center justify-center rounded-md
+ ${open && 'bg-divider-regular'}
+ `}
+ >
+ <RiMoreFill className='h-4 w-4 text-text-tertiary' />
+ </div>
+ )
+ }
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className={popupClassName}>
+ <div className='rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg text-sm text-text-secondary shadow-lg'>
+ {
+ !!items.length && (
+ <div className='p-1'>
+ {
+ items.map(item => (
+ <div
+ key={item.value}
+ className='flex h-8 cursor-pointer items-center rounded-lg px-3 hover:bg-components-panel-on-panel-item-bg-hover'
+ onClick={() => handleSelect(item)}
+ >
+ {item.text}
+ </div>
+ ))
+ }
+ </div>
+ )
+ }
+ {
+ (!!items.length && !!secondItems?.length) && (
+ <div className='h-[1px] bg-divider-regular' />
+ )
+ }
+ {
+ !!secondItems?.length && (
+ <div className='p-1'>
+ {
+ secondItems.map(item => (
+ <div
+ key={item.value}
+ className='flex h-8 cursor-pointer items-center rounded-lg px-3 hover:bg-components-panel-on-panel-item-bg-hover'
+ onClick={() => handleSelect(item)}
+ >
+ {item.text}
+ </div>
+ ))
+ }
+ </div>
+ )
+ }
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default Dropdown
diff --git a/app/components/base/emoji-picker/Inner.tsx b/app/components/base/emoji-picker/Inner.tsx
new file mode 100644
index 0000000..34ce3f7
--- /dev/null
+++ b/app/components/base/emoji-picker/Inner.tsx
@@ -0,0 +1,173 @@
+'use client'
+import type { ChangeEvent, FC } from 'react'
+import React, { useState } from 'react'
+import data from '@emoji-mart/data'
+import type { EmojiMartData } from '@emoji-mart/data'
+import { init } from 'emoji-mart'
+import {
+ MagnifyingGlassIcon,
+} from '@heroicons/react/24/outline'
+import Input from '@/app/components/base/input'
+import Divider from '@/app/components/base/divider'
+import { searchEmoji } from '@/utils/emoji'
+import cn from '@/utils/classnames'
+
+declare global {
+ // eslint-disable-next-line ts/no-namespace
+ namespace JSX {
+ // eslint-disable-next-line ts/consistent-type-definitions
+ interface IntrinsicElements {
+ 'em-emoji': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
+ }
+ }
+}
+
+init({ data })
+
+const backgroundColors = [
+ '#FFEAD5',
+ '#E4FBCC',
+ '#D3F8DF',
+ '#E0F2FE',
+
+ '#E0EAFF',
+ '#EFF1F5',
+ '#FBE8FF',
+ '#FCE7F6',
+
+ '#FEF7C3',
+ '#E6F4D7',
+ '#D5F5F6',
+ '#D1E9FF',
+
+ '#D1E0FF',
+ '#D5D9EB',
+ '#ECE9FE',
+ '#FFE4E8',
+]
+
+type IEmojiPickerInnerProps = {
+ emoji?: string
+ background?: string
+ onSelect?: (emoji: string, background: string) => void
+ className?: string
+}
+
+const EmojiPickerInner: FC<IEmojiPickerInnerProps> = ({
+ onSelect,
+ className,
+}) => {
+ const { categories } = data as EmojiMartData
+ const [selectedEmoji, setSelectedEmoji] = useState('')
+ const [selectedBackground, setSelectedBackground] = useState(backgroundColors[0])
+
+ const [searchedEmojis, setSearchedEmojis] = useState<string[]>([])
+ const [isSearching, setIsSearching] = useState(false)
+
+ React.useEffect(() => {
+ if (selectedEmoji && selectedBackground)
+ onSelect?.(selectedEmoji, selectedBackground)
+ }, [onSelect, selectedEmoji, selectedBackground])
+
+ return <div className={cn(className)}>
+ <div className='flex w-full flex-col items-center px-3 pb-2'>
+ <div className="relative w-full">
+ <div className="pointer-events-none absolute inset-y-0 left-0 z-10 flex items-center pl-3">
+ <MagnifyingGlassIcon className="h-5 w-5 text-text-quaternary" aria-hidden="true" />
+ </div>
+ <Input
+ className="pl-10"
+ type="search"
+ id="search"
+ placeholder="Search emojis..."
+ onChange={async (e: ChangeEvent<HTMLInputElement>) => {
+ if (e.target.value === '') {
+ setIsSearching(false)
+ }
+ else {
+ setIsSearching(true)
+ const emojis = await searchEmoji(e.target.value)
+ setSearchedEmojis(emojis)
+ }
+ }}
+ />
+ </div>
+ </div>
+ <Divider className='my-3' />
+
+ <div className="max-h-[200px] w-full overflow-y-auto overflow-x-hidden px-3">
+ {isSearching && <>
+ <div key={'category-search'} className='flex flex-col'>
+ <p className='system-xs-medium-uppercase mb-1 text-text-primary'>Search</p>
+ <div className='grid h-full w-full grid-cols-8 gap-1'>
+ {searchedEmojis.map((emoji: string, index: number) => {
+ return <div
+ key={`emoji-search-${index}`}
+ className='inline-flex h-10 w-10 items-center justify-center rounded-lg'
+ onClick={() => {
+ setSelectedEmoji(emoji)
+ }}
+ >
+ <div className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg p-1 ring-components-input-border-hover ring-offset-1 hover:ring-1'>
+ <em-emoji id={emoji} />
+ </div>
+ </div>
+ })}
+ </div>
+ </div>
+ </>}
+
+ {categories.map((category, index: number) => {
+ return <div key={`category-${index}`} className='flex flex-col'>
+ <p className='system-xs-medium-uppercase mb-1 text-text-primary'>{category.id}</p>
+ <div className='grid h-full w-full grid-cols-8 gap-1'>
+ {category.emojis.map((emoji, index: number) => {
+ return <div
+ key={`emoji-${index}`}
+ className='inline-flex h-10 w-10 items-center justify-center rounded-lg'
+ onClick={() => {
+ setSelectedEmoji(emoji)
+ }}
+ >
+ <div className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg p-1 ring-components-input-border-hover ring-offset-1 hover:ring-1'>
+ <em-emoji id={emoji} />
+ </div>
+ </div>
+ })}
+
+ </div>
+ </div>
+ })}
+ </div>
+
+ {/* Color Select */}
+ <div className={cn('p-3 pb-0', selectedEmoji === '' ? 'opacity-25' : '')}>
+ <p className='system-xs-medium-uppercase mb-2 text-text-primary'>Choose Style</p>
+ <div className='grid h-full w-full grid-cols-8 gap-1'>
+ {backgroundColors.map((color) => {
+ return <div
+ key={color}
+ className={
+ cn(
+ 'cursor-pointer',
+ 'ring-offset-1 hover:ring-1',
+ 'inline-flex h-10 w-10 items-center justify-center rounded-lg',
+ color === selectedBackground ? 'ring-1 ring-components-input-border-hover' : '',
+ )}
+ onClick={() => {
+ setSelectedBackground(color)
+ }}
+ >
+ <div className={cn(
+ 'flex h-8 w-8 items-center justify-center rounded-lg p-1',
+ )
+ } style={{ background: color }}>
+ {selectedEmoji !== '' && <em-emoji id={selectedEmoji} />}
+ </div>
+ </div>
+ })}
+ </div>
+ </div>
+ </div>
+}
+export default EmojiPickerInner
diff --git a/app/components/base/emoji-picker/index.tsx b/app/components/base/emoji-picker/index.tsx
new file mode 100644
index 0000000..d3b20bb
--- /dev/null
+++ b/app/components/base/emoji-picker/index.tsx
@@ -0,0 +1,65 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import EmojiPickerInner from './Inner'
+import cn from '@/utils/classnames'
+import Divider from '@/app/components/base/divider'
+import Button from '@/app/components/base/button'
+import Modal from '@/app/components/base/modal'
+import { noop } from 'lodash-es'
+
+type IEmojiPickerProps = {
+ isModal?: boolean
+ onSelect?: (emoji: string, background: string) => void
+ onClose?: () => void
+ className?: string
+}
+
+const EmojiPicker: FC<IEmojiPickerProps> = ({
+ isModal = true,
+ onSelect,
+ onClose,
+ className,
+}) => {
+ const { t } = useTranslation()
+ const [selectedEmoji, setSelectedEmoji] = useState('')
+ const [selectedBackground, setSelectedBackground] = useState<string>()
+
+ const handleSelectEmoji = useCallback((emoji: string, background: string) => {
+ setSelectedEmoji(emoji)
+ setSelectedBackground(background)
+ }, [setSelectedEmoji, setSelectedBackground])
+
+ return isModal
+ ? <Modal
+ onClose={noop}
+ isShow
+ closable={false}
+ wrapperClassName={className}
+ className={cn('flex max-h-[552px] flex-col rounded-xl border-[0.5px] border-divider-subtle p-0 shadow-xl')}
+ >
+ <EmojiPickerInner
+ className="pt-3"
+ onSelect={handleSelectEmoji} />
+ <Divider className='mb-0 mt-3' />
+ <div className='flex w-full items-center justify-center gap-2 p-3'>
+ <Button className='w-full' onClick={() => {
+ onClose && onClose()
+ }}>
+ {t('app.iconPicker.cancel')}
+ </Button>
+ <Button
+ disabled={selectedEmoji === '' || !selectedBackground}
+ variant="primary"
+ className='w-full'
+ onClick={() => {
+ onSelect && onSelect(selectedEmoji, selectedBackground!)
+ }}>
+ {t('app.iconPicker.ok')}
+ </Button>
+ </div>
+ </Modal>
+ : <></>
+}
+export default EmojiPicker
diff --git a/app/components/base/features/context.tsx b/app/components/base/features/context.tsx
new file mode 100644
index 0000000..dc04f6b
--- /dev/null
+++ b/app/components/base/features/context.tsx
@@ -0,0 +1,27 @@
+import {
+ createContext,
+ useRef,
+} from 'react'
+import type {
+ FeaturesState,
+ FeaturesStore,
+} from './store'
+import { createFeaturesStore } from './store'
+
+export const FeaturesContext = createContext<FeaturesStore | null>(null)
+
+type FeaturesProviderProps = {
+ children: React.ReactNode
+} & Partial<FeaturesState>
+export const FeaturesProvider = ({ children, ...props }: FeaturesProviderProps) => {
+ const storeRef = useRef<FeaturesStore | undefined>(undefined)
+
+ if (!storeRef.current)
+ storeRef.current = createFeaturesStore(props)
+
+ return (
+ <FeaturesContext.Provider value={storeRef.current}>
+ {children}
+ </FeaturesContext.Provider>
+ )
+}
diff --git a/app/components/base/features/hooks.ts b/app/components/base/features/hooks.ts
new file mode 100644
index 0000000..933685b
--- /dev/null
+++ b/app/components/base/features/hooks.ts
@@ -0,0 +1,16 @@
+import { useContext } from 'react'
+import { useStore } from 'zustand'
+import { FeaturesContext } from './context'
+import type { FeatureStoreState } from './store'
+
+export function useFeatures<T>(selector: (state: FeatureStoreState) => T): T {
+ const store = useContext(FeaturesContext)
+ if (!store)
+ throw new Error('Missing FeaturesContext.Provider in the tree')
+
+ return useStore(store, selector)
+}
+
+export function useFeaturesStore() {
+ return useContext(FeaturesContext)
+}
diff --git a/app/components/base/features/index.tsx b/app/components/base/features/index.tsx
new file mode 100644
index 0000000..daea711
--- /dev/null
+++ b/app/components/base/features/index.tsx
@@ -0,0 +1 @@
+export { FeaturesProvider } from './context'
diff --git a/app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button.tsx b/app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button.tsx
new file mode 100644
index 0000000..3050249
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button.tsx
@@ -0,0 +1,79 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiEditLine,
+ RiFileEditLine,
+} from '@remixicon/react'
+import ActionButton from '@/app/components/base/action-button'
+import Tooltip from '@/app/components/base/tooltip'
+import { addAnnotation } from '@/service/annotation'
+import Toast from '@/app/components/base/toast'
+import { useProviderContext } from '@/context/provider-context'
+import { useModalContext } from '@/context/modal-context'
+
+type Props = {
+ appId: string
+ messageId?: string
+ cached: boolean
+ query: string
+ answer: string
+ onAdded: (annotationId: string, authorName: string) => void
+ onEdit: () => void
+}
+
+const AnnotationCtrlButton: FC<Props> = ({
+ cached,
+ query,
+ answer,
+ appId,
+ messageId,
+ onAdded,
+ onEdit,
+}) => {
+ const { t } = useTranslation()
+ const { plan, enableBilling } = useProviderContext()
+ const isAnnotationFull = (enableBilling && plan.usage.annotatedResponse >= plan.total.annotatedResponse)
+ const { setShowAnnotationFullModal } = useModalContext()
+ const handleAdd = async () => {
+ if (isAnnotationFull) {
+ setShowAnnotationFullModal()
+ return
+ }
+ const res: any = await addAnnotation(appId, {
+ message_id: messageId,
+ question: query,
+ answer,
+ })
+ Toast.notify({
+ message: t('common.api.actionSuccess') as string,
+ type: 'success',
+ })
+ onAdded(res.id, res.account?.name)
+ }
+
+ return (
+ <>
+ {cached && (
+ <Tooltip
+ popupContent={t('appDebug.feature.annotation.edit')}
+ >
+ <ActionButton onClick={onEdit}>
+ <RiEditLine className='h-4 w-4' />
+ </ActionButton>
+ </Tooltip>
+ )}
+ {!cached && answer && (
+ <Tooltip
+ popupContent={t('appDebug.feature.annotation.add')}
+ >
+ <ActionButton onClick={handleAdd}>
+ <RiFileEditLine className='h-4 w-4' />
+ </ActionButton>
+ </Tooltip>
+ )}
+ </>
+ )
+}
+export default React.memo(AnnotationCtrlButton)
diff --git a/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal.tsx b/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal.tsx
new file mode 100644
index 0000000..33677f0
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal.tsx
@@ -0,0 +1,139 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import ScoreSlider from './score-slider'
+import { Item } from './config-param'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import Toast from '@/app/components/base/toast'
+import type { AnnotationReplyConfig } from '@/models/debug'
+import { ANNOTATION_DEFAULT } from '@/config'
+import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
+import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+
+type Props = {
+ appId: string
+ isShow: boolean
+ onHide: () => void
+ onSave: (embeddingModel: {
+ embedding_provider_name: string
+ embedding_model_name: string
+ }, score: number) => void
+ isInit?: boolean
+ annotationConfig: AnnotationReplyConfig
+}
+
+const ConfigParamModal: FC<Props> = ({
+ isShow,
+ onHide: doHide,
+ onSave,
+ isInit,
+ annotationConfig: oldAnnotationConfig,
+}) => {
+ const { t } = useTranslation()
+ const {
+ modelList: embeddingsModelList,
+ defaultModel: embeddingsDefaultModel,
+ currentModel: isEmbeddingsDefaultModelValid,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.textEmbedding)
+ const [annotationConfig, setAnnotationConfig] = useState(oldAnnotationConfig)
+
+ const [isLoading, setLoading] = useState(false)
+ const [embeddingModel, setEmbeddingModel] = useState(oldAnnotationConfig.embedding_model
+ ? {
+ providerName: oldAnnotationConfig.embedding_model.embedding_provider_name,
+ modelName: oldAnnotationConfig.embedding_model.embedding_model_name,
+ }
+ : (embeddingsDefaultModel
+ ? {
+ providerName: embeddingsDefaultModel.provider.provider,
+ modelName: embeddingsDefaultModel.model,
+ }
+ : undefined))
+ const onHide = () => {
+ if (!isLoading)
+ doHide()
+ }
+
+ const handleSave = async () => {
+ if (!embeddingModel || !embeddingModel.modelName || (embeddingModel.modelName === embeddingsDefaultModel?.model && !isEmbeddingsDefaultModelValid)) {
+ Toast.notify({
+ message: t('common.modelProvider.embeddingModel.required'),
+ type: 'error',
+ })
+ return
+ }
+ setLoading(true)
+ await onSave({
+ embedding_provider_name: embeddingModel.providerName,
+ embedding_model_name: embeddingModel.modelName,
+ }, annotationConfig.score_threshold)
+ setLoading(false)
+ }
+
+ return (
+ <Modal
+ isShow={isShow}
+ onClose={onHide}
+ className='!mt-14 !w-[640px] !max-w-none !p-6'
+ >
+ <div className='title-2xl-semi-bold mb-2 text-text-primary'>
+ {t(`appAnnotation.initSetup.${isInit ? 'title' : 'configTitle'}`)}
+ </div>
+
+ <div className='mt-6 space-y-3'>
+ <Item
+ title={t('appDebug.feature.annotation.scoreThreshold.title')}
+ tooltip={t('appDebug.feature.annotation.scoreThreshold.description')}
+ >
+ <ScoreSlider
+ className='mt-1'
+ value={(annotationConfig.score_threshold || ANNOTATION_DEFAULT.score_threshold) * 100}
+ onChange={(val) => {
+ setAnnotationConfig({
+ ...annotationConfig,
+ score_threshold: val / 100,
+ })
+ }}
+ />
+ </Item>
+
+ <Item
+ title={t('common.modelProvider.embeddingModel.key')}
+ tooltip={t('appAnnotation.embeddingModelSwitchTip')}
+ >
+ <div className='pt-1'>
+ <ModelSelector
+ defaultModel={embeddingModel && {
+ provider: embeddingModel.providerName,
+ model: embeddingModel.modelName,
+ }}
+ modelList={embeddingsModelList}
+ onSelect={(val) => {
+ setEmbeddingModel({
+ providerName: val.provider,
+ modelName: val.model,
+ })
+ }}
+ />
+ </div>
+ </Item>
+ </div>
+
+ <div className='mt-6 flex justify-end gap-2'>
+ <Button onClick={onHide}>{t('common.operation.cancel')}</Button>
+ <Button
+ variant='primary'
+ onClick={handleSave}
+ loading={isLoading}
+ >
+ <div></div>
+ <div>{t(`appAnnotation.initSetup.${isInit ? 'confirmBtn' : 'configConfirmBtn'}`)}</div>
+ </Button >
+ </div >
+ </Modal >
+ )
+}
+export default React.memo(ConfigParamModal)
diff --git a/app/components/base/features/new-feature-panel/annotation-reply/config-param.tsx b/app/components/base/features/new-feature-panel/annotation-reply/config-param.tsx
new file mode 100644
index 0000000..e2febcf
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/annotation-reply/config-param.tsx
@@ -0,0 +1,24 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import Tooltip from '@/app/components/base/tooltip'
+
+export const Item: FC<{ title: string; tooltip: string; children: React.JSX.Element }> = ({
+ title,
+ tooltip,
+ children,
+}) => {
+ return (
+ <div>
+ <div className='mb-1 flex items-center space-x-1'>
+ <div className='system-sm-semibold py-1 text-text-secondary'>{title}</div>
+ <Tooltip
+ popupContent={
+ <div className='system-sm-regular max-w-[200px] text-text-secondary'>{tooltip}</div>
+ }
+ />
+ </div>
+ <div>{children}</div>
+ </div>
+ )
+}
diff --git a/app/components/base/features/new-feature-panel/annotation-reply/index.tsx b/app/components/base/features/new-feature-panel/annotation-reply/index.tsx
new file mode 100644
index 0000000..34ecf23
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/annotation-reply/index.tsx
@@ -0,0 +1,153 @@
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { usePathname, useRouter } from 'next/navigation'
+import produce from 'immer'
+import { RiEqualizer2Line, RiExternalLinkLine } from '@remixicon/react'
+import { MessageFast } from '@/app/components/base/icons/src/vender/features'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import Button from '@/app/components/base/button'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import useAnnotationConfig from '@/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config'
+import ConfigParamModal from '@/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal'
+import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
+import { ANNOTATION_DEFAULT } from '@/config'
+import type { AnnotationReplyConfig } from '@/models/debug'
+
+type Props = {
+ disabled?: boolean
+ onChange?: OnFeaturesChange
+}
+
+const AnnotationReply = ({
+ disabled,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const pathname = usePathname()
+ const matched = pathname.match(/\/app\/([^/]+)/)
+ const appId = (matched?.length && matched[1]) ? matched[1] : ''
+ const featuresStore = useFeaturesStore()
+ const annotationReply = useFeatures(s => s.features.annotationReply)
+
+ const updateAnnotationReply = useCallback((newConfig: AnnotationReplyConfig) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+ const newFeatures = produce(features, (draft) => {
+ draft.annotationReply = newConfig
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange(newFeatures)
+ }, [featuresStore, onChange])
+
+ const {
+ handleEnableAnnotation,
+ handleDisableAnnotation,
+ isShowAnnotationConfigInit,
+ setIsShowAnnotationConfigInit,
+ isShowAnnotationFullModal,
+ setIsShowAnnotationFullModal,
+ } = useAnnotationConfig({
+ appId,
+ annotationConfig: annotationReply as any || {
+ id: '',
+ enabled: false,
+ score_threshold: ANNOTATION_DEFAULT.score_threshold,
+ embedding_model: {
+ embedding_provider_name: '',
+ embedding_model_name: '',
+ },
+ },
+ setAnnotationConfig: updateAnnotationReply,
+ })
+
+ const handleSwitch = useCallback((enabled: boolean) => {
+ if (enabled)
+ setIsShowAnnotationConfigInit(true)
+ else
+ handleDisableAnnotation(annotationReply?.embedding_model as any)
+ }, [annotationReply?.embedding_model, handleDisableAnnotation, setIsShowAnnotationConfigInit])
+
+ const [isHovering, setIsHovering] = useState(false)
+
+ return (
+ <>
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
+ <MessageFast className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={t('appDebug.feature.annotation.title')}
+ value={!!annotationReply?.enabled}
+ onChange={state => handleSwitch(state)}
+ onMouseEnter={() => setIsHovering(true)}
+ onMouseLeave={() => setIsHovering(false)}
+ disabled={disabled}
+ >
+ <>
+ {!annotationReply?.enabled && (
+ <div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.annotation.description')}</div>
+ )}
+ {!!annotationReply?.enabled && (
+ <>
+ {!isHovering && (
+ <div className='flex items-center gap-4 pt-0.5'>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.annotation.scoreThreshold.title')}</div>
+ <div className='system-xs-regular text-text-secondary'>{annotationReply.score_threshold || '-'}</div>
+ </div>
+ <div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('common.modelProvider.embeddingModel.key')}</div>
+ <div className='system-xs-regular text-text-secondary'>{annotationReply.embedding_model?.embedding_model_name}</div>
+ </div>
+ </div>
+ )}
+ {isHovering && (
+ <div className='flex items-center justify-between'>
+ <Button className='w-[178px]' onClick={() => setIsShowAnnotationConfigInit(true)} disabled={disabled}>
+ <RiEqualizer2Line className='mr-1 h-4 w-4' />
+ {t('common.operation.params')}
+ </Button>
+ <Button className='w-[178px]' onClick={() => {
+ router.push(`/app/${appId}/annotations`)
+ }}>
+ <RiExternalLinkLine className='mr-1 h-4 w-4' />
+ {t('appDebug.feature.annotation.cacheManagement')}
+ </Button>
+ </div>
+ )}
+ </>
+ )}
+ </>
+ </FeatureCard>
+ <ConfigParamModal
+ appId={appId}
+ isInit
+ isShow={isShowAnnotationConfigInit}
+ onHide={() => {
+ setIsShowAnnotationConfigInit(false)
+ // showChooseFeatureTrue()
+ }}
+ onSave={async (embeddingModel, score) => {
+ await handleEnableAnnotation(embeddingModel, score)
+ setIsShowAnnotationConfigInit(false)
+ }}
+ annotationConfig={annotationReply as any}
+ />
+ {isShowAnnotationFullModal && (
+ <AnnotationFullModal
+ show={isShowAnnotationFullModal}
+ onHide={() => setIsShowAnnotationFullModal(false)}
+ />
+ )}
+ </>
+ )
+}
+
+export default AnnotationReply
diff --git a/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.tsx b/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.tsx
new file mode 100644
index 0000000..cc8e125
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.tsx
@@ -0,0 +1,38 @@
+import ReactSlider from 'react-slider'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+
+type ISliderProps = {
+ className?: string
+ value: number
+ max?: number
+ min?: number
+ step?: number
+ disabled?: boolean
+ onChange: (value: number) => void
+}
+
+const Slider: React.FC<ISliderProps> = ({ className, max, min, step, value, disabled, onChange }) => {
+ return <ReactSlider
+ disabled={disabled}
+ value={isNaN(value) ? 0 : value}
+ min={min || 0}
+ max={max || 100}
+ step={step || 1}
+ className={cn(className, s.slider)}
+ thumbClassName={cn(s['slider-thumb'], 'top-[-7px] h-[18px] w-2 cursor-pointer rounded-[36px] border !border-black/8 bg-white shadow-md')}
+ trackClassName={s['slider-track']}
+ onChange={onChange}
+ renderThumb={(props, state) => (
+ <div {...props}>
+ <div className='relative h-full w-full'>
+ <div className='system-sm-semibold absolute left-[50%] top-[-16px] translate-x-[-50%] text-text-primary'>
+ {(state.valueNow / 100).toFixed(2)}
+ </div>
+ </div>
+ </div>
+ )}
+ />
+}
+
+export default Slider
diff --git a/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/style.module.css b/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/style.module.css
new file mode 100644
index 0000000..8ef23b5
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/style.module.css
@@ -0,0 +1,20 @@
+.slider {
+ position: relative;
+}
+
+.slider.disabled {
+ opacity: 0.6;
+}
+
+.slider-thumb:focus {
+ outline: none;
+}
+
+.slider-track {
+ background-color: #528BFF;
+ height: 2px;
+}
+
+.slider-track-1 {
+ background-color: #E5E7EB;
+}
diff --git a/app/components/base/features/new-feature-panel/annotation-reply/score-slider/index.tsx b/app/components/base/features/new-feature-panel/annotation-reply/score-slider/index.tsx
new file mode 100644
index 0000000..2fc89b9
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/annotation-reply/score-slider/index.tsx
@@ -0,0 +1,46 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Slider from '@/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider'
+
+type Props = {
+ className?: string
+ value: number
+ onChange: (value: number) => void
+}
+
+const ScoreSlider: FC<Props> = ({
+ className,
+ value,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={className}>
+ <div className='mt-[14px] h-[1px]'>
+ <Slider
+ max={100}
+ min={80}
+ step={1}
+ value={value}
+ onChange={onChange}
+ />
+ </div>
+ <div className='system-xs-semibold-uppercase mt-[10px] flex items-center justify-between'>
+ <div className='flex space-x-1 text-util-colors-cyan-cyan-500'>
+ <div>0.8</div>
+ <div>路</div>
+ <div>{t('appDebug.feature.annotation.scoreThreshold.easyMatch')}</div>
+ </div>
+ <div className='flex space-x-1 text-util-colors-blue-blue-500'>
+ <div>1.0</div>
+ <div>路</div>
+ <div>{t('appDebug.feature.annotation.scoreThreshold.accurateMatch')}</div>
+ </div>
+ </div>
+ </div>
+ )
+}
+export default React.memo(ScoreSlider)
diff --git a/app/components/base/features/new-feature-panel/annotation-reply/type.ts b/app/components/base/features/new-feature-panel/annotation-reply/type.ts
new file mode 100644
index 0000000..9104534
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/annotation-reply/type.ts
@@ -0,0 +1,4 @@
+export enum PageType {
+ log = 'log',
+ annotation = 'annotation',
+}
diff --git a/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config.ts b/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config.ts
new file mode 100644
index 0000000..540302c
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config.ts
@@ -0,0 +1,89 @@
+import React, { useState } from 'react'
+import produce from 'immer'
+import type { AnnotationReplyConfig } from '@/models/debug'
+import { queryAnnotationJobStatus, updateAnnotationStatus } from '@/service/annotation'
+import type { EmbeddingModelConfig } from '@/app/components/app/annotation/type'
+import { AnnotationEnableStatus, JobStatus } from '@/app/components/app/annotation/type'
+import { sleep } from '@/utils'
+import { ANNOTATION_DEFAULT } from '@/config'
+import { useProviderContext } from '@/context/provider-context'
+
+type Params = {
+ appId: string
+ annotationConfig: AnnotationReplyConfig
+ setAnnotationConfig: (annotationConfig: AnnotationReplyConfig) => void
+}
+const useAnnotationConfig = ({
+ appId,
+ annotationConfig,
+ setAnnotationConfig,
+}: Params) => {
+ const { plan, enableBilling } = useProviderContext()
+ const isAnnotationFull = (enableBilling && plan.usage.annotatedResponse >= plan.total.annotatedResponse)
+ const [isShowAnnotationFullModal, setIsShowAnnotationFullModal] = useState(false)
+ const [isShowAnnotationConfigInit, doSetIsShowAnnotationConfigInit] = React.useState(false)
+ const setIsShowAnnotationConfigInit = (isShow: boolean) => {
+ if (isShow) {
+ if (isAnnotationFull) {
+ setIsShowAnnotationFullModal(true)
+ return
+ }
+ }
+ doSetIsShowAnnotationConfigInit(isShow)
+ }
+ const ensureJobCompleted = async (jobId: string, status: AnnotationEnableStatus) => {
+ let isCompleted = false
+ while (!isCompleted) {
+ const res: any = await queryAnnotationJobStatus(appId, status, jobId)
+ isCompleted = res.job_status === JobStatus.completed
+ if (isCompleted)
+ break
+
+ await sleep(2000)
+ }
+ }
+
+ const handleEnableAnnotation = async (embeddingModel: EmbeddingModelConfig, score?: number) => {
+ if (isAnnotationFull)
+ return
+
+ const { job_id: jobId }: any = await updateAnnotationStatus(appId, AnnotationEnableStatus.enable, embeddingModel, score)
+ await ensureJobCompleted(jobId, AnnotationEnableStatus.enable)
+ setAnnotationConfig(produce(annotationConfig, (draft: AnnotationReplyConfig) => {
+ draft.enabled = true
+ draft.embedding_model = embeddingModel
+ if (!draft.score_threshold)
+ draft.score_threshold = ANNOTATION_DEFAULT.score_threshold
+ }))
+ }
+
+ const setScore = (score: number, embeddingModel?: EmbeddingModelConfig) => {
+ setAnnotationConfig(produce(annotationConfig, (draft: AnnotationReplyConfig) => {
+ draft.score_threshold = score
+ if (embeddingModel)
+ draft.embedding_model = embeddingModel
+ }))
+ }
+
+ const handleDisableAnnotation = async (embeddingModel: EmbeddingModelConfig) => {
+ if (!annotationConfig.enabled)
+ return
+
+ await updateAnnotationStatus(appId, AnnotationEnableStatus.disable, embeddingModel)
+ setAnnotationConfig(produce(annotationConfig, (draft: AnnotationReplyConfig) => {
+ draft.enabled = false
+ }))
+ }
+
+ return {
+ handleEnableAnnotation,
+ handleDisableAnnotation,
+ isShowAnnotationConfigInit,
+ setIsShowAnnotationConfigInit,
+ isShowAnnotationFullModal,
+ setIsShowAnnotationFullModal,
+ setScore,
+ }
+}
+
+export default useAnnotationConfig
diff --git a/app/components/base/features/new-feature-panel/citation.tsx b/app/components/base/features/new-feature-panel/citation.tsx
new file mode 100644
index 0000000..773304d
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/citation.tsx
@@ -0,0 +1,56 @@
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { Citations } from '@/app/components/base/icons/src/vender/features'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import { FeatureEnum } from '@/app/components/base/features/types'
+
+type Props = {
+ disabled?: boolean
+ onChange?: OnFeaturesChange
+}
+
+const Citation = ({
+ disabled,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ const features = useFeatures(s => s.features)
+ const featuresStore = useFeaturesStore()
+
+ const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft[type] = {
+ ...draft[type],
+ enabled,
+ }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange(newFeatures)
+ }, [featuresStore, onChange])
+
+ return (
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs'>
+ <Citations className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={t('appDebug.feature.citation.title')}
+ value={!!features.citation?.enabled}
+ description={t('appDebug.feature.citation.description')!}
+ onChange={state => handleChange(FeatureEnum.citation, state)}
+ disabled={disabled}
+ />
+ )
+}
+
+export default Citation
diff --git a/app/components/base/features/new-feature-panel/conversation-opener/index.tsx b/app/components/base/features/new-feature-panel/conversation-opener/index.tsx
new file mode 100644
index 0000000..e407588
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/conversation-opener/index.tsx
@@ -0,0 +1,119 @@
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { RiEditLine } from '@remixicon/react'
+import { LoveMessage } from '@/app/components/base/icons/src/vender/features'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import Button from '@/app/components/base/button'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import { FeatureEnum } from '@/app/components/base/features/types'
+import { useModalContext } from '@/context/modal-context'
+import type { PromptVariable } from '@/models/debug'
+import type { InputVar } from '@/app/components/workflow/types'
+
+type Props = {
+ disabled?: boolean
+ onChange?: OnFeaturesChange
+ promptVariables?: PromptVariable[]
+ workflowVariables?: InputVar[]
+ onAutoAddPromptVariable?: (variable: PromptVariable[]) => void
+}
+
+const ConversationOpener = ({
+ disabled,
+ onChange,
+ promptVariables,
+ workflowVariables,
+ onAutoAddPromptVariable,
+}: Props) => {
+ const { t } = useTranslation()
+ const { setShowOpeningModal } = useModalContext()
+ const opening = useFeatures(s => s.features.opening)
+ const featuresStore = useFeaturesStore()
+ const [isHovering, setIsHovering] = useState(false)
+ const handleOpenOpeningModal = useCallback(() => {
+ if (disabled)
+ return
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+ setShowOpeningModal({
+ payload: {
+ ...opening,
+ promptVariables,
+ workflowVariables,
+ onAutoAddPromptVariable,
+ },
+ onSaveCallback: (newOpening) => {
+ const newFeatures = produce(features, (draft) => {
+ draft.opening = newOpening
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ },
+ onCancelCallback: () => {
+ if (onChange)
+ onChange()
+ },
+ })
+ }, [disabled, featuresStore, onAutoAddPromptVariable, onChange, opening, promptVariables, setShowOpeningModal])
+
+ const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft[type] = {
+ ...draft[type],
+ enabled,
+ }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ }, [featuresStore, onChange])
+
+ return (
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
+ <LoveMessage className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={t('appDebug.feature.conversationOpener.title')}
+ value={!!opening?.enabled}
+ onChange={state => handleChange(FeatureEnum.opening, state)}
+ onMouseEnter={() => setIsHovering(true)}
+ onMouseLeave={() => setIsHovering(false)}
+ disabled={disabled}
+ >
+ <>
+ {!opening?.enabled && (
+ <div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.conversationOpener.description')}</div>
+ )}
+ {!!opening?.enabled && (
+ <>
+ {!isHovering && (
+ <div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>
+ {opening.opening_statement || t('appDebug.openingStatement.placeholder')}
+ </div>
+ )}
+ {isHovering && (
+ <Button className='w-full' onClick={handleOpenOpeningModal} disabled={disabled}>
+ <RiEditLine className='mr-1 h-4 w-4' />
+ {t('appDebug.openingStatement.writeOpener')}
+ </Button>
+ )}
+ </>
+ )}
+ </>
+ </FeatureCard>
+ )
+}
+
+export default ConversationOpener
diff --git a/app/components/base/features/new-feature-panel/conversation-opener/modal.tsx b/app/components/base/features/new-feature-panel/conversation-opener/modal.tsx
new file mode 100644
index 0000000..117c8a5
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/conversation-opener/modal.tsx
@@ -0,0 +1,223 @@
+import React, { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import produce from 'immer'
+import { ReactSortable } from 'react-sortablejs'
+import { RiAddLine, RiAsterisk, RiCloseLine, RiDeleteBinLine, RiDraggable } from '@remixicon/react'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import Divider from '@/app/components/base/divider'
+import ConfirmAddVar from '@/app/components/app/configuration/config-prompt/confirm-add-var'
+import type { OpeningStatement } from '@/app/components/base/features/types'
+import { getInputKeys } from '@/app/components/base/block-input'
+import type { PromptVariable } from '@/models/debug'
+import type { InputVar } from '@/app/components/workflow/types'
+import { getNewVar } from '@/utils/var'
+import cn from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+type OpeningSettingModalProps = {
+ data: OpeningStatement
+ onSave: (newState: OpeningStatement) => void
+ onCancel: () => void
+ promptVariables?: PromptVariable[]
+ workflowVariables?: InputVar[]
+ onAutoAddPromptVariable?: (variable: PromptVariable[]) => void
+}
+
+const MAX_QUESTION_NUM = 10
+
+const OpeningSettingModal = ({
+ data,
+ onSave,
+ onCancel,
+ promptVariables = [],
+ workflowVariables = [],
+ onAutoAddPromptVariable,
+}: OpeningSettingModalProps) => {
+ const { t } = useTranslation()
+ const [tempValue, setTempValue] = useState(data?.opening_statement || '')
+ useEffect(() => {
+ setTempValue(data.opening_statement || '')
+ }, [data.opening_statement])
+ const [tempSuggestedQuestions, setTempSuggestedQuestions] = useState(data.suggested_questions || [])
+ const [isShowConfirmAddVar, { setTrue: showConfirmAddVar, setFalse: hideConfirmAddVar }] = useBoolean(false)
+ const [notIncludeKeys, setNotIncludeKeys] = useState<string[]>([])
+
+ const handleSave = useCallback((ignoreVariablesCheck?: boolean) => {
+ if (!ignoreVariablesCheck) {
+ const keys = getInputKeys(tempValue)
+ const promptKeys = promptVariables.map(item => item.key)
+ const workflowVariableKeys = workflowVariables.map(item => item.variable)
+ let notIncludeKeys: string[] = []
+
+ if (promptKeys.length === 0 && workflowVariables.length === 0) {
+ if (keys.length > 0)
+ notIncludeKeys = keys
+ }
+ else {
+ if (workflowVariables.length > 0)
+ notIncludeKeys = keys.filter(key => !workflowVariableKeys.includes(key))
+ else notIncludeKeys = keys.filter(key => !promptKeys.includes(key))
+ }
+
+ if (notIncludeKeys.length > 0) {
+ setNotIncludeKeys(notIncludeKeys)
+ showConfirmAddVar()
+ return
+ }
+ }
+ const newOpening = produce(data, (draft) => {
+ if (draft) {
+ draft.opening_statement = tempValue
+ draft.suggested_questions = tempSuggestedQuestions
+ }
+ })
+ onSave(newOpening)
+ }, [data, onSave, promptVariables, workflowVariables, showConfirmAddVar, tempSuggestedQuestions, tempValue])
+
+ const cancelAutoAddVar = useCallback(() => {
+ hideConfirmAddVar()
+ handleSave(true)
+ }, [handleSave, hideConfirmAddVar])
+
+ const autoAddVar = useCallback(() => {
+ onAutoAddPromptVariable?.([
+ ...notIncludeKeys.map(key => getNewVar(key, 'string')),
+ ])
+ hideConfirmAddVar()
+ handleSave(true)
+ }, [handleSave, hideConfirmAddVar, notIncludeKeys, onAutoAddPromptVariable])
+
+ const [focusID, setFocusID] = useState<number | null>(null)
+ const [deletingID, setDeletingID] = useState<number | null>(null)
+
+ const renderQuestions = () => {
+ return (
+ <div>
+ <div className='flex items-center py-2'>
+ <div className='flex shrink-0 space-x-0.5 text-xs font-medium leading-[18px] text-text-tertiary'>
+ <div className='uppercase'>{t('appDebug.openingStatement.openingQuestion')}</div>
+ <div>路</div>
+ <div>{tempSuggestedQuestions.length}/{MAX_QUESTION_NUM}</div>
+ </div>
+ <Divider bgStyle='gradient' className='ml-3 h-px w-0 grow'/>
+ </div>
+ <ReactSortable
+ className="space-y-1"
+ list={tempSuggestedQuestions.map((name, index) => {
+ return {
+ id: index,
+ name,
+ }
+ })}
+ setList={list => setTempSuggestedQuestions(list.map(item => item.name))}
+ handle='.handle'
+ ghostClass="opacity-50"
+ animation={150}
+ >
+ {tempSuggestedQuestions.map((question, index) => {
+ return (
+ <div
+ className={cn(
+ 'group relative flex items-center rounded-lg border border-components-panel-border-subtle bg-components-panel-on-panel-item-bg pl-2.5 hover:bg-components-panel-on-panel-item-bg-hover',
+ focusID === index && 'border-components-input-border-active bg-components-input-bg-active hover:border-components-input-border-active hover:bg-components-input-bg-active',
+ deletingID === index && 'border-components-input-border-destructive bg-state-destructive-hover hover:border-components-input-border-destructive hover:bg-state-destructive-hover',
+ )}
+ key={index}
+ >
+ <RiDraggable className='handle h-4 w-4 cursor-grab text-text-quaternary' />
+ <input
+ type="input"
+ value={question || ''}
+ onChange={(e) => {
+ const value = e.target.value
+ setTempSuggestedQuestions(tempSuggestedQuestions.map((item, i) => {
+ if (index === i)
+ return value
+
+ return item
+ }))
+ }}
+ className={'h-9 w-full grow cursor-pointer overflow-x-auto rounded-lg border-0 bg-transparent pl-1.5 pr-8 text-sm leading-9 text-text-secondary focus:outline-none'}
+ onFocus={() => setFocusID(index)}
+ onBlur={() => setFocusID(null)}
+ />
+
+ <div
+ className='absolute right-1.5 top-1/2 block translate-y-[-50%] cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive'
+ onClick={() => {
+ setTempSuggestedQuestions(tempSuggestedQuestions.filter((_, i) => index !== i))
+ }}
+ onMouseEnter={() => setDeletingID(index)}
+ onMouseLeave={() => setDeletingID(null)}
+ >
+ <RiDeleteBinLine className='h-3.5 w-3.5' />
+ </div>
+ </div>
+ )
+ })}</ReactSortable>
+ {tempSuggestedQuestions.length < MAX_QUESTION_NUM && (
+ <div
+ onClick={() => { setTempSuggestedQuestions([...tempSuggestedQuestions, '']) }}
+ className='mt-1 flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-components-button-tertiary-bg px-3 text-components-button-tertiary-text hover:bg-components-button-tertiary-bg-hover'>
+ <RiAddLine className='h-4 w-4' />
+ <div className='system-sm-medium text-[13px]'>{t('appDebug.variableConfig.addOption')}</div>
+ </div>
+ )}
+ </div>
+ )
+ }
+
+ return (
+ <Modal
+ isShow
+ onClose={noop}
+ className='!mt-14 !w-[640px] !max-w-none !bg-components-panel-bg-blur !p-6'
+ >
+ <div className='mb-6 flex items-center justify-between'>
+ <div className='title-2xl-semi-bold text-text-primary'>{t('appDebug.feature.conversationOpener.title')}</div>
+ <div className='cursor-pointer p-1' onClick={onCancel}><RiCloseLine className='h-4 w-4 text-text-tertiary'/></div>
+ </div>
+ <div className='mb-8 flex gap-2'>
+ <div className='mt-1.5 h-8 w-8 shrink-0 rounded-lg border-components-panel-border bg-util-colors-orange-dark-orange-dark-500 p-1.5'>
+ <RiAsterisk className='h-5 w-5 text-text-primary-on-surface' />
+ </div>
+ <div className='grow rounded-2xl border-t border-divider-subtle bg-chat-bubble-bg p-3 shadow-xs'>
+ <textarea
+ value={tempValue}
+ rows={3}
+ onChange={e => setTempValue(e.target.value)}
+ className="system-md-regular w-full border-0 bg-transparent px-0 text-text-secondary focus:outline-none"
+ placeholder={t('appDebug.openingStatement.placeholder') as string}
+ />
+ {renderQuestions()}
+ </div>
+ </div>
+ <div className='flex items-center justify-end'>
+ <Button
+ onClick={onCancel}
+ className='mr-2'
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ onClick={() => handleSave()}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ {isShowConfirmAddVar && (
+ <ConfirmAddVar
+ varNameArr={notIncludeKeys}
+ onConfirm={autoAddVar}
+ onCancel={cancelAutoAddVar}
+ onHide={hideConfirmAddVar}
+ />
+ )}
+ </Modal>
+ )
+}
+
+export default OpeningSettingModal
diff --git a/app/components/base/features/new-feature-panel/dialog-wrapper.tsx b/app/components/base/features/new-feature-panel/dialog-wrapper.tsx
new file mode 100644
index 0000000..b87b635
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/dialog-wrapper.tsx
@@ -0,0 +1,55 @@
+import { Fragment, useCallback } from 'react'
+import type { ReactNode } from 'react'
+import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react'
+import cn from '@/utils/classnames'
+
+type DialogProps = {
+ className?: string
+ children: ReactNode
+ show: boolean
+ onClose?: () => void
+ inWorkflow?: boolean
+}
+
+const DialogWrapper = ({
+ className,
+ children,
+ show,
+ onClose,
+ inWorkflow = true,
+}: DialogProps) => {
+ const close = useCallback(() => onClose?.(), [onClose])
+ return (
+ <Transition appear show={show} as={Fragment}>
+ <Dialog as="div" className="relative z-40" onClose={close}>
+ <TransitionChild>
+ <div className={cn(
+ 'fixed inset-0 bg-black bg-opacity-25',
+ 'data-[closed]:opacity-0',
+ 'data-[enter]:opacity-100 data-[enter]:duration-300 data-[enter]:ease-out',
+ 'data-[leave]:opacity-0 data-[leave]:duration-200 data-[leave]:ease-in',
+ )} />
+ </TransitionChild>
+
+ <div className="fixed inset-0">
+ <div className={cn('flex min-h-full flex-col items-end justify-center pb-2', inWorkflow ? 'pt-[112px]' : 'pr-2 pt-[64px]')}>
+ <TransitionChild>
+ <DialogPanel className={cn(
+ 'relative flex h-0 w-[420px] grow flex-col overflow-hidden border-components-panel-border bg-components-panel-bg-alt p-0 text-left align-middle shadow-xl transition-all',
+ inWorkflow ? 'rounded-l-2xl border-b-[0.5px] border-l-[0.5px] border-t-[0.5px]' : 'rounded-2xl border-[0.5px]',
+ 'data-[closed]:scale-95 data-[closed]:opacity-0',
+ 'data-[enter]:scale-100 data-[enter]:opacity-100 data-[enter]:duration-300 data-[enter]:ease-out',
+ 'data-[leave]:scale-95 data-[leave]:opacity-0 data-[leave]:duration-200 data-[leave]:ease-in',
+ className,
+ )}>
+ {children}
+ </DialogPanel>
+ </TransitionChild>
+ </div>
+ </div>
+ </Dialog>
+ </Transition >
+ )
+}
+
+export default DialogWrapper
diff --git a/app/components/base/features/new-feature-panel/feature-bar.tsx b/app/components/base/features/new-feature-panel/feature-bar.tsx
new file mode 100644
index 0000000..bea26d8
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/feature-bar.tsx
@@ -0,0 +1,145 @@
+import React, { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiApps2AddLine, RiArrowRightLine, RiSparklingFill } from '@remixicon/react'
+import { Citations, ContentModeration, FolderUpload, LoveMessage, MessageFast, Microphone01, TextToAudio, VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
+import Button from '@/app/components/base/button'
+import Tooltip from '@/app/components/base/tooltip'
+import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
+import { useFeatures } from '@/app/components/base/features/hooks'
+import cn from '@/utils/classnames'
+
+type Props = {
+ isChatMode?: boolean
+ showFileUpload?: boolean
+ disabled?: boolean
+ onFeatureBarClick?: (state: boolean) => void
+}
+
+const FeatureBar = ({
+ isChatMode = true,
+ showFileUpload = true,
+ disabled,
+ onFeatureBarClick,
+}: Props) => {
+ const { t } = useTranslation()
+ const features = useFeatures(s => s.features)
+ const [modalOpen, setModalOpen] = useState(false)
+
+ const noFeatureEnabled = useMemo(() => {
+ // completion app citation is always true but not enabled for setting
+ const data = {
+ ...features,
+ citation: { enabled: isChatMode ? features.citation?.enabled : false },
+ file: showFileUpload ? features.file! : { enabled: false },
+ }
+ return !Object.values(data).some(f => f.enabled)
+ }, [features, isChatMode, showFileUpload])
+
+ return (
+ <div className='m-1 mt-0 -translate-y-2 rounded-b-[10px] border-b border-l border-r border-components-panel-border-subtle bg-util-colors-indigo-indigo-50 px-2.5 py-2 pt-4'>
+ {noFeatureEnabled && (
+ <div className='flex cursor-pointer items-end gap-1' onClick={() => onFeatureBarClick?.(true)}>
+ <RiApps2AddLine className='h-3.5 w-3.5 text-text-accent' />
+ <div className='body-xs-medium text-text-accent'>{t('appDebug.feature.bar.empty')}</div>
+ <RiArrowRightLine className='h-3.5 w-3.5 text-text-accent' />
+ </div>
+ )}
+ {!noFeatureEnabled && (
+ <div className='flex items-center gap-2'>
+ <div className='flex shrink-0 items-center gap-0.5'>
+ {!!features.moreLikeThis?.enabled && (
+ <Tooltip
+ popupContent={t('appDebug.feature.moreLikeThis.title')}
+ >
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
+ <RiSparklingFill className='h-3.5 w-3.5 text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ )}
+ {!!features.opening?.enabled && (
+ <Tooltip
+ popupContent={t('appDebug.feature.conversationOpener.title')}
+ >
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
+ <LoveMessage className='h-3.5 w-3.5 text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ )}
+ {!!features.moderation?.enabled && (
+ <Tooltip
+ popupContent={t('appDebug.feature.moderation.title')}
+ >
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs'>
+ <ContentModeration className='h-3.5 w-3.5 text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ )}
+ {!!features.speech2text?.enabled && (
+ <Tooltip
+ popupContent={t('appDebug.feature.speechToText.title')}
+ >
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs'>
+ <Microphone01 className='h-3.5 w-3.5 text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ )}
+ {!!features.text2speech?.enabled && (
+ <VoiceSettings placementLeft={false} open={modalOpen && !disabled} onOpen={setModalOpen}>
+ <Tooltip
+ popupContent={t('appDebug.feature.textToSpeech.title')}
+ >
+ <div className={cn('shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs', !disabled && 'cursor-pointer')}>
+ <TextToAudio className='h-3.5 w-3.5 text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ </VoiceSettings>
+ )}
+ {showFileUpload && !!features.file?.enabled && (
+ <Tooltip
+ popupContent={t('appDebug.feature.fileUpload.title')}
+ >
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs'>
+ <FolderUpload className='h-3.5 w-3.5 text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ )}
+ {!!features.suggested?.enabled && (
+ <Tooltip
+ popupContent={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}
+ >
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
+ <VirtualAssistant className='h-3.5 w-3.5 text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ )}
+ {isChatMode && !!features.citation?.enabled && (
+ <Tooltip
+ popupContent={t('appDebug.feature.citation.title')}
+ >
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs'>
+ <Citations className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ )}
+ {isChatMode && !!features.annotationReply?.enabled && (
+ <Tooltip
+ popupContent={t('appDebug.feature.annotation.title')}
+ >
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
+ <MessageFast className='h-3.5 w-3.5 text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ )}
+ </div>
+ <div className='body-xs-regular grow text-text-tertiary'>{t('appDebug.feature.bar.enableText')}</div>
+ <Button className='shrink-0' variant='ghost-accent' size='small' onClick={() => onFeatureBarClick?.(true)}>
+ <div className='mx-1'>{t('appDebug.feature.bar.manage')}</div>
+ <RiArrowRightLine className='h-3.5 w-3.5 text-text-accent' />
+ </Button>
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default FeatureBar
diff --git a/app/components/base/features/new-feature-panel/feature-card.tsx b/app/components/base/features/new-feature-panel/feature-card.tsx
new file mode 100644
index 0000000..c895ef1
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/feature-card.tsx
@@ -0,0 +1,61 @@
+import React from 'react'
+import {
+ RiQuestionLine,
+} from '@remixicon/react'
+import Switch from '@/app/components/base/switch'
+import Tooltip from '@/app/components/base/tooltip'
+
+type Props = {
+ icon: any
+ title: any
+ tooltip?: any
+ value: any
+ description?: string
+ children?: React.ReactNode
+ disabled?: boolean
+ onChange?: (state: any) => void
+ onMouseEnter?: () => void
+ onMouseLeave?: () => void
+}
+
+const FeatureCard = ({
+ icon,
+ title,
+ tooltip,
+ value,
+ description,
+ children,
+ disabled,
+ onChange,
+ onMouseEnter,
+ onMouseLeave,
+}: Props) => {
+ return (
+ <div
+ className='mb-1 rounded-xl border-l-[0.5px] border-t-[0.5px] border-effects-highlight bg-background-section-burn p-3'
+ onMouseEnter={onMouseEnter}
+ onMouseLeave={onMouseLeave}
+ >
+ <div className='mb-2 flex items-center gap-2'>
+ {icon}
+ <div className='system-sm-semibold flex grow items-center text-text-secondary'>
+ {title}
+ {tooltip && (
+ <Tooltip
+ popupContent={tooltip}
+ >
+ <div className='ml-0.5 p-px'><RiQuestionLine className='h-3.5 w-3.5 text-text-quaternary' /></div>
+ </Tooltip>
+ )}
+ </div>
+ <Switch disabled={disabled} className='shrink-0' onChange={state => onChange?.(state)} defaultValue={value} />
+ </div>
+ {description && (
+ <div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{description}</div>
+ )}
+ {children}
+ </div>
+ )
+}
+
+export default FeatureCard
diff --git a/app/components/base/features/new-feature-panel/file-upload/index.tsx b/app/components/base/features/new-feature-panel/file-upload/index.tsx
new file mode 100644
index 0000000..1fc1bff
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/file-upload/index.tsx
@@ -0,0 +1,105 @@
+import React, { useCallback, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { RiEqualizer2Line } from '@remixicon/react'
+import { FolderUpload } from '@/app/components/base/icons/src/vender/features'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
+import Button from '@/app/components/base/button'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import { FeatureEnum } from '@/app/components/base/features/types'
+
+type Props = {
+ disabled: boolean
+ onChange?: OnFeaturesChange
+}
+
+const FileUpload = ({
+ disabled,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ const file = useFeatures(s => s.features.file)
+ const featuresStore = useFeaturesStore()
+ const [modalOpen, setModalOpen] = useState(false)
+ const [isHovering, setIsHovering] = useState(false)
+
+ const supportedTypes = useMemo(() => {
+ return file?.allowed_file_types?.join(',') || '-'
+ }, [file?.allowed_file_types])
+
+ const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft[type] = {
+ ...draft[type],
+ enabled,
+ image: { enabled },
+ }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ }, [featuresStore, onChange])
+
+ return (
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs'>
+ <FolderUpload className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={t('appDebug.feature.fileUpload.title')}
+ value={file?.enabled}
+ onChange={state => handleChange(FeatureEnum.file, state)}
+ onMouseEnter={() => setIsHovering(true)}
+ onMouseLeave={() => setIsHovering(false)}
+ disabled={disabled}
+ >
+ <>
+ {!file?.enabled && (
+ <div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.fileUpload.description')}</div>
+ )}
+ {file?.enabled && (
+ <>
+ {!isHovering && !modalOpen && (
+ <div className='flex items-center gap-4 pt-0.5'>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.fileUpload.supportedTypes')}</div>
+ <div className='system-xs-regular text-text-secondary'>{supportedTypes}</div>
+ </div>
+ <div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.fileUpload.numberLimit')}</div>
+ <div className='system-xs-regular text-text-secondary'>{file?.number_limits}</div>
+ </div>
+ </div>
+ )}
+ {(isHovering || modalOpen) && (
+ <SettingModal
+ open={modalOpen && !disabled}
+ onOpen={(v) => {
+ setModalOpen(v)
+ setIsHovering(v)
+ }}
+ onChange={onChange}
+ >
+ <Button className='w-full' disabled={disabled}>
+ <RiEqualizer2Line className='mr-1 h-4 w-4' />
+ {t('common.operation.settings')}
+ </Button>
+ </SettingModal>
+ )}
+ </>
+ )}
+ </>
+ </FeatureCard>
+ )
+}
+
+export default FileUpload
diff --git a/app/components/base/features/new-feature-panel/file-upload/setting-content.tsx b/app/components/base/features/new-feature-panel/file-upload/setting-content.tsx
new file mode 100644
index 0000000..5a53aa4
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/file-upload/setting-content.tsx
@@ -0,0 +1,89 @@
+import React, { useCallback, useMemo, useState } from 'react'
+import produce from 'immer'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import FileUploadSetting from '@/app/components/workflow/nodes/_base/components/file-upload-setting'
+import Button from '@/app/components/base/button'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import type { UploadFileSetting } from '@/app/components/workflow/types'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
+
+type SettingContentProps = {
+ imageUpload?: boolean
+ onClose: () => void
+ onChange?: OnFeaturesChange
+}
+const SettingContent = ({
+ imageUpload,
+ onClose,
+ onChange,
+}: SettingContentProps) => {
+ const { t } = useTranslation()
+ const featuresStore = useFeaturesStore()
+ const file = useFeatures(state => state.features.file)
+ const fileSettingPayload = useMemo(() => {
+ return {
+ allowed_file_upload_methods: file?.allowed_file_upload_methods || ['local_file', 'remote_url'],
+ allowed_file_types: file?.allowed_file_types || [SupportUploadFileTypes.image],
+ allowed_file_extensions: file?.allowed_file_extensions || FILE_EXTS[SupportUploadFileTypes.image],
+ max_length: file?.number_limits || 3,
+ } as UploadFileSetting
+ }, [file])
+ const [tempPayload, setTempPayload] = useState<UploadFileSetting>(fileSettingPayload)
+
+ const handleChange = useCallback(() => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft.file = {
+ ...draft.file,
+ allowed_file_upload_methods: tempPayload.allowed_file_upload_methods,
+ number_limits: tempPayload.max_length,
+ allowed_file_types: tempPayload.allowed_file_types,
+ allowed_file_extensions: tempPayload.allowed_file_extensions,
+ }
+ })
+
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ }, [featuresStore, onChange, tempPayload])
+
+ return (
+ <>
+ <div className='mb-4 flex items-center justify-between'>
+ <div className='system-xl-semibold text-text-primary'>{!imageUpload ? t('appDebug.feature.fileUpload.modalTitle') : t('appDebug.feature.imageUpload.modalTitle')}</div>
+ <div className='cursor-pointer p-1' onClick={onClose}><RiCloseLine className='h-4 w-4 text-text-tertiary'/></div>
+ </div>
+ <FileUploadSetting
+ isMultiple
+ inFeaturePanel
+ hideSupportFileType={imageUpload}
+ payload={tempPayload}
+ onChange={(p: UploadFileSetting) => setTempPayload(p)}
+ />
+ <div className='mt-4 flex items-center justify-end'>
+ <Button
+ onClick={onClose}
+ className='mr-2'
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ onClick={handleChange}
+ disabled={tempPayload.allowed_file_types.length === 0}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ </>
+ )
+}
+
+export default React.memo(SettingContent)
diff --git a/app/components/base/features/new-feature-panel/file-upload/setting-modal.tsx b/app/components/base/features/new-feature-panel/file-upload/setting-modal.tsx
new file mode 100644
index 0000000..92f93b8
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/file-upload/setting-modal.tsx
@@ -0,0 +1,53 @@
+'use client'
+import { memo } from 'react'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import SettingContent from '@/app/components/base/features/new-feature-panel/file-upload/setting-content'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+
+type FileUploadSettingsProps = {
+ open: boolean
+ onOpen: (state: any) => void
+ onChange?: OnFeaturesChange
+ disabled?: boolean
+ children?: React.ReactNode
+ imageUpload?: boolean
+}
+const FileUploadSettings = ({
+ open,
+ onOpen,
+ onChange,
+ disabled,
+ children,
+ imageUpload,
+}: FileUploadSettingsProps) => {
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={onOpen}
+ placement='left'
+ offset={{
+ mainAxis: 32,
+ }}
+ >
+ <PortalToFollowElemTrigger className='flex' onClick={() => !disabled && onOpen((open: boolean) => !open)}>
+ {children}
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 50 }}>
+ <div className='w-[360px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl'>
+ <SettingContent
+ imageUpload={imageUpload}
+ onClose={() => onOpen(false)}
+ onChange={(v) => {
+ onChange?.(v)
+ onOpen(false)
+ }} />
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default memo(FileUploadSettings)
diff --git a/app/components/base/features/new-feature-panel/follow-up.tsx b/app/components/base/features/new-feature-panel/follow-up.tsx
new file mode 100644
index 0000000..a81bc94
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/follow-up.tsx
@@ -0,0 +1,56 @@
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import { FeatureEnum } from '@/app/components/base/features/types'
+
+type Props = {
+ disabled?: boolean
+ onChange?: OnFeaturesChange
+}
+
+const FollowUp = ({
+ disabled,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ const features = useFeatures(s => s.features)
+ const featuresStore = useFeaturesStore()
+
+ const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft[type] = {
+ ...draft[type],
+ enabled,
+ }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange(newFeatures)
+ }, [featuresStore, onChange])
+
+ return (
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
+ <VirtualAssistant className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}
+ value={!!features.suggested?.enabled}
+ description={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')!}
+ onChange={state => handleChange(FeatureEnum.suggested, state)}
+ disabled={disabled}
+ />
+ )
+}
+
+export default FollowUp
diff --git a/app/components/base/features/new-feature-panel/image-upload/index.tsx b/app/components/base/features/new-feature-panel/image-upload/index.tsx
new file mode 100644
index 0000000..f09c35a
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/image-upload/index.tsx
@@ -0,0 +1,114 @@
+import React, { useCallback, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { RiEqualizer2Line, RiImage2Fill } from '@remixicon/react'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
+import Badge from '@/app/components/base/badge'
+import Button from '@/app/components/base/button'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import { FeatureEnum } from '@/app/components/base/features/types'
+
+type Props = {
+ disabled: boolean
+ onChange?: OnFeaturesChange
+}
+
+const FileUpload = ({
+ disabled,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ const file = useFeatures(s => s.features.file)
+ const featuresStore = useFeaturesStore()
+ const [modalOpen, setModalOpen] = useState(false)
+ const [isHovering, setIsHovering] = useState(false)
+
+ const supportedTypes = useMemo(() => {
+ return file?.allowed_file_types?.join(',') || '-'
+ }, [file?.allowed_file_types])
+
+ const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft[type] = {
+ ...draft[type],
+ enabled,
+ image: { enabled },
+ }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ }, [featuresStore, onChange])
+
+ return (
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
+ <RiImage2Fill className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={
+ <div className='flex items-center'>
+ {t('appDebug.feature.imageUpload.title')}
+ <Badge
+ text='LEGACY'
+ className='mx-1 shrink-0 border-text-accent-secondary text-text-accent-secondary'
+ />
+ </div>
+ }
+ value={file?.enabled}
+ onChange={state => handleChange(FeatureEnum.file, state)}
+ onMouseEnter={() => setIsHovering(true)}
+ onMouseLeave={() => setIsHovering(false)}
+ disabled={disabled}
+ >
+ <>
+ {!file?.enabled && (
+ <div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.imageUpload.description')}</div>
+ )}
+ {file?.enabled && (
+ <>
+ {!isHovering && !modalOpen && (
+ <div className='flex items-center gap-4 pt-0.5'>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.imageUpload.supportedTypes')}</div>
+ <div className='system-xs-regular text-text-secondary'>{supportedTypes}</div>
+ </div>
+ <div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.imageUpload.numberLimit')}</div>
+ <div className='system-xs-regular text-text-secondary'>{file?.number_limits}</div>
+ </div>
+ </div>
+ )}
+ {(isHovering || modalOpen) && (
+ <SettingModal
+ imageUpload
+ open={modalOpen && !disabled}
+ onOpen={(v) => {
+ setModalOpen(v)
+ setIsHovering(v)
+ }}
+ onChange={onChange}
+ >
+ <Button className='w-full' disabled={disabled}>
+ <RiEqualizer2Line className='mr-1 h-4 w-4' />
+ {t('common.operation.settings')}
+ </Button>
+ </SettingModal>
+ )}
+ </>
+ )}
+ </>
+ </FeatureCard>
+ )
+}
+
+export default FileUpload
diff --git a/app/components/base/features/new-feature-panel/index.tsx b/app/components/base/features/new-feature-panel/index.tsx
new file mode 100644
index 0000000..eee6805
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/index.tsx
@@ -0,0 +1,126 @@
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { RiCloseLine, RiInformation2Fill } from '@remixicon/react'
+import DialogWrapper from '@/app/components/base/features/new-feature-panel/dialog-wrapper'
+import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+
+import MoreLikeThis from '@/app/components/base/features/new-feature-panel/more-like-this'
+import ConversationOpener from '@/app/components/base/features/new-feature-panel/conversation-opener'
+import FollowUp from '@/app/components/base/features/new-feature-panel/follow-up'
+import SpeechToText from '@/app/components/base/features/new-feature-panel/speech-to-text'
+import TextToSpeech from '@/app/components/base/features/new-feature-panel/text-to-speech'
+import FileUpload from '@/app/components/base/features/new-feature-panel/file-upload'
+import Citation from '@/app/components/base/features/new-feature-panel/citation'
+import ImageUpload from '@/app/components/base/features/new-feature-panel/image-upload'
+import Moderation from '@/app/components/base/features/new-feature-panel/moderation'
+import AnnotationReply from '@/app/components/base/features/new-feature-panel/annotation-reply'
+import type { PromptVariable } from '@/models/debug'
+import type { InputVar } from '@/app/components/workflow/types'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+
+type Props = {
+ show: boolean
+ isChatMode: boolean
+ disabled: boolean
+ onChange?: OnFeaturesChange
+ onClose: () => void
+ inWorkflow?: boolean
+ showFileUpload?: boolean
+ promptVariables?: PromptVariable[]
+ workflowVariables?: InputVar[]
+ onAutoAddPromptVariable?: (variable: PromptVariable[]) => void
+}
+
+const NewFeaturePanel = ({
+ show,
+ isChatMode,
+ disabled,
+ onChange,
+ onClose,
+ inWorkflow = true,
+ showFileUpload = true,
+ promptVariables,
+ workflowVariables,
+ onAutoAddPromptVariable,
+}: Props) => {
+ const { t } = useTranslation()
+ const { locale } = useContext(I18n)
+ const { data: speech2textDefaultModel } = useDefaultModel(ModelTypeEnum.speech2text)
+ const { data: text2speechDefaultModel } = useDefaultModel(ModelTypeEnum.tts)
+
+ return (
+ <DialogWrapper
+ show={show}
+ onClose={onClose}
+ inWorkflow={inWorkflow}
+ >
+ <div className='flex h-full grow flex-col'>
+ {/* header */}
+ <div className='flex shrink-0 justify-between p-4 pb-3'>
+ <div>
+ <div className='system-xl-semibold text-text-primary'>{t('workflow.common.features')}</div>
+ <div className='body-xs-regular text-text-tertiary'>{t('workflow.common.featuresDescription')}</div>
+ </div>
+ <div className='h-8 w-8 cursor-pointer p-2' onClick={onClose}><RiCloseLine className='h-4 w-4 text-text-tertiary'/></div>
+ </div>
+ {/* list */}
+ <div className='grow basis-0 overflow-y-auto px-4 pb-4'>
+ {showFileUpload && (
+ <div className='relative mb-1 rounded-xl border border-components-panel-border p-2 shadow-xs'>
+ <div className='absolute left-0 top-0 h-full w-full rounded-xl opacity-40' style={{ background: 'linear-gradient(92deg, rgba(11, 165, 236, 0.25) 18.12%, rgba(255, 255, 255, 0.00) 167.31%)' }}></div>
+ <div className='relative flex h-full w-full items-start'>
+ <div className='mr-0.5 shrink-0 p-0.5'>
+ <RiInformation2Fill className='h-5 w-5 text-text-accent' />
+ </div>
+ <div className='system-xs-medium p-1 text-text-primary'>
+ <span>{isChatMode ? t('workflow.common.fileUploadTip') : t('workflow.common.ImageUploadLegacyTip')}</span>
+ <a
+ className='text-text-accent'
+ href={`https://docs.dify.ai/${locale === LanguagesSupported[1] ? 'v/zh-hans/' : ''}guides/workflow/bulletin`}
+ target='_blank' rel='noopener noreferrer'
+ >{t('workflow.common.featuresDocLink')}</a>
+ </div>
+ </div>
+ </div>
+ )}
+ {!isChatMode && !inWorkflow && (
+ <MoreLikeThis disabled={disabled} onChange={onChange} />
+ )}
+ {isChatMode && (
+ <ConversationOpener
+ disabled={disabled}
+ onChange={onChange}
+ promptVariables={promptVariables}
+ workflowVariables={workflowVariables}
+ onAutoAddPromptVariable={onAutoAddPromptVariable}
+ />
+ )}
+ {isChatMode && (
+ <FollowUp disabled={disabled} onChange={onChange} />
+ )}
+ {text2speechDefaultModel && (isChatMode || !inWorkflow) && (
+ <TextToSpeech disabled={disabled} onChange={onChange} />
+ )}
+ {isChatMode && speech2textDefaultModel && (
+ <SpeechToText disabled={disabled} onChange={onChange} />
+ )}
+ {showFileUpload && isChatMode && <FileUpload disabled={disabled} onChange={onChange} />}
+ {showFileUpload && !isChatMode && <ImageUpload disabled={disabled} onChange={onChange} />}
+ {isChatMode && (
+ <Citation disabled={disabled} onChange={onChange} />
+ )}
+ {(isChatMode || !inWorkflow) && <Moderation disabled={disabled} onChange={onChange} />}
+ {!inWorkflow && isChatMode && (
+ <AnnotationReply disabled={disabled} onChange={onChange} />
+ )}
+ </div>
+ </div>
+ </DialogWrapper>
+ )
+}
+
+export default NewFeaturePanel
diff --git a/app/components/base/features/new-feature-panel/moderation/form-generation.tsx b/app/components/base/features/new-feature-panel/moderation/form-generation.tsx
new file mode 100644
index 0000000..dccf10d
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/moderation/form-generation.tsx
@@ -0,0 +1,80 @@
+import type { FC } from 'react'
+import { useContext } from 'use-context-selector'
+import type { CodeBasedExtensionForm } from '@/models/common'
+import I18n from '@/context/i18n'
+import { PortalSelect } from '@/app/components/base/select'
+import Textarea from '@/app/components/base/textarea'
+import type { ModerationConfig } from '@/models/debug'
+
+type FormGenerationProps = {
+ forms: CodeBasedExtensionForm[]
+ value: ModerationConfig['config']
+ onChange: (v: Record<string, string>) => void
+}
+const FormGeneration: FC<FormGenerationProps> = ({
+ forms,
+ value,
+ onChange,
+}) => {
+ const { locale } = useContext(I18n)
+
+ const handleFormChange = (type: string, v: string) => {
+ onChange({ ...value, [type]: v })
+ }
+
+ return (
+ <>
+ {
+ forms.map((form, index) => (
+ <div
+ key={index}
+ className='py-2'
+ >
+ <div className='flex h-9 items-center text-sm font-medium text-text-primary'>
+ {locale === 'zh-Hans' ? form.label['zh-Hans'] : form.label['en-US']}
+ </div>
+ {
+ form.type === 'text-input' && (
+ <input
+ value={value?.[form.variable] || ''}
+ className='block h-9 w-full appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-text-primary outline-none'
+ placeholder={form.placeholder}
+ onChange={e => handleFormChange(form.variable, e.target.value)}
+ />
+ )
+ }
+ {
+ form.type === 'paragraph' && (
+ <div className='relative'>
+ <Textarea
+ className='resize-none'
+ value={value?.[form.variable] || ''}
+ placeholder={form.placeholder}
+ onChange={e => handleFormChange(form.variable, e.target.value)}
+ />
+ </div>
+ )
+ }
+ {
+ form.type === 'select' && (
+ <PortalSelect
+ value={value?.[form.variable]}
+ items={form.options.map((option) => {
+ return {
+ name: option.label[locale === 'zh-Hans' ? 'zh-Hans' : 'en-US'],
+ value: option.value,
+ }
+ })}
+ onSelect={item => handleFormChange(form.variable, item.value as string)}
+ popupClassName='w-[576px] !z-[102]'
+ />
+ )
+ }
+ </div>
+ ))
+ }
+ </>
+ )
+}
+
+export default FormGeneration
diff --git a/app/components/base/features/new-feature-panel/moderation/index.tsx b/app/components/base/features/new-feature-panel/moderation/index.tsx
new file mode 100644
index 0000000..78f4f2d
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/moderation/index.tsx
@@ -0,0 +1,176 @@
+import React, { useCallback, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import produce from 'immer'
+import { useContext } from 'use-context-selector'
+import { RiEqualizer2Line } from '@remixicon/react'
+import { ContentModeration } from '@/app/components/base/icons/src/vender/features'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import Button from '@/app/components/base/button'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import { FeatureEnum } from '@/app/components/base/features/types'
+import { fetchCodeBasedExtensionList } from '@/service/common'
+import { useModalContext } from '@/context/modal-context'
+import I18n from '@/context/i18n'
+
+type Props = {
+ disabled?: boolean
+ onChange?: OnFeaturesChange
+}
+
+const Moderation = ({
+ disabled,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ const { setShowModerationSettingModal } = useModalContext()
+ const { locale } = useContext(I18n)
+ const featuresStore = useFeaturesStore()
+ const moderation = useFeatures(s => s.features.moderation)
+ const { data: codeBasedExtensionList } = useSWR(
+ '/code-based-extension?module=moderation',
+ fetchCodeBasedExtensionList,
+ )
+ const [isHovering, setIsHovering] = useState(false)
+
+ const handleOpenModerationSettingModal = () => {
+ if (disabled)
+ return
+
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+ setShowModerationSettingModal({
+ payload: moderation as any,
+ onSaveCallback: (newModeration) => {
+ const newFeatures = produce(features, (draft) => {
+ draft.moderation = newModeration
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange(newFeatures)
+ },
+ onCancelCallback: () => {
+ if (onChange)
+ onChange()
+ },
+ })
+ }
+
+ const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ if (enabled && !features.moderation?.type && type === FeatureEnum.moderation) {
+ setShowModerationSettingModal({
+ payload: {
+ enabled: true,
+ type: 'keywords',
+ config: {
+ keywords: '',
+ inputs_config: {
+ enabled: true,
+ preset_response: '',
+ },
+ },
+ },
+ onSaveCallback: (newModeration) => {
+ const newFeatures = produce(features, (draft) => {
+ draft.moderation = newModeration
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange(newFeatures)
+ },
+ onCancelCallback: () => {
+ const newFeatures = produce(features, (draft) => {
+ draft.moderation = { enabled: false }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ },
+ })
+ }
+
+ if (!enabled) {
+ const newFeatures = produce(features, (draft) => {
+ draft.moderation = { enabled: false }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange(newFeatures)
+ }
+ }, [featuresStore, onChange, setShowModerationSettingModal])
+
+ const providerContent = useMemo(() => {
+ if (moderation?.type === 'openai_moderation')
+ return t('appDebug.feature.moderation.modal.provider.openai')
+ else if (moderation?.type === 'keywords')
+ return t('appDebug.feature.moderation.modal.provider.keywords')
+ else if (moderation?.type === 'api')
+ return t('common.apiBasedExtension.selector.title')
+ else
+ return codeBasedExtensionList?.data.find(item => item.name === moderation?.type)?.label[locale] || '-'
+ }, [codeBasedExtensionList?.data, locale, moderation?.type, t])
+
+ const enableContent = useMemo(() => {
+ if (moderation?.config?.inputs_config?.enabled && moderation.config?.outputs_config?.enabled)
+ return t('appDebug.feature.moderation.allEnabled')
+ else if (moderation?.config?.inputs_config?.enabled)
+ return t('appDebug.feature.moderation.inputEnabled')
+ else if (moderation?.config?.outputs_config?.enabled)
+ return t('appDebug.feature.moderation.outputEnabled')
+ }, [moderation?.config?.inputs_config?.enabled, moderation?.config?.outputs_config?.enabled, t])
+
+ return (
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs'>
+ <ContentModeration className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={t('appDebug.feature.moderation.title')}
+ value={!!moderation?.enabled}
+ onChange={state => handleChange(FeatureEnum.moderation, state)}
+ onMouseEnter={() => setIsHovering(true)}
+ onMouseLeave={() => setIsHovering(false)}
+ disabled={disabled}
+ >
+ <>
+ {!moderation?.enabled && (
+ <div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.moderation.description')}</div>
+ )}
+ {!!moderation?.enabled && (
+ <>
+ {!isHovering && (
+ <div className='flex items-center gap-4 pt-0.5'>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.moderation.modal.provider.title')}</div>
+ <div className='system-xs-regular text-text-secondary'>{providerContent}</div>
+ </div>
+ <div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.moderation.contentEnableLabel')}</div>
+ <div className='system-xs-regular text-text-secondary'>{enableContent}</div>
+ </div>
+ </div>
+ )}
+ {isHovering && (
+ <Button className='w-full' onClick={handleOpenModerationSettingModal} disabled={disabled}>
+ <RiEqualizer2Line className='mr-1 h-4 w-4' />
+ {t('common.operation.settings')}
+ </Button>
+ )}
+ </>
+ )}
+ </>
+ </FeatureCard>
+ )
+}
+
+export default Moderation
diff --git a/app/components/base/features/new-feature-panel/moderation/moderation-content.tsx b/app/components/base/features/new-feature-panel/moderation/moderation-content.tsx
new file mode 100644
index 0000000..9c00a7d
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/moderation/moderation-content.tsx
@@ -0,0 +1,72 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import Switch from '@/app/components/base/switch'
+import type { ModerationContentConfig } from '@/models/debug'
+
+type ModerationContentProps = {
+ title: string
+ info?: string
+ showPreset?: boolean
+ config: ModerationContentConfig
+ onConfigChange: (config: ModerationContentConfig) => void
+}
+const ModerationContent: FC<ModerationContentProps> = ({
+ title,
+ info,
+ showPreset = true,
+ config,
+ onConfigChange,
+}) => {
+ const { t } = useTranslation()
+
+ const handleConfigChange = (field: string, value: boolean | string) => {
+ if (field === 'preset_response' && typeof value === 'string')
+ value = value.slice(0, 100)
+ onConfigChange({ ...config, [field]: value })
+ }
+
+ return (
+ <div className='py-2'>
+ <div className='rounded-lg border border-components-panel-border bg-components-panel-bg'>
+ <div className='flex h-10 items-center justify-between rounded-lg px-3'>
+ <div className='shrink-0 text-sm font-medium text-text-primary'>{title}</div>
+ <div className='flex grow items-center justify-end'>
+ {
+ info && (
+ <div className='mr-2 truncate text-xs text-text-tertiary' title={info}>{info}</div>
+ )
+ }
+ <Switch
+ size='l'
+ defaultValue={config.enabled}
+ onChange={v => handleConfigChange('enabled', v)}
+ />
+ </div>
+ </div>
+ {
+ config.enabled && showPreset && (
+ <div className='rounded-lg bg-components-panel-bg px-3 pb-3 pt-1'>
+ <div className='flex h-8 items-center justify-between text-[13px] font-medium text-text-secondary'>
+ {t('appDebug.feature.moderation.modal.content.preset')}
+ <span className='text-xs font-normal text-text-tertiary'>{t('appDebug.feature.moderation.modal.content.supportMarkdown')}</span>
+ </div>
+ <div className='relative h-20 rounded-lg bg-components-input-bg-normal px-3 py-2'>
+ <textarea
+ value={config.preset_response || ''}
+ className='block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none'
+ placeholder={t('appDebug.feature.moderation.modal.content.placeholder') || ''}
+ onChange={e => handleConfigChange('preset_response', e.target.value)}
+ />
+ <div className='absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary'>
+ <span>{(config.preset_response || '').length}</span>/<span className='text-text-tertiary'>100</span>
+ </div>
+ </div>
+ </div>
+ )
+ }
+ </div>
+ </div>
+ )
+}
+
+export default ModerationContent
diff --git a/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx b/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx
new file mode 100644
index 0000000..ab5200f
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx
@@ -0,0 +1,380 @@
+import type { ChangeEvent, FC } from 'react'
+import { useState } from 'react'
+import useSWR from 'swr'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import ModerationContent from './moderation-content'
+import FormGeneration from './form-generation'
+import ApiBasedExtensionSelector from '@/app/components/header/account-setting/api-based-extension-page/selector'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import Divider from '@/app/components/base/divider'
+import { BookOpen01 } from '@/app/components/base/icons/src/vender/line/education'
+import type { ModerationConfig, ModerationContentConfig } from '@/models/debug'
+import { useToastContext } from '@/app/components/base/toast'
+import {
+ fetchCodeBasedExtensionList,
+ fetchModelProviders,
+} from '@/service/common'
+import type { CodeBasedExtensionItem } from '@/models/common'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
+import { useModalContext } from '@/context/modal-context'
+import { CustomConfigurationStatusEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import cn from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+const systemTypes = ['openai_moderation', 'keywords', 'api']
+
+type Provider = {
+ key: string
+ name: string
+ form_schema?: CodeBasedExtensionItem['form_schema']
+}
+
+type ModerationSettingModalProps = {
+ data: ModerationConfig
+ onCancel: () => void
+ onSave: (moderationConfig: ModerationConfig) => void
+}
+
+const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
+ data,
+ onCancel,
+ onSave,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const { locale } = useContext(I18n)
+ const { data: modelProviders, isLoading, mutate } = useSWR('/workspaces/current/model-providers', fetchModelProviders)
+ const [localeData, setLocaleData] = useState<ModerationConfig>(data)
+ const { setShowAccountSettingModal } = useModalContext()
+ const handleOpenSettingsModal = () => {
+ setShowAccountSettingModal({
+ payload: 'provider',
+ onCancelCallback: () => {
+ mutate()
+ },
+ })
+ }
+ const { data: codeBasedExtensionList } = useSWR(
+ '/code-based-extension?module=moderation',
+ fetchCodeBasedExtensionList,
+ )
+ const openaiProvider = modelProviders?.data.find(item => item.provider === 'langgenius/openai/openai')
+ const systemOpenaiProviderEnabled = openaiProvider?.system_configuration.enabled
+ const systemOpenaiProviderQuota = systemOpenaiProviderEnabled ? openaiProvider?.system_configuration.quota_configurations.find(item => item.quota_type === openaiProvider.system_configuration.current_quota_type) : undefined
+ const systemOpenaiProviderCanUse = systemOpenaiProviderQuota?.is_valid
+ const customOpenaiProvidersCanUse = openaiProvider?.custom_configuration.status === CustomConfigurationStatusEnum.active
+ const isOpenAIProviderConfigured = customOpenaiProvidersCanUse || systemOpenaiProviderCanUse
+ const providers: Provider[] = [
+ {
+ key: 'openai_moderation',
+ name: t('appDebug.feature.moderation.modal.provider.openai'),
+ },
+ {
+ key: 'keywords',
+ name: t('appDebug.feature.moderation.modal.provider.keywords'),
+ },
+ {
+ key: 'api',
+ name: t('common.apiBasedExtension.selector.title'),
+ },
+ ...(
+ codeBasedExtensionList
+ ? codeBasedExtensionList.data.map((item) => {
+ return {
+ key: item.name,
+ name: locale === 'zh-Hans' ? item.label['zh-Hans'] : item.label['en-US'],
+ form_schema: item.form_schema,
+ }
+ })
+ : []
+ ),
+ ]
+
+ const currentProvider = providers.find(provider => provider.key === localeData.type)
+
+ const handleDataTypeChange = (type: string) => {
+ let config: undefined | Record<string, any>
+ const currProvider = providers.find(provider => provider.key === type)
+
+ if (systemTypes.findIndex(t => t === type) < 0 && currProvider?.form_schema) {
+ config = currProvider?.form_schema.reduce((prev, next) => {
+ prev[next.variable] = next.default
+ return prev
+ }, {} as Record<string, any>)
+ }
+ setLocaleData({
+ ...localeData,
+ type,
+ config,
+ })
+ }
+
+ const handleDataKeywordsChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
+ const value = e.target.value
+
+ const arr = value.split('\n').reduce((prev: string[], next: string) => {
+ if (next !== '')
+ prev.push(next.slice(0, 100))
+ if (next === '' && prev[prev.length - 1] !== '')
+ prev.push(next)
+
+ return prev
+ }, [])
+
+ setLocaleData({
+ ...localeData,
+ config: {
+ ...localeData.config,
+ keywords: arr.slice(0, 100).join('\n'),
+ },
+ })
+ }
+
+ const handleDataContentChange = (contentType: string, contentConfig: ModerationContentConfig) => {
+ setLocaleData({
+ ...localeData,
+ config: {
+ ...localeData.config,
+ [contentType]: contentConfig,
+ },
+ })
+ }
+
+ const handleDataApiBasedChange = (apiBasedExtensionId: string) => {
+ setLocaleData({
+ ...localeData,
+ config: {
+ ...localeData.config,
+ api_based_extension_id: apiBasedExtensionId,
+ },
+ })
+ }
+
+ const handleDataExtraChange = (extraValue: Record<string, string>) => {
+ setLocaleData({
+ ...localeData,
+ config: {
+ ...localeData.config,
+ ...extraValue,
+ },
+ })
+ }
+
+ const formatData = (originData: ModerationConfig) => {
+ const { enabled, type, config } = originData
+ const { inputs_config, outputs_config } = config!
+ const params: Record<string, string | undefined> = {}
+
+ if (type === 'keywords')
+ params.keywords = config?.keywords
+
+ if (type === 'api')
+ params.api_based_extension_id = config?.api_based_extension_id
+
+ if (systemTypes.findIndex(t => t === type) < 0 && currentProvider?.form_schema) {
+ currentProvider.form_schema.forEach((form) => {
+ params[form.variable] = config?.[form.variable]
+ })
+ }
+
+ return {
+ type,
+ enabled,
+ config: {
+ inputs_config: inputs_config || { enabled: false },
+ outputs_config: outputs_config || { enabled: false },
+ ...params,
+ },
+ }
+ }
+
+ const handleSave = () => {
+ if (localeData.type === 'openai_moderation' && !isOpenAIProviderConfigured)
+ return
+
+ if (!localeData.config?.inputs_config?.enabled && !localeData.config?.outputs_config?.enabled) {
+ notify({ type: 'error', message: t('appDebug.feature.moderation.modal.content.condition') })
+ return
+ }
+
+ if (localeData.type === 'keywords' && !localeData.config.keywords) {
+ notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale !== LanguagesSupported[1] ? 'keywords' : '鍏抽敭璇�' }) })
+ return
+ }
+
+ if (localeData.type === 'api' && !localeData.config.api_based_extension_id) {
+ notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale !== LanguagesSupported[1] ? 'API Extension' : 'API 鎵╁睍' }) })
+ return
+ }
+
+ if (systemTypes.findIndex(t => t === localeData.type) < 0 && currentProvider?.form_schema) {
+ for (let i = 0; i < currentProvider.form_schema.length; i++) {
+ if (!localeData.config?.[currentProvider.form_schema[i].variable] && currentProvider.form_schema[i].required) {
+ notify({
+ type: 'error',
+ message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale !== LanguagesSupported[1] ? currentProvider.form_schema[i].label['en-US'] : currentProvider.form_schema[i].label['zh-Hans'] }),
+ })
+ return
+ }
+ }
+ }
+
+ if (localeData.config.inputs_config?.enabled && !localeData.config.inputs_config.preset_response && localeData.type !== 'api') {
+ notify({ type: 'error', message: t('appDebug.feature.moderation.modal.content.errorMessage') })
+ return
+ }
+
+ if (localeData.config.outputs_config?.enabled && !localeData.config.outputs_config.preset_response && localeData.type !== 'api') {
+ notify({ type: 'error', message: t('appDebug.feature.moderation.modal.content.errorMessage') })
+ return
+ }
+
+ onSave(formatData(localeData))
+ }
+
+ return (
+ <Modal
+ isShow
+ onClose={noop}
+ className='!mt-14 !w-[600px] !max-w-none !p-6'
+ >
+ <div className='flex items-center justify-between'>
+ <div className='title-2xl-semi-bold text-text-primary'>{t('appDebug.feature.moderation.modal.title')}</div>
+ <div className='cursor-pointer p-1' onClick={onCancel}><RiCloseLine className='h-4 w-4 text-text-tertiary' /></div>
+ </div>
+ <div className='py-2'>
+ <div className='text-sm font-medium leading-9 text-text-primary'>
+ {t('appDebug.feature.moderation.modal.provider.title')}
+ </div>
+ <div className='grid grid-cols-3 gap-2.5'>
+ {
+ providers.map(provider => (
+ <div
+ key={provider.key}
+ className={cn(
+ 'system-sm-regular flex h-8 cursor-default items-center rounded-md border border-components-option-card-option-border bg-components-option-card-option-bg px-2 text-text-secondary',
+ localeData.type !== provider.key && 'cursor-pointer hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover hover:shadow-xs',
+ localeData.type === provider.key && 'system-sm-medium border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg shadow-xs',
+ localeData.type === 'openai_moderation' && provider.key === 'openai_moderation' && !isOpenAIProviderConfigured && 'text-text-disabled',
+ )}
+ onClick={() => handleDataTypeChange(provider.key)}
+ >
+ <div className={cn(
+ 'mr-2 h-4 w-4 rounded-full border border-components-radio-border bg-components-radio-bg shadow-xs',
+ localeData.type === provider.key && 'border-[5px] border-components-radio-border-checked',
+ )}></div>
+ {provider.name}
+ </div>
+ ))
+ }
+ </div>
+ {
+ !isLoading && !isOpenAIProviderConfigured && localeData.type === 'openai_moderation' && (
+ <div className='mt-2 flex items-center rounded-lg border border-[#FEF0C7] bg-[#FFFAEB] px-3 py-2'>
+ <InfoCircle className='mr-1 h-4 w-4 text-[#F79009]' />
+ <div className='flex items-center text-xs font-medium text-gray-700'>
+ {t('appDebug.feature.moderation.modal.openaiNotConfig.before')}
+ <span
+ className='cursor-pointer text-primary-600'
+ onClick={handleOpenSettingsModal}
+ >
+ {t('common.settings.provider')}
+ </span>
+ {t('appDebug.feature.moderation.modal.openaiNotConfig.after')}
+ </div>
+ </div>
+ )
+ }
+ </div>
+ {
+ localeData.type === 'keywords' && (
+ <div className='py-2'>
+ <div className='mb-1 text-sm font-medium text-text-primary'>{t('appDebug.feature.moderation.modal.provider.keywords')}</div>
+ <div className='mb-2 text-xs text-text-tertiary'>{t('appDebug.feature.moderation.modal.keywords.tip')}</div>
+ <div className='relative h-[88px] rounded-lg bg-components-input-bg-normal px-3 py-2'>
+ <textarea
+ value={localeData.config?.keywords || ''}
+ onChange={handleDataKeywordsChange}
+ className='block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none'
+ placeholder={t('appDebug.feature.moderation.modal.keywords.placeholder') || ''}
+ />
+ <div className='absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary'>
+ <span>{(localeData.config?.keywords || '').split('\n').filter(Boolean).length}</span>/<span className='text-text-tertiary'>100 {t('appDebug.feature.moderation.modal.keywords.line')}</span>
+ </div>
+ </div>
+ </div>
+ )
+ }
+ {
+ localeData.type === 'api' && (
+ <div className='py-2'>
+ <div className='flex h-9 items-center justify-between'>
+ <div className='text-sm font-medium text-text-primary'>{t('common.apiBasedExtension.selector.title')}</div>
+ <a
+ href={t('common.apiBasedExtension.linkUrl') || '/'}
+ target='_blank' rel='noopener noreferrer'
+ className='group flex items-center text-xs text-text-tertiary hover:text-primary-600'
+ >
+ <BookOpen01 className='mr-1 h-3 w-3 text-text-tertiary group-hover:text-primary-600' />
+ {t('common.apiBasedExtension.link')}
+ </a>
+ </div>
+ <ApiBasedExtensionSelector
+ value={localeData.config?.api_based_extension_id || ''}
+ onChange={handleDataApiBasedChange}
+ />
+ </div>
+ )
+ }
+ {
+ systemTypes.findIndex(t => t === localeData.type) < 0
+ && currentProvider?.form_schema
+ && (
+ <FormGeneration
+ forms={currentProvider?.form_schema}
+ value={localeData.config}
+ onChange={handleDataExtraChange}
+ />
+ )
+ }
+ <Divider bgStyle='gradient' className='my-3 h-px' />
+ <ModerationContent
+ title={t('appDebug.feature.moderation.modal.content.input') || ''}
+ config={localeData.config?.inputs_config || { enabled: false, preset_response: '' }}
+ onConfigChange={config => handleDataContentChange('inputs_config', config)}
+ info={(localeData.type === 'api' && t('appDebug.feature.moderation.modal.content.fromApi')) || ''}
+ showPreset={localeData.type !== 'api'}
+ />
+ <ModerationContent
+ title={t('appDebug.feature.moderation.modal.content.output') || ''}
+ config={localeData.config?.outputs_config || { enabled: false, preset_response: '' }}
+ onConfigChange={config => handleDataContentChange('outputs_config', config)}
+ info={(localeData.type === 'api' && t('appDebug.feature.moderation.modal.content.fromApi')) || ''}
+ showPreset={localeData.type !== 'api'}
+ />
+ <div className='mb-8 mt-1 text-xs font-medium text-text-tertiary'>{t('appDebug.feature.moderation.modal.content.condition')}</div>
+ <div className='flex items-center justify-end'>
+ <Button
+ onClick={onCancel}
+ className='mr-2'
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ onClick={handleSave}
+ disabled={localeData.type === 'openai_moderation' && !isOpenAIProviderConfigured}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ </Modal>
+ )
+}
+
+export default ModerationSettingModal
diff --git a/app/components/base/features/new-feature-panel/more-like-this.tsx b/app/components/base/features/new-feature-panel/more-like-this.tsx
new file mode 100644
index 0000000..d2e2fc6
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/more-like-this.tsx
@@ -0,0 +1,57 @@
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { RiSparklingFill } from '@remixicon/react'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import { FeatureEnum } from '@/app/components/base/features/types'
+
+type Props = {
+ disabled?: boolean
+ onChange?: OnFeaturesChange
+}
+
+const MoreLikeThis = ({
+ disabled,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ const features = useFeatures(s => s.features)
+ const featuresStore = useFeaturesStore()
+
+ const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft[type] = {
+ ...draft[type],
+ enabled,
+ }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ }, [featuresStore, onChange])
+
+ return (
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
+ <RiSparklingFill className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={t('appDebug.feature.moreLikeThis.title')}
+ tooltip={t('appDebug.feature.moreLikeThis.tip')}
+ value={!!features.moreLikeThis?.enabled}
+ description={t('appDebug.feature.moreLikeThis.description')!}
+ onChange={state => handleChange(FeatureEnum.moreLikeThis, state)}
+ disabled={disabled}
+ />
+ )
+}
+
+export default MoreLikeThis
diff --git a/app/components/base/features/new-feature-panel/speech-to-text.tsx b/app/components/base/features/new-feature-panel/speech-to-text.tsx
new file mode 100644
index 0000000..7905f8a
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/speech-to-text.tsx
@@ -0,0 +1,56 @@
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { Microphone01 } from '@/app/components/base/icons/src/vender/features'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import { FeatureEnum } from '@/app/components/base/features/types'
+
+type Props = {
+ disabled: boolean
+ onChange?: OnFeaturesChange
+}
+
+const SpeechToText = ({
+ disabled,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ const features = useFeatures(s => s.features)
+ const featuresStore = useFeaturesStore()
+
+ const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft[type] = {
+ ...draft[type],
+ enabled,
+ }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ }, [featuresStore, onChange])
+
+ return (
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs'>
+ <Microphone01 className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={t('appDebug.feature.speechToText.title')}
+ value={!!features.speech2text?.enabled}
+ description={t('appDebug.feature.speechToText.description')!}
+ onChange={state => handleChange(FeatureEnum.speech2text, state)}
+ disabled={disabled}
+ />
+ )
+}
+
+export default SpeechToText
diff --git a/app/components/base/features/new-feature-panel/text-to-speech/index.tsx b/app/components/base/features/new-feature-panel/text-to-speech/index.tsx
new file mode 100644
index 0000000..39f77f6
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/text-to-speech/index.tsx
@@ -0,0 +1,102 @@
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import produce from 'immer'
+import { RiEqualizer2Line } from '@remixicon/react'
+import { TextToAudio } from '@/app/components/base/icons/src/vender/features'
+import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
+import Button from '@/app/components/base/button'
+import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import { FeatureEnum } from '@/app/components/base/features/types'
+import { languages } from '@/i18n/language'
+import { TtsAutoPlay } from '@/types/app'
+
+type Props = {
+ disabled: boolean
+ onChange?: OnFeaturesChange
+}
+
+const TextToSpeech = ({
+ disabled,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ const textToSpeech = useFeatures(s => s.features.text2speech) // .language .voice .autoPlay
+ const languageInfo = languages.find(i => i.value === textToSpeech?.language)
+ const [modalOpen, setModalOpen] = useState(false)
+ const [isHovering, setIsHovering] = useState(false)
+ const features = useFeatures(s => s.features)
+ const featuresStore = useFeaturesStore()
+
+ const handleChange = useCallback((type: FeatureEnum, enabled: boolean) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft[type] = {
+ ...draft[type],
+ enabled,
+ }
+ })
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ }, [featuresStore, onChange])
+
+ return (
+ <FeatureCard
+ icon={
+ <div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs'>
+ <TextToAudio className='h-4 w-4 text-text-primary-on-surface' />
+ </div>
+ }
+ title={t('appDebug.feature.textToSpeech.title')}
+ value={!!features.text2speech?.enabled}
+ onChange={state => handleChange(FeatureEnum.text2speech, state)}
+ onMouseEnter={() => setIsHovering(true)}
+ onMouseLeave={() => setIsHovering(false)}
+ disabled={disabled}
+ >
+ <>
+ {!features.text2speech?.enabled && (
+ <div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.textToSpeech.description')}</div>
+ )}
+ {!!features.text2speech?.enabled && (
+ <>
+ {!isHovering && !modalOpen && (
+ <div className='flex items-center gap-4 pt-0.5'>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.voice.voiceSettings.language')}</div>
+ <div className='system-xs-regular text-text-secondary'>{languageInfo?.name || '-'}</div>
+ </div>
+ <div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.voice.voiceSettings.voice')}</div>
+ <div className='system-xs-regular text-text-secondary'>{features.text2speech?.voice || t('appDebug.voice.defaultDisplay')}</div>
+ </div>
+ <div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
+ <div className=''>
+ <div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.voice.voiceSettings.autoPlay')}</div>
+ <div className='system-xs-regular text-text-secondary'>{features.text2speech?.autoPlay === TtsAutoPlay.enabled ? t('appDebug.voice.voiceSettings.autoPlayEnabled') : t('appDebug.voice.voiceSettings.autoPlayDisabled')}</div>
+ </div>
+ </div>
+ )}
+ {(isHovering || modalOpen) && (
+ <VoiceSettings open={modalOpen && !disabled} onOpen={setModalOpen} onChange={onChange}>
+ <Button className='w-full' disabled={disabled}>
+ <RiEqualizer2Line className='mr-1 h-4 w-4' />
+ {t('appDebug.voice.voiceSettings.title')}
+ </Button>
+ </VoiceSettings>
+ )}
+ </>
+ )}
+ </>
+ </FeatureCard>
+ )
+}
+
+export default TextToSpeech
diff --git a/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx b/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx
new file mode 100644
index 0000000..57659d6
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx
@@ -0,0 +1,240 @@
+'use client'
+import useSWR from 'swr'
+import produce from 'immer'
+import React, { Fragment } from 'react'
+import { usePathname } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import { Listbox, ListboxButton, ListboxOption, ListboxOptions, Transition } from '@headlessui/react'
+import { CheckIcon, ChevronDownIcon } from '@heroicons/react/20/solid'
+import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
+import type { Item } from '@/app/components/base/select'
+import { fetchAppVoices } from '@/service/apps'
+import Tooltip from '@/app/components/base/tooltip'
+import Switch from '@/app/components/base/switch'
+import AudioBtn from '@/app/components/base/audio-btn'
+import { languages } from '@/i18n/language'
+import { TtsAutoPlay } from '@/types/app'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+import classNames from '@/utils/classnames'
+
+type VoiceParamConfigProps = {
+ onClose: () => void
+ onChange?: OnFeaturesChange
+}
+const VoiceParamConfig = ({
+ onClose,
+ onChange,
+}: VoiceParamConfigProps) => {
+ const { t } = useTranslation()
+ const pathname = usePathname()
+ const matched = pathname.match(/\/app\/([^/]+)/)
+ const appId = (matched?.length && matched[1]) ? matched[1] : ''
+ const text2speech = useFeatures(state => state.features.text2speech)
+ const featuresStore = useFeaturesStore()
+
+ let languageItem = languages.find(item => item.value === text2speech?.language)
+ if (languages && !languageItem)
+ languageItem = languages[0]
+ const localLanguagePlaceholder = languageItem?.name || t('common.placeholder.select')
+
+ const language = languageItem?.value
+ const voiceItems = useSWR({ appId, language }, fetchAppVoices).data
+ let voiceItem = voiceItems?.find(item => item.value === text2speech?.voice)
+ if (voiceItems && !voiceItem)
+ voiceItem = voiceItems[0]
+ const localVoicePlaceholder = voiceItem?.name || t('common.placeholder.select')
+
+ const handleChange = (value: Record<string, string>) => {
+ const {
+ features,
+ setFeatures,
+ } = featuresStore!.getState()
+
+ const newFeatures = produce(features, (draft) => {
+ draft.text2speech = {
+ ...draft.text2speech,
+ ...value,
+ }
+ })
+
+ setFeatures(newFeatures)
+ if (onChange)
+ onChange()
+ }
+
+ return (
+ <>
+ <div className='mb-4 flex items-center justify-between'>
+ <div className='system-xl-semibold text-text-primary'>{t('appDebug.voice.voiceSettings.title')}</div>
+ <div className='cursor-pointer p-1' onClick={onClose}><RiCloseLine className='h-4 w-4 text-text-tertiary' /></div>
+ </div>
+ <div className='mb-3'>
+ <div className='system-sm-semibold mb-1 flex items-center py-1 text-text-secondary'>
+ {t('appDebug.voice.voiceSettings.language')}
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]'>
+ {t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
+ <div key={item}>{item}
+ </div>
+ ))}
+ </div>
+ }
+ />
+ </div>
+ <Listbox
+ value={languageItem}
+ onChange={(value: Item) => {
+ handleChange({
+ language: String(value.value),
+ })
+ }}
+ >
+ <div className='relative h-8'>
+ <ListboxButton
+ className={'h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6'}>
+ <span className={classNames('block truncate text-left text-text-secondary', !languageItem?.name && 'text-text-tertiary')}>
+ {languageItem?.name ? t(`common.voice.language.${languageItem?.value.replace('-', '')}`) : localLanguagePlaceholder}
+ </span>
+ <span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
+ <ChevronDownIcon
+ className="h-4 w-4 text-text-tertiary"
+ aria-hidden="true"
+ />
+ </span>
+ </ListboxButton>
+ <Transition
+ as={Fragment}
+ leave="transition ease-in duration-100"
+ leaveFrom="opacity-100"
+ leaveTo="opacity-0"
+ >
+
+ <ListboxOptions
+ className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm">
+ {languages.map((item: Item) => (
+ <ListboxOption
+ key={item.value}
+ className={
+ 'relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active'
+ }
+ value={item}
+ disabled={false}
+ >
+ {({ /* active, */ selected }) => (
+ <>
+ <span
+ className={classNames('block', selected && 'font-normal')}>{t(`common.voice.language.${(item.value).toString().replace('-', '')}`)}</span>
+ {(selected || item.value === text2speech?.language) && (
+ <span
+ className={classNames(
+ 'absolute inset-y-0 right-0 flex items-center pr-4 text-text-secondary',
+ )}
+ >
+ <CheckIcon className="h-4 w-4" aria-hidden="true" />
+ </span>
+ )}
+ </>
+ )}
+ </ListboxOption>
+ ))}
+ </ListboxOptions>
+ </Transition>
+ </div>
+ </Listbox>
+ </div>
+ <div className='mb-3'>
+ <div className='system-sm-semibold mb-1 py-1 text-text-secondary'>
+ {t('appDebug.voice.voiceSettings.voice')}
+ </div>
+ <div className='flex items-center gap-1'>
+ <Listbox
+ value={voiceItem ?? {}}
+ disabled={!languageItem}
+ onChange={(value: Item) => {
+ handleChange({
+ voice: String(value.value),
+ })
+ }}
+ >
+ <div className={'relative h-8 grow'}>
+ <ListboxButton
+ className={'h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6'}>
+ <span
+ className={classNames('block truncate text-left text-text-secondary', !voiceItem?.name && 'text-text-tertiary')}>{voiceItem?.name ?? localVoicePlaceholder}</span>
+ <span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
+ <ChevronDownIcon
+ className="h-4 w-4 text-text-tertiary"
+ aria-hidden="true"
+ />
+ </span>
+ </ListboxButton>
+ <Transition
+ as={Fragment}
+ leave="transition ease-in duration-100"
+ leaveFrom="opacity-100"
+ leaveTo="opacity-0"
+ >
+
+ <ListboxOptions
+ className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm">
+ {voiceItems?.map((item: Item) => (
+ <ListboxOption
+ key={item.value}
+ className={
+ 'relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active'
+ }
+ value={item}
+ disabled={false}
+ >
+ {({ /* active, */ selected }) => (
+ <>
+ <span className={classNames('block', selected && 'font-normal')}>{item.name}</span>
+ {(selected || item.value === text2speech?.voice) && (
+ <span
+ className={classNames(
+ 'absolute inset-y-0 right-0 flex items-center pr-4 text-text-secondary',
+ )}
+ >
+ <CheckIcon className="h-4 w-4" aria-hidden="true" />
+ </span>
+ )}
+ </>
+ )}
+ </ListboxOption>
+ ))}
+ </ListboxOptions>
+ </Transition>
+ </div>
+ </Listbox>
+ {languageItem?.example && (
+ <div className='h-8 shrink-0 rounded-lg bg-components-button-tertiary-bg p-1'>
+ <AudioBtn
+ value={languageItem?.example}
+ isAudition
+ voice={text2speech?.voice}
+ noCache
+ />
+ </div>
+ )}
+ </div>
+ </div>
+ <div>
+ <div className='system-sm-semibold mb-1 py-1 text-text-secondary'>
+ {t('appDebug.voice.voiceSettings.autoPlay')}
+ </div>
+ <Switch className='shrink-0'
+ defaultValue={text2speech?.autoPlay === TtsAutoPlay.enabled}
+ onChange={(value: boolean) => {
+ handleChange({
+ autoPlay: value ? TtsAutoPlay.enabled : TtsAutoPlay.disabled,
+ })
+ }}
+ />
+ </div>
+ </>
+ )
+}
+
+export default React.memo(VoiceParamConfig)
diff --git a/app/components/base/features/new-feature-panel/text-to-speech/voice-settings.tsx b/app/components/base/features/new-feature-panel/text-to-speech/voice-settings.tsx
new file mode 100644
index 0000000..3c77897
--- /dev/null
+++ b/app/components/base/features/new-feature-panel/text-to-speech/voice-settings.tsx
@@ -0,0 +1,47 @@
+'use client'
+import { memo } from 'react'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import ParamConfigContent from '@/app/components/base/features/new-feature-panel/text-to-speech/param-config-content'
+import type { OnFeaturesChange } from '@/app/components/base/features/types'
+
+type VoiceSettingsProps = {
+ open: boolean
+ onOpen: (state: any) => void
+ onChange?: OnFeaturesChange
+ disabled?: boolean
+ children?: React.ReactNode
+ placementLeft?: boolean
+}
+const VoiceSettings = ({
+ open,
+ onOpen,
+ onChange,
+ disabled,
+ children,
+ placementLeft = true,
+}: VoiceSettingsProps) => {
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={onOpen}
+ placement={placementLeft ? 'left' : 'top'}
+ offset={{
+ mainAxis: placementLeft ? 32 : 4,
+ }}
+ >
+ <PortalToFollowElemTrigger className='flex' onClick={() => !disabled && onOpen((open: boolean) => !open)}>
+ {children}
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 50 }}>
+ <div className='w-[360px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl'>
+ <ParamConfigContent onClose={() => onOpen(false)} onChange={onChange} />
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default memo(VoiceSettings)
diff --git a/app/components/base/features/store.ts b/app/components/base/features/store.ts
new file mode 100644
index 0000000..2b8c3f7
--- /dev/null
+++ b/app/components/base/features/store.ts
@@ -0,0 +1,66 @@
+import { createStore } from 'zustand'
+import type { Features } from './types'
+import { Resolution, TransferMethod } from '@/types/app'
+
+export type FeaturesModal = {
+ showFeaturesModal: boolean
+ setShowFeaturesModal: (showFeaturesModal: boolean) => void
+}
+
+export type FeaturesState = {
+ features: Features
+}
+
+export type FeaturesAction = {
+ setFeatures: (features: Features) => void
+}
+
+export type FeatureStoreState = FeaturesState & FeaturesAction & FeaturesModal
+
+export type FeaturesStore = ReturnType<typeof createFeaturesStore>
+
+export const createFeaturesStore = (initProps?: Partial<FeaturesState>) => {
+ const DEFAULT_PROPS: FeaturesState = {
+ features: {
+ moreLikeThis: {
+ enabled: false,
+ },
+ opening: {
+ enabled: false,
+ },
+ suggested: {
+ enabled: false,
+ },
+ text2speech: {
+ enabled: false,
+ },
+ speech2text: {
+ enabled: false,
+ },
+ citation: {
+ enabled: false,
+ },
+ moderation: {
+ enabled: false,
+ },
+ file: {
+ image: {
+ enabled: false,
+ detail: Resolution.high,
+ number_limits: 3,
+ transfer_methods: [TransferMethod.local_file, TransferMethod.remote_url],
+ },
+ },
+ annotationReply: {
+ enabled: false,
+ },
+ },
+ }
+ return createStore<FeatureStoreState>()(set => ({
+ ...DEFAULT_PROPS,
+ ...initProps,
+ setFeatures: features => set(() => ({ features })),
+ showFeaturesModal: false,
+ setShowFeaturesModal: showFeaturesModal => set(() => ({ showFeaturesModal })),
+ }))
+}
diff --git a/app/components/base/features/types.ts b/app/components/base/features/types.ts
new file mode 100644
index 0000000..83f8763
--- /dev/null
+++ b/app/components/base/features/types.ts
@@ -0,0 +1,79 @@
+import type { Resolution, TransferMethod, TtsAutoPlay } from '@/types/app'
+import type { FileUploadConfigResponse } from '@/models/common'
+
+export type EnabledOrDisabled = {
+ enabled?: boolean
+}
+
+export type MoreLikeThis = EnabledOrDisabled
+
+export type OpeningStatement = EnabledOrDisabled & {
+ opening_statement?: string
+ suggested_questions?: string[]
+}
+
+export type SuggestedQuestionsAfterAnswer = EnabledOrDisabled
+
+export type TextToSpeech = EnabledOrDisabled & {
+ language?: string
+ voice?: string
+ autoPlay?: TtsAutoPlay
+}
+
+export type SpeechToText = EnabledOrDisabled
+
+export type RetrieverResource = EnabledOrDisabled
+
+export type SensitiveWordAvoidance = EnabledOrDisabled & {
+ type?: string
+ config?: any
+}
+
+export type FileUpload = {
+ image?: EnabledOrDisabled & {
+ detail?: Resolution
+ number_limits?: number
+ transfer_methods?: TransferMethod[]
+ }
+ allowed_file_types?: string[]
+ allowed_file_extensions?: string[]
+ allowed_file_upload_methods?: TransferMethod[]
+ number_limits?: number
+ fileUploadConfig?: FileUploadConfigResponse
+} & EnabledOrDisabled
+
+export type AnnotationReplyConfig = {
+ enabled: boolean
+ id?: string
+ score_threshold?: number
+ embedding_model?: {
+ embedding_provider_name: string
+ embedding_model_name: string
+ }
+}
+
+export enum FeatureEnum {
+ moreLikeThis = 'moreLikeThis',
+ opening = 'opening',
+ suggested = 'suggested',
+ text2speech = 'text2speech',
+ speech2text = 'speech2text',
+ citation = 'citation',
+ moderation = 'moderation',
+ file = 'file',
+ annotationReply = 'annotationReply',
+}
+
+export type Features = {
+ [FeatureEnum.moreLikeThis]?: MoreLikeThis
+ [FeatureEnum.opening]?: OpeningStatement
+ [FeatureEnum.suggested]?: SuggestedQuestionsAfterAnswer
+ [FeatureEnum.text2speech]?: TextToSpeech
+ [FeatureEnum.speech2text]?: SpeechToText
+ [FeatureEnum.citation]?: RetrieverResource
+ [FeatureEnum.moderation]?: SensitiveWordAvoidance
+ [FeatureEnum.file]?: FileUpload
+ [FeatureEnum.annotationReply]?: AnnotationReplyConfig
+}
+
+export type OnFeaturesChange = (features?: Features) => void
diff --git a/app/components/base/file-icon/index.tsx b/app/components/base/file-icon/index.tsx
new file mode 100644
index 0000000..6b217b1
--- /dev/null
+++ b/app/components/base/file-icon/index.tsx
@@ -0,0 +1,55 @@
+import type { FC } from 'react'
+import {
+ Csv,
+ Doc,
+ Docx,
+ Html,
+ Json,
+ Md,
+ Pdf,
+ Txt,
+ Unknown,
+ Xlsx,
+} from '@/app/components/base/icons/src/public/files'
+import { Notion } from '@/app/components/base/icons/src/public/common'
+
+type FileIconProps = {
+ type: string
+ className?: string
+}
+
+const FileIcon: FC<FileIconProps> = ({
+ type,
+ className,
+}) => {
+ switch (type) {
+ case 'csv':
+ return <Csv className={className} />
+ case 'doc':
+ return <Doc className={className} />
+ case 'docx':
+ return <Docx className={className} />
+ case 'htm':
+ case 'html':
+ return <Html className={className} />
+ case 'json':
+ return <Json className={className} />
+ case 'md':
+ case 'markdown':
+ case 'mdx':
+ return <Md className={className} />
+ case 'pdf':
+ return <Pdf className={className} />
+ case 'txt':
+ return <Txt className={className} />
+ case 'xls':
+ case 'xlsx':
+ return <Xlsx className={className} />
+ case 'notion':
+ return <Notion className={className} />
+ default:
+ return <Unknown className={className} />
+ }
+}
+
+export default FileIcon
diff --git a/app/components/base/file-uploader/audio-preview.tsx b/app/components/base/file-uploader/audio-preview.tsx
new file mode 100644
index 0000000..22d244a
--- /dev/null
+++ b/app/components/base/file-uploader/audio-preview.tsx
@@ -0,0 +1,46 @@
+import type { FC } from 'react'
+import { createPortal } from 'react-dom'
+import { RiCloseLine } from '@remixicon/react'
+import React from 'react'
+
+import { useHotkeys } from 'react-hotkeys-hook'
+
+type AudioPreviewProps = {
+ url: string
+ title: string
+ onCancel: () => void
+}
+const AudioPreview: FC<AudioPreviewProps> = ({
+ url,
+ title,
+ onCancel,
+}) => {
+ useHotkeys('esc', onCancel)
+
+ return createPortal(
+ <div
+ className='fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 p-8'
+ onClick={e => e.stopPropagation()}
+ tabIndex={-1}
+ >
+ <div>
+ <audio controls title={title} autoPlay={false} preload="metadata">
+ <source
+ type="audio/mpeg"
+ src={url}
+ className='max-h-full max-w-full'
+ />
+ </audio>
+ </div>
+ <div
+ className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/[0.08] backdrop-blur-[2px]'
+ onClick={onCancel}
+ >
+ <RiCloseLine className='h-4 w-4 text-gray-500'/>
+ </div>
+ </div>,
+ document.body,
+ )
+}
+
+export default AudioPreview
diff --git a/app/components/base/file-uploader/constants.ts b/app/components/base/file-uploader/constants.ts
new file mode 100644
index 0000000..a749d73
--- /dev/null
+++ b/app/components/base/file-uploader/constants.ts
@@ -0,0 +1,8 @@
+// fallback for file size limit of dify_config
+export const IMG_SIZE_LIMIT = 10 * 1024 * 1024
+export const FILE_SIZE_LIMIT = 15 * 1024 * 1024
+export const AUDIO_SIZE_LIMIT = 50 * 1024 * 1024
+export const VIDEO_SIZE_LIMIT = 100 * 1024 * 1024
+export const MAX_FILE_UPLOAD_LIMIT = 10
+
+export const FILE_URL_REGEX = /^(https?|ftp):\/\//
diff --git a/app/components/base/file-uploader/dynamic-pdf-preview.tsx b/app/components/base/file-uploader/dynamic-pdf-preview.tsx
new file mode 100644
index 0000000..116db89
--- /dev/null
+++ b/app/components/base/file-uploader/dynamic-pdf-preview.tsx
@@ -0,0 +1,17 @@
+'use client'
+
+import dynamic from 'next/dynamic'
+
+type DynamicPdfPreviewProps = {
+ url: string
+ onCancel: () => void
+}
+const DynamicPdfPreview = dynamic<DynamicPdfPreviewProps>(
+ (() => {
+ if (typeof window !== 'undefined')
+ return import('./pdf-preview')
+ }) as any,
+ { ssr: false }, // This will prevent the module from being loaded on the server-side
+)
+
+export default DynamicPdfPreview
diff --git a/app/components/base/file-uploader/file-from-link-or-local/index.tsx b/app/components/base/file-uploader/file-from-link-or-local/index.tsx
new file mode 100644
index 0000000..4f11923
--- /dev/null
+++ b/app/components/base/file-uploader/file-from-link-or-local/index.tsx
@@ -0,0 +1,129 @@
+import {
+ memo,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiUploadCloud2Line } from '@remixicon/react'
+import FileInput from '../file-input'
+import { useFile } from '../hooks'
+import { useStore } from '../store'
+import { FILE_URL_REGEX } from '../constants'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import Button from '@/app/components/base/button'
+import type { FileUpload } from '@/app/components/base/features/types'
+import cn from '@/utils/classnames'
+
+type FileFromLinkOrLocalProps = {
+ showFromLink?: boolean
+ showFromLocal?: boolean
+ trigger: (open: boolean) => React.ReactNode
+ fileConfig: FileUpload
+}
+const FileFromLinkOrLocal = ({
+ showFromLink = true,
+ showFromLocal = true,
+ trigger,
+ fileConfig,
+}: FileFromLinkOrLocalProps) => {
+ const { t } = useTranslation()
+ const files = useStore(s => s.files)
+ const [open, setOpen] = useState(false)
+ const [url, setUrl] = useState('')
+ const [showError, setShowError] = useState(false)
+ const { handleLoadFileFromLink } = useFile(fileConfig)
+ const disabled = !!fileConfig.number_limits && files.length >= fileConfig.number_limits
+
+ const handleSaveUrl = () => {
+ if (!url)
+ return
+
+ if (!FILE_URL_REGEX.test(url)) {
+ setShowError(true)
+ return
+ }
+ handleLoadFileFromLink(url)
+ setUrl('')
+ }
+
+ return (
+ <PortalToFollowElem
+ placement='top'
+ offset={4}
+ open={open}
+ onOpenChange={setOpen}
+ >
+ <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)} asChild>
+ {trigger(open)}
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1001]'>
+ <div className='w-[280px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-3 shadow-lg'>
+ {
+ showFromLink && (
+ <>
+ <div className={cn(
+ 'flex h-8 items-center rounded-lg border border-components-input-border-active bg-components-input-bg-active p-1 shadow-xs',
+ showError && 'border-components-input-border-destructive',
+ )}>
+ <input
+ className='system-sm-regular mr-0.5 block grow appearance-none bg-transparent px-1 outline-none'
+ placeholder={t('common.fileUploader.pasteFileLinkInputPlaceholder') || ''}
+ value={url}
+ onChange={(e) => {
+ setShowError(false)
+ setUrl(e.target.value.trim())
+ }}
+ disabled={disabled}
+ />
+ <Button
+ className='shrink-0'
+ size='small'
+ variant='primary'
+ disabled={!url || disabled}
+ onClick={handleSaveUrl}
+ >
+ {t('common.operation.ok')}
+ </Button>
+ </div>
+ {
+ showError && (
+ <div className='body-xs-regular mt-0.5 text-text-destructive'>
+ {t('common.fileUploader.pasteFileLinkInvalid')}
+ </div>
+ )
+ }
+ </>
+ )
+ }
+ {
+ showFromLink && showFromLocal && (
+ <div className='system-2xs-medium-uppercase flex h-7 items-center p-2 text-text-quaternary'>
+ <div className='mr-2 h-[1px] w-[93px] bg-gradient-to-l from-[rgba(16,24,40,0.08)]' />
+ OR
+ <div className='ml-2 h-[1px] w-[93px] bg-gradient-to-r from-[rgba(16,24,40,0.08)]' />
+ </div>
+ )
+ }
+ {
+ showFromLocal && (
+ <Button
+ className='relative w-full'
+ variant='secondary-accent'
+ disabled={disabled}
+ >
+ <RiUploadCloud2Line className='mr-1 h-4 w-4' />
+ {t('common.fileUploader.uploadFromComputer')}
+ <FileInput fileConfig={fileConfig} />
+ </Button>
+ )
+ }
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default memo(FileFromLinkOrLocal)
diff --git a/app/components/base/file-uploader/file-image-render.tsx b/app/components/base/file-uploader/file-image-render.tsx
new file mode 100644
index 0000000..d613505
--- /dev/null
+++ b/app/components/base/file-uploader/file-image-render.tsx
@@ -0,0 +1,32 @@
+import cn from '@/utils/classnames'
+
+type FileImageRenderProps = {
+ imageUrl: string
+ className?: string
+ alt?: string
+ onLoad?: () => void
+ onError?: () => void
+ showDownloadAction?: boolean
+}
+const FileImageRender = ({
+ imageUrl,
+ className,
+ alt,
+ onLoad,
+ onError,
+ showDownloadAction,
+}: FileImageRenderProps) => {
+ return (
+ <div className={cn('border-[2px] border-effects-image-frame shadow-xs', className)}>
+ <img
+ className={cn('h-full w-full object-cover', showDownloadAction && 'cursor-pointer')}
+ alt={alt || 'Preview'}
+ onLoad={onLoad}
+ onError={onError}
+ src={imageUrl}
+ />
+ </div>
+ )
+}
+
+export default FileImageRender
diff --git a/app/components/base/file-uploader/file-input.tsx b/app/components/base/file-uploader/file-input.tsx
new file mode 100644
index 0000000..ba3bade
--- /dev/null
+++ b/app/components/base/file-uploader/file-input.tsx
@@ -0,0 +1,49 @@
+import { useFile } from './hooks'
+import { useStore } from './store'
+import type { FileUpload } from '@/app/components/base/features/types'
+import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+
+type FileInputProps = {
+ fileConfig: FileUpload
+}
+const FileInput = ({
+ fileConfig,
+}: FileInputProps) => {
+ const files = useStore(s => s.files)
+ const { handleLocalFileUpload } = useFile(fileConfig)
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ const targetFiles = e.target.files
+
+ if (targetFiles) {
+ if (fileConfig.number_limits) {
+ for (let i = 0; i < targetFiles.length; i++) {
+ if (i + 1 + files.length <= fileConfig.number_limits)
+ handleLocalFileUpload(targetFiles[i])
+ }
+ }
+ else {
+ handleLocalFileUpload(targetFiles[0])
+ }
+ }
+ }
+
+ const allowedFileTypes = fileConfig.allowed_file_types
+ const isCustom = allowedFileTypes?.includes(SupportUploadFileTypes.custom)
+ const exts = isCustom ? (fileConfig.allowed_file_extensions || []) : (allowedFileTypes?.map(type => FILE_EXTS[type]) || []).flat().map(item => `.${item}`)
+ const accept = exts.join(',')
+
+ return (
+ <input
+ className='absolute inset-0 block w-full cursor-pointer text-[0] opacity-0 disabled:cursor-not-allowed'
+ onClick={e => ((e.target as HTMLInputElement).value = '')}
+ type='file'
+ onChange={handleChange}
+ accept={accept}
+ disabled={!!(fileConfig.number_limits && files.length >= fileConfig?.number_limits)}
+ multiple={!!fileConfig.number_limits && fileConfig.number_limits > 1}
+ />
+ )
+}
+
+export default FileInput
diff --git a/app/components/base/file-uploader/file-list-in-log.tsx b/app/components/base/file-uploader/file-list-in-log.tsx
new file mode 100644
index 0000000..c28b41e
--- /dev/null
+++ b/app/components/base/file-uploader/file-list-in-log.tsx
@@ -0,0 +1,106 @@
+import React, { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowRightSLine } from '@remixicon/react'
+import FileImageRender from './file-image-render'
+import FileTypeIcon from './file-type-icon'
+import FileItem from './file-uploader-in-attachment/file-item'
+import type { FileEntity } from './types'
+import {
+ getFileAppearanceType,
+} from './utils'
+import Tooltip from '@/app/components/base/tooltip'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+import cn from '@/utils/classnames'
+
+type Props = {
+ fileList: {
+ varName: string
+ list: FileEntity[]
+ }[]
+ isExpanded?: boolean
+ noBorder?: boolean
+ noPadding?: boolean
+}
+
+const FileListInLog = ({ fileList, isExpanded = false, noBorder = false, noPadding = false }: Props) => {
+ const { t } = useTranslation()
+ const [expanded, setExpanded] = useState(isExpanded)
+ const fullList = useMemo(() => {
+ return fileList.reduce((acc: FileEntity[], { list }) => {
+ return [...acc, ...list]
+ }, [])
+ }, [fileList])
+
+ if (!fileList.length)
+ return null
+
+ return (
+ <div className={cn('px-3 py-2', expanded && 'py-3', !noBorder && 'border-t border-divider-subtle', noPadding && '!p-0')}>
+ <div className='flex justify-between gap-1'>
+ {expanded && (
+ <div className='system-xs-semibold-uppercase grow cursor-pointer py-1 text-text-secondary' onClick={() => setExpanded(!expanded)}>{t('appLog.runDetail.fileListLabel')}</div>
+ )}
+ {!expanded && (
+ <div className='flex gap-1'>
+ {fullList.map((file) => {
+ const { id, name, type, supportFileType, base64Url, url } = file
+ const isImageFile = supportFileType === SupportUploadFileTypes.image
+ return (
+ <>
+ {isImageFile && (
+ <Tooltip
+ popupContent={name}
+ >
+ <div key={id}>
+ <FileImageRender
+ className='h-8 w-8'
+ imageUrl={base64Url || url || ''}
+ />
+ </div>
+ </Tooltip>
+ )}
+ {!isImageFile && (
+ <Tooltip
+ popupContent={name}
+ >
+ <div key={id} className='rounded-md border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg p-1.5 shadow-xs'>
+ <FileTypeIcon
+ type={getFileAppearanceType(name, type)}
+ size='md'
+ />
+ </div>
+ </Tooltip>
+ )}
+ </>
+ )
+ })}
+ </div>
+ )}
+ <div className='flex cursor-pointer items-center gap-1' onClick={() => setExpanded(!expanded)}>
+ {!expanded && <div className='system-xs-medium-uppercase text-text-tertiary'>{t('appLog.runDetail.fileListDetail')}</div>}
+ <RiArrowRightSLine className={cn('h-4 w-4 text-text-tertiary', expanded && 'rotate-90')} />
+ </div>
+ </div>
+ {expanded && (
+ <div className='flex flex-col gap-3'>
+ {fileList.map(item => (
+ <div key={item.varName} className='system-xs-regular flex flex-col gap-1'>
+ <div className='py-1 text-text-tertiary '>{item.varName}</div>
+ {item.list.map(file => (
+ <FileItem
+ key={file.id}
+ file={file}
+ showDeleteAction={false}
+ showDownloadAction
+ canPreview
+ />
+ ))}
+ </div>
+ ))}
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default FileListInLog
diff --git a/app/components/base/file-uploader/file-type-icon.tsx b/app/components/base/file-uploader/file-type-icon.tsx
new file mode 100644
index 0000000..08d0131
--- /dev/null
+++ b/app/components/base/file-uploader/file-type-icon.tsx
@@ -0,0 +1,91 @@
+import { memo } from 'react'
+import {
+ RiFile3Fill,
+ RiFileCodeFill,
+ RiFileExcelFill,
+ RiFileGifFill,
+ RiFileImageFill,
+ RiFileMusicFill,
+ RiFilePdf2Fill,
+ RiFilePpt2Fill,
+ RiFileTextFill,
+ RiFileVideoFill,
+ RiFileWordFill,
+ RiMarkdownFill,
+} from '@remixicon/react'
+import { FileAppearanceTypeEnum } from './types'
+import type { FileAppearanceType } from './types'
+import cn from '@/utils/classnames'
+
+const FILE_TYPE_ICON_MAP = {
+ [FileAppearanceTypeEnum.pdf]: {
+ component: RiFilePdf2Fill,
+ color: 'text-[#EA3434]',
+ },
+ [FileAppearanceTypeEnum.image]: {
+ component: RiFileImageFill,
+ color: 'text-[#00B2EA]',
+ },
+ [FileAppearanceTypeEnum.video]: {
+ component: RiFileVideoFill,
+ color: 'text-[#844FDA]',
+ },
+ [FileAppearanceTypeEnum.audio]: {
+ component: RiFileMusicFill,
+ color: 'text-[#FF3093]',
+ },
+ [FileAppearanceTypeEnum.document]: {
+ component: RiFileTextFill,
+ color: 'text-[#6F8BB5]',
+ },
+ [FileAppearanceTypeEnum.code]: {
+ component: RiFileCodeFill,
+ color: 'text-[#BCC0D1]',
+ },
+ [FileAppearanceTypeEnum.markdown]: {
+ component: RiMarkdownFill,
+ color: 'text-[#309BEC]',
+ },
+ [FileAppearanceTypeEnum.custom]: {
+ component: RiFile3Fill,
+ color: 'text-[#BCC0D1]',
+ },
+ [FileAppearanceTypeEnum.excel]: {
+ component: RiFileExcelFill,
+ color: 'text-[#01AC49]',
+ },
+ [FileAppearanceTypeEnum.word]: {
+ component: RiFileWordFill,
+ color: 'text-[#2684FF]',
+ },
+ [FileAppearanceTypeEnum.ppt]: {
+ component: RiFilePpt2Fill,
+ color: 'text-[#FF650F]',
+ },
+ [FileAppearanceTypeEnum.gif]: {
+ component: RiFileGifFill,
+ color: 'text-[#00B2EA]',
+ },
+}
+type FileTypeIconProps = {
+ type: FileAppearanceType
+ size?: 'sm' | 'lg' | 'md'
+ className?: string
+}
+const SizeMap = {
+ sm: 'w-4 h-4',
+ md: 'w-5 h-5',
+ lg: 'w-6 h-6',
+}
+const FileTypeIcon = ({
+ type,
+ size = 'sm',
+ className,
+}: FileTypeIconProps) => {
+ const Icon = FILE_TYPE_ICON_MAP[type]?.component || FILE_TYPE_ICON_MAP[FileAppearanceTypeEnum.document].component
+ const color = FILE_TYPE_ICON_MAP[type]?.color || FILE_TYPE_ICON_MAP[FileAppearanceTypeEnum.document].color
+
+ return <Icon className={cn('shrink-0', SizeMap[size], color, className)} />
+}
+
+export default memo(FileTypeIcon)
diff --git a/app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx b/app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx
new file mode 100644
index 0000000..fab1c36
--- /dev/null
+++ b/app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx
@@ -0,0 +1,154 @@
+import {
+ memo,
+ useState,
+} from 'react'
+import {
+ RiDeleteBinLine,
+ RiDownloadLine,
+ RiEyeLine,
+} from '@remixicon/react'
+import FileTypeIcon from '../file-type-icon'
+import {
+ downloadFile,
+ fileIsUploaded,
+ getFileAppearanceType,
+ getFileExtension,
+} from '../utils'
+import FileImageRender from '../file-image-render'
+import type { FileEntity } from '../types'
+import ActionButton from '@/app/components/base/action-button'
+import ProgressCircle from '@/app/components/base/progress-bar/progress-circle'
+import { formatFileSize } from '@/utils/format'
+import cn from '@/utils/classnames'
+import { ReplayLine } from '@/app/components/base/icons/src/vender/other'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+import ImagePreview from '@/app/components/base/image-uploader/image-preview'
+
+type FileInAttachmentItemProps = {
+ file: FileEntity
+ showDeleteAction?: boolean
+ showDownloadAction?: boolean
+ onRemove?: (fileId: string) => void
+ onReUpload?: (fileId: string) => void
+ canPreview?: boolean
+}
+const FileInAttachmentItem = ({
+ file,
+ showDeleteAction,
+ showDownloadAction = true,
+ onRemove,
+ onReUpload,
+ canPreview,
+}: FileInAttachmentItemProps) => {
+ const { id, name, type, progress, supportFileType, base64Url, url, isRemote } = file
+ const ext = getFileExtension(name, type, isRemote)
+ const isImageFile = supportFileType === SupportUploadFileTypes.image
+ const [imagePreviewUrl, setImagePreviewUrl] = useState('')
+ return (
+ <>
+ <div className={cn(
+ 'flex h-12 items-center rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg pr-3 shadow-xs',
+ progress === -1 && 'border-state-destructive-border bg-state-destructive-hover',
+ )}>
+ <div className='flex h-12 w-12 items-center justify-center'>
+ {
+ isImageFile && (
+ <FileImageRender
+ className='h-8 w-8'
+ imageUrl={base64Url || url || ''}
+ />
+ )
+ }
+ {
+ !isImageFile && (
+ <FileTypeIcon
+ type={getFileAppearanceType(name, type)}
+ size='lg'
+ />
+ )
+ }
+ </div>
+ <div className='mr-1 w-0 grow'>
+ <div
+ className='system-xs-medium mb-0.5 flex items-center truncate text-text-secondary'
+ title={file.name}
+ >
+ <div className='truncate'>{name}</div>
+ </div>
+ <div className='system-2xs-medium-uppercase flex items-center text-text-tertiary'>
+ {
+ ext && (
+ <span>{ext.toLowerCase()}</span>
+ )
+ }
+ {
+ ext && (
+ <span className='system-2xs-medium mx-1'>鈥�</span>
+ )
+ }
+ {
+ !!file.size && (
+ <span>{formatFileSize(file.size)}</span>
+ )
+ }
+ </div>
+ </div>
+ <div className='flex shrink-0 items-center'>
+ {
+ progress >= 0 && !fileIsUploaded(file) && (
+ <ProgressCircle
+ className='mr-2.5'
+ percentage={progress}
+ />
+ )
+ }
+ {
+ progress === -1 && (
+ <ActionButton
+ className='mr-1'
+ onClick={() => onReUpload?.(id)}
+ >
+ <ReplayLine className='h-4 w-4 text-text-tertiary' />
+ </ActionButton>
+ )
+ }
+ {
+ showDeleteAction && (
+ <ActionButton onClick={() => onRemove?.(id)}>
+ <RiDeleteBinLine className='h-4 w-4' />
+ </ActionButton>
+ )
+ }
+ {
+ canPreview && isImageFile && (
+ <ActionButton className='mr-1' onClick={() => setImagePreviewUrl(url || '')}>
+ <RiEyeLine className='h-4 w-4' />
+ </ActionButton>
+ )
+ }
+ {
+ showDownloadAction && (
+ <ActionButton onClick={(e) => {
+ e.stopPropagation()
+ downloadFile(url || base64Url || '', name)
+ }}>
+ <RiDownloadLine className='h-4 w-4' />
+ </ActionButton>
+ )
+ }
+ </div>
+ </div>
+ {
+ imagePreviewUrl && canPreview && (
+ <ImagePreview
+ title={name}
+ url={imagePreviewUrl}
+ onCancel={() => setImagePreviewUrl('')}
+ />
+ )
+ }
+ </>
+ )
+}
+
+export default memo(FileInAttachmentItem)
diff --git a/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx b/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx
new file mode 100644
index 0000000..ab4e2aa
--- /dev/null
+++ b/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx
@@ -0,0 +1,133 @@
+import {
+ useCallback,
+} from 'react'
+import {
+ RiLink,
+ RiUploadCloud2Line,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import FileFromLinkOrLocal from '../file-from-link-or-local'
+import {
+ FileContextProvider,
+ useStore,
+} from '../store'
+import type { FileEntity } from '../types'
+import FileInput from '../file-input'
+import { useFile } from '../hooks'
+import FileItem from './file-item'
+import Button from '@/app/components/base/button'
+import cn from '@/utils/classnames'
+import type { FileUpload } from '@/app/components/base/features/types'
+import { TransferMethod } from '@/types/app'
+
+type Option = {
+ value: string
+ label: string
+ icon: React.JSX.Element
+}
+type FileUploaderInAttachmentProps = {
+ fileConfig: FileUpload
+}
+const FileUploaderInAttachment = ({
+ fileConfig,
+}: FileUploaderInAttachmentProps) => {
+ const { t } = useTranslation()
+ const files = useStore(s => s.files)
+ const {
+ handleRemoveFile,
+ handleReUploadFile,
+ } = useFile(fileConfig)
+ const options = [
+ {
+ value: TransferMethod.local_file,
+ label: t('common.fileUploader.uploadFromComputer'),
+ icon: <RiUploadCloud2Line className='h-4 w-4' />,
+ },
+ {
+ value: TransferMethod.remote_url,
+ label: t('common.fileUploader.pasteFileLink'),
+ icon: <RiLink className='h-4 w-4' />,
+ },
+ ]
+
+ const renderButton = useCallback((option: Option, open?: boolean) => {
+ return (
+ <Button
+ key={option.value}
+ variant='tertiary'
+ className={cn('relative grow', open && 'bg-components-button-tertiary-bg-hover')}
+ disabled={!!(fileConfig.number_limits && files.length >= fileConfig.number_limits)}
+ >
+ {option.icon}
+ <span className='ml-1'>{option.label}</span>
+ {
+ option.value === TransferMethod.local_file && (
+ <FileInput fileConfig={fileConfig} />
+ )
+ }
+ </Button>
+ )
+ }, [fileConfig, files.length])
+ const renderTrigger = useCallback((option: Option) => {
+ return (open: boolean) => renderButton(option, open)
+ }, [renderButton])
+ const renderOption = useCallback((option: Option) => {
+ if (option.value === TransferMethod.local_file && fileConfig?.allowed_file_upload_methods?.includes(TransferMethod.local_file))
+ return renderButton(option)
+
+ if (option.value === TransferMethod.remote_url && fileConfig?.allowed_file_upload_methods?.includes(TransferMethod.remote_url)) {
+ return (
+ <FileFromLinkOrLocal
+ key={option.value}
+ showFromLocal={false}
+ trigger={renderTrigger(option)}
+ fileConfig={fileConfig}
+ />
+ )
+ }
+ }, [renderButton, renderTrigger, fileConfig])
+
+ return (
+ <div>
+ <div className='flex items-center space-x-1'>
+ {options.map(renderOption)}
+ </div>
+ <div className='mt-1 space-y-1'>
+ {
+ files.map(file => (
+ <FileItem
+ key={file.id}
+ file={file}
+ showDeleteAction
+ showDownloadAction={false}
+ onRemove={() => handleRemoveFile(file.id)}
+ onReUpload={() => handleReUploadFile(file.id)}
+ />
+ ))
+ }
+ </div>
+ </div>
+ )
+}
+
+type FileUploaderInAttachmentWrapperProps = {
+ value?: FileEntity[]
+ onChange: (files: FileEntity[]) => void
+ fileConfig: FileUpload
+}
+const FileUploaderInAttachmentWrapper = ({
+ value,
+ onChange,
+ fileConfig,
+}: FileUploaderInAttachmentWrapperProps) => {
+ return (
+ <FileContextProvider
+ value={value}
+ onChange={onChange}
+ >
+ <FileUploaderInAttachment fileConfig={fileConfig} />
+ </FileContextProvider>
+ )
+}
+
+export default FileUploaderInAttachmentWrapper
diff --git a/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx b/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx
new file mode 100644
index 0000000..5160348
--- /dev/null
+++ b/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx
@@ -0,0 +1,110 @@
+import { useState } from 'react'
+import {
+ RiCloseLine,
+ RiDownloadLine,
+} from '@remixicon/react'
+import FileImageRender from '../file-image-render'
+import type { FileEntity } from '../types'
+import {
+ downloadFile,
+ fileIsUploaded,
+} from '../utils'
+import Button from '@/app/components/base/button'
+import ProgressCircle from '@/app/components/base/progress-bar/progress-circle'
+import { ReplayLine } from '@/app/components/base/icons/src/vender/other'
+import ImagePreview from '@/app/components/base/image-uploader/image-preview'
+
+type FileImageItemProps = {
+ file: FileEntity
+ showDeleteAction?: boolean
+ showDownloadAction?: boolean
+ canPreview?: boolean
+ onRemove?: (fileId: string) => void
+ onReUpload?: (fileId: string) => void
+}
+const FileImageItem = ({
+ file,
+ showDeleteAction,
+ showDownloadAction,
+ canPreview,
+ onRemove,
+ onReUpload,
+}: FileImageItemProps) => {
+ const { id, progress, base64Url, url, name } = file
+ const [imagePreviewUrl, setImagePreviewUrl] = useState('')
+ const download_url = url ? `${url}&as_attachment=true` : base64Url
+
+ return (
+ <>
+ <div
+ className='group/file-image relative cursor-pointer'
+ onClick={() => canPreview && setImagePreviewUrl(base64Url || url || '')}
+ >
+ {
+ showDeleteAction && (
+ <Button
+ className='absolute -right-1.5 -top-1.5 z-[11] hidden h-5 w-5 rounded-full p-0 group-hover/file-image:flex'
+ onClick={() => onRemove?.(id)}
+ >
+ <RiCloseLine className='h-4 w-4 text-components-button-secondary-text' />
+ </Button>
+ )
+ }
+ <FileImageRender
+ className='h-[68px] w-[68px] shadow-md'
+ imageUrl={base64Url || url || ''}
+ showDownloadAction={showDownloadAction}
+ />
+ {
+ progress >= 0 && !fileIsUploaded(file) && (
+ <div className='absolute inset-0 z-10 flex items-center justify-center border-[2px] border-effects-image-frame bg-background-overlay-alt'>
+ <ProgressCircle
+ percentage={progress}
+ size={12}
+ circleStrokeColor='stroke-components-progress-white-border'
+ circleFillColor='fill-transparent'
+ sectorFillColor='fill-components-progress-white-progress'
+ />
+ </div>
+ )
+ }
+ {
+ progress === -1 && (
+ <div className='absolute inset-0 z-10 flex items-center justify-center border-[2px] border-state-destructive-border bg-background-overlay-destructive'>
+ <ReplayLine
+ className='h-5 w-5'
+ onClick={() => onReUpload?.(id)}
+ />
+ </div>
+ )
+ }
+ {
+ showDownloadAction && (
+ <div className='absolute inset-0.5 z-10 hidden bg-background-overlay-alt bg-opacity-[0.3] group-hover/file-image:block'>
+ <div
+ className='absolute bottom-0.5 right-0.5 flex h-6 w-6 items-center justify-center rounded-lg bg-components-actionbar-bg shadow-md'
+ onClick={(e) => {
+ e.stopPropagation()
+ downloadFile(download_url || '', name)
+ }}
+ >
+ <RiDownloadLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ )
+ }
+ </div>
+ {
+ imagePreviewUrl && canPreview && (
+ <ImagePreview
+ title={name}
+ url={imagePreviewUrl}
+ onCancel={() => setImagePreviewUrl('')}
+ />
+ )
+ }
+ </>
+ )
+}
+
+export default FileImageItem
diff --git a/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.tsx b/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.tsx
new file mode 100644
index 0000000..667bf7c
--- /dev/null
+++ b/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.tsx
@@ -0,0 +1,156 @@
+import {
+ RiCloseLine,
+ RiDownloadLine,
+} from '@remixicon/react'
+import { useState } from 'react'
+import {
+ downloadFile,
+ fileIsUploaded,
+ getFileAppearanceType,
+ getFileExtension,
+} from '../utils'
+import FileTypeIcon from '../file-type-icon'
+import type { FileEntity } from '../types'
+import cn from '@/utils/classnames'
+import { formatFileSize } from '@/utils/format'
+import ProgressCircle from '@/app/components/base/progress-bar/progress-circle'
+import { ReplayLine } from '@/app/components/base/icons/src/vender/other'
+import ActionButton from '@/app/components/base/action-button'
+import Button from '@/app/components/base/button'
+import PdfPreview from '@/app/components/base/file-uploader/dynamic-pdf-preview'
+import AudioPreview from '@/app/components/base/file-uploader/audio-preview'
+import VideoPreview from '@/app/components/base/file-uploader/video-preview'
+
+type FileItemProps = {
+ file: FileEntity
+ showDeleteAction?: boolean
+ showDownloadAction?: boolean
+ canPreview?: boolean
+ onRemove?: (fileId: string) => void
+ onReUpload?: (fileId: string) => void
+}
+const FileItem = ({
+ file,
+ showDeleteAction,
+ showDownloadAction = true,
+ onRemove,
+ onReUpload,
+ canPreview,
+}: FileItemProps) => {
+ const { id, name, type, progress, url, base64Url, isRemote } = file
+ const [previewUrl, setPreviewUrl] = useState('')
+ const ext = getFileExtension(name, type, isRemote)
+ const uploadError = progress === -1
+
+ let tmp_preview_url = url || base64Url
+ if (!tmp_preview_url && file?.originalFile)
+ tmp_preview_url = URL.createObjectURL(file.originalFile.slice()).toString()
+ const download_url = url ? `${url}&as_attachment=true` : base64Url
+
+ return (
+ <>
+ <div
+ className={cn(
+ 'group/file-item relative h-[68px] w-[144px] rounded-lg border-[0.5px] border-components-panel-border bg-components-card-bg p-2 shadow-xs',
+ !uploadError && 'hover:bg-components-card-bg-alt',
+ uploadError && 'border border-state-destructive-border bg-state-destructive-hover',
+ uploadError && 'bg-state-destructive-hover-alt hover:border-[0.5px] hover:border-state-destructive-border',
+ )}
+ >
+ {
+ showDeleteAction && (
+ <Button
+ className='absolute -right-1.5 -top-1.5 z-[11] hidden h-5 w-5 rounded-full p-0 group-hover/file-item:flex'
+ onClick={() => onRemove?.(id)}
+ >
+ <RiCloseLine className='h-4 w-4 text-components-button-secondary-text' />
+ </Button>
+ )
+ }
+ <div
+ className='system-xs-medium mb-1 line-clamp-2 h-8 cursor-pointer break-all text-text-tertiary'
+ title={name}
+ onClick={() => canPreview && setPreviewUrl(tmp_preview_url || '')}
+ >
+ {name}
+ </div>
+ <div className='relative flex items-center justify-between'>
+ <div className='system-2xs-medium-uppercase flex items-center text-text-tertiary'>
+ <FileTypeIcon
+ size='sm'
+ type={getFileAppearanceType(name, type)}
+ className='mr-1'
+ />
+ {
+ ext && (
+ <>
+ {ext}
+ <div className='mx-1'>路</div>
+ </>
+ )
+ }
+ {
+ !!file.size && formatFileSize(file.size)
+ }
+ </div>
+ {
+ showDownloadAction && download_url && (
+ <ActionButton
+ size='m'
+ className='absolute -right-1 -top-1 hidden group-hover/file-item:flex'
+ onClick={(e) => {
+ e.stopPropagation()
+ downloadFile(download_url || '', name)
+ }}
+ >
+ <RiDownloadLine className='h-3.5 w-3.5 text-text-tertiary' />
+ </ActionButton>
+ )
+ }
+ {
+ progress >= 0 && !fileIsUploaded(file) && (
+ <ProgressCircle
+ percentage={progress}
+ size={12}
+ className='shrink-0'
+ />
+ )
+ }
+ {
+ uploadError && (
+ <ReplayLine
+ className='h-4 w-4 text-text-tertiary'
+ onClick={() => onReUpload?.(id)}
+ />
+ )
+ }
+ </div>
+ </div>
+ {
+ type.split('/')[0] === 'audio' && canPreview && previewUrl && (
+ <AudioPreview
+ title={name}
+ url={previewUrl}
+ onCancel={() => setPreviewUrl('')}
+ />
+ )
+ }
+ {
+ type.split('/')[0] === 'video' && canPreview && previewUrl && (
+ <VideoPreview
+ title={name}
+ url={previewUrl}
+ onCancel={() => setPreviewUrl('')}
+ />
+ )
+ }
+ {
+ type.split('/')[1] === 'pdf' && canPreview && previewUrl && (
+ <PdfPreview url={previewUrl} onCancel={() => { setPreviewUrl('') }} />
+ )
+ }
+ </>
+ )
+}
+
+export default FileItem
diff --git a/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.tsx b/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.tsx
new file mode 100644
index 0000000..ba90904
--- /dev/null
+++ b/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.tsx
@@ -0,0 +1,82 @@
+import { useFile } from '../hooks'
+import { useStore } from '../store'
+import type { FileEntity } from '../types'
+import FileImageItem from './file-image-item'
+import FileItem from './file-item'
+import type { FileUpload } from '@/app/components/base/features/types'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+import cn from '@/utils/classnames'
+
+type FileListProps = {
+ className?: string
+ files: FileEntity[]
+ onRemove?: (fileId: string) => void
+ onReUpload?: (fileId: string) => void
+ showDeleteAction?: boolean
+ showDownloadAction?: boolean
+ canPreview?: boolean
+}
+export const FileList = ({
+ className,
+ files,
+ onReUpload,
+ onRemove,
+ showDeleteAction = true,
+ showDownloadAction = false,
+ canPreview = true,
+}: FileListProps) => {
+ return (
+ <div className={cn('flex flex-wrap gap-2', className)}>
+ {
+ files.map((file) => {
+ if (file.supportFileType === SupportUploadFileTypes.image) {
+ return (
+ <FileImageItem
+ key={file.id}
+ file={file}
+ showDeleteAction={showDeleteAction}
+ showDownloadAction={showDownloadAction}
+ onRemove={onRemove}
+ onReUpload={onReUpload}
+ canPreview={canPreview}
+ />
+ )
+ }
+
+ return (
+ <FileItem
+ key={file.id}
+ file={file}
+ showDeleteAction={showDeleteAction}
+ showDownloadAction={showDownloadAction}
+ onRemove={onRemove}
+ onReUpload={onReUpload}
+ canPreview={canPreview}
+ />
+ )
+ })
+ }
+ </div>
+ )
+}
+
+type FileListInChatInputProps = {
+ fileConfig: FileUpload
+}
+export const FileListInChatInput = ({
+ fileConfig,
+}: FileListInChatInputProps) => {
+ const files = useStore(s => s.files)
+ const {
+ handleRemoveFile,
+ handleReUploadFile,
+ } = useFile(fileConfig)
+
+ return (
+ <FileList
+ files={files}
+ onReUpload={handleReUploadFile}
+ onRemove={handleRemoveFile}
+ />
+ )
+}
diff --git a/app/components/base/file-uploader/file-uploader-in-chat-input/index.tsx b/app/components/base/file-uploader/file-uploader-in-chat-input/index.tsx
new file mode 100644
index 0000000..7e6e190
--- /dev/null
+++ b/app/components/base/file-uploader/file-uploader-in-chat-input/index.tsx
@@ -0,0 +1,41 @@
+import {
+ memo,
+ useCallback,
+} from 'react'
+import {
+ RiAttachmentLine,
+} from '@remixicon/react'
+import FileFromLinkOrLocal from '../file-from-link-or-local'
+import ActionButton from '@/app/components/base/action-button'
+import cn from '@/utils/classnames'
+import type { FileUpload } from '@/app/components/base/features/types'
+import { TransferMethod } from '@/types/app'
+
+type FileUploaderInChatInputProps = {
+ fileConfig: FileUpload
+}
+const FileUploaderInChatInput = ({
+ fileConfig,
+}: FileUploaderInChatInputProps) => {
+ const renderTrigger = useCallback((open: boolean) => {
+ return (
+ <ActionButton
+ size='l'
+ className={cn(open && 'bg-state-base-hover')}
+ >
+ <RiAttachmentLine className='h-5 w-5' />
+ </ActionButton>
+ )
+ }, [])
+
+ return (
+ <FileFromLinkOrLocal
+ trigger={renderTrigger}
+ fileConfig={fileConfig}
+ showFromLocal={fileConfig?.allowed_file_upload_methods?.includes(TransferMethod.local_file)}
+ showFromLink={fileConfig?.allowed_file_upload_methods?.includes(TransferMethod.remote_url)}
+ />
+ )
+}
+
+export default memo(FileUploaderInChatInput)
diff --git a/app/components/base/file-uploader/hooks.ts b/app/components/base/file-uploader/hooks.ts
new file mode 100644
index 0000000..66d5b46
--- /dev/null
+++ b/app/components/base/file-uploader/hooks.ts
@@ -0,0 +1,367 @@
+import type { ClipboardEvent } from 'react'
+import {
+ useCallback,
+ useState,
+} from 'react'
+import { useParams } from 'next/navigation'
+import produce from 'immer'
+import { v4 as uuid4 } from 'uuid'
+import { useTranslation } from 'react-i18next'
+import type { FileEntity } from './types'
+import { useFileStore } from './store'
+import {
+ fileUpload,
+ getSupportFileType,
+ isAllowedFileExtension,
+} from './utils'
+import {
+ AUDIO_SIZE_LIMIT,
+ FILE_SIZE_LIMIT,
+ IMG_SIZE_LIMIT,
+ MAX_FILE_UPLOAD_LIMIT,
+ VIDEO_SIZE_LIMIT,
+} from '@/app/components/base/file-uploader/constants'
+import { useToastContext } from '@/app/components/base/toast'
+import { TransferMethod } from '@/types/app'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+import type { FileUpload } from '@/app/components/base/features/types'
+import { formatFileSize } from '@/utils/format'
+import { uploadRemoteFileInfo } from '@/service/common'
+import type { FileUploadConfigResponse } from '@/models/common'
+import { noop } from 'lodash-es'
+
+export const useFileSizeLimit = (fileUploadConfig?: FileUploadConfigResponse) => {
+ const imgSizeLimit = Number(fileUploadConfig?.image_file_size_limit) * 1024 * 1024 || IMG_SIZE_LIMIT
+ const docSizeLimit = Number(fileUploadConfig?.file_size_limit) * 1024 * 1024 || FILE_SIZE_LIMIT
+ const audioSizeLimit = Number(fileUploadConfig?.audio_file_size_limit) * 1024 * 1024 || AUDIO_SIZE_LIMIT
+ const videoSizeLimit = Number(fileUploadConfig?.video_file_size_limit) * 1024 * 1024 || VIDEO_SIZE_LIMIT
+ const maxFileUploadLimit = Number(fileUploadConfig?.workflow_file_upload_limit) || MAX_FILE_UPLOAD_LIMIT
+
+ return {
+ imgSizeLimit,
+ docSizeLimit,
+ audioSizeLimit,
+ videoSizeLimit,
+ maxFileUploadLimit,
+ }
+}
+
+export const useFile = (fileConfig: FileUpload) => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const fileStore = useFileStore()
+ const params = useParams()
+ const { imgSizeLimit, docSizeLimit, audioSizeLimit, videoSizeLimit } = useFileSizeLimit(fileConfig.fileUploadConfig)
+
+ const checkSizeLimit = useCallback((fileType: string, fileSize: number) => {
+ switch (fileType) {
+ case SupportUploadFileTypes.image: {
+ if (fileSize > imgSizeLimit) {
+ notify({
+ type: 'error',
+ message: t('common.fileUploader.uploadFromComputerLimit', {
+ type: SupportUploadFileTypes.image,
+ size: formatFileSize(imgSizeLimit),
+ }),
+ })
+ return false
+ }
+ return true
+ }
+ case SupportUploadFileTypes.document: {
+ if (fileSize > docSizeLimit) {
+ notify({
+ type: 'error',
+ message: t('common.fileUploader.uploadFromComputerLimit', {
+ type: SupportUploadFileTypes.document,
+ size: formatFileSize(docSizeLimit),
+ }),
+ })
+ return false
+ }
+ return true
+ }
+ case SupportUploadFileTypes.audio: {
+ if (fileSize > audioSizeLimit) {
+ notify({
+ type: 'error',
+ message: t('common.fileUploader.uploadFromComputerLimit', {
+ type: SupportUploadFileTypes.audio,
+ size: formatFileSize(audioSizeLimit),
+ }),
+ })
+ return false
+ }
+ return true
+ }
+ case SupportUploadFileTypes.video: {
+ if (fileSize > videoSizeLimit) {
+ notify({
+ type: 'error',
+ message: t('common.fileUploader.uploadFromComputerLimit', {
+ type: SupportUploadFileTypes.video,
+ size: formatFileSize(videoSizeLimit),
+ }),
+ })
+ return false
+ }
+ return true
+ }
+ case SupportUploadFileTypes.custom: {
+ if (fileSize > docSizeLimit) {
+ notify({
+ type: 'error',
+ message: t('common.fileUploader.uploadFromComputerLimit', {
+ type: SupportUploadFileTypes.document,
+ size: formatFileSize(docSizeLimit),
+ }),
+ })
+ return false
+ }
+ return true
+ }
+ default: {
+ return true
+ }
+ }
+ }, [audioSizeLimit, docSizeLimit, imgSizeLimit, notify, t, videoSizeLimit])
+
+ const handleAddFile = useCallback((newFile: FileEntity) => {
+ const {
+ files,
+ setFiles,
+ } = fileStore.getState()
+
+ const newFiles = produce(files, (draft) => {
+ draft.push(newFile)
+ })
+ setFiles(newFiles)
+ }, [fileStore])
+
+ const handleUpdateFile = useCallback((newFile: FileEntity) => {
+ const {
+ files,
+ setFiles,
+ } = fileStore.getState()
+
+ const newFiles = produce(files, (draft) => {
+ const index = draft.findIndex(file => file.id === newFile.id)
+
+ if (index > -1)
+ draft[index] = newFile
+ })
+ setFiles(newFiles)
+ }, [fileStore])
+
+ const handleRemoveFile = useCallback((fileId: string) => {
+ const {
+ files,
+ setFiles,
+ } = fileStore.getState()
+
+ const newFiles = files.filter(file => file.id !== fileId)
+ setFiles(newFiles)
+ }, [fileStore])
+
+ const handleReUploadFile = useCallback((fileId: string) => {
+ const {
+ files,
+ setFiles,
+ } = fileStore.getState()
+ const index = files.findIndex(file => file.id === fileId)
+
+ if (index > -1) {
+ const uploadingFile = files[index]
+ const newFiles = produce(files, (draft) => {
+ draft[index].progress = 0
+ })
+ setFiles(newFiles)
+ fileUpload({
+ file: uploadingFile.originalFile!,
+ onProgressCallback: (progress) => {
+ handleUpdateFile({ ...uploadingFile, progress })
+ },
+ onSuccessCallback: (res) => {
+ handleUpdateFile({ ...uploadingFile, uploadedId: res.id, progress: 100 })
+ },
+ onErrorCallback: () => {
+ notify({ type: 'error', message: t('common.fileUploader.uploadFromComputerUploadError') })
+ handleUpdateFile({ ...uploadingFile, progress: -1 })
+ },
+ }, !!params.token)
+ }
+ }, [fileStore, notify, t, handleUpdateFile, params])
+
+ const startProgressTimer = useCallback((fileId: string) => {
+ const timer = setInterval(() => {
+ const files = fileStore.getState().files
+ const file = files.find(file => file.id === fileId)
+
+ if (file && file.progress < 80 && file.progress >= 0)
+ handleUpdateFile({ ...file, progress: file.progress + 20 })
+ else
+ clearTimeout(timer)
+ }, 200)
+ }, [fileStore, handleUpdateFile])
+ const handleLoadFileFromLink = useCallback((url: string) => {
+ const allowedFileTypes = fileConfig.allowed_file_types
+
+ const uploadingFile = {
+ id: uuid4(),
+ name: url,
+ type: '',
+ size: 0,
+ progress: 0,
+ transferMethod: TransferMethod.remote_url,
+ supportFileType: '',
+ url,
+ isRemote: true,
+ }
+ handleAddFile(uploadingFile)
+ startProgressTimer(uploadingFile.id)
+
+ uploadRemoteFileInfo(url, !!params.token).then((res) => {
+ const newFile = {
+ ...uploadingFile,
+ type: res.mime_type,
+ size: res.size,
+ progress: 100,
+ supportFileType: getSupportFileType(res.name, res.mime_type, allowedFileTypes?.includes(SupportUploadFileTypes.custom)),
+ uploadedId: res.id,
+ url: res.url,
+ }
+ if (!isAllowedFileExtension(res.name, res.mime_type, fileConfig.allowed_file_types || [], fileConfig.allowed_file_extensions || [])) {
+ notify({ type: 'error', message: t('common.fileUploader.fileExtensionNotSupport') })
+ handleRemoveFile(uploadingFile.id)
+ }
+ if (!checkSizeLimit(newFile.supportFileType, newFile.size))
+ handleRemoveFile(uploadingFile.id)
+ else
+ handleUpdateFile(newFile)
+ }).catch(() => {
+ notify({ type: 'error', message: t('common.fileUploader.pasteFileLinkInvalid') })
+ handleRemoveFile(uploadingFile.id)
+ })
+ }, [checkSizeLimit, handleAddFile, handleUpdateFile, notify, t, handleRemoveFile, fileConfig?.allowed_file_types, fileConfig.allowed_file_extensions, startProgressTimer, params.token])
+
+ const handleLoadFileFromLinkSuccess = useCallback(noop, [])
+
+ const handleLoadFileFromLinkError = useCallback(noop, [])
+
+ const handleClearFiles = useCallback(() => {
+ const {
+ setFiles,
+ } = fileStore.getState()
+ setFiles([])
+ }, [fileStore])
+
+ const handleLocalFileUpload = useCallback((file: File) => {
+ if (!isAllowedFileExtension(file.name, file.type, fileConfig.allowed_file_types || [], fileConfig.allowed_file_extensions || [])) {
+ notify({ type: 'error', message: t('common.fileUploader.fileExtensionNotSupport') })
+ return
+ }
+ const allowedFileTypes = fileConfig.allowed_file_types
+ const fileType = getSupportFileType(file.name, file.type, allowedFileTypes?.includes(SupportUploadFileTypes.custom))
+ if (!checkSizeLimit(fileType, file.size))
+ return
+
+ const reader = new FileReader()
+ const isImage = file.type.startsWith('image')
+
+ reader.addEventListener(
+ 'load',
+ () => {
+ const uploadingFile = {
+ id: uuid4(),
+ name: file.name,
+ type: file.type,
+ size: file.size,
+ progress: 0,
+ transferMethod: TransferMethod.local_file,
+ supportFileType: getSupportFileType(file.name, file.type, allowedFileTypes?.includes(SupportUploadFileTypes.custom)),
+ originalFile: file,
+ base64Url: isImage ? reader.result as string : '',
+ }
+ handleAddFile(uploadingFile)
+ fileUpload({
+ file: uploadingFile.originalFile,
+ onProgressCallback: (progress) => {
+ handleUpdateFile({ ...uploadingFile, progress })
+ },
+ onSuccessCallback: (res) => {
+ handleUpdateFile({ ...uploadingFile, uploadedId: res.id, progress: 100 })
+ },
+ onErrorCallback: () => {
+ notify({ type: 'error', message: t('common.fileUploader.uploadFromComputerUploadError') })
+ handleUpdateFile({ ...uploadingFile, progress: -1 })
+ },
+ }, !!params.token)
+ },
+ false,
+ )
+ reader.addEventListener(
+ 'error',
+ () => {
+ notify({ type: 'error', message: t('common.fileUploader.uploadFromComputerReadError') })
+ },
+ false,
+ )
+ reader.readAsDataURL(file)
+ }, [checkSizeLimit, notify, t, handleAddFile, handleUpdateFile, params.token, fileConfig?.allowed_file_types, fileConfig?.allowed_file_extensions])
+
+ const handleClipboardPasteFile = useCallback((e: ClipboardEvent<HTMLTextAreaElement>) => {
+ const file = e.clipboardData?.files[0]
+ const text = e.clipboardData?.getData('text/plain')
+ if (file && !text) {
+ e.preventDefault()
+ handleLocalFileUpload(file)
+ }
+ }, [handleLocalFileUpload])
+
+ const [isDragActive, setIsDragActive] = useState(false)
+ const handleDragFileEnter = useCallback((e: React.DragEvent<HTMLElement>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragActive(true)
+ }, [])
+
+ const handleDragFileOver = useCallback((e: React.DragEvent<HTMLElement>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }, [])
+
+ const handleDragFileLeave = useCallback((e: React.DragEvent<HTMLElement>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragActive(false)
+ }, [])
+
+ const handleDropFile = useCallback((e: React.DragEvent<HTMLElement>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragActive(false)
+
+ const file = e.dataTransfer.files[0]
+
+ if (file)
+ handleLocalFileUpload(file)
+ }, [handleLocalFileUpload])
+
+ return {
+ handleAddFile,
+ handleUpdateFile,
+ handleRemoveFile,
+ handleReUploadFile,
+ handleLoadFileFromLink,
+ handleLoadFileFromLinkSuccess,
+ handleLoadFileFromLinkError,
+ handleClearFiles,
+ handleLocalFileUpload,
+ handleClipboardPasteFile,
+ isDragActive,
+ handleDragFileEnter,
+ handleDragFileOver,
+ handleDragFileLeave,
+ handleDropFile,
+ }
+}
diff --git a/app/components/base/file-uploader/index.ts b/app/components/base/file-uploader/index.ts
new file mode 100644
index 0000000..ff5914c
--- /dev/null
+++ b/app/components/base/file-uploader/index.ts
@@ -0,0 +1,7 @@
+export { default as FileUploaderInAttachmentWrapper } from './file-uploader-in-attachment'
+export { default as FileItemInAttachment } from './file-uploader-in-attachment/file-item'
+export { default as FileUploaderInChatInput } from './file-uploader-in-chat-input'
+export { default as FileTypeIcon } from './file-type-icon'
+export { FileListInChatInput } from './file-uploader-in-chat-input/file-list'
+export { FileList } from './file-uploader-in-chat-input/file-list'
+export { default as FileItem } from './file-uploader-in-chat-input/file-item'
diff --git a/app/components/base/file-uploader/pdf-preview.tsx b/app/components/base/file-uploader/pdf-preview.tsx
new file mode 100644
index 0000000..f8a02e8
--- /dev/null
+++ b/app/components/base/file-uploader/pdf-preview.tsx
@@ -0,0 +1,103 @@
+import type { FC } from 'react'
+import { createPortal } from 'react-dom'
+import 'react-pdf-highlighter/dist/style.css'
+import { PdfHighlighter, PdfLoader } from 'react-pdf-highlighter'
+import { t } from 'i18next'
+import { RiCloseLine, RiZoomInLine, RiZoomOutLine } from '@remixicon/react'
+import React, { useState } from 'react'
+import { useHotkeys } from 'react-hotkeys-hook'
+import Loading from '@/app/components/base/loading'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import Tooltip from '@/app/components/base/tooltip'
+import { noop } from 'lodash-es'
+
+type PdfPreviewProps = {
+ url: string
+ onCancel: () => void
+}
+
+const PdfPreview: FC<PdfPreviewProps> = ({
+ url,
+ onCancel,
+}) => {
+ const media = useBreakpoints()
+ const [scale, setScale] = useState(1)
+ const [position, setPosition] = useState({ x: 0, y: 0 })
+ const isMobile = media === MediaType.mobile
+
+ const zoomIn = () => {
+ setScale(prevScale => Math.min(prevScale * 1.2, 15))
+ setPosition({ x: position.x - 50, y: position.y - 50 })
+ }
+
+ const zoomOut = () => {
+ setScale((prevScale) => {
+ const newScale = Math.max(prevScale / 1.2, 0.5)
+ if (newScale === 1)
+ setPosition({ x: 0, y: 0 })
+ else
+ setPosition({ x: position.x + 50, y: position.y + 50 })
+
+ return newScale
+ })
+ }
+
+ useHotkeys('esc', onCancel)
+ useHotkeys('up', zoomIn)
+ useHotkeys('down', zoomOut)
+
+ return createPortal(
+ <div
+ className={`fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 ${!isMobile && 'p-8'}`}
+ onClick={e => e.stopPropagation()}
+ tabIndex={-1}
+ >
+ <div
+ className='h-[95vh] max-h-full w-[100vw] max-w-full overflow-hidden'
+ style={{ transform: `scale(${scale})`, transformOrigin: 'center', scrollbarWidth: 'none', msOverflowStyle: 'none' }}
+ >
+ <PdfLoader
+ workerSrc='/pdf.worker.min.mjs'
+ url={url}
+ beforeLoad={<div className='flex h-64 items-center justify-center'><Loading type='app' /></div>}
+ >
+ {(pdfDocument) => {
+ return (
+ <PdfHighlighter
+ pdfDocument={pdfDocument}
+ enableAreaSelection={event => event.altKey}
+ scrollRef={noop}
+ onScrollChange={noop}
+ onSelectionFinished={() => null}
+ highlightTransform={() => { return <div/> }}
+ highlights={[]}
+ />
+ )
+ }}
+ </PdfLoader>
+ </div>
+ <Tooltip popupContent={t('common.operation.zoomOut')}>
+ <div className='absolute right-24 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
+ onClick={zoomOut}>
+ <RiZoomOutLine className='h-4 w-4 text-gray-500'/>
+ </div>
+ </Tooltip>
+ <Tooltip popupContent={t('common.operation.zoomIn')}>
+ <div className='absolute right-16 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
+ onClick={zoomIn}>
+ <RiZoomInLine className='h-4 w-4 text-gray-500'/>
+ </div>
+ </Tooltip>
+ <Tooltip popupContent={t('common.operation.cancel')}>
+ <div
+ className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/8 backdrop-blur-[2px]'
+ onClick={onCancel}>
+ <RiCloseLine className='h-4 w-4 text-gray-500'/>
+ </div>
+ </Tooltip>
+ </div>,
+ document.body,
+ )
+}
+
+export default PdfPreview
diff --git a/app/components/base/file-uploader/store.tsx b/app/components/base/file-uploader/store.tsx
new file mode 100644
index 0000000..cddfdf6
--- /dev/null
+++ b/app/components/base/file-uploader/store.tsx
@@ -0,0 +1,67 @@
+import {
+ createContext,
+ useContext,
+ useRef,
+} from 'react'
+import {
+ create,
+ useStore as useZustandStore,
+} from 'zustand'
+import type {
+ FileEntity,
+} from './types'
+
+type Shape = {
+ files: FileEntity[]
+ setFiles: (files: FileEntity[]) => void
+}
+
+export const createFileStore = (
+ value: FileEntity[] = [],
+ onChange?: (files: FileEntity[]) => void,
+) => {
+ return create<Shape>(set => ({
+ files: value ? [...value] : [],
+ setFiles: (files) => {
+ set({ files })
+ onChange?.(files)
+ },
+ }))
+}
+
+type FileStore = ReturnType<typeof createFileStore>
+export const FileContext = createContext<FileStore | null>(null)
+
+export function useStore<T>(selector: (state: Shape) => T): T {
+ const store = useContext(FileContext)
+ if (!store)
+ throw new Error('Missing FileContext.Provider in the tree')
+
+ return useZustandStore(store, selector)
+}
+
+export const useFileStore = () => {
+ return useContext(FileContext)!
+}
+
+type FileProviderProps = {
+ children: React.ReactNode
+ value?: FileEntity[]
+ onChange?: (files: FileEntity[]) => void
+}
+export const FileContextProvider = ({
+ children,
+ value,
+ onChange,
+}: FileProviderProps) => {
+ const storeRef = useRef<FileStore | undefined>(undefined)
+
+ if (!storeRef.current)
+ storeRef.current = createFileStore(value, onChange)
+
+ return (
+ <FileContext.Provider value={storeRef.current}>
+ {children}
+ </FileContext.Provider>
+ )
+}
diff --git a/app/components/base/file-uploader/types.ts b/app/components/base/file-uploader/types.ts
new file mode 100644
index 0000000..285023f
--- /dev/null
+++ b/app/components/base/file-uploader/types.ts
@@ -0,0 +1,33 @@
+import type { TransferMethod } from '@/types/app'
+
+export enum FileAppearanceTypeEnum {
+ image = 'image',
+ video = 'video',
+ audio = 'audio',
+ document = 'document',
+ code = 'code',
+ pdf = 'pdf',
+ markdown = 'markdown',
+ excel = 'excel',
+ word = 'word',
+ ppt = 'ppt',
+ gif = 'gif',
+ custom = 'custom',
+}
+
+export type FileAppearanceType = keyof typeof FileAppearanceTypeEnum
+
+export type FileEntity = {
+ id: string
+ name: string
+ size: number
+ type: string
+ progress: number
+ transferMethod: TransferMethod
+ supportFileType: string
+ originalFile?: File
+ uploadedId?: string
+ base64Url?: string
+ url?: string
+ isRemote?: boolean
+}
diff --git a/app/components/base/file-uploader/utils.spec.ts b/app/components/base/file-uploader/utils.spec.ts
new file mode 100644
index 0000000..c8cf9fb
--- /dev/null
+++ b/app/components/base/file-uploader/utils.spec.ts
@@ -0,0 +1,614 @@
+import mime from 'mime'
+import { upload } from '@/service/base'
+import {
+ downloadFile,
+ fileIsUploaded,
+ fileUpload,
+ getFileAppearanceType,
+ getFileExtension,
+ getFileNameFromUrl,
+ getFilesInLogs,
+ getProcessedFiles,
+ getProcessedFilesFromResponse,
+ getSupportFileExtensionList,
+ getSupportFileType,
+ isAllowedFileExtension,
+} from './utils'
+import { FileAppearanceTypeEnum } from './types'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+import { TransferMethod } from '@/types/app'
+import { FILE_EXTS } from '../prompt-editor/constants'
+
+jest.mock('mime', () => ({
+ __esModule: true,
+ default: {
+ getExtension: jest.fn(),
+ },
+}))
+
+jest.mock('@/service/base', () => ({
+ upload: jest.fn(),
+}))
+
+describe('file-uploader utils', () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+ })
+
+ describe('fileUpload', () => {
+ it('should handle successful file upload', async () => {
+ const mockFile = new File(['test'], 'test.txt')
+ const mockCallbacks = {
+ onProgressCallback: jest.fn(),
+ onSuccessCallback: jest.fn(),
+ onErrorCallback: jest.fn(),
+ }
+
+ jest.mocked(upload).mockResolvedValue({ id: '123' })
+
+ await fileUpload({
+ file: mockFile,
+ ...mockCallbacks,
+ })
+
+ expect(upload).toHaveBeenCalled()
+ expect(mockCallbacks.onSuccessCallback).toHaveBeenCalledWith({ id: '123' })
+ })
+ })
+
+ describe('getFileExtension', () => {
+ it('should get extension from mimetype', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('pdf')
+ expect(getFileExtension('file', 'application/pdf')).toBe('pdf')
+ })
+
+ it('should get extension from filename if mimetype fails', () => {
+ jest.mocked(mime.getExtension).mockReturnValue(null)
+ expect(getFileExtension('file.txt', '')).toBe('txt')
+ expect(getFileExtension('file.txt.docx', '')).toBe('docx')
+ expect(getFileExtension('file', '')).toBe('')
+ })
+
+ it('should return empty string for remote files', () => {
+ expect(getFileExtension('file.txt', '', true)).toBe('')
+ })
+ })
+
+ describe('getFileAppearanceType', () => {
+ it('should identify gif files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('gif')
+ expect(getFileAppearanceType('image.gif', 'image/gif'))
+ .toBe(FileAppearanceTypeEnum.gif)
+ })
+
+ it('should identify image files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('jpg')
+ expect(getFileAppearanceType('image.jpg', 'image/jpeg'))
+ .toBe(FileAppearanceTypeEnum.image)
+
+ jest.mocked(mime.getExtension).mockReturnValue('jpeg')
+ expect(getFileAppearanceType('image.jpeg', 'image/jpeg'))
+ .toBe(FileAppearanceTypeEnum.image)
+
+ jest.mocked(mime.getExtension).mockReturnValue('png')
+ expect(getFileAppearanceType('image.png', 'image/png'))
+ .toBe(FileAppearanceTypeEnum.image)
+
+ jest.mocked(mime.getExtension).mockReturnValue('webp')
+ expect(getFileAppearanceType('image.webp', 'image/webp'))
+ .toBe(FileAppearanceTypeEnum.image)
+
+ jest.mocked(mime.getExtension).mockReturnValue('svg')
+ expect(getFileAppearanceType('image.svg', 'image/svgxml'))
+ .toBe(FileAppearanceTypeEnum.image)
+ })
+
+ it('should identify video files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('mp4')
+ expect(getFileAppearanceType('video.mp4', 'video/mp4'))
+ .toBe(FileAppearanceTypeEnum.video)
+
+ jest.mocked(mime.getExtension).mockReturnValue('mov')
+ expect(getFileAppearanceType('video.mov', 'video/quicktime'))
+ .toBe(FileAppearanceTypeEnum.video)
+
+ jest.mocked(mime.getExtension).mockReturnValue('mpeg')
+ expect(getFileAppearanceType('video.mpeg', 'video/mpeg'))
+ .toBe(FileAppearanceTypeEnum.video)
+
+ jest.mocked(mime.getExtension).mockReturnValue('webm')
+ expect(getFileAppearanceType('video.web', 'video/webm'))
+ .toBe(FileAppearanceTypeEnum.video)
+ })
+
+ it('should identify audio files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('mp3')
+ expect(getFileAppearanceType('audio.mp3', 'audio/mpeg'))
+ .toBe(FileAppearanceTypeEnum.audio)
+
+ jest.mocked(mime.getExtension).mockReturnValue('m4a')
+ expect(getFileAppearanceType('audio.m4a', 'audio/mp4'))
+ .toBe(FileAppearanceTypeEnum.audio)
+
+ jest.mocked(mime.getExtension).mockReturnValue('wav')
+ expect(getFileAppearanceType('audio.wav', 'audio/vnd.wav'))
+ .toBe(FileAppearanceTypeEnum.audio)
+
+ jest.mocked(mime.getExtension).mockReturnValue('amr')
+ expect(getFileAppearanceType('audio.amr', 'audio/AMR'))
+ .toBe(FileAppearanceTypeEnum.audio)
+
+ jest.mocked(mime.getExtension).mockReturnValue('mpga')
+ expect(getFileAppearanceType('audio.mpga', 'audio/mpeg'))
+ .toBe(FileAppearanceTypeEnum.audio)
+ })
+
+ it('should identify code files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('html')
+ expect(getFileAppearanceType('index.html', 'text/html'))
+ .toBe(FileAppearanceTypeEnum.code)
+ })
+
+ it('should identify PDF files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('pdf')
+ expect(getFileAppearanceType('doc.pdf', 'application/pdf'))
+ .toBe(FileAppearanceTypeEnum.pdf)
+ })
+
+ it('should identify markdown files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('md')
+ expect(getFileAppearanceType('file.md', 'text/markdown'))
+ .toBe(FileAppearanceTypeEnum.markdown)
+
+ jest.mocked(mime.getExtension).mockReturnValue('markdown')
+ expect(getFileAppearanceType('file.markdown', 'text/markdown'))
+ .toBe(FileAppearanceTypeEnum.markdown)
+
+ jest.mocked(mime.getExtension).mockReturnValue('mdx')
+ expect(getFileAppearanceType('file.mdx', 'text/mdx'))
+ .toBe(FileAppearanceTypeEnum.markdown)
+ })
+
+ it('should identify excel files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('xlsx')
+ expect(getFileAppearanceType('doc.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'))
+ .toBe(FileAppearanceTypeEnum.excel)
+
+ jest.mocked(mime.getExtension).mockReturnValue('xls')
+ expect(getFileAppearanceType('doc.xls', 'application/vnd.ms-excel'))
+ .toBe(FileAppearanceTypeEnum.excel)
+ })
+
+ it('should identify word files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('doc')
+ expect(getFileAppearanceType('doc.doc', 'application/msword'))
+ .toBe(FileAppearanceTypeEnum.word)
+
+ jest.mocked(mime.getExtension).mockReturnValue('docx')
+ expect(getFileAppearanceType('doc.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'))
+ .toBe(FileAppearanceTypeEnum.word)
+ })
+
+ it('should identify word files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('ppt')
+ expect(getFileAppearanceType('doc.ppt', 'application/vnd.ms-powerpoint'))
+ .toBe(FileAppearanceTypeEnum.ppt)
+
+ jest.mocked(mime.getExtension).mockReturnValue('pptx')
+ expect(getFileAppearanceType('doc.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'))
+ .toBe(FileAppearanceTypeEnum.ppt)
+ })
+
+ it('should identify document files', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('txt')
+ expect(getFileAppearanceType('file.txt', 'text/plain'))
+ .toBe(FileAppearanceTypeEnum.document)
+
+ jest.mocked(mime.getExtension).mockReturnValue('csv')
+ expect(getFileAppearanceType('file.csv', 'text/csv'))
+ .toBe(FileAppearanceTypeEnum.document)
+
+ jest.mocked(mime.getExtension).mockReturnValue('msg')
+ expect(getFileAppearanceType('file.msg', 'application/vnd.ms-outlook'))
+ .toBe(FileAppearanceTypeEnum.document)
+
+ jest.mocked(mime.getExtension).mockReturnValue('eml')
+ expect(getFileAppearanceType('file.eml', 'message/rfc822'))
+ .toBe(FileAppearanceTypeEnum.document)
+
+ jest.mocked(mime.getExtension).mockReturnValue('xml')
+ expect(getFileAppearanceType('file.xml', 'application/rssxml'))
+ .toBe(FileAppearanceTypeEnum.document)
+
+ jest.mocked(mime.getExtension).mockReturnValue('epub')
+ expect(getFileAppearanceType('file.epub', 'application/epubzip'))
+ .toBe(FileAppearanceTypeEnum.document)
+ })
+
+ it('should handle null mime extension', () => {
+ jest.mocked(mime.getExtension).mockReturnValue(null)
+ expect(getFileAppearanceType('file.txt', 'text/plain'))
+ .toBe(FileAppearanceTypeEnum.document)
+ })
+ })
+
+ describe('getSupportFileType', () => {
+ it('should return custom type when isCustom is true', () => {
+ expect(getSupportFileType('file.txt', '', true))
+ .toBe(SupportUploadFileTypes.custom)
+ })
+
+ it('should return file type when isCustom is false', () => {
+ expect(getSupportFileType('file.txt', 'text/plain'))
+ .toBe(SupportUploadFileTypes.document)
+ })
+ })
+
+ describe('getProcessedFiles', () => {
+ it('should process files correctly', () => {
+ const files = [{
+ id: '123',
+ name: 'test.txt',
+ size: 1024,
+ type: 'text/plain',
+ progress: 100,
+ supportFileType: 'document',
+ transferMethod: TransferMethod.remote_url,
+ url: 'http://example.com',
+ uploadedId: '123',
+ }]
+
+ const result = getProcessedFiles(files)
+ expect(result[0]).toEqual({
+ type: 'document',
+ transfer_method: TransferMethod.remote_url,
+ url: 'http://example.com',
+ upload_file_id: '123',
+ })
+ })
+ })
+
+ describe('getProcessedFilesFromResponse', () => {
+ it('should process files correctly', () => {
+ const files = [{
+ related_id: '2a38e2ca-1295-415d-a51d-65d4ff9912d9',
+ extension: '.jpeg',
+ filename: 'test.jpeg',
+ size: 2881761,
+ mime_type: 'image/jpeg',
+ transfer_method: TransferMethod.local_file,
+ type: 'image',
+ url: 'https://upload.dify.dev/files/xxx/file-preview',
+ }]
+
+ const result = getProcessedFilesFromResponse(files)
+ expect(result[0]).toEqual({
+ id: '2a38e2ca-1295-415d-a51d-65d4ff9912d9',
+ name: 'test.jpeg',
+ size: 2881761,
+ type: 'image/jpeg',
+ progress: 100,
+ transferMethod: TransferMethod.local_file,
+ supportFileType: 'image',
+ uploadedId: '2a38e2ca-1295-415d-a51d-65d4ff9912d9',
+ url: 'https://upload.dify.dev/files/xxx/file-preview',
+ })
+ })
+ })
+
+ describe('getFileNameFromUrl', () => {
+ it('should extract filename from URL', () => {
+ expect(getFileNameFromUrl('http://example.com/path/file.txt'))
+ .toBe('file.txt')
+ })
+ })
+
+ describe('getSupportFileExtensionList', () => {
+ it('should handle custom file types', () => {
+ const result = getSupportFileExtensionList(
+ [SupportUploadFileTypes.custom],
+ ['.pdf', '.txt', '.doc'],
+ )
+ expect(result).toEqual(['PDF', 'TXT', 'DOC'])
+ })
+
+ it('should handle standard file types', () => {
+ const mockFileExts = {
+ image: ['JPG', 'PNG'],
+ document: ['PDF', 'TXT'],
+ video: ['MP4', 'MOV'],
+ }
+
+ // Temporarily mock FILE_EXTS
+ const originalFileExts = { ...FILE_EXTS }
+ Object.assign(FILE_EXTS, mockFileExts)
+
+ const result = getSupportFileExtensionList(
+ ['image', 'document'],
+ [],
+ )
+ expect(result).toEqual(['JPG', 'PNG', 'PDF', 'TXT'])
+
+ // Restore original FILE_EXTS
+ Object.assign(FILE_EXTS, originalFileExts)
+ })
+
+ it('should return empty array for empty inputs', () => {
+ const result = getSupportFileExtensionList([], [])
+ expect(result).toEqual([])
+ })
+
+ it('should prioritize custom types over standard types', () => {
+ const mockFileExts = {
+ image: ['JPG', 'PNG'],
+ }
+
+ // Temporarily mock FILE_EXTS
+ const originalFileExts = { ...FILE_EXTS }
+ Object.assign(FILE_EXTS, mockFileExts)
+
+ const result = getSupportFileExtensionList(
+ [SupportUploadFileTypes.custom, 'image'],
+ ['.csv', '.xml'],
+ )
+ expect(result).toEqual(['CSV', 'XML'])
+
+ // Restore original FILE_EXTS
+ Object.assign(FILE_EXTS, originalFileExts)
+ })
+ })
+
+ describe('isAllowedFileExtension', () => {
+ it('should validate allowed file extensions', () => {
+ jest.mocked(mime.getExtension).mockReturnValue('pdf')
+ expect(isAllowedFileExtension(
+ 'test.pdf',
+ 'application/pdf',
+ ['document'],
+ ['.pdf'],
+ )).toBe(true)
+ })
+ })
+
+ describe('getFilesInLogs', () => {
+ const mockFileData = {
+ dify_model_identity: '__dify__file__',
+ related_id: '123',
+ filename: 'test.pdf',
+ size: 1024,
+ mime_type: 'application/pdf',
+ transfer_method: 'local_file',
+ type: 'document',
+ url: 'http://example.com/test.pdf',
+ }
+
+ it('should handle empty or null input', () => {
+ expect(getFilesInLogs(null)).toEqual([])
+ expect(getFilesInLogs({})).toEqual([])
+ expect(getFilesInLogs(undefined)).toEqual([])
+ })
+
+ it('should process single file object', () => {
+ const input = {
+ file1: mockFileData,
+ }
+
+ const expected = [{
+ varName: 'file1',
+ list: [{
+ id: '123',
+ name: 'test.pdf',
+ size: 1024,
+ type: 'application/pdf',
+ progress: 100,
+ transferMethod: 'local_file',
+ supportFileType: 'document',
+ uploadedId: '123',
+ url: 'http://example.com/test.pdf',
+ }],
+ }]
+
+ expect(getFilesInLogs(input)).toEqual(expected)
+ })
+
+ it('should process array of files', () => {
+ const input = {
+ files: [mockFileData, mockFileData],
+ }
+
+ const expected = [{
+ varName: 'files',
+ list: [
+ {
+ id: '123',
+ name: 'test.pdf',
+ size: 1024,
+ type: 'application/pdf',
+ progress: 100,
+ transferMethod: 'local_file',
+ supportFileType: 'document',
+ uploadedId: '123',
+ url: 'http://example.com/test.pdf',
+ },
+ {
+ id: '123',
+ name: 'test.pdf',
+ size: 1024,
+ type: 'application/pdf',
+ progress: 100,
+ transferMethod: 'local_file',
+ supportFileType: 'document',
+ uploadedId: '123',
+ url: 'http://example.com/test.pdf',
+ },
+ ],
+ }]
+
+ expect(getFilesInLogs(input)).toEqual(expected)
+ })
+
+ it('should ignore non-file objects and arrays', () => {
+ const input = {
+ regularString: 'not a file',
+ regularNumber: 123,
+ regularArray: [1, 2, 3],
+ regularObject: { key: 'value' },
+ file: mockFileData,
+ }
+
+ const expected = [{
+ varName: 'file',
+ list: [{
+ id: '123',
+ name: 'test.pdf',
+ size: 1024,
+ type: 'application/pdf',
+ progress: 100,
+ transferMethod: 'local_file',
+ supportFileType: 'document',
+ uploadedId: '123',
+ url: 'http://example.com/test.pdf',
+ }],
+ }]
+
+ expect(getFilesInLogs(input)).toEqual(expected)
+ })
+
+ it('should handle mixed file types in array', () => {
+ const input = {
+ mixedFiles: [
+ mockFileData,
+ { notAFile: true },
+ mockFileData,
+ ],
+ }
+
+ const expected = [{
+ varName: 'mixedFiles',
+ list: [
+ {
+ id: '123',
+ name: 'test.pdf',
+ size: 1024,
+ type: 'application/pdf',
+ progress: 100,
+ transferMethod: 'local_file',
+ supportFileType: 'document',
+ uploadedId: '123',
+ url: 'http://example.com/test.pdf',
+ },
+ {
+ id: undefined,
+ name: undefined,
+ progress: 100,
+ size: 0,
+ supportFileType: undefined,
+ transferMethod: undefined,
+ type: undefined,
+ uploadedId: undefined,
+ url: undefined,
+ },
+ {
+ id: '123',
+ name: 'test.pdf',
+ size: 1024,
+ type: 'application/pdf',
+ progress: 100,
+ transferMethod: 'local_file',
+ supportFileType: 'document',
+ uploadedId: '123',
+ url: 'http://example.com/test.pdf',
+ },
+ ],
+ }]
+
+ expect(getFilesInLogs(input)).toEqual(expected)
+ })
+ })
+
+ describe('fileIsUploaded', () => {
+ it('should identify uploaded files', () => {
+ expect(fileIsUploaded({
+ uploadedId: '123',
+ progress: 100,
+ } as any)).toBe(true)
+ })
+
+ it('should identify remote files as uploaded', () => {
+ expect(fileIsUploaded({
+ transferMethod: TransferMethod.remote_url,
+ progress: 100,
+ } as any)).toBe(true)
+ })
+ })
+
+ describe('downloadFile', () => {
+ let mockAnchor: HTMLAnchorElement
+ let createElementMock: jest.SpyInstance
+ let appendChildMock: jest.SpyInstance
+ let removeChildMock: jest.SpyInstance
+
+ beforeEach(() => {
+ // Mock createElement and appendChild
+ mockAnchor = {
+ href: '',
+ download: '',
+ style: { display: '' },
+ target: '',
+ title: '',
+ click: jest.fn(),
+ } as unknown as HTMLAnchorElement
+
+ createElementMock = jest.spyOn(document, 'createElement').mockReturnValue(mockAnchor as any)
+ appendChildMock = jest.spyOn(document.body, 'appendChild').mockImplementation((node: Node) => {
+ return node
+ })
+ removeChildMock = jest.spyOn(document.body, 'removeChild').mockImplementation((node: Node) => {
+ return node
+ })
+ })
+
+ afterEach(() => {
+ jest.resetAllMocks()
+ })
+
+ it('should create and trigger download with correct attributes', () => {
+ const url = 'https://example.com/test.pdf'
+ const filename = 'test.pdf'
+
+ downloadFile(url, filename)
+
+ // Verify anchor element was created with correct properties
+ expect(createElementMock).toHaveBeenCalledWith('a')
+ expect(mockAnchor.href).toBe(url)
+ expect(mockAnchor.download).toBe(filename)
+ expect(mockAnchor.style.display).toBe('none')
+ expect(mockAnchor.target).toBe('_blank')
+ expect(mockAnchor.title).toBe(filename)
+
+ // Verify DOM operations
+ expect(appendChildMock).toHaveBeenCalledWith(mockAnchor)
+ expect(mockAnchor.click).toHaveBeenCalled()
+ expect(removeChildMock).toHaveBeenCalledWith(mockAnchor)
+ })
+
+ it('should handle empty filename', () => {
+ const url = 'https://example.com/test.pdf'
+ const filename = ''
+
+ downloadFile(url, filename)
+
+ expect(mockAnchor.download).toBe('')
+ expect(mockAnchor.title).toBe('')
+ })
+
+ it('should handle empty url', () => {
+ const url = ''
+ const filename = 'test.pdf'
+
+ downloadFile(url, filename)
+
+ expect(mockAnchor.href).toBe('')
+ })
+ })
+})
diff --git a/app/components/base/file-uploader/utils.ts b/app/components/base/file-uploader/utils.ts
new file mode 100644
index 0000000..e05c0b2
--- /dev/null
+++ b/app/components/base/file-uploader/utils.ts
@@ -0,0 +1,196 @@
+import mime from 'mime'
+import { FileAppearanceTypeEnum } from './types'
+import type { FileEntity } from './types'
+import { upload } from '@/service/base'
+import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+import type { FileResponse } from '@/types/workflow'
+import { TransferMethod } from '@/types/app'
+
+type FileUploadParams = {
+ file: File
+ onProgressCallback: (progress: number) => void
+ onSuccessCallback: (res: { id: string }) => void
+ onErrorCallback: () => void
+}
+type FileUpload = (v: FileUploadParams, isPublic?: boolean, url?: string) => void
+export const fileUpload: FileUpload = ({
+ file,
+ onProgressCallback,
+ onSuccessCallback,
+ onErrorCallback,
+}, isPublic, url) => {
+ const formData = new FormData()
+ formData.append('file', file)
+ const onProgress = (e: ProgressEvent) => {
+ if (e.lengthComputable) {
+ const percent = Math.floor(e.loaded / e.total * 100)
+ onProgressCallback(percent)
+ }
+ }
+
+ upload({
+ xhr: new XMLHttpRequest(),
+ data: formData,
+ onprogress: onProgress,
+ }, isPublic, url)
+ .then((res: { id: string }) => {
+ onSuccessCallback(res)
+ })
+ .catch(() => {
+ onErrorCallback()
+ })
+}
+
+export const getFileExtension = (fileName: string, fileMimetype: string, isRemote?: boolean) => {
+ let extension = ''
+ if (fileMimetype)
+ extension = mime.getExtension(fileMimetype) || ''
+
+ if (fileName && !extension) {
+ const fileNamePair = fileName.split('.')
+ const fileNamePairLength = fileNamePair.length
+
+ if (fileNamePairLength > 1)
+ extension = fileNamePair[fileNamePairLength - 1]
+ else
+ extension = ''
+ }
+
+ if (isRemote)
+ extension = ''
+
+ return extension
+}
+
+export const getFileAppearanceType = (fileName: string, fileMimetype: string) => {
+ const extension = getFileExtension(fileName, fileMimetype)
+
+ if (extension === 'gif')
+ return FileAppearanceTypeEnum.gif
+
+ if (FILE_EXTS.image.includes(extension.toUpperCase()))
+ return FileAppearanceTypeEnum.image
+
+ if (FILE_EXTS.video.includes(extension.toUpperCase()))
+ return FileAppearanceTypeEnum.video
+
+ if (FILE_EXTS.audio.includes(extension.toUpperCase()))
+ return FileAppearanceTypeEnum.audio
+
+ if (extension === 'html')
+ return FileAppearanceTypeEnum.code
+
+ if (extension === 'pdf')
+ return FileAppearanceTypeEnum.pdf
+
+ if (extension === 'md' || extension === 'markdown' || extension === 'mdx')
+ return FileAppearanceTypeEnum.markdown
+
+ if (extension === 'xlsx' || extension === 'xls')
+ return FileAppearanceTypeEnum.excel
+
+ if (extension === 'docx' || extension === 'doc')
+ return FileAppearanceTypeEnum.word
+
+ if (extension === 'pptx' || extension === 'ppt')
+ return FileAppearanceTypeEnum.ppt
+
+ if (FILE_EXTS.document.includes(extension.toUpperCase()))
+ return FileAppearanceTypeEnum.document
+
+ return FileAppearanceTypeEnum.custom
+}
+
+export const getSupportFileType = (fileName: string, fileMimetype: string, isCustom?: boolean) => {
+ if (isCustom)
+ return SupportUploadFileTypes.custom
+
+ const extension = getFileExtension(fileName, fileMimetype)
+ for (const key in FILE_EXTS) {
+ if ((FILE_EXTS[key]).includes(extension.toUpperCase()))
+ return key
+ }
+
+ return ''
+}
+
+export const getProcessedFiles = (files: FileEntity[]) => {
+ return files.filter(file => file.progress !== -1).map(fileItem => ({
+ type: fileItem.supportFileType,
+ transfer_method: fileItem.transferMethod,
+ url: fileItem.url || '',
+ upload_file_id: fileItem.uploadedId || '',
+ }))
+}
+
+export const getProcessedFilesFromResponse = (files: FileResponse[]) => {
+ return files.map((fileItem) => {
+ return {
+ id: fileItem.related_id,
+ name: fileItem.filename,
+ size: fileItem.size || 0,
+ type: fileItem.mime_type,
+ progress: 100,
+ transferMethod: fileItem.transfer_method,
+ supportFileType: fileItem.type,
+ uploadedId: fileItem.upload_file_id || fileItem.related_id,
+ url: fileItem.url,
+ }
+ })
+}
+
+export const getFileNameFromUrl = (url: string) => {
+ const urlParts = url.split('/')
+ return urlParts[urlParts.length - 1] || ''
+}
+
+export const getSupportFileExtensionList = (allowFileTypes: string[], allowFileExtensions: string[]) => {
+ if (allowFileTypes.includes(SupportUploadFileTypes.custom))
+ return allowFileExtensions.map(item => item.slice(1).toUpperCase())
+
+ return allowFileTypes.map(type => FILE_EXTS[type]).flat()
+}
+
+export const isAllowedFileExtension = (fileName: string, fileMimetype: string, allowFileTypes: string[], allowFileExtensions: string[]) => {
+ return getSupportFileExtensionList(allowFileTypes, allowFileExtensions).includes(getFileExtension(fileName, fileMimetype).toUpperCase())
+}
+
+export const getFilesInLogs = (rawData: any) => {
+ const result = Object.keys(rawData || {}).map((key) => {
+ if (typeof rawData[key] === 'object' && rawData[key]?.dify_model_identity === '__dify__file__') {
+ return {
+ varName: key,
+ list: getProcessedFilesFromResponse([rawData[key]]),
+ }
+ }
+ if (Array.isArray(rawData[key]) && rawData[key].some(item => item?.dify_model_identity === '__dify__file__')) {
+ return {
+ varName: key,
+ list: getProcessedFilesFromResponse(rawData[key]),
+ }
+ }
+ return undefined
+ }).filter(Boolean)
+ return result
+}
+
+export const fileIsUploaded = (file: FileEntity) => {
+ if (file.uploadedId)
+ return true
+
+ if (file.transferMethod === TransferMethod.remote_url && file.progress === 100)
+ return true
+}
+
+export const downloadFile = (url: string, filename: string) => {
+ const anchor = document.createElement('a')
+ anchor.href = url
+ anchor.download = filename
+ anchor.style.display = 'none'
+ anchor.target = '_blank'
+ anchor.title = filename
+ document.body.appendChild(anchor)
+ anchor.click()
+ document.body.removeChild(anchor)
+}
diff --git a/app/components/base/file-uploader/video-preview.tsx b/app/components/base/file-uploader/video-preview.tsx
new file mode 100644
index 0000000..16ae27c
--- /dev/null
+++ b/app/components/base/file-uploader/video-preview.tsx
@@ -0,0 +1,45 @@
+import type { FC } from 'react'
+import { createPortal } from 'react-dom'
+import { RiCloseLine } from '@remixicon/react'
+import React from 'react'
+import { useHotkeys } from 'react-hotkeys-hook'
+
+type VideoPreviewProps = {
+ url: string
+ title: string
+ onCancel: () => void
+}
+const VideoPreview: FC<VideoPreviewProps> = ({
+ url,
+ title,
+ onCancel,
+}) => {
+ useHotkeys('esc', onCancel)
+
+ return createPortal(
+ <div
+ className='fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 p-8'
+ onClick={e => e.stopPropagation()}
+ tabIndex={-1}
+ >
+ <div>
+ <video controls title={title} autoPlay={false} preload="metadata">
+ <source
+ type="video/mp4"
+ src={url}
+ className='max-h-full max-w-full'
+ />
+ </video>
+ </div>
+ <div
+ className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/[0.08] backdrop-blur-[2px]'
+ onClick={onCancel}
+ >
+ <RiCloseLine className='h-4 w-4 text-gray-500'/>
+ </div>
+ </div>,
+ document.body,
+ )
+}
+
+export default VideoPreview
diff --git a/app/components/base/float-popover-container/index.tsx b/app/components/base/float-popover-container/index.tsx
new file mode 100644
index 0000000..be5db82
--- /dev/null
+++ b/app/components/base/float-popover-container/index.tsx
@@ -0,0 +1,37 @@
+'use client'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import type { PortalToFollowElemOptions } from '@/app/components/base/portal-to-follow-elem'
+
+type IFloatRightContainerProps = {
+ isMobile: boolean
+ open: boolean
+ toggle: () => void
+ triggerElement?: React.ReactNode
+ children?: React.ReactNode
+} & PortalToFollowElemOptions
+
+const FloatRightContainer = ({ open, toggle, triggerElement, isMobile, children, ...portalProps }: IFloatRightContainerProps) => {
+ return (
+ <>
+ {isMobile && (
+ <PortalToFollowElem open={open} {...portalProps}>
+ <PortalToFollowElemTrigger onClick={toggle}>
+ {triggerElement}
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent>
+ {children}
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )}
+ {!isMobile && open && (
+ <>{children}</>
+ )}
+ </>
+ )
+}
+
+export default FloatRightContainer
diff --git a/app/components/base/float-right-container/index.tsx b/app/components/base/float-right-container/index.tsx
new file mode 100644
index 0000000..4148c70
--- /dev/null
+++ b/app/components/base/float-right-container/index.tsx
@@ -0,0 +1,23 @@
+'use client'
+import Drawer from '@/app/components/base/drawer'
+import type { IDrawerProps } from '@/app/components/base/drawer'
+
+type IFloatRightContainerProps = {
+ isMobile: boolean
+ children?: React.ReactNode
+} & IDrawerProps
+
+const FloatRightContainer = ({ isMobile, children, isOpen, ...drawerProps }: IFloatRightContainerProps) => {
+ return (
+ <>
+ {isMobile && (
+ <Drawer isOpen={isOpen} {...drawerProps}>{children}</Drawer>
+ )}
+ {(!isMobile && isOpen) && (
+ <>{children}</>
+ )}
+ </>
+ )
+}
+
+export default FloatRightContainer
diff --git a/app/components/base/form/components/field/checkbox.tsx b/app/components/base/form/components/field/checkbox.tsx
new file mode 100644
index 0000000..855dbd8
--- /dev/null
+++ b/app/components/base/form/components/field/checkbox.tsx
@@ -0,0 +1,43 @@
+import cn from '@/utils/classnames'
+import { useFieldContext } from '../..'
+import Checkbox from '../../../checkbox'
+
+type CheckboxFieldProps = {
+ label: string;
+ labelClassName?: string;
+}
+
+const CheckboxField = ({
+ label,
+ labelClassName,
+}: CheckboxFieldProps) => {
+ const field = useFieldContext<boolean>()
+
+ return (
+ <div className='flex gap-2'>
+ <div className='flex h-6 shrink-0 items-center'>
+ <Checkbox
+ id={field.name}
+ checked={field.state.value}
+ onCheck={() => {
+ field.handleChange(!field.state.value)
+ }}
+ />
+ </div>
+ <label
+ htmlFor={field.name}
+ className={cn(
+ 'system-sm-medium grow cursor-pointer pt-1 text-text-secondary',
+ labelClassName,
+ )}
+ onClick={() => {
+ field.handleChange(!field.state.value)
+ }}
+ >
+ {label}
+ </label>
+ </div>
+ )
+}
+
+export default CheckboxField
diff --git a/app/components/base/form/components/field/number-input.tsx b/app/components/base/form/components/field/number-input.tsx
new file mode 100644
index 0000000..fce3143
--- /dev/null
+++ b/app/components/base/form/components/field/number-input.tsx
@@ -0,0 +1,49 @@
+import React from 'react'
+import { useFieldContext } from '../..'
+import Label from '../label'
+import cn from '@/utils/classnames'
+import type { InputNumberProps } from '../../../input-number'
+import { InputNumber } from '../../../input-number'
+
+type TextFieldProps = {
+ label: string
+ isRequired?: boolean
+ showOptional?: boolean
+ tooltip?: string
+ className?: string
+ labelClassName?: string
+} & Omit<InputNumberProps, 'id' | 'value' | 'onChange' | 'onBlur'>
+
+const NumberInputField = ({
+ label,
+ isRequired,
+ showOptional,
+ tooltip,
+ className,
+ labelClassName,
+ ...inputProps
+}: TextFieldProps) => {
+ const field = useFieldContext<number | undefined>()
+
+ return (
+ <div className={cn('flex flex-col gap-y-0.5', className)}>
+ <Label
+ htmlFor={field.name}
+ label={label}
+ isRequired={isRequired}
+ showOptional={showOptional}
+ tooltip={tooltip}
+ className={labelClassName}
+ />
+ <InputNumber
+ id={field.name}
+ value={field.state.value}
+ onChange={value => field.handleChange(value)}
+ onBlur={field.handleBlur}
+ {...inputProps}
+ />
+ </div>
+ )
+}
+
+export default NumberInputField
diff --git a/app/components/base/form/components/field/options.tsx b/app/components/base/form/components/field/options.tsx
new file mode 100644
index 0000000..9ff71e5
--- /dev/null
+++ b/app/components/base/form/components/field/options.tsx
@@ -0,0 +1,34 @@
+import cn from '@/utils/classnames'
+import { useFieldContext } from '../..'
+import Label from '../label'
+import ConfigSelect from '@/app/components/app/configuration/config-var/config-select'
+
+type OptionsFieldProps = {
+ label: string;
+ className?: string;
+ labelClassName?: string;
+}
+
+const OptionsField = ({
+ label,
+ className,
+ labelClassName,
+}: OptionsFieldProps) => {
+ const field = useFieldContext<string[]>()
+
+ return (
+ <div className={cn('flex flex-col gap-y-0.5', className)}>
+ <Label
+ htmlFor={field.name}
+ label={label}
+ className={labelClassName}
+ />
+ <ConfigSelect
+ options={field.state.value}
+ onChange={value => field.handleChange(value)}
+ />
+ </div>
+ )
+}
+
+export default OptionsField
diff --git a/app/components/base/form/components/field/select.tsx b/app/components/base/form/components/field/select.tsx
new file mode 100644
index 0000000..95af3c0
--- /dev/null
+++ b/app/components/base/form/components/field/select.tsx
@@ -0,0 +1,51 @@
+import cn from '@/utils/classnames'
+import { useFieldContext } from '../..'
+import PureSelect from '../../../select/pure'
+import Label from '../label'
+
+type SelectOption = {
+ value: string
+ label: string
+}
+
+type SelectFieldProps = {
+ label: string
+ options: SelectOption[]
+ isRequired?: boolean
+ showOptional?: boolean
+ tooltip?: string
+ className?: string
+ labelClassName?: string
+}
+
+const SelectField = ({
+ label,
+ options,
+ isRequired,
+ showOptional,
+ tooltip,
+ className,
+ labelClassName,
+}: SelectFieldProps) => {
+ const field = useFieldContext<string>()
+
+ return (
+ <div className={cn('flex flex-col gap-y-0.5', className)}>
+ <Label
+ htmlFor={field.name}
+ label={label}
+ isRequired={isRequired}
+ showOptional={showOptional}
+ tooltip={tooltip}
+ className={labelClassName}
+ />
+ <PureSelect
+ value={field.state.value}
+ options={options}
+ onChange={value => field.handleChange(value)}
+ />
+ </div>
+ )
+}
+
+export default SelectField
diff --git a/app/components/base/form/components/field/text.tsx b/app/components/base/form/components/field/text.tsx
new file mode 100644
index 0000000..b209029
--- /dev/null
+++ b/app/components/base/form/components/field/text.tsx
@@ -0,0 +1,48 @@
+import React from 'react'
+import { useFieldContext } from '../..'
+import Input, { type InputProps } from '../../../input'
+import Label from '../label'
+import cn from '@/utils/classnames'
+
+type TextFieldProps = {
+ label: string
+ isRequired?: boolean
+ showOptional?: boolean
+ tooltip?: string
+ className?: string
+ labelClassName?: string
+} & Omit<InputProps, 'className' | 'onChange' | 'onBlur' | 'value' | 'id'>
+
+const TextField = ({
+ label,
+ isRequired,
+ showOptional,
+ tooltip,
+ className,
+ labelClassName,
+ ...inputProps
+}: TextFieldProps) => {
+ const field = useFieldContext<string>()
+
+ return (
+ <div className={cn('flex flex-col gap-y-0.5', className)}>
+ <Label
+ htmlFor={field.name}
+ label={label}
+ isRequired={isRequired}
+ showOptional={showOptional}
+ tooltip={tooltip}
+ className={labelClassName}
+ />
+ <Input
+ id={field.name}
+ value={field.state.value}
+ onChange={e => field.handleChange(e.target.value)}
+ onBlur={field.handleBlur}
+ {...inputProps}
+ />
+ </div>
+ )
+}
+
+export default TextField
diff --git a/app/components/base/form/components/form/submit-button.tsx b/app/components/base/form/components/form/submit-button.tsx
new file mode 100644
index 0000000..494d19b
--- /dev/null
+++ b/app/components/base/form/components/form/submit-button.tsx
@@ -0,0 +1,25 @@
+import { useStore } from '@tanstack/react-form'
+import { useFormContext } from '../..'
+import Button, { type ButtonProps } from '../../../button'
+
+type SubmitButtonProps = Omit<ButtonProps, 'disabled' | 'loading' | 'onClick'>
+
+const SubmitButton = ({ ...buttonProps }: SubmitButtonProps) => {
+ const form = useFormContext()
+
+ const [isSubmitting, canSubmit] = useStore(form.store, state => [
+ state.isSubmitting,
+ state.canSubmit,
+ ])
+
+ return (
+ <Button
+ disabled={isSubmitting || !canSubmit}
+ loading={isSubmitting}
+ onClick={() => form.handleSubmit()}
+ {...buttonProps}
+ />
+ )
+}
+
+export default SubmitButton
diff --git a/app/components/base/form/components/label.spec.tsx b/app/components/base/form/components/label.spec.tsx
new file mode 100644
index 0000000..b2dc98a
--- /dev/null
+++ b/app/components/base/form/components/label.spec.tsx
@@ -0,0 +1,53 @@
+import { fireEvent, render, screen } from '@testing-library/react'
+import Label from './label'
+
+jest.mock('react-i18next', () => ({
+ useTranslation: () => ({
+ t: (key: string) => key,
+ }),
+}))
+
+describe('Label Component', () => {
+ const defaultProps = {
+ htmlFor: 'test-input',
+ label: 'Test Label',
+ }
+
+ it('renders basic label correctly', () => {
+ render(<Label {...defaultProps} />)
+ const label = screen.getByTestId('label')
+ expect(label).toBeInTheDocument()
+ expect(label).toHaveAttribute('for', 'test-input')
+ })
+
+ it('shows optional text when showOptional is true', () => {
+ render(<Label {...defaultProps} showOptional />)
+ expect(screen.getByText('common.label.optional')).toBeInTheDocument()
+ })
+
+ it('shows required asterisk when isRequired is true', () => {
+ render(<Label {...defaultProps} isRequired />)
+ expect(screen.getByText('*')).toBeInTheDocument()
+ })
+
+ it('renders tooltip when tooltip prop is provided', () => {
+ const tooltipText = 'Test Tooltip'
+ render(<Label {...defaultProps} tooltip={tooltipText} />)
+ const trigger = screen.getByTestId('test-input-tooltip')
+ fireEvent.mouseEnter(trigger)
+ expect(screen.getByText(tooltipText)).toBeInTheDocument()
+ })
+
+ it('applies custom className when provided', () => {
+ const customClass = 'custom-label'
+ render(<Label {...defaultProps} className={customClass} />)
+ const label = screen.getByTestId('label')
+ expect(label).toHaveClass(customClass)
+ })
+
+ it('does not show optional text and required asterisk simultaneously', () => {
+ render(<Label {...defaultProps} isRequired showOptional />)
+ expect(screen.queryByText('common.label.optional')).not.toBeInTheDocument()
+ expect(screen.getByText('*')).toBeInTheDocument()
+ })
+})
diff --git a/app/components/base/form/components/label.tsx b/app/components/base/form/components/label.tsx
new file mode 100644
index 0000000..4b104c9
--- /dev/null
+++ b/app/components/base/form/components/label.tsx
@@ -0,0 +1,48 @@
+import cn from '@/utils/classnames'
+import Tooltip from '../../tooltip'
+import { useTranslation } from 'react-i18next'
+
+export type LabelProps = {
+ htmlFor: string
+ label: string
+ isRequired?: boolean
+ showOptional?: boolean
+ tooltip?: string
+ className?: string
+}
+
+const Label = ({
+ htmlFor,
+ label,
+ isRequired,
+ showOptional,
+ tooltip,
+ className,
+}: LabelProps) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex h-6 items-center'>
+ <label
+ data-testid='label'
+ htmlFor={htmlFor}
+ className={cn('system-sm-medium text-text-secondary', className)}
+ >
+ {label}
+ </label>
+ {!isRequired && showOptional && <div className='system-xs-regular ml-1 text-text-tertiary'>{t('common.label.optional')}</div>}
+ {isRequired && <div className='system-xs-regular ml-1 text-text-destructive-secondary'>*</div>}
+ {tooltip && (
+ <Tooltip
+ popupContent={
+ <div className='w-[200px]'>{tooltip}</div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4'
+ triggerTestId={`${htmlFor}-tooltip`}
+ />
+ )}
+ </div>
+ )
+}
+
+export default Label
diff --git a/app/components/base/form/form-scenarios/demo/contact-fields.tsx b/app/components/base/form/form-scenarios/demo/contact-fields.tsx
new file mode 100644
index 0000000..9ba664f
--- /dev/null
+++ b/app/components/base/form/form-scenarios/demo/contact-fields.tsx
@@ -0,0 +1,35 @@
+import { withForm } from '../..'
+import { demoFormOpts } from './shared-options'
+import { ContactMethods } from './types'
+
+const ContactFields = withForm({
+ ...demoFormOpts,
+ render: ({ form }) => {
+ return (
+ <div className='my-2'>
+ <h3 className='title-lg-bold text-text-primary'>Contacts</h3>
+ <div className='flex flex-col gap-4'>
+ <form.AppField
+ name='contact.email'
+ children={field => <field.TextField label='Email' />}
+ />
+ <form.AppField
+ name='contact.phone'
+ children={field => <field.TextField label='Phone' />}
+ />
+ <form.AppField
+ name='contact.preferredContactMethod'
+ children={field => (
+ <field.SelectField
+ label='Preferred Contact Method'
+ options={ContactMethods}
+ />
+ )}
+ />
+ </div>
+ </div>
+ )
+ },
+})
+
+export default ContactFields
diff --git a/app/components/base/form/form-scenarios/demo/index.tsx b/app/components/base/form/form-scenarios/demo/index.tsx
new file mode 100644
index 0000000..f08edee
--- /dev/null
+++ b/app/components/base/form/form-scenarios/demo/index.tsx
@@ -0,0 +1,68 @@
+import { useStore } from '@tanstack/react-form'
+import { useAppForm } from '../..'
+import ContactFields from './contact-fields'
+import { demoFormOpts } from './shared-options'
+import { UserSchema } from './types'
+
+const DemoForm = () => {
+ const form = useAppForm({
+ ...demoFormOpts,
+ validators: {
+ onSubmit: ({ value }) => {
+ // Validate the entire form
+ const result = UserSchema.safeParse(value)
+ if (!result.success) {
+ const issues = result.error.issues
+ console.log('Validation errors:', issues)
+ return issues[0].message
+ }
+ return undefined
+ },
+ },
+ onSubmit: ({ value }) => {
+ console.log('Form submitted:', value)
+ },
+ })
+
+const name = useStore(form.store, state => state.values.name)
+
+ return (
+ <form
+ className='flex w-[400px] flex-col gap-4'
+ onSubmit={(e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ form.handleSubmit()
+ }}
+ >
+ <form.AppField
+ name='name'
+ children={field => (
+ <field.TextField label='Name' />
+ )}
+ />
+ <form.AppField
+ name='surname'
+ children={field => (
+ <field.TextField label='Surname' />
+ )}
+ />
+ <form.AppField
+ name='isAcceptingTerms'
+ children={field => (
+ <field.CheckboxField label='I accept the terms and conditions.' />
+ )}
+ />
+ {
+ !!name && (
+ <ContactFields form={form} />
+ )
+ }
+ <form.AppForm>
+ <form.SubmitButton>Submit</form.SubmitButton>
+ </form.AppForm>
+ </form>
+ )
+}
+
+export default DemoForm
diff --git a/app/components/base/form/form-scenarios/demo/shared-options.tsx b/app/components/base/form/form-scenarios/demo/shared-options.tsx
new file mode 100644
index 0000000..8b216c8
--- /dev/null
+++ b/app/components/base/form/form-scenarios/demo/shared-options.tsx
@@ -0,0 +1,14 @@
+import { formOptions } from '@tanstack/react-form'
+
+export const demoFormOpts = formOptions({
+ defaultValues: {
+ name: '',
+ surname: '',
+ isAcceptingTerms: false,
+ contact: {
+ email: '',
+ phone: '',
+ preferredContactMethod: 'email',
+ },
+ },
+})
diff --git a/app/components/base/form/form-scenarios/demo/types.ts b/app/components/base/form/form-scenarios/demo/types.ts
new file mode 100644
index 0000000..c4e626e
--- /dev/null
+++ b/app/components/base/form/form-scenarios/demo/types.ts
@@ -0,0 +1,34 @@
+import { z } from 'zod'
+
+const ContactMethod = z.union([
+ z.literal('email'),
+ z.literal('phone'),
+ z.literal('whatsapp'),
+ z.literal('sms'),
+])
+
+export const ContactMethods = ContactMethod.options.map(({ value }) => ({
+ value,
+ label: value.charAt(0).toUpperCase() + value.slice(1),
+}))
+
+export const UserSchema = z.object({
+ name: z
+ .string()
+ .regex(/^[A-Z]/, 'Name must start with a capital letter')
+ .min(3, 'Name must be at least 3 characters long'),
+ surname: z
+ .string()
+ .min(3, 'Surname must be at least 3 characters long')
+ .regex(/^[A-Z]/, 'Surname must start with a capital letter'),
+ isAcceptingTerms: z.boolean().refine(val => val, {
+ message: 'You must accept the terms and conditions',
+ }),
+ contact: z.object({
+ email: z.string().email('Invalid email address'),
+ phone: z.string().optional(),
+ preferredContactMethod: ContactMethod,
+ }),
+})
+
+export type User = z.infer<typeof UserSchema>
diff --git a/app/components/base/form/index.tsx b/app/components/base/form/index.tsx
new file mode 100644
index 0000000..aeb482a
--- /dev/null
+++ b/app/components/base/form/index.tsx
@@ -0,0 +1,25 @@
+import { createFormHook, createFormHookContexts } from '@tanstack/react-form'
+import TextField from './components/field/text'
+import NumberInputField from './components/field/number-input'
+import CheckboxField from './components/field/checkbox'
+import SelectField from './components/field/select'
+import OptionsField from './components/field/options'
+import SubmitButton from './components/form/submit-button'
+
+export const { fieldContext, useFieldContext, formContext, useFormContext }
+ = createFormHookContexts()
+
+export const { useAppForm, withForm } = createFormHook({
+ fieldComponents: {
+ TextField,
+ NumberInputField,
+ CheckboxField,
+ SelectField,
+ OptionsField,
+ },
+ formComponents: {
+ SubmitButton,
+ },
+ fieldContext,
+ formContext,
+})
diff --git a/app/components/base/fullscreen-modal/index.tsx b/app/components/base/fullscreen-modal/index.tsx
new file mode 100644
index 0000000..209507a
--- /dev/null
+++ b/app/components/base/fullscreen-modal/index.tsx
@@ -0,0 +1,74 @@
+import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react'
+import { RiCloseLargeLine } from '@remixicon/react'
+import classNames from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+type IModal = {
+ className?: string
+ wrapperClassName?: string
+ open: boolean
+ onClose?: () => void
+ title?: React.ReactNode
+ description?: React.ReactNode
+ children?: React.ReactNode
+ closable?: boolean
+ overflowVisible?: boolean
+}
+
+export default function FullScreenModal({
+ className,
+ wrapperClassName,
+ open,
+ onClose = noop,
+ children,
+ closable = false,
+ overflowVisible = false,
+}: IModal) {
+ return (
+ <Transition show={open} appear>
+ <Dialog as="div" className={classNames('modal-dialog', wrapperClassName)} onClose={onClose}>
+ <TransitionChild>
+ <div className={classNames(
+ 'fixed inset-0 bg-background-overlay-backdrop backdrop-blur-[6px]',
+ 'duration-300 ease-in data-[closed]:opacity-0',
+ 'data-[enter]:opacity-100',
+ 'data-[leave]:opacity-0',
+ )} />
+ </TransitionChild>
+
+ <div
+ className="fixed inset-0 h-screen w-screen p-4"
+ onClick={(e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }}
+ >
+ <div className="relative h-full w-full rounded-2xl border border-effects-highlight bg-background-default-subtle">
+ <TransitionChild>
+ <DialogPanel className={classNames(
+ 'h-full',
+ overflowVisible ? 'overflow-visible' : 'overflow-hidden',
+ 'duration-100 ease-in data-[closed]:opacity-0 data-[closed]:scale-95',
+ 'data-[enter]:opacity-100 data-[enter]:scale-100',
+ 'data-[leave]:opacity-0 data-[enter]:scale-95',
+ className,
+ )}>
+ {closable
+ && <div
+ className='absolute right-3 top-3 z-50 flex h-9 w-9 cursor-pointer items-center justify-center
+ rounded-[10px] bg-components-button-tertiary-bg hover:bg-components-button-tertiary-bg-hover'
+ onClick={(e) => {
+ e.stopPropagation()
+ onClose()
+ }}>
+ <RiCloseLargeLine className='h-3.5 w-3.5 text-components-button-tertiary-text' />
+ </div>}
+ {children}
+ </DialogPanel>
+ </TransitionChild>
+ </div>
+ </div>
+ </Dialog>
+ </Transition>
+ )
+}
diff --git a/app/components/base/ga/index.tsx b/app/components/base/ga/index.tsx
new file mode 100644
index 0000000..7a95561
--- /dev/null
+++ b/app/components/base/ga/index.tsx
@@ -0,0 +1,60 @@
+import type { FC } from 'react'
+import React from 'react'
+import Script from 'next/script'
+import { type UnsafeUnwrappedHeaders, headers } from 'next/headers'
+import { IS_CE_EDITION } from '@/config'
+
+export enum GaType {
+ admin = 'admin',
+ webapp = 'webapp',
+}
+
+const gaIdMaps = {
+ [GaType.admin]: 'G-DM9497FN4V',
+ [GaType.webapp]: 'G-2MFWXK7WYT',
+}
+
+export type IGAProps = {
+ gaType: GaType
+}
+
+const GA: FC<IGAProps> = ({
+ gaType,
+}) => {
+ if (IS_CE_EDITION)
+ return null
+
+ const nonce = process.env.NODE_ENV === 'production' ? (headers() as unknown as UnsafeUnwrappedHeaders).get('x-nonce') : ''
+
+ return (
+ <>
+ <Script
+ strategy="beforeInteractive"
+ async
+ src={`https://www.googletagmanager.com/gtag/js?id=${gaIdMaps[gaType]}`}
+ nonce={nonce!}
+ ></Script>
+ <Script
+ id="ga-init"
+ dangerouslySetInnerHTML={{
+ __html: `
+window.dataLayer = window.dataLayer || [];
+function gtag(){dataLayer.push(arguments);}
+gtag('js', new Date());
+gtag('config', '${gaIdMaps[gaType]}');
+ `,
+ }}
+ nonce={nonce!}
+ >
+ </Script>
+ {/* Cookie banner */}
+ <Script
+ id="cookieyes"
+ src='https://cdn-cookieyes.com/client_data/2a645945fcae53f8e025a2b1/script.js'
+ nonce={nonce!}
+ ></Script>
+ </>
+
+ )
+}
+export default React.memo(GA)
diff --git a/app/components/base/grid-mask/Grid.svg b/app/components/base/grid-mask/Grid.svg
new file mode 100644
index 0000000..88cdeea
--- /dev/null
+++ b/app/components/base/grid-mask/Grid.svg
@@ -0,0 +1,2146 @@
+<svg width="1480" height="800" viewBox="0 0 1480 800" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.3">
+<rect x="-17.7148" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.7" x="342.285" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.5" x="990.285" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="24" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="24" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="24" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="48" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.7" x="582.285" y="48" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="48" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="48" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="72" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="72" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.5" x="102.285" y="96" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.7" x="270.285" y="96" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.7" x="606.285" y="96" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.5" x="822.285" y="96" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.7" x="1182.29" y="96" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="96" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="120" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="120" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.5" x="318.285" y="144" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="144" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.5" x="774.285" y="144" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="144" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="144" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="168" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.5" x="510.285" y="192" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="192" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="192" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="216" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="216" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="216" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="216" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.5" x="678.285" y="240" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="240" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="264" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.3" x="846.285" y="264" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="264" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="264" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="288" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="312" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="312" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="312" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="312" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="336" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="336" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="360" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="360" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect opacity="0.5" x="678.285" y="384" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="384" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="408" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="408" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="408" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="432" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="432" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="456" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="480" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="480" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="480" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="504" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="528" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="552" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="552" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="576" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="576" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="600" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="600" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="624" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="648" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="672" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="696" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="720" width="24" height="24" fill="#C8CEDA" fill-opacity="0.5" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="720" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="744" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="768" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="-17.7148" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="6.28516" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="30.2852" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="54.2852" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="78.2852" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="102.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="126.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="150.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="174.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="198.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="222.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="246.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="270.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="294.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="318.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="342.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="366.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="390.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="414.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="438.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="462.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="486.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="510.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="534.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="558.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="582.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="606.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="630.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="654.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="678.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="702.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="726.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="750.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="774.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="798.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="822.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="846.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="870.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="894.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="918.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="942.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="966.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="990.285" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1014.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1038.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1062.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1086.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1110.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1134.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1158.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1182.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1206.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1230.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1254.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1278.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1302.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1326.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1350.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1374.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1398.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1422.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1446.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+<rect x="1470.29" y="792" width="24" height="24" stroke="#101828" stroke-opacity="0.04"/>
+</g>
+</svg>
diff --git a/app/components/base/grid-mask/index.tsx b/app/components/base/grid-mask/index.tsx
new file mode 100644
index 0000000..6805c3d
--- /dev/null
+++ b/app/components/base/grid-mask/index.tsx
@@ -0,0 +1,26 @@
+import type { FC } from 'react'
+import Style from './style.module.css'
+import classNames from '@/utils/classnames'
+
+type GridMaskProps = {
+ children: React.ReactNode
+ wrapperClassName?: string
+ canvasClassName?: string
+ gradientClassName?: string
+}
+const GridMask: FC<GridMaskProps> = ({
+ children,
+ wrapperClassName,
+ canvasClassName,
+ gradientClassName,
+}) => {
+ return (
+ <div className={classNames('relative bg-saas-background', wrapperClassName)}>
+ <div className={classNames('absolute inset-0 w-full h-full z-0 opacity-70', canvasClassName, Style.gridBg)} />
+ <div className={classNames('absolute w-full h-full z-[1] bg-grid-mask-background rounded-lg', gradientClassName)} />
+ <div className='relative z-[2]'>{children}</div>
+ </div>
+ )
+}
+
+export default GridMask
diff --git a/app/components/base/grid-mask/style.module.css b/app/components/base/grid-mask/style.module.css
new file mode 100644
index 0000000..e051271
--- /dev/null
+++ b/app/components/base/grid-mask/style.module.css
@@ -0,0 +1,5 @@
+.gridBg{
+ background-image: url(./Grid.svg);
+ background-repeat: repeat;
+ background-position: 0 0;
+}
diff --git a/app/components/base/icons/IconBase.spec.tsx b/app/components/base/icons/IconBase.spec.tsx
new file mode 100644
index 0000000..e440040
--- /dev/null
+++ b/app/components/base/icons/IconBase.spec.tsx
@@ -0,0 +1,67 @@
+import { fireEvent, render, screen } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import React from 'react'
+import type { IconData } from './IconBase'
+import IconBase from './IconBase'
+import * as utils from './utils'
+
+// Mock the utils module
+jest.mock('./utils', () => ({
+ generate: jest.fn((icon, key, props) => (
+ <svg
+ data-testid="mock-svg"
+ key={key}
+ {...props}
+ >
+ mocked svg content
+ </svg>
+ )),
+}))
+
+describe('IconBase Component', () => {
+ const mockData: IconData = {
+ name: 'test-icon',
+ icon: { name: 'svg', attributes: {}, children: [] },
+ }
+
+ beforeEach(() => {
+ jest.clearAllMocks()
+ })
+
+ it('renders properly with required props', () => {
+ render(<IconBase data={mockData} />)
+ const svg = screen.getByTestId('mock-svg')
+ expect(svg).toBeInTheDocument()
+ expect(svg).toHaveAttribute('data-icon', mockData.name)
+ expect(svg).toHaveAttribute('aria-hidden', 'true')
+ })
+
+ it('passes className to the generated SVG', () => {
+ render(<IconBase data={mockData} className="custom-class" />)
+ const svg = screen.getByTestId('mock-svg')
+ expect(svg).toHaveAttribute('class', 'custom-class')
+ expect(utils.generate).toHaveBeenCalledWith(
+ mockData.icon,
+ 'svg-test-icon',
+ expect.objectContaining({ className: 'custom-class' }),
+ )
+ })
+
+ it('handles onClick events', () => {
+ const handleClick = jest.fn()
+ render(<IconBase data={mockData} onClick={handleClick} />)
+ const svg = screen.getByTestId('mock-svg')
+ fireEvent.click(svg)
+ expect(handleClick).toHaveBeenCalledTimes(1)
+ })
+
+ it('applies custom styles', () => {
+ const customStyle = { color: 'red', fontSize: '24px' }
+ render(<IconBase data={mockData} style={customStyle} />)
+ expect(utils.generate).toHaveBeenCalledWith(
+ mockData.icon,
+ 'svg-test-icon',
+ expect.objectContaining({ style: customStyle }),
+ )
+ })
+})
diff --git a/app/components/base/icons/IconBase.tsx b/app/components/base/icons/IconBase.tsx
new file mode 100644
index 0000000..134c948
--- /dev/null
+++ b/app/components/base/icons/IconBase.tsx
@@ -0,0 +1,39 @@
+import { generate } from './utils'
+import type { AbstractNode } from './utils'
+
+export type IconData = {
+ name: string
+ icon: AbstractNode
+}
+
+export type IconBaseProps = {
+ data: IconData
+ className?: string
+ onClick?: React.MouseEventHandler<SVGElement>
+ style?: React.CSSProperties
+}
+
+const IconBase = (
+ {
+ ref,
+ ...props
+ }: IconBaseProps & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => {
+ const { data, className, onClick, style, ...restProps } = props
+
+ return generate(data.icon, `svg-${data.name}`, {
+ className,
+ onClick,
+ style,
+ 'data-icon': data.name,
+ 'aria-hidden': 'true',
+ ...restProps,
+ 'ref': ref,
+ })
+}
+
+IconBase.displayName = 'IconBase'
+
+export default IconBase
diff --git a/app/components/base/icons/assets/image/llm/baichuan-text-cn.png b/app/components/base/icons/assets/image/llm/baichuan-text-cn.png
new file mode 100644
index 0000000..9346b69
--- /dev/null
+++ b/app/components/base/icons/assets/image/llm/baichuan-text-cn.png
Binary files differ
diff --git a/app/components/base/icons/assets/image/llm/minimax-text.png b/app/components/base/icons/assets/image/llm/minimax-text.png
new file mode 100644
index 0000000..5066b52
--- /dev/null
+++ b/app/components/base/icons/assets/image/llm/minimax-text.png
Binary files differ
diff --git a/app/components/base/icons/assets/image/llm/minimax.png b/app/components/base/icons/assets/image/llm/minimax.png
new file mode 100644
index 0000000..30c71e9
--- /dev/null
+++ b/app/components/base/icons/assets/image/llm/minimax.png
Binary files differ
diff --git a/app/components/base/icons/assets/image/llm/tongyi-text-cn.png b/app/components/base/icons/assets/image/llm/tongyi-text-cn.png
new file mode 100644
index 0000000..bd8f276
--- /dev/null
+++ b/app/components/base/icons/assets/image/llm/tongyi-text-cn.png
Binary files differ
diff --git a/app/components/base/icons/assets/image/llm/tongyi-text.png b/app/components/base/icons/assets/image/llm/tongyi-text.png
new file mode 100644
index 0000000..94de011
--- /dev/null
+++ b/app/components/base/icons/assets/image/llm/tongyi-text.png
Binary files differ
diff --git a/app/components/base/icons/assets/image/llm/tongyi.png b/app/components/base/icons/assets/image/llm/tongyi.png
new file mode 100644
index 0000000..c1aff40
--- /dev/null
+++ b/app/components/base/icons/assets/image/llm/tongyi.png
Binary files differ
diff --git a/app/components/base/icons/assets/image/llm/wxyy-text-cn.png b/app/components/base/icons/assets/image/llm/wxyy-text-cn.png
new file mode 100644
index 0000000..669d3c7
--- /dev/null
+++ b/app/components/base/icons/assets/image/llm/wxyy-text-cn.png
Binary files differ
diff --git a/app/components/base/icons/assets/image/llm/wxyy-text.png b/app/components/base/icons/assets/image/llm/wxyy-text.png
new file mode 100644
index 0000000..fb50487
--- /dev/null
+++ b/app/components/base/icons/assets/image/llm/wxyy-text.png
Binary files differ
diff --git a/app/components/base/icons/assets/image/llm/wxyy.png b/app/components/base/icons/assets/image/llm/wxyy.png
new file mode 100644
index 0000000..9239199
--- /dev/null
+++ b/app/components/base/icons/assets/image/llm/wxyy.png
Binary files differ
diff --git a/app/components/base/icons/assets/public/avatar/robot.svg b/app/components/base/icons/assets/public/avatar/robot.svg
new file mode 100644
index 0000000..55b70bb
--- /dev/null
+++ b/app/components/base/icons/assets/public/avatar/robot.svg
@@ -0,0 +1,11 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<rect width="24" height="24" rx="12" fill="#D5F5F6"/>
+<rect x="0.25" y="0.25" width="23.5" height="23.5" rx="11.75" stroke="black" stroke-opacity="0.05" stroke-width="0.5"/>
+<path d="M4 20.12H20V4.12H4V20.12Z" fill="url(#pattern0)"/>
+<defs>
+<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
+<use xlink:href="#image0_13843_72627" transform="scale(0.00625)"/>
+</pattern>
+<image id="image0_13843_72627" width="160" height="160" xlink:href="data:image/png;base64,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"/>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/avatar/user.svg b/app/components/base/icons/assets/public/avatar/user.svg
new file mode 100644
index 0000000..1608b0a
--- /dev/null
+++ b/app/components/base/icons/assets/public/avatar/user.svg
@@ -0,0 +1,12 @@
+<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5968_39205)">
+<rect width="512" height="512" rx="256" fill="#B2DDFF"/>
+<circle opacity="0.68" cx="256" cy="196" r="84" fill="white"/>
+<ellipse opacity="0.68" cx="256" cy="583.5" rx="266" ry="274.5" fill="white"/>
+</g>
+<defs>
+<clipPath id="clip0_5968_39205">
+<rect width="512" height="512" rx="256" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/ar-cube-1.svg b/app/components/base/icons/assets/public/billing/ar-cube-1.svg
new file mode 100644
index 0000000..2022ecd
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/ar-cube-1.svg
@@ -0,0 +1,3 @@
+<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.0002 14V23.9166M14.0002 14L5.25 9.07806M14.0002 14L22.4731 9.2338M23.625 9.95052V18.0493C23.625 18.8924 23.1703 19.6697 22.4356 20.0831L15.1439 24.1846C14.4336 24.5842 13.5663 24.5842 12.8561 24.1846L5.56439 20.0831C4.82967 19.6697 4.375 18.8924 4.375 18.0493V9.95052C4.375 9.10756 4.82967 8.33012 5.56439 7.91684L12.8561 3.81529C13.5663 3.41574 14.4336 3.41574 15.1439 3.81529L22.4356 7.91684C23.1703 8.33012 23.625 9.10756 23.625 9.95052Z" stroke="#101828" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/asterisk.svg b/app/components/base/icons/assets/public/billing/asterisk.svg
new file mode 100644
index 0000000..1ee4059
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/asterisk.svg
@@ -0,0 +1,5 @@
+<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="asterisk">
+<path id="Vector" d="M14.0033 3.20837V24.7917M4.65747 8.60421L23.3492 19.3959M4.6586 19.3959L23.3503 8.60421" stroke="#101828" stroke-width="1.5" stroke-linecap="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/aws-marketplace.svg b/app/components/base/icons/assets/public/billing/aws-marketplace.svg
new file mode 100644
index 0000000..02fb327
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/aws-marketplace.svg
@@ -0,0 +1,23 @@
+<svg width="126" height="24" viewBox="0 0 126 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_394_42756)">
+<path d="M47.3963 14.5593V8.71609C47.3963 8.14631 47.2869 7.73413 47.0682 7.45531C46.8494 7.1886 46.5091 7.04313 46.0473 7.04313C45.2209 7.04313 44.3824 7.29771 43.5438 7.80687C43.556 7.89173 43.556 7.97659 43.556 8.06145C43.556 8.14631 43.556 8.2433 43.556 8.32816V14.5351H41.8667V8.69184C41.8667 8.12207 41.7573 7.70989 41.5386 7.43106C41.3198 7.16436 40.9795 7.01888 40.5177 7.01888C39.6549 7.01888 38.8284 7.27346 38.0385 7.7705V14.523H36.3492V5.9157H37.759L37.9291 6.77642C39.0229 6.0248 40.0802 5.66112 41.1132 5.66112C42.1705 5.66112 42.8875 6.06117 43.2521 6.86128C44.3702 6.06117 45.5004 5.66112 46.6185 5.66112C47.3963 5.66112 48.004 5.87933 48.4172 6.32788C48.8425 6.7643 49.0491 7.39469 49.0491 8.20693V14.523H47.3963V14.5593Z" fill="white"/>
+<path d="M56.0492 14.5593L55.9156 13.6744C55.5023 14.0259 55.0527 14.2926 54.5666 14.4866C54.0683 14.6806 53.5822 14.7775 53.0961 14.7775C52.294 14.7775 51.6498 14.5472 51.1637 14.0865C50.6776 13.6259 50.4346 13.0197 50.4346 12.2439C50.4346 11.4195 50.7262 10.7527 51.3217 10.2678C51.9172 9.77078 52.7072 9.52832 53.7037 9.52832C54.36 9.52832 55.077 9.62531 55.8426 9.81927V8.70397C55.8426 8.09782 55.709 7.6614 55.4294 7.41894C55.1499 7.16436 54.6759 7.04313 54.0075 7.04313C53.0474 7.04313 52.0509 7.21285 51.0179 7.56441V6.37637C51.4311 6.15816 51.9294 6.00056 52.5127 5.87933C53.1082 5.7581 53.7037 5.69749 54.2992 5.69749C55.3808 5.69749 56.1708 5.9157 56.6812 6.36425C57.1916 6.81279 57.4468 7.49168 57.4468 8.41302V14.5593H56.0492ZM53.4971 13.5046C54.2627 13.5046 55.0527 13.2137 55.8426 12.6439V10.9103C55.2471 10.7649 54.6516 10.6921 54.044 10.6921C52.7679 10.6921 52.1238 11.1892 52.1238 12.1711C52.1238 12.5954 52.2453 12.9349 52.4763 13.1652C52.7193 13.3834 53.0596 13.5046 53.4971 13.5046Z" fill="white"/>
+<path d="M59.3792 14.5593V5.95207H60.7889L60.9712 7.22497C61.2872 6.88553 61.5788 6.61883 61.8584 6.43698C62.1379 6.25514 62.4053 6.10966 62.6969 6.0248C62.9764 5.93994 63.2924 5.89145 63.6206 5.89145C63.8393 5.89145 64.0702 5.90357 64.3133 5.93994V7.46743C63.9487 7.41894 63.6449 7.39469 63.3896 7.39469C62.4782 7.39469 61.7004 7.6614 61.0563 8.20693V14.5593H59.3792Z" fill="white"/>
+<path d="M65.3584 14.5593V2H67.0477V9.71017L70.7057 5.96419H72.7596L68.6762 10.0496L73.027 14.5593H70.9002L67.0355 10.486V14.5593H65.3584Z" fill="white"/>
+<path d="M74.5704 10.6194C74.5947 11.5892 74.8378 12.3166 75.2996 12.7773C75.7614 13.2379 76.4663 13.4683 77.4385 13.4683C78.3378 13.4683 79.2493 13.2985 80.1729 12.947V14.1472C79.3587 14.5836 78.3621 14.8139 77.1833 14.8139C75.7857 14.8139 74.7284 14.426 74.0235 13.6622C73.3065 12.8985 72.954 11.7589 72.954 10.2557C72.954 8.81307 73.3065 7.69776 74.0235 6.90978C74.7405 6.12179 75.7371 5.70961 77.0131 5.70961C78.0948 5.70961 78.9212 6.01268 79.4924 6.61883C80.0757 7.22497 80.3552 8.0857 80.3552 9.18888C80.3552 9.72229 80.3066 10.2072 80.2215 10.6315H74.5704V10.6194ZM76.9159 6.97039C76.1989 6.97039 75.6399 7.1886 75.251 7.60078C74.8499 8.02508 74.6312 8.65547 74.5704 9.49195H78.8118C78.824 9.40709 78.824 9.2495 78.824 9.05553C78.824 8.36452 78.666 7.84324 78.3379 7.49168C78.0219 7.15223 77.5479 6.97039 76.9159 6.97039Z" fill="white"/>
+<path d="M86.9421 14.3532C86.3831 14.5715 85.7511 14.6806 85.0584 14.6806C83.4421 14.6806 82.64 13.8804 82.64 12.2681V7.27346H81.0722V6.1824L82.6886 5.97631L82.9438 3.52749H84.3171V5.93994H86.8692V7.26134H84.3171V12.1832C84.3171 12.6075 84.4143 12.8985 84.5966 13.0682C84.7789 13.2379 85.107 13.3228 85.5567 13.3228C86.0185 13.3228 86.4803 13.2622 86.93 13.1531V14.3532H86.9421Z" fill="white"/>
+<path d="M88.0967 5.95207H89.5064L89.6644 6.83704C90.5273 6.0733 91.4874 5.69749 92.5447 5.69749C93.6506 5.69749 94.5135 6.09754 95.1454 6.89765C95.7774 7.69776 96.0933 8.7767 96.0933 10.1466C96.0933 11.5407 95.7531 12.656 95.0846 13.4925C94.4162 14.329 93.5291 14.7533 92.411 14.7533C91.3901 14.7533 90.5151 14.4139 89.7738 13.7471V18.0628H88.0967V5.95207ZM92.0585 7.05525C91.2564 7.05525 90.4908 7.30983 89.7738 7.83112V12.5712C90.5151 13.1167 91.2564 13.3834 92.0221 13.3834C93.5898 13.3834 94.3676 12.3287 94.3676 10.2315C94.3676 9.15251 94.1732 8.36453 93.7964 7.84324C93.4318 7.32196 92.8485 7.05525 92.0585 7.05525Z" fill="white"/>
+<path d="M100.711 14.4381C100.335 14.5715 99.9337 14.6442 99.484 14.6442C98.8885 14.6442 98.4267 14.4745 98.1107 14.1229C97.7948 13.7835 97.6368 13.2864 97.6368 12.6439V2H99.326V12.5348C99.326 12.7894 99.3746 12.9834 99.484 13.1046C99.5934 13.2258 99.7757 13.2864 100.019 13.2864C100.25 13.2864 100.481 13.2743 100.711 13.2379V14.4381Z" fill="white"/>
+<path d="M107.225 14.5593L107.092 13.6744C106.679 14.0259 106.229 14.2926 105.743 14.4866C105.245 14.6806 104.758 14.7775 104.272 14.7775C103.47 14.7775 102.826 14.5472 102.34 14.0865C101.854 13.6259 101.611 13.0197 101.611 12.2439C101.611 11.4195 101.902 10.7527 102.498 10.2678C103.093 9.77078 103.883 9.52832 104.88 9.52832C105.536 9.52832 106.253 9.62531 107.019 9.81927V8.70397C107.019 8.09782 106.885 7.6614 106.606 7.41894C106.326 7.16436 105.852 7.04313 105.184 7.04313C104.224 7.04313 103.227 7.21285 102.194 7.56441V6.37637C102.607 6.15816 103.106 6.00056 103.689 5.87933C104.284 5.7581 104.88 5.69749 105.475 5.69749C106.557 5.69749 107.347 5.9157 107.857 6.36425C108.368 6.81279 108.623 7.49168 108.623 8.41302V14.5593H107.225ZM104.673 13.5046C105.439 13.5046 106.229 13.2137 107.019 12.6439V10.9103C106.423 10.7649 105.828 10.6921 105.22 10.6921C103.944 10.6921 103.3 11.1892 103.3 12.1711C103.3 12.5954 103.422 12.9349 103.652 13.1652C103.896 13.3834 104.236 13.5046 104.673 13.5046Z" fill="white"/>
+<path d="M116.571 14.232C115.915 14.5715 115.149 14.7412 114.286 14.7412C112.95 14.7412 111.929 14.3532 111.212 13.5895C110.507 12.8258 110.142 11.7226 110.142 10.2678C110.142 8.82519 110.507 7.72201 111.236 6.93402C111.965 6.14603 112.998 5.7581 114.335 5.7581C115.101 5.7581 115.805 5.9157 116.474 6.23089V7.43106C115.83 7.22497 115.198 7.12799 114.566 7.12799C113.618 7.12799 112.925 7.37045 112.512 7.85536C112.087 8.34028 111.88 9.10402 111.88 10.1587V10.3769C111.88 11.4074 112.099 12.159 112.512 12.6439C112.937 13.1288 113.606 13.3713 114.529 13.3713C115.137 13.3713 115.805 13.2622 116.535 13.0318V14.232H116.571Z" fill="white"/>
+<path d="M118.965 10.6194C118.99 11.5892 119.233 12.3166 119.694 12.7773C120.156 13.2379 120.861 13.4683 121.833 13.4683C122.733 13.4683 123.644 13.2985 124.568 12.947V14.1472C123.754 14.5836 122.757 14.8139 121.578 14.8139C120.181 14.8139 119.123 14.426 118.418 13.6622C117.701 12.8985 117.349 11.7589 117.349 10.2557C117.349 8.81307 117.701 7.69776 118.418 6.90978C119.135 6.12179 120.132 5.70961 121.408 5.70961C122.49 5.70961 123.316 6.01268 123.887 6.61883C124.471 7.22497 124.75 8.0857 124.75 9.18888C124.75 9.72229 124.701 10.2072 124.616 10.6315H118.965V10.6194ZM121.311 6.97039C120.594 6.97039 120.035 7.1886 119.646 7.60078C119.245 8.02508 119.026 8.65547 118.965 9.49195H123.207C123.219 9.40709 123.219 9.2495 123.219 9.05553C123.219 8.36452 123.061 7.84324 122.733 7.49168C122.405 7.15223 121.931 6.97039 121.311 6.97039Z" fill="white"/>
+<path d="M27.0036 14.8139C26.4567 14.8139 25.922 14.7533 25.3994 14.6321C24.8768 14.5108 24.4758 14.3775 24.1962 14.2199C24.0261 14.1229 23.9167 14.0259 23.8803 13.9289C23.8317 13.832 23.8195 13.735 23.8195 13.638V13.1167C23.8195 12.8985 23.8924 12.7894 24.0504 12.7894C24.1112 12.7894 24.1719 12.8015 24.2449 12.8258C24.3056 12.85 24.4029 12.8864 24.5122 12.9349C24.8647 13.0925 25.2414 13.2137 25.6546 13.2985C26.0678 13.3834 26.481 13.4198 26.8942 13.4198C27.5505 13.4198 28.0487 13.3107 28.4133 13.0803C28.7658 12.85 28.9481 12.5227 28.9481 12.0984C28.9481 11.8074 28.8508 11.565 28.6686 11.371C28.4862 11.177 28.1338 10.9952 27.6234 10.8255L26.1164 10.3527C25.3508 10.1102 24.8039 9.75866 24.4515 9.29799C24.1112 8.83732 23.9289 8.34028 23.9289 7.79475C23.9289 7.35832 24.0261 6.97039 24.2084 6.64307C24.3907 6.31575 24.6459 6.0248 24.9497 5.79447C25.2536 5.56413 25.6182 5.38229 26.0313 5.26106C26.4446 5.13983 26.8821 5.07922 27.3439 5.07922C27.5748 5.07922 27.8057 5.09134 28.0487 5.12771C28.2797 5.16408 28.5106 5.20045 28.7172 5.24894C28.9238 5.29743 29.1304 5.34592 29.3127 5.40654C29.495 5.46715 29.6408 5.52777 29.7502 5.58838C29.896 5.67324 29.9932 5.7581 30.054 5.84296C30.1148 5.92782 30.1391 6.03693 30.1391 6.1824V6.66732C30.1391 6.88553 30.0661 6.99464 29.9082 6.99464C29.8231 6.99464 29.6894 6.95827 29.5071 6.87341C28.9116 6.6067 28.2432 6.47335 27.514 6.47335C26.9185 6.47335 26.4567 6.57033 26.1286 6.7643C25.8004 6.95827 25.6425 7.26134 25.6425 7.68564C25.6425 7.97659 25.7397 8.21905 25.9463 8.42514C26.1529 8.61911 26.5296 8.81307 27.0887 8.99492L28.5592 9.46771C29.3127 9.71017 29.8474 10.0375 30.1634 10.4618C30.4793 10.8861 30.6495 11.371 30.6495 11.9165C30.6495 12.3651 30.5644 12.7651 30.3821 13.1167C30.1998 13.4683 29.9446 13.7835 29.6286 14.038C29.3127 14.2926 28.9238 14.4866 28.4741 14.6199C28.0244 14.7412 27.5383 14.8139 27.0036 14.8139ZM13.6718 14.5351C13.4895 14.5351 13.3558 14.4987 13.2707 14.4381C13.1856 14.3775 13.1127 14.232 13.052 14.0259L10.6214 6.01268C10.5606 5.80659 10.5363 5.67324 10.5363 5.6005C10.5363 5.43078 10.6214 5.34592 10.7915 5.34592H11.8124C12.0068 5.34592 12.1405 5.38229 12.2256 5.4429C12.2985 5.50352 12.3714 5.64899 12.4322 5.85508L14.1822 12.7045L15.7742 5.85508C15.8228 5.64899 15.8836 5.51564 15.9687 5.4429C16.0538 5.38229 16.1874 5.34592 16.3819 5.34592H17.2204C17.4149 5.34592 17.5486 5.38229 17.6336 5.4429C17.7187 5.50352 17.7795 5.64899 17.8281 5.85508L19.4687 12.8015L21.2674 5.85508C21.3281 5.64899 21.4011 5.51564 21.474 5.4429C21.5469 5.38229 21.6927 5.34592 21.8872 5.34592H22.8473C23.0174 5.34592 23.1025 5.43078 23.1025 5.6005C23.1025 5.64899 23.0903 5.69749 23.0903 5.7581C23.0781 5.81871 23.0538 5.90357 23.0174 6.01268L20.5138 14.0259C20.4531 14.232 20.3802 14.3654 20.2951 14.4381C20.21 14.4987 20.0763 14.5351 19.894 14.5351H19.0069C18.8124 14.5351 18.6787 14.4987 18.5937 14.426C18.5086 14.3532 18.4478 14.2199 18.3992 14.0138L16.7829 7.3462L15.1787 14.0138C15.1301 14.2199 15.0693 14.3532 14.9842 14.426C14.8992 14.4987 14.7655 14.5351 14.571 14.5351H13.6718ZM5.32267 13.4077C5.66296 13.4077 6.0154 13.347 6.39214 13.2137C6.76888 13.0925 7.09701 12.8621 7.37653 12.5469C7.54667 12.353 7.6682 12.1347 7.72897 11.8802C7.78973 11.6377 7.82619 11.3346 7.82619 10.9831V10.5466C7.52237 10.4739 7.20639 10.4133 6.86611 10.3769C6.53797 10.3406 6.20984 10.3163 5.89387 10.3163C5.20114 10.3163 4.69072 10.4497 4.35044 10.7285C4.01015 11.0073 3.84001 11.4074 3.84001 11.9287C3.84001 12.4136 3.96154 12.7773 4.21675 13.0197C4.49627 13.2864 4.84871 13.4077 5.32267 13.4077ZM9.53976 11.8317C9.53976 12.2196 9.57622 12.5227 9.66129 12.753C9.73421 12.9834 9.85574 13.2258 10.0016 13.4925C10.0502 13.5774 10.0745 13.6501 10.0745 13.7228C10.0745 13.832 10.0137 13.9289 9.88005 14.0259L9.21163 14.4866C9.11441 14.5472 9.02934 14.5715 8.94427 14.5715C8.83489 14.5715 8.73767 14.523 8.64044 14.426C8.49461 14.2805 8.37308 14.1229 8.2637 13.9411C8.16647 13.7713 8.0571 13.5653 7.94772 13.3349C7.13347 14.2926 6.11262 14.7654 4.89732 14.7654C4.0223 14.7654 3.32959 14.523 2.83131 14.0259C2.32089 13.5289 2.06567 12.8621 2.06567 12.0378C2.06567 11.1528 2.38165 10.4497 3.01361 9.90413C3.64556 9.37073 4.49627 9.0919 5.55358 9.0919C5.90602 9.0919 6.27061 9.11614 6.64735 9.17676C7.02409 9.22525 7.42514 9.31011 7.83834 9.40709V8.64335C7.83834 7.85536 7.68036 7.30983 7.35222 6.98251C7.02409 6.66732 6.46506 6.4976 5.66296 6.4976C5.29837 6.4976 4.92163 6.54609 4.54488 6.63095C4.16814 6.71581 3.7914 6.83704 3.42681 6.98251C3.25667 7.05525 3.13514 7.10374 3.06222 7.11587C2.9893 7.12799 2.94069 7.14011 2.90423 7.14011C2.75839 7.14011 2.68548 7.031 2.68548 6.81279V6.30363C2.68548 6.13391 2.70978 6.01268 2.75839 5.93994C2.80701 5.86721 2.90423 5.79447 3.05007 5.72173C3.41466 5.53989 3.85216 5.38229 4.36259 5.24894C4.87301 5.11559 5.40775 5.05497 5.97894 5.05497C7.21854 5.05497 8.11786 5.3338 8.70121 5.90357C9.2724 6.46123 9.56407 7.30983 9.56407 8.44938V11.8317H9.53976Z" fill="white"/>
+<path d="M28.9723 19.8449C25.5573 22.3665 20.5989 23.7 16.3332 23.7C10.3539 23.7 4.97014 21.4936 0.886731 17.8204C0.570753 17.5294 0.850272 17.1415 1.23917 17.3597C5.63855 19.9177 11.0709 21.4451 16.6978 21.4451C20.4895 21.4451 24.658 20.6572 28.4862 19.0448C29.0573 18.8023 29.5313 19.4327 28.9723 19.8449Z" fill="#FF9900"/>
+<path d="M30.3942 18.2205C29.9567 17.6628 27.5018 17.9537 26.3958 18.0871C26.0677 18.1235 26.0069 17.8325 26.3108 17.6264C28.2674 16.2565 31.4758 16.6566 31.8525 17.1051C32.2293 17.5658 31.7553 20.7784 29.9202 22.3059C29.6407 22.5362 29.3733 22.415 29.4949 22.0998C29.9081 21.0815 30.8317 18.7902 30.3942 18.2205Z" fill="#FF9900"/>
+</g>
+<defs>
+<clipPath id="clip0_394_42756">
+<rect width="124.5" height="24" fill="white" transform="translate(0.75)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/azure.svg b/app/components/base/icons/assets/public/billing/azure.svg
new file mode 100644
index 0000000..186ab0a
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/azure.svg
@@ -0,0 +1,25 @@
+<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Group 5">
+<path id="Vector" d="M7.08403 0.812966H12.8543L6.86419 18.5609C6.80263 18.7433 6.68542 18.9018 6.52907 19.0141C6.37271 19.1263 6.18509 19.1867 5.99261 19.1868H1.50193C1.35609 19.1868 1.21234 19.1521 1.08258 19.0855C0.952814 19.019 0.840765 18.9225 0.755699 18.804C0.670633 18.6855 0.614995 18.5485 0.593389 18.4043C0.571782 18.2601 0.584829 18.1128 0.631448 17.9746L6.21222 1.43879C6.27376 1.25634 6.39099 1.09779 6.54739 0.985482C6.70379 0.873171 6.89148 0.812976 7.08403 0.812966Z" fill="url(#paint0_linear_644_3772)"/>
+<path id="Vector_2" d="M15.469 12.7173H6.31874C6.23367 12.7173 6.15054 12.7428 6.08019 12.7906C6.00984 12.8384 5.95552 12.9063 5.92431 12.9855C5.8931 13.0646 5.88644 13.1513 5.90521 13.2343C5.92398 13.3173 5.96731 13.3927 6.02954 13.4506L11.9093 18.9386C12.0805 19.0983 12.3059 19.187 12.54 19.187H17.7212L15.469 12.7173Z" fill="#0078D4"/>
+<path id="Vector_3" d="M7.08432 0.813056C6.88967 0.812309 6.69988 0.873821 6.54267 0.988606C6.38547 1.10339 6.26908 1.26543 6.21052 1.45107L0.638609 17.9596C0.588854 18.0983 0.573233 18.2469 0.593069 18.3929C0.612904 18.5389 0.667613 18.678 0.752567 18.7984C0.83752 18.9188 0.950219 19.0169 1.08113 19.0845C1.21204 19.1522 1.35731 19.1873 1.50466 19.1869H6.11124C6.28281 19.1562 6.44316 19.0806 6.57593 18.9676C6.7087 18.8547 6.80911 18.7086 6.86692 18.5442L7.97807 15.2695L11.9471 18.9715C12.1134 19.109 12.3221 19.1851 12.5379 19.1869H17.6998L15.4359 12.7172L8.83614 12.7188L12.8754 0.813056H7.08432Z" fill="url(#paint1_linear_644_3772)"/>
+<path id="Vector_4" d="M14.4539 1.43799C14.3925 1.25583 14.2754 1.09755 14.1193 0.985434C13.9631 0.87332 13.7757 0.813027 13.5835 0.813049H7.15259C7.34482 0.81306 7.53221 0.873366 7.68837 0.985475C7.84453 1.09758 7.96159 1.25585 8.02307 1.43799L13.6041 17.9744C13.6507 18.1126 13.6638 18.26 13.6422 18.4042C13.6206 18.5485 13.565 18.6856 13.4799 18.8041C13.3949 18.9226 13.2828 19.0191 13.153 19.0857C13.0232 19.1523 12.8795 19.1871 12.7336 19.1871H19.1647C19.3105 19.187 19.4543 19.1523 19.584 19.0856C19.7138 19.019 19.8258 18.9225 19.9109 18.804C19.9959 18.6855 20.0515 18.5484 20.0731 18.4042C20.0947 18.2599 20.0816 18.1126 20.0349 17.9744L14.4539 1.43799Z" fill="url(#paint2_linear_644_3772)"/>
+</g>
+<defs>
+<linearGradient id="paint0_linear_644_3772" x1="9.1871" y1="2.17453" x2="3.19457" y2="19.878" gradientUnits="userSpaceOnUse">
+<stop stop-color="#114A8B"/>
+<stop offset="1" stop-color="#0669BC"/>
+</linearGradient>
+<linearGradient id="paint1_linear_644_3772" x1="11.0593" y1="10.4249" x2="9.67315" y2="10.8936" gradientUnits="userSpaceOnUse">
+<stop stop-opacity="0.3"/>
+<stop offset="0.071" stop-opacity="0.2"/>
+<stop offset="0.321" stop-opacity="0.1"/>
+<stop offset="0.623" stop-opacity="0.05"/>
+<stop offset="1" stop-opacity="0"/>
+</linearGradient>
+<linearGradient id="paint2_linear_644_3772" x1="10.2966" y1="1.65827" x2="16.8746" y2="19.1833" gradientUnits="userSpaceOnUse">
+<stop stop-color="#3CCBF4"/>
+<stop offset="1" stop-color="#2892DF"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/buildings.svg b/app/components/base/icons/assets/public/billing/buildings.svg
new file mode 100644
index 0000000..34e784d
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/buildings.svg
@@ -0,0 +1,5 @@
+<svg width="29" height="28" viewBox="0 0 29 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="buildings">
+<path id="Vector" d="M5.04134 22.4583H17.2913M5.04134 22.4583V6.70833C5.04134 5.41967 6.08601 4.375 7.37467 4.375H14.958C16.2467 4.375 17.2913 5.41967 17.2913 6.70833V9.33333M5.04134 22.4583H2.70801M17.2913 22.4583V9.33333M17.2913 22.4583H24.2913M17.2913 9.33333H21.958C23.2467 9.33333 24.2913 10.378 24.2913 11.6667V22.4583M24.2913 22.4583H26.6247M12.6247 10.2083H9.70801M9.70801 14.875H12.6247" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/diamond.svg b/app/components/base/icons/assets/public/billing/diamond.svg
new file mode 100644
index 0000000..f3692f8
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/diamond.svg
@@ -0,0 +1,5 @@
+<svg width="29" height="28" viewBox="0 0 29 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="diamond">
+<path id="Vector" d="M10.2499 9.04167L7.62486 11.6667L10.2499 14.2917M15.9831 22.8501L25.4978 13.3353C26.4164 12.4168 26.408 10.925 25.4791 10.017L20.3883 5.03988C19.9523 4.61365 19.3668 4.375 18.7571 4.375H9.90929C9.29958 4.375 8.71408 4.61365 8.27811 5.03988L3.18727 10.017C2.25844 10.925 2.25002 12.4168 3.16852 13.3353L12.6833 22.8501C13.5945 23.7613 15.0719 23.7613 15.9831 22.8501Z" stroke="#DC6803" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/google-cloud.svg b/app/components/base/icons/assets/public/billing/google-cloud.svg
new file mode 100644
index 0000000..61e30a3
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/google-cloud.svg
@@ -0,0 +1,8 @@
+<svg width="22" height="18" viewBox="0 0 22 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Group 4">
+<path id="Vector" d="M14.1587 5.40399H14.7992L16.6247 3.57855L16.7143 2.80353C15.6686 1.88054 14.4049 1.23936 13.0424 0.94058C11.68 0.641797 10.2639 0.695269 8.92788 1.09594C7.59187 1.49662 6.38006 2.23127 5.40691 3.2305C4.43376 4.22973 3.73142 5.46055 3.36621 6.80669C3.56957 6.72334 3.79485 6.70982 4.00672 6.76826L7.6576 6.16619C7.6576 6.16619 7.84334 5.85874 7.93942 5.87796C8.72169 5.01883 9.80276 4.4912 10.9613 4.40309C12.1199 4.31497 13.2683 4.67304 14.1715 5.40399H14.1587Z" fill="#EA4335"/>
+<path id="Vector_2" d="M19.225 6.80663C18.8055 5.2615 17.944 3.87244 16.7463 2.80988L14.1843 5.3719C14.7182 5.80819 15.1461 6.36003 15.4357 6.9858C15.7253 7.61158 15.869 8.29494 15.856 8.98435V9.43911C16.1554 9.43911 16.4519 9.49809 16.7286 9.61268C17.0052 9.72727 17.2566 9.89523 17.4683 10.107C17.6801 10.3187 17.848 10.5701 17.9626 10.8467C18.0772 11.1234 18.1362 11.4199 18.1362 11.7193C18.1362 12.0187 18.0772 12.3153 17.9626 12.5919C17.848 12.8685 17.6801 13.1199 17.4683 13.3316C17.2566 13.5434 17.0052 13.7113 16.7286 13.8259C16.4519 13.9405 16.1554 13.9995 15.856 13.9995H11.2956L10.8408 14.4607V17.1956L11.2956 17.6504H15.856C17.1295 17.6603 18.3723 17.2601 19.4007 16.5089C20.429 15.7577 21.1883 14.6954 21.5662 13.4792C21.944 12.2631 21.9204 10.9576 21.4988 9.75589C21.0771 8.55419 20.2799 7.52012 19.225 6.80663Z" fill="#4285F4"/>
+<path id="Vector_3" d="M6.72886 17.625H11.2893V13.9741H6.72886C6.40396 13.9741 6.08286 13.9042 5.78732 13.7692L5.14681 13.9677L3.30856 15.7932L3.14844 16.4337C4.17929 17.2121 5.43714 17.6306 6.72886 17.625Z" fill="#34A853"/>
+<path id="Vector_4" d="M6.7289 5.78196C5.49325 5.78934 4.29076 6.18247 3.28939 6.90643C2.28801 7.6304 1.53775 8.64904 1.1434 9.8201C0.749049 10.9912 0.730302 12.2561 1.08978 13.4384C1.44925 14.6206 2.16899 15.661 3.14848 16.4143L5.79377 13.7691C5.4576 13.6172 5.16331 13.386 4.93613 13.0954C4.70895 12.8048 4.55567 12.4634 4.48944 12.1005C4.42321 11.7376 4.446 11.3641 4.55587 11.0119C4.66574 10.6598 4.8594 10.3396 5.12024 10.0788C5.38107 9.81792 5.7013 9.62426 6.05343 9.51439C6.40557 9.40452 6.7791 9.38172 7.14198 9.44795C7.50487 9.51418 7.84626 9.66747 8.13688 9.89465C8.4275 10.1218 8.65867 10.4161 8.81055 10.7523L11.4558 8.10699C10.9006 7.38115 10.185 6.79357 9.36499 6.39023C8.54496 5.98688 7.64275 5.7787 6.7289 5.78196Z" fill="#FBBC05"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/group-2.svg b/app/components/base/icons/assets/public/billing/group-2.svg
new file mode 100644
index 0000000..22970f8
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/group-2.svg
@@ -0,0 +1,3 @@
+<svg width="29" height="28" viewBox="0 0 29 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M17.4942 15.3771C21.1508 13.8584 25.694 15.7846 27.1017 21.1559C27.4448 22.465 26.348 23.625 24.9948 23.625H19.6233M13.2066 8.16667C13.2066 10.2608 11.509 11.9583 9.41493 11.9583C7.32086 11.9583 5.62326 10.2608 5.62326 8.16667C5.62326 6.07258 7.32086 4.375 9.41493 4.375C11.509 4.375 13.2066 6.07258 13.2066 8.16667ZM23.7066 8.16667C23.7066 10.2608 22.009 11.9583 19.9149 11.9583C17.8209 11.9583 16.1232 10.2608 16.1232 8.16667C16.1232 6.07258 17.8209 4.375 19.9149 4.375C22.009 4.375 23.7066 6.07258 23.7066 8.16667ZM14.328 23.625H4.3352C2.98193 23.625 1.88599 22.4589 2.22976 21.15C4.42721 12.7833 14.2359 12.7833 16.4335 21.15C16.7772 22.4589 15.6813 23.625 14.328 23.625Z" stroke="#444CE7" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/keyframe.svg b/app/components/base/icons/assets/public/billing/keyframe.svg
new file mode 100644
index 0000000..2690394
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/keyframe.svg
@@ -0,0 +1,3 @@
+<svg width="29" height="28" viewBox="0 0 29 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M15.9831 3.98321C15.072 3.072 13.5945 3.072 12.6833 3.98321L4.31648 12.35C3.40526 13.2612 3.40524 14.7386 4.31647 15.6499L12.6833 24.0167C13.5945 24.9279 15.072 24.9279 15.9831 24.0167L24.35 15.6499C25.2612 14.7386 25.2612 13.2612 24.35 12.35L15.9831 3.98321Z" stroke="#155AEF" stroke-width="1.5" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/sparkles-soft.svg b/app/components/base/icons/assets/public/billing/sparkles-soft.svg
new file mode 100644
index 0000000..7a24c14
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/sparkles-soft.svg
@@ -0,0 +1,4 @@
+<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.5" d="M9.75878 1.67256C9.74813 1.57435 9.6684 1.5001 9.5735 1.5C9.47861 1.4999 9.39874 1.57397 9.38789 1.67217C9.33725 2.12931 9.20693 2.44292 9.00273 2.65564C8.79849 2.86835 8.49744 3.00411 8.05857 3.05683C7.9643 3.06816 7.89321 3.15136 7.89331 3.2502C7.89341 3.34905 7.96469 3.43208 8.05896 3.44321C8.49038 3.49411 8.79835 3.62984 9.00773 3.84402C9.216 4.05703 9.34877 4.3702 9.38736 4.82276C9.39595 4.92317 9.47673 5.00011 9.5735 5C9.67027 4.99988 9.75096 4.92276 9.75926 4.82232C9.79627 4.37742 9.92894 4.05719 10.1386 3.83882C10.3482 3.62045 10.6556 3.48223 11.0827 3.44372C11.1792 3.43503 11.2532 3.35103 11.2533 3.25022C11.2534 3.14942 11.1795 3.06524 11.0832 3.05632C10.6487 3.01612 10.3481 2.87779 10.1436 2.66085C9.93797 2.44273 9.80765 2.12197 9.75878 1.67256Z" fill="#FCFCFD"/>
+<path d="M6.45025 2.94373C6.42279 2.69117 6.21783 2.50026 5.9738 2.5C5.72982 2.49974 5.52443 2.69021 5.49649 2.94271C5.36631 4.11822 5.0312 4.92465 4.50609 5.47164C3.98098 6.0186 3.20681 6.3677 2.07832 6.5033C1.83592 6.5324 1.65307 6.74635 1.65332 7.0005C1.65357 7.2547 1.83684 7.4682 2.0793 7.4968C3.1887 7.6277 3.9805 7.97675 4.51896 8.5275C5.05449 9.07525 5.39598 9.8805 5.49519 11.0442C5.51722 11.3024 5.72502 11.5003 5.97385 11.5C6.22273 11.4997 6.43009 11.3014 6.45154 11.0431C6.54658 9.89905 6.88782 9.07565 7.42686 8.5141C7.96595 7.9526 8.75641 7.59715 9.8547 7.49815C10.1026 7.4758 10.293 7.2598 10.2933 7.00055C10.2936 6.74135 10.1037 6.5249 9.8558 6.50195C8.7386 6.3986 7.96556 6.0429 7.43972 5.48504C6.911 4.92415 6.57591 4.09936 6.45025 2.94373Z" fill="#FCFCFD"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/billing/sparkles.svg b/app/components/base/icons/assets/public/billing/sparkles.svg
new file mode 100644
index 0000000..fced090
--- /dev/null
+++ b/app/components/base/icons/assets/public/billing/sparkles.svg
@@ -0,0 +1,14 @@
+<svg width="600" height="600" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g clip-path="url(#clip0_1_382)">
+<rect width="600" height="600" fill="url(#pattern999)"/>
+</g>
+<defs>
+<pattern id="pattern999" patternContentUnits="objectBoundingBox" width="1" height="1">
+<use xlink:href="#image0_1_382" transform="scale(0.000976562)"/>
+</pattern>
+<clipPath id="clip0_1_382">
+<rect width="600" height="600" fill="white"/>
+</clipPath>
+<image id="image0_1_382" width="1024" height="1024" xlink:href="data:image/png;base64,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fAkQAMjX8WZvEUAAAQQQQGAaBfav3Va5+vLVF91w5YXXrzm15sZZI+3L0janXjw2vhMAt5ACBGmVfFs/rOzbPLX272rbdefa7XvWPdz30v+uuOFDI/YaJQIIIIBA/gQIAOTvmLPHCCCAAAIIIJABAQsGXLFq2TWXllf+9qr5yy9pFhCY6uaqwv/KWwd276zu2/rq4aPbt+/Zv5PW/qnqsRwCCCAw8wUIAMz8Y8weIoAAAggggEALCCggsOzs7s7fWL5w5col3ef2zJ69oFQsLzx/UVdn59GFC8NdGFzQ3//y4YHBWr3a/+bQ0NF9vzy+98jAO2/2vXzodVr5QynGEUAAAQRCAQIAoQbjCCCAAAIIIIAAAggggAACCMxQgeB5MzN0D9ktBBBAAAEEEEAAAQQQQAABBBAoEADgS4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCOgv+e0AAABaSURBVCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCPwfNaPiwKKqjBIAAAAASUVORK5CYII="/>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/d.svg b/app/components/base/icons/assets/public/common/d.svg
new file mode 100644
index 0000000..fdcd607
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/d.svg
@@ -0,0 +1,16 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M2 1H7.94339C11.8094 1 14.9434 4.13401 14.9434 8C14.9434 11.866 11.8094 15 7.9434 15H2V1Z" fill="white"/>
+<path d="M2 1H7.94339C11.8094 1 14.9434 4.13401 14.9434 8C14.9434 11.866 11.8094 15 7.9434 15H2V1Z" fill="url(#paint0_angular_19344_240446)"/>
+<path d="M7.94336 8H8.20751V15H7.94336V8Z" fill="url(#paint1_linear_19344_240446)"/>
+<defs>
+<radialGradient id="paint0_angular_19344_240446" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(7.9434 8) rotate(90) scale(8.75 8.75)">
+<stop stop-color="#001FC2"/>
+<stop offset="0.711334" stop-color="#0667F8" stop-opacity="0.2"/>
+<stop offset="1" stop-color="#155EEF" stop-opacity="0"/>
+</radialGradient>
+<linearGradient id="paint1_linear_19344_240446" x1="8.06244" y1="8.43754" x2="7.93744" y2="9.20317" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/diagonal-dividing-line.svg b/app/components/base/icons/assets/public/common/diagonal-dividing-line.svg
new file mode 100644
index 0000000..608e53e
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/diagonal-dividing-line.svg
@@ -0,0 +1,3 @@
+<svg width="7" height="20" viewBox="0 0 7 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path id="Line 3" d="M1 19.3544L5.94174 0.645657" stroke="#EAECF0" stroke-linecap="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/dify.svg b/app/components/base/icons/assets/public/common/dify.svg
new file mode 100644
index 0000000..7cbccc4
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/dify.svg
@@ -0,0 +1,8 @@
+<svg width="50" height="26" viewBox="0 0 50 26" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Dify">
+<path d="M6.61784 2.064C8.37784 2.064 9.92184 2.408 11.2498 3.096C12.5938 3.784 13.6258 4.768 14.3458 6.048C15.0818 7.312 15.4498 8.784 15.4498 10.464C15.4498 12.144 15.0818 13.616 14.3458 14.88C13.6258 16.128 12.5938 17.096 11.2498 17.784C9.92184 18.472 8.37784 18.816 6.61784 18.816H0.761841V2.064H6.61784ZM6.49784 15.96C8.25784 15.96 9.61784 15.48 10.5778 14.52C11.5378 13.56 12.0178 12.208 12.0178 10.464C12.0178 8.72 11.5378 7.36 10.5778 6.384C9.61784 5.392 8.25784 4.896 6.49784 4.896H4.12184V15.96H6.49784Z" fill="#1D2939"/>
+<path d="M20.869 3.936C20.277 3.936 19.781 3.752 19.381 3.384C18.997 3 18.805 2.528 18.805 1.968C18.805 1.408 18.997 0.944 19.381 0.576C19.781 0.192 20.277 0 20.869 0C21.461 0 21.949 0.192 22.333 0.576C22.733 0.944 22.933 1.408 22.933 1.968C22.933 2.528 22.733 3 22.333 3.384C21.949 3.752 21.461 3.936 20.869 3.936ZM22.525 5.52V18.816H19.165V5.52H22.525Z" fill="#1D2939"/>
+<path d="M33.1407 8.28H30.8127V18.816H27.4047V8.28H25.8927V5.52H27.4047V4.848C27.4047 3.216 27.8687 2.016 28.7967 1.248C29.7247 0.48 31.1247 0.12 32.9967 0.168001V3C32.1807 2.984 31.6127 3.12 31.2927 3.408C30.9727 3.696 30.8127 4.216 30.8127 4.968V5.52H33.1407V8.28Z" fill="#1D2939"/>
+<path d="M49.2381 5.52L41.0061 25.104H37.4301L40.3101 18.48L34.9821 5.52H38.7501L42.1821 14.808L45.6621 5.52H49.2381Z" fill="#1D2939"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/gdpr.svg b/app/components/base/icons/assets/public/common/gdpr.svg
new file mode 100644
index 0000000..163a983
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/gdpr.svg
@@ -0,0 +1,53 @@
+<svg width="23" height="28" viewBox="0 0 23 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Group">
+<g id="Group_2">
+<path id="Vector" d="M11.0371 28L10.7001 27.8596C8.90271 27.1013 0 23.001 0 16.8786V4.32497L11.0371 0L22.0742 4.32497V16.8786C22.0742 23.001 13.1434 27.1013 11.3741 27.8596L11.0371 28ZM1.71314 5.47643V16.8786C1.71314 18.9569 3.11735 21.0632 5.86961 23.1414C7.89167 24.658 10.0822 25.7252 11.0652 26.1464C12.0481 25.6971 14.2387 24.658 16.2608 23.1414C19.013 21.0632 20.4173 18.9569 20.4173 16.8786V5.47643L11.0652 1.82548L1.71314 5.47643Z" fill="white"/>
+</g>
+<g id="Group_3">
+<g id="Group_4">
+<path id="Vector_2" d="M11.0371 0.898682V27.0732C12.666 26.3711 21.2317 22.4674 21.2317 16.8786C21.2317 10.672 21.2317 4.88664 21.2317 4.88664L11.0371 0.898682Z" fill="#1611D3"/>
+</g>
+<g id="Group_5">
+<path id="Vector_3" d="M11.0371 0.898682V27.0732C9.40823 26.3711 0.842529 22.4674 0.842529 16.8786C0.842529 10.672 0.842529 4.88664 0.842529 4.88664L11.0371 0.898682Z" fill="#0D00A0"/>
+</g>
+</g>
+<g id="Group_6">
+<path id="Vector_4" d="M7.1333 15.5306C7.04905 15.5867 6.93671 15.6429 6.82437 15.671C6.71204 15.7272 6.5997 15.7552 6.48736 15.7833C6.37503 15.8114 6.23461 15.8395 6.0661 15.8676C5.92568 15.8957 5.72909 15.8957 5.56058 15.8957C5.33591 15.8957 5.1674 15.8676 4.97081 15.8114C4.80231 15.7552 4.6338 15.671 4.52147 15.5867C4.40913 15.5025 4.26871 15.3621 4.18445 15.2216C4.07212 15.0812 4.01595 14.9408 3.9317 14.7723C3.84745 14.6038 3.81936 14.4353 3.79128 14.2668C3.76319 14.0983 3.73511 13.9017 3.73511 13.7332C3.73511 13.5366 3.76319 13.34 3.79128 13.1715C3.81936 12.9749 3.87553 12.8064 3.95978 12.6379C4.04403 12.4694 4.12829 12.329 4.24062 12.1885C4.35296 12.0481 4.4653 11.9358 4.60572 11.8235C4.74614 11.7111 4.91465 11.6549 5.08315 11.5988C5.25166 11.5426 5.44825 11.5145 5.64484 11.5145C5.75717 11.5145 5.84143 11.5145 5.92568 11.5145C6.00993 11.5145 6.09418 11.5426 6.15035 11.5426C6.2346 11.5426 6.29077 11.5707 6.34694 11.5988C6.40311 11.6269 6.48736 11.6549 6.54353 11.683C6.5997 11.7111 6.68395 11.7673 6.74012 11.8235C6.79629 11.8796 6.88054 11.9358 6.9648 11.992L6.57162 12.5256C6.48736 12.4413 6.40311 12.3571 6.31886 12.3009C6.23461 12.2447 6.15035 12.1885 6.09418 12.1605C6.00993 12.1324 5.92568 12.1043 5.84143 12.1043C5.75717 12.1043 5.67292 12.0762 5.56058 12.0762C5.39208 12.0762 5.22357 12.1043 5.08315 12.1885C4.94273 12.2728 4.83039 12.3851 4.74614 12.5256C4.66189 12.666 4.57764 12.8345 4.52147 13.003C4.4653 13.1715 4.43721 13.3962 4.43721 13.6208C4.43721 13.8455 4.4653 14.0702 4.49338 14.2668C4.52147 14.4634 4.60572 14.66 4.68997 14.8004C4.77422 14.9408 4.88656 15.0812 5.05507 15.1655C5.19549 15.2497 5.36399 15.3059 5.58867 15.3059C5.64484 15.3059 5.70101 15.3059 5.75717 15.3059C5.81334 15.3059 5.89759 15.3059 5.95376 15.2778C6.00993 15.2778 6.09418 15.2497 6.15035 15.2497C6.20652 15.2497 6.26269 15.2216 6.31886 15.2216V13.7894H7.04905V15.5306H7.1333Z" fill="white"/>
+<path id="Vector_5" d="M8.93074 11.5707C9.32391 11.5707 9.66093 11.6268 9.91368 11.7392C10.1945 11.8515 10.3911 11.9919 10.5877 12.1885C10.7562 12.3851 10.8685 12.5817 10.9528 12.8345C11.0371 13.0872 11.0651 13.34 11.0651 13.6208C11.0651 13.8174 11.0371 14.014 11.009 14.1825C10.9809 14.351 10.9247 14.5476 10.8685 14.7161C10.7843 14.8846 10.7 15.025 10.5877 15.1655C10.4754 15.3059 10.3349 15.4182 10.1664 15.5025C9.99794 15.5867 9.82943 15.671 9.60476 15.7271C9.38008 15.7833 9.15541 15.8114 8.87457 15.8114H7.83545V11.5988H8.93074V11.5707ZM8.62181 12.1324V15.2497H8.84648C9.04307 15.2497 9.23966 15.2216 9.43625 15.1374C9.60476 15.0812 9.77326 14.9689 9.8856 14.8285C10.026 14.688 10.1103 14.5195 10.1945 14.3229C10.2788 14.1263 10.3069 13.8736 10.3069 13.5927C10.3069 13.3962 10.2788 13.2276 10.2226 13.0311C10.1664 12.8626 10.0822 12.694 9.96985 12.5536C9.85752 12.4132 9.7171 12.3009 9.54859 12.2166C9.38008 12.1324 9.15541 12.0762 8.90265 12.0762H8.62181V12.1324Z" fill="white"/>
+<path id="Vector_6" d="M12.5537 14.1825V15.8114H11.8235V11.5988H13.0311C13.312 11.5988 13.5366 11.6268 13.7332 11.683C13.9298 11.7392 14.0983 11.8234 14.2106 11.9358C14.3511 12.0481 14.4353 12.1885 14.4915 12.3289C14.5477 12.4694 14.5757 12.6379 14.5757 12.8345C14.5757 12.8906 14.5757 12.9749 14.5477 13.0872C14.5196 13.1715 14.4915 13.2838 14.4634 13.3681C14.4072 13.4804 14.3511 13.5647 14.2668 13.6489C14.1826 13.7332 14.0983 13.8174 13.9579 13.9017C13.8175 13.9859 13.677 14.0421 13.5085 14.0983C13.34 14.1544 13.1434 14.1544 12.8907 14.1544H12.5537V14.1825ZM12.5537 13.6208H12.9188C13.0592 13.6208 13.1715 13.5927 13.2839 13.5647C13.3962 13.5366 13.4805 13.4804 13.5647 13.4242C13.649 13.3681 13.7051 13.2838 13.7613 13.1715C13.8175 13.0872 13.8175 12.9749 13.8175 12.8345C13.8175 12.7221 13.7894 12.6379 13.7613 12.5536C13.7332 12.4694 13.677 12.3851 13.6209 12.3289C13.5647 12.2728 13.4524 12.2166 13.34 12.1604C13.2277 12.1324 13.0873 12.1043 12.9188 12.1043H12.5537V13.6208Z" fill="white"/>
+<path id="Vector_7" d="M15.9519 15.8114H15.2217V11.5988H16.4293C16.7101 11.5988 16.9348 11.6268 17.1314 11.683C17.328 11.7392 17.4965 11.8234 17.6088 11.9077C17.7493 12.02 17.8335 12.1324 17.8897 12.2728C17.9459 12.4132 17.9739 12.5817 17.9739 12.7502C17.9739 12.8625 17.9459 13.003 17.9178 13.1153C17.8897 13.2276 17.8335 13.3681 17.7493 13.4804C17.665 13.5927 17.5808 13.7051 17.4403 13.7893C17.2999 13.8736 17.1595 13.9578 16.9629 14.014L18.2548 15.8114H17.4123L16.2889 14.0983C16.2327 14.0983 16.2046 14.0983 16.1485 14.0983C16.0923 14.0983 16.0361 14.0983 15.9519 14.0702V15.8114ZM15.9519 13.5085C16.008 13.5085 16.0642 13.5085 16.1204 13.5085C16.1765 13.5085 16.2327 13.5085 16.2889 13.5085C16.4293 13.5085 16.5697 13.4804 16.6821 13.4523C16.7944 13.4242 16.9067 13.3681 16.991 13.3119C17.0752 13.2557 17.1314 13.1715 17.1876 13.0872C17.2437 13.003 17.2437 12.8906 17.2437 12.7783C17.2437 12.666 17.2157 12.5536 17.1876 12.4694C17.1595 12.3851 17.1033 12.3289 17.0472 12.2728C16.991 12.2166 16.8787 12.1885 16.7663 12.1604C16.654 12.1324 16.4855 12.1324 16.317 12.1324H15.98V13.5085H15.9519Z" fill="white"/>
+</g>
+<g id="Group_7">
+<g id="Group_8">
+<path id="Vector_8" d="M11.0372 4.63391L11.3461 5.56069H12.301L11.5427 6.12238L11.8236 7.02107L11.0372 6.45939L10.2789 7.02107L10.5598 6.12238L9.80151 5.56069H10.7564L11.0372 4.63391Z" fill="#F7BC37"/>
+</g>
+<g id="Group_9">
+<path id="Vector_9" d="M14.3231 5.53259L14.632 6.43129H15.5869L14.8005 6.99297L15.1095 7.91975L14.3231 7.35807L13.5648 7.91975L13.8457 6.99297L13.0593 6.43129H14.0423L14.3231 5.53259Z" fill="#F7BC37"/>
+</g>
+<g id="Group_10">
+<path id="Vector_10" d="M17.0472 7.9198L17.3281 8.81849H18.2829L17.5247 9.38018L17.8055 10.307L17.0472 9.74528L16.2609 10.307L16.5698 9.38018L15.7834 8.81849H16.7383L17.0472 7.9198Z" fill="#F7BC37"/>
+</g>
+<g id="Group_11">
+<path id="Vector_11" d="M11.0372 19.7714L11.3461 20.6981H12.301L11.5427 21.2598L11.8236 22.1585L11.0372 21.5968L10.2789 22.1585L10.5598 21.2598L9.80151 20.6981H10.7564L11.0372 19.7714Z" fill="#F7BC37"/>
+</g>
+<g id="Group_12">
+<path id="Vector_12" d="M14.3231 18.985L14.632 19.8837H15.5869L14.8005 20.4454L15.1095 21.3721L14.3231 20.8105L13.5648 21.3721L13.8457 20.4454L13.0593 19.8837H14.0423L14.3231 18.985Z" fill="#F7BC37"/>
+</g>
+<g id="Group_13">
+<path id="Vector_13" d="M17.0472 17.019L17.3281 17.9458H18.2829L17.5247 18.5075L17.8055 19.4062L17.0472 18.8445L16.2609 19.4062L16.5698 18.5075L15.7834 17.9458H16.7383L17.0472 17.019Z" fill="#F7BC37"/>
+</g>
+<g id="Group_14">
+<path id="Vector_14" d="M7.77942 5.53259L7.47049 6.43129H6.51562L7.30199 6.99297L6.99306 7.91975L7.77942 7.35807L8.53769 7.91975L8.25685 6.99297L9.01512 6.43129H8.06026L7.77942 5.53259Z" fill="#F7BC37"/>
+</g>
+<g id="Group_15">
+<path id="Vector_15" d="M5.05529 7.9198L4.77444 8.81849H3.81958L4.57785 9.38018L4.29701 10.307L5.05529 9.74528L5.84165 10.307L5.53272 9.38018L6.31908 8.81849H5.36421L5.05529 7.9198Z" fill="#F7BC37"/>
+</g>
+<g id="Group_16">
+<path id="Vector_16" d="M7.77942 18.985L7.47049 19.8837H6.51562L7.30199 20.4454L6.99306 21.3721L7.77942 20.8105L8.53769 21.3721L8.25685 20.4454L9.01512 19.8837H8.06026L7.77942 18.985Z" fill="#F7BC37"/>
+</g>
+<g id="Group_17">
+<path id="Vector_17" d="M5.05529 17.019L4.77444 17.9458H3.81958L4.57785 18.5075L4.29701 19.4062L5.05529 18.8445L5.84165 19.4062L5.53272 18.5075L6.31908 17.9458H5.36421L5.05529 17.019Z" fill="#F7BC37"/>
+</g>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/github.svg b/app/components/base/icons/assets/public/common/github.svg
new file mode 100644
index 0000000..df07bfb
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/github.svg
@@ -0,0 +1,5 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="github">
+<path id="Vector" d="M9 1.125C4.64906 1.125 1.125 4.64906 1.125 9C1.125 12.4847 3.37922 15.428 6.50953 16.4714C6.90328 16.5403 7.05094 16.3041 7.05094 16.0973C7.05094 15.9103 7.04109 15.2902 7.04109 14.6306C5.0625 14.9948 4.55062 14.1483 4.39312 13.7053C4.30453 13.4789 3.92063 12.78 3.58594 12.593C3.31031 12.4453 2.91656 12.0811 3.57609 12.0712C4.19625 12.0614 4.63922 12.6422 4.78688 12.8784C5.49563 14.0695 6.62766 13.7348 7.08047 13.5281C7.14938 13.0163 7.35609 12.6717 7.5825 12.4748C5.83031 12.278 3.99938 11.5987 3.99938 8.58656C3.99938 7.73016 4.30453 7.02141 4.80656 6.47016C4.72781 6.27328 4.45219 5.46609 4.88531 4.38328C4.88531 4.38328 5.54484 4.17656 7.05094 5.19047C7.68094 5.01328 8.35031 4.92469 9.01969 4.92469C9.68906 4.92469 10.3584 5.01328 10.9884 5.19047C12.4945 4.16672 13.1541 4.38328 13.1541 4.38328C13.5872 5.46609 13.3116 6.27328 13.2328 6.47016C13.7348 7.02141 14.04 7.72031 14.04 8.58656C14.04 11.6086 12.1992 12.278 10.447 12.4748C10.7325 12.7209 10.9786 13.1934 10.9786 13.9317C10.9786 14.985 10.9688 15.8316 10.9688 16.0973C10.9688 16.3041 11.1164 16.5502 11.5102 16.4714C13.0735 15.9436 14.432 14.9389 15.3943 13.5986C16.3567 12.2583 16.8746 10.65 16.875 9C16.875 4.64906 13.3509 1.125 9 1.125Z" fill="#24292F"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/highlight.svg b/app/components/base/icons/assets/public/common/highlight.svg
new file mode 100644
index 0000000..f4b8090
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/highlight.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="46" height="24" viewBox="0 0 46 24" fill="none">
+ <path opacity="0.5" d="M-6.5 8C-6.5 3.58172 -2.91828 0 1.5 0H45.5L33.0248 24H1.49999C-2.91829 24 -6.5 20.4183 -6.5 16V8Z" fill="url(#paint0_linear_6333_42118)"/>
+ <defs>
+ <linearGradient id="paint0_linear_6333_42118" x1="1.81679" y1="5.47784e-07" x2="101.257" y2="30.3866" gradientUnits="userSpaceOnUse">
+ <stop stop-color="white" stop-opacity="0.12"/>
+ <stop offset="1" stop-color="white" stop-opacity="0.3"/>
+ </linearGradient>
+ </defs>
+</svg>
\ No newline at end of file
diff --git a/app/components/base/icons/assets/public/common/iso.svg b/app/components/base/icons/assets/public/common/iso.svg
new file mode 100644
index 0000000..c48c357
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/iso.svg
@@ -0,0 +1 @@
+<svg fill="none" height="64" viewBox="0 0 64 64" width="64" xmlns="http://www.w3.org/2000/svg"><path d="m8 9.82143c0-2.6628 2.2386-4.82143 5-4.82143h38c2.7614 0 5 2.15863 5 4.82143v44.35717c0 2.6628-2.2386 4.8214-5 4.8214h-38c-2.7614 0-5-2.1586-5-4.8214z" fill="#2a3e92"/><g fill="#fff"><path d="m43.4424 46.9899v-1.84h3.08v7.31h-2.05v-5.47z"/><path d="m36.5801 48.7c0-1.1467.2333-2.05.7-2.71.4666-.66 1.2-.99 2.2-.99s1.7333.33 2.2.99c.4733.66.71 1.5633.71 2.71 0 1.16-.2334 2.07-.7 2.73-.4667.66-1.2034.99-2.21.99-1.0067 0-1.7434-.33-2.21-.99-.46-.66-.69-1.57-.69-2.73zm3.87 0c0-.6-.0634-1.0567-.19-1.37-.1267-.32-.3867-.48-.78-.48-.3934 0-.6534.16-.78.48-.1267.3133-.19.77-.19 1.37 0 .6133.06 1.08.18 1.4.1266.3133.39.47.79.47s.66-.1567.78-.47c.1266-.32.19-.7867.19-1.4z"/><path d="m29.5078 48.7c0-1.1467.2333-2.05.7-2.71s1.2-.99 2.2-.99 1.7333.33 2.2.99c.4733.66.71 1.5633.71 2.71 0 1.16-.2333 2.07-.7 2.73s-1.2033.99-2.21.99-1.7433-.33-2.21-.99c-.46-.66-.69-1.57-.69-2.73zm3.87 0c0-.6-.0633-1.0567-.19-1.37-.1267-.32-.3867-.48-.78-.48s-.6533.16-.78.48c-.1267.3133-.19.77-.19 1.37 0 .6133.06 1.08.18 1.4.1267.3133.39.47.79.47s.66-.1567.78-.47c.1267-.32.19-.7867.19-1.4z"/><path d="m28.4533 46.6099-2.4 5.85h-2.01l2.42-5.62h-2.85v-1.68h4.84z"/><path d="m17.52 50.89c.6467-.5067 1.1767-.9433 1.59-1.31s.76-.7433 1.04-1.13c.28-.3933.42-.7667.42-1.12 0-.2133-.05-.38-.15-.5-.0933-.12-.2333-.18-.42-.18-.1933 0-.3433.0833-.45.25-.1067.16-.1567.3967-.15.71h-1.9c.02-.5933.15-1.0833.39-1.47.24-.3933.5533-.68.94-.86.3867-.1867.8167-.28 1.29-.28.82 0 1.43.2033 1.83.61s.6.9333.6 1.58c0 .6933-.2333 1.3433-.7 1.95-.46.6067-1.0367 1.15-1.73 1.63h2.5v1.59h-5.1z"/><path clip-rule="evenodd" d="m32.5672 11.0281c1.0059.0357 2.2045.2319 3.2746.5387 3.289.9417 6.1071 2.9857 8.1332 5.8894.1106.1605.2033.3103.2033.3317 0 .0286-.1605.0393-.5136.0393h-.5137l-.1641-.2319c-.453-.6278-1.3377-1.6123-1.9191-2.1296l-.2497-.2212-.61.1534c-1.0916.2676-2.2937.4852-3.4923.6314-.2711.0357-.4923.0749-.4923.0856 0 .0143.05.1855.1106.3782.1391.4601.3532 1.2306.3532 1.2877 0 .0357-.1106.0464-.4459.0464h-.4424l-.0606-.2069c-.0144-.0559-.0371-.1365-.0606-.22-.0229-.0816-.0466-.1661-.0643-.233-.1141-.3924-.2889-.9239-.3174-.956-.0143-.0179-.2497-.0143-.5208.0071-.2676.0214-1.0274.0571-1.6838.082-1.2592.0428-3.0321.0036-4.2164-.0963-.3032-.0249-.5636-.0357-.5778-.0214-.0286.0286-.2854.8312-.4067 1.2842l-.0963.3603h-.4388c-.4031 0-.4423-.0071-.4423-.0642 0-.0785.2033-.8347.3567-1.3234.0607-.1855.0963-.3496.0785-.3639-.0143-.0107-.1926-.0428-.3995-.0642-.9739-.1106-2.3865-.371-3.4673-.635l-.6671-.1641-.1891.1606c-.5743.4922-1.4982 1.5053-1.9726 2.1581l-.214.2961h-.5244c-.2925 0-.528-.0107-.528-.0214 0-.0464.5708-.8383.8918-1.245 1.3698-1.7158 3.0464-3.0642 5.0298-4.0451 1.5124-.7492 2.9893-1.1879 4.7265-1.4126.4387-.0571 1.6016-.1178 1.8727-.0999.0678.0035.3675.0178.66.0249zm-1.2702.8884c-.824.2818-1.6088 1.1736-2.3293 2.6468-.1641.3318-.3068.635-.3175.6671-.0179.0499.0107.0642.1641.0821.8846.0963 3.2033.1462 4.4661.0927 1.516-.0642 1.6587-.0749 1.6587-.1427 0-.0892-.5351-1.1629-.7634-1.5267-.4637-.7491-.9239-1.27-1.3947-1.5803-.4959-.321-.9988-.4031-1.484-.239zm-1.9937.139c-1.912.4031-3.4745 1.0487-5.1082 2.1189-.3996.2604-.528.371-.4281.371.0123 0 .1824.0368.3973.0833l.1093.0237c.8632.1962 2.6646.4922 3.2925.5422l.1355.0107.1498-.3567c.4352-1.0167 1.113-2.1261 1.6623-2.704.1213-.1284.1213-.1319.0393-.1284-.05.0036-.1605.0179-.2497.0393zm5.6573 1.2843c-.2069-.3318-.6135-.8918-.8597-1.1772l-.0035-.004c-.0584-.0664-.0945-.1073-.0853-.126.0148-.0301.1474-.0021.4938.0711l.0088.0018c1.673.3532 3.3567 1.0666 4.8764 2.069.2782.1819.5065.346.5065.3639 0 .0891-2.6576.5564-3.7812.667l-.2319.0214-.1248-.3103c-.1641-.4174-.5458-1.1665-.7991-1.5767z" fill-rule="evenodd"/><path d="m30.8906 19.1863c.5565.0678.8704.082 2.365.0927l1.7194.0143v3.849h-3.0642l-.0214-.8383-.214-.0856c-.6136-.2426-1.4376-.3746-2.3544-.3781-.9025 0-1.3091.0784-1.6979.3388-.3996.2605-.4566.792-.1249 1.1201.346.3496.7705.4602 2.6611.6956 1.6338.2069 2.2652.3389 3.0571.6493.3817.1498.8633.4316 1.1629.6849.4423.3674.8062.9738.9738 1.6159.1249.478.1606 1.3983.0714 1.887-.1534.8348-.4673 1.434-1.0416 1.9798-.6207.5922-1.4198.981-2.522 1.2271-1.2164.2747-2.9394.3175-4.6659.1213-.5922-.0642-.9346-.0785-2.3579-.0892l-1.6694-.0142v-3.8133h3.0677v.7847l.1391.0714c.4531.2283 1.3841.3959 2.3651.4173 1.6908.0428 2.4506-.2568 2.4542-.9702 0-.2783-.0785-.4281-.3139-.5922-.3425-.2426-.824-.3531-2.3615-.5493-1.8478-.239-2.579-.4067-3.3817-.7848-1.2806-.6064-1.912-1.5303-2.0404-2.9857-.0713-.7706.0535-1.4911.3567-2.1189.6814-1.4091 2.2402-2.2188 4.6552-2.4186.4851-.0392 2.1617.0143 2.7824.0892z"/><path clip-rule="evenodd" d="m48.2307 20.9806c-.981-.9774-2.2474-1.5767-3.8383-1.8157-.3924-.0607-1.8371-.1035-2.1938-.0678-1.0631.1106-1.9228.3353-2.7182.7099-1.9049.9025-3.0892 2.579-3.3817 4.7907-.0607.4673-.0714 1.5945-.0179 2.0404.1356 1.1166.4745 2.0726 1.0238 2.9073.4531.6849 1.2913 1.4375 2.0797 1.8656 1.1665.635 2.7967.9524 4.3983.8597 3.0571-.1819 5.2295-1.6873 6.0678-4.2057.2461-.742.3496-1.4483.3496-2.39.0035-1.9655-.5743-3.4994-1.7693-4.6944zm-7.7841 3.6847c.214-1.5268.906-2.3722 2.0939-2.5541.2961-.0464.9132-.0179 1.2093.0499.5279.1284 1.0023.4566 1.2949.9025.4209.635.5957 1.4019.5957 2.6112-.0036 1.4732-.2533 2.3258-.874 2.9429-.4459.4495-.8561.6136-1.6088.6492-1.4447.0678-2.3187-.6635-2.6575-2.2259-.1071-.4994-.1356-1.78-.0535-2.3757z" fill-rule="evenodd"/><path d="m22.2402 22.5002h-2.069v6.4209h2.069v3.1748l-8.2224-.0178-.0107-1.5803-.0071-1.5767h2.069v-6.4209l-1.0238-.0071-1.0274-.0107-.0107-1.5803-.0071-1.5767h8.2402z"/><path clip-rule="evenodd" d="m22.5684 35.9913c-.5601-.4852-1.5518-1.5874-2.0048-2.2295l-.1177-.1677h-.5315c-.4174 0-.528.0107-.5066.0428.4495.767 1.4769 2.0012 2.2973 2.7646 2.3865 2.2188 5.1367 3.503 8.4007 3.9239.6278.0785 2.547.0892 3.2105.0178 4.0202-.4459 7.6551-2.472 10.1165-5.6432.2747-.3532.7455-1.031.7455-1.0773 0-.0143-.2318-.0286-.5136-.0286h-.5101l-.3104.4067c-.1676.2247-.4816.6064-.6956.8525-.371.4174-1.1415 1.1843-1.3127 1.2985-.0713.0464-.132.0392-.6421-.0928-.9845-.2497-2.283-.4958-3.3282-.6278-.2461-.0285-.4958-.0642-.56-.0749l-.1142-.0178.0892-.2569c.0963-.2782.4067-1.3912.4067-1.4518 0-.025-.1499-.0357-.4495-.0285l-.4495.0107-.1177.428c-.0642.2355-.1712.5957-.239.8026l-.1213.3746h-.2318c-.1249 0-.5886-.025-1.0309-.0535-1.4091-.0928-4.4126-.0607-5.5648.0571l-.1998.0214-.1498-.4745-.0158-.053c-.0769-.2586-.1768-.5945-.2268-.7746l-.0963-.346h-.4388c-.3995 0-.4423.0072-.4423.0642 0 .0785.2105.8419.3567 1.3021.0607.1962.107.3567.0999.3602-.0071.0036-.2997.0428-.6528.0857-1.1415.1391-2.2473.3424-3.3639.6171l-.5814.1427zm7.698.0141c-.9631.0535-1.623.0927-1.6337.1034-.0286.0286.4209.9525.6563 1.3591.5066.8704 1.006 1.4554 1.5196 1.7907.3354.2176.5387.289.8704.3175.3246.025.5601-.0285.9239-.214.4103-.2105 1.0024-.8062 1.4055-1.4162.2675-.4031.931-1.6694.931-1.7764 0-.0571-.0749-.0678-.7669-.1142-.585-.0392-3.4352-.0749-3.9061-.0499zm-3.7032.3211c.3603-.0499.7027-.0963.7598-.1035.0606-.0107.1676-.0142.2425-.0107l.1356.0036.1712.3924c.4424 1.0166.9881 1.9156 1.566 2.5755.107.1249.1748.2247.1534.2247s-.264-.0463-.5386-.107c-1.327-.2782-2.654-.7812-3.874-1.4625-.4709-.2604-1.409-.8633-1.4732-.9418-.0286-.0356.0998-.0749.5778-.1783.7527-.1605 1.4233-.2747 2.2795-.3924zm9.2354.0962c-.132.3353-.5743 1.2129-.8062 1.5946-.2497.4137-.5529.8347-.8169 1.1379-.1105.1284-.1926.2354-.1855.2461.0393.0393 1.2521-.2532 1.9014-.4601 1.1664-.371 2.6361-1.0987 3.6991-1.83l.3139-.2176-.189-.0428c-.956-.2212-2.1011-.4281-3.0107-.5458-.3139-.0392-.6279-.0785-.6956-.0892-.0483-.0055-.0779-.0089-.101.0018-.0367.017-.057.0694-.1095.2051z" fill-rule="evenodd"/></g></svg>
\ No newline at end of file
diff --git a/app/components/base/icons/assets/public/common/line-3.svg b/app/components/base/icons/assets/public/common/line-3.svg
new file mode 100644
index 0000000..f4fdb70
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/line-3.svg
@@ -0,0 +1,3 @@
+<svg width="5" height="12" viewBox="0 0 5 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path id="Line 3" d="M1 11.3545L3.94174 0.645781" stroke="#D0D5DD" stroke-linecap="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/lock.svg b/app/components/base/icons/assets/public/common/lock.svg
new file mode 100644
index 0000000..a698784
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/lock.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="lock">
+<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M8 1.75C6.27411 1.75 4.875 3.14911 4.875 4.875V6.125C3.83947 6.125 3 6.96444 3 8V12.375C3 13.4106 3.83947 14.25 4.875 14.25H11.125C12.1606 14.25 13 13.4106 13 12.375V8C13 6.96444 12.1606 6.125 11.125 6.125V4.875C11.125 3.14911 9.72587 1.75 8 1.75ZM9.875 6.125V4.875C9.875 3.83947 9.03556 3 8 3C6.96444 3 6.125 3.83947 6.125 4.875V6.125H9.875ZM8 8.625C8.34519 8.625 8.625 8.90481 8.625 9.25V11.125C8.625 11.4702 8.34519 11.75 8 11.75C7.65481 11.75 7.375 11.4702 7.375 11.125V9.25C7.375 8.90481 7.65481 8.625 8 8.625Z" fill="#155AEF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/message-chat-square.svg b/app/components/base/icons/assets/public/common/message-chat-square.svg
new file mode 100644
index 0000000..cf7f642
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/message-chat-square.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.77438 6.6665H12.5591C12.9105 6.66649 13.2137 6.66648 13.4634 6.68688C13.727 6.70842 13.9891 6.75596 14.2414 6.88449C14.6177 7.07624 14.9237 7.3822 15.1154 7.75852C15.244 8.01078 15.2915 8.27292 15.313 8.53649C15.3334 8.7862 15.3334 9.08938 15.3334 9.44082V11.2974C15.3334 11.5898 15.3334 11.8421 15.3192 12.0509C15.3042 12.2708 15.2712 12.4908 15.1812 12.7081C14.9782 13.1981 14.5888 13.5875 14.0988 13.7905C13.8815 13.8805 13.6616 13.9135 13.4417 13.9285C13.4068 13.9308 13.3707 13.9328 13.3334 13.9345V14.6665C13.3334 14.9147 13.1955 15.1424 12.9756 15.2573C12.7556 15.3723 12.49 15.3556 12.2862 15.2139L10.8353 14.2051C10.6118 14.0498 10.5666 14.0214 10.5238 14.0021C10.4746 13.9798 10.4228 13.9635 10.3696 13.9537C10.3235 13.9452 10.2702 13.9427 9.99803 13.9427H8.7744C8.42296 13.9427 8.11978 13.9427 7.87006 13.9223C7.6065 13.9008 7.34435 13.8532 7.0921 13.7247C6.71578 13.533 6.40981 13.227 6.21807 12.8507C6.08954 12.5984 6.04199 12.3363 6.02046 12.0727C6.00006 11.823 6.00007 11.5198 6.00008 11.1684V9.44081C6.00007 9.08938 6.00006 8.7862 6.02046 8.53649C6.04199 8.27292 6.08954 8.01078 6.21807 7.75852C6.40981 7.3822 6.71578 7.07624 7.0921 6.88449C7.34435 6.75596 7.6065 6.70842 7.87006 6.68688C8.11978 6.66648 8.42295 6.66649 8.77438 6.6665Z" fill="#444CE7"/>
+<path d="M9.4943 0.666504H4.5059C3.96926 0.666496 3.52635 0.666489 3.16555 0.695967C2.79082 0.726584 2.44635 0.792293 2.12279 0.957154C1.62103 1.21282 1.21308 1.62076 0.957417 2.12253C0.792557 2.44609 0.726847 2.79056 0.69623 3.16529C0.666752 3.52608 0.666759 3.96899 0.666768 4.50564L0.666758 7.6804C0.666669 7.97482 0.666603 8.19298 0.694924 8.38632C0.86568 9.55207 1.78121 10.4676 2.94695 10.6383C2.99461 10.6453 3.02432 10.6632 3.03714 10.6739L3.03714 11.7257C3.03711 11.9075 3.03708 12.0858 3.04976 12.2291C3.06103 12.3565 3.09053 12.6202 3.27795 12.8388C3.48686 13.0825 3.80005 13.2111 4.11993 13.1845C4.40689 13.1607 4.61323 12.9938 4.71072 12.9111C4.73849 12.8875 4.76726 12.8618 4.7968 12.8344C4.73509 12.594 4.70707 12.3709 4.69157 12.1813C4.66659 11.8756 4.66668 11.5224 4.66676 11.1966V9.41261C4.66668 9.08685 4.66659 8.73364 4.69157 8.42793C4.71984 8.08191 4.78981 7.62476 5.03008 7.15322C5.34965 6.52601 5.85959 6.01608 6.4868 5.6965C6.95834 5.45624 7.41549 5.38627 7.7615 5.358C8.06722 5.33302 8.42041 5.3331 8.74617 5.33318H12.5873C12.8311 5.33312 13.0903 5.33306 13.3334 5.3435V4.50562C13.3334 3.96898 13.3334 3.52608 13.304 3.16529C13.2734 2.79056 13.2076 2.44609 13.0428 2.12253C12.7871 1.62076 12.3792 1.21282 11.8774 0.957154C11.5539 0.792293 11.2094 0.726584 10.8347 0.695967C10.4739 0.666489 10.0309 0.666496 9.4943 0.666504Z" fill="#444CE7"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/multi-path-retrieval.svg b/app/components/base/icons/assets/public/common/multi-path-retrieval.svg
new file mode 100644
index 0000000..cdfaa2e
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/multi-path-retrieval.svg
@@ -0,0 +1,19 @@
+<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_13429_43710)">
+<rect width="36" height="36" rx="8" fill="#FFF6ED"/>
+<path opacity="0.7" d="M22.25 28C22.25 29.7949 20.7949 31.25 19 31.25C17.2051 31.25 15.75 29.7949 15.75 28C15.75 26.2051 17.2051 24.75 19 24.75C20.7949 24.75 22.25 26.2051 22.25 28Z" stroke="#FB6514" stroke-width="1.5"/>
+<path d="M19 12C21.2091 12 23 10.2091 23 8C23 5.79086 21.2091 4 19 4C16.7909 4 15 5.79086 15 8C15 10.2091 16.7909 12 19 12Z" fill="#FB6514"/>
+<path d="M15 22C17.2091 22 19 20.2091 19 18C19 15.7909 17.2091 14 15 14C12.7909 14 11 15.7909 11 18C11 20.2091 12.7909 22 15 22Z" fill="#FB6514"/>
+<path d="M36 23C38.7614 23 41 20.7614 41 18C41 15.2386 38.7614 13 36 13C33.2386 13 31 15.2386 31 18C31 20.7614 33.2386 23 36 23Z" fill="#FB6514"/>
+<path d="M0 18H10" stroke="#FB6514" stroke-width="1.5"/>
+<path d="M20 18L30 18" stroke="#FB6514" stroke-width="1.5"/>
+<path d="M0.00112438 15C0.00112438 15 -5.64364 15 0.851673 15C7.34699 15 7.84654 8 14 8" stroke="#FB6514" stroke-width="1.5"/>
+<path d="M23.75 9.28125C26.5688 10.1847 27.699 13.2045 30.625 15.0312" stroke="#FB6514" stroke-width="1.5"/>
+<path opacity="0.7" d="M-0.000543833 21C-0.000543833 21 -5.57819 21 0.893635 21C7.36546 21 7.8688 28 14 28" stroke="#FB6514" stroke-width="1.5"/>
+</g>
+<defs>
+<clipPath id="clip0_13429_43710">
+<rect width="36" height="36" rx="8" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/n-to-1-retrieval.svg b/app/components/base/icons/assets/public/common/n-to-1-retrieval.svg
new file mode 100644
index 0000000..8862829
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/n-to-1-retrieval.svg
@@ -0,0 +1,18 @@
+<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_13429_43700)">
+<rect width="36" height="36" rx="8" fill="#EEF4FF"/>
+<path opacity="0.7" d="M23.25 28C23.25 29.7949 21.7949 31.25 20 31.25C18.2051 31.25 16.75 29.7949 16.75 28C16.75 26.2051 18.2051 24.75 20 24.75C21.7949 24.75 23.25 26.2051 23.25 28Z" stroke="#444CE7" stroke-width="1.5"/>
+<path opacity="0.7" d="M23.25 8C23.25 9.79493 21.7949 11.25 20 11.25C18.2051 11.25 16.75 9.79493 16.75 8C16.75 6.20507 18.2051 4.75 20 4.75C21.7949 4.75 23.25 6.20507 23.25 8Z" stroke="#444CE7" stroke-width="1.5"/>
+<path d="M16 22C18.2091 22 20 20.2091 20 18C20 15.7909 18.2091 14 16 14C13.7909 14 12 15.7909 12 18C12 20.2091 13.7909 22 16 22Z" fill="#444CE7"/>
+<path d="M36 23C38.7614 23 41 20.7614 41 18C41 15.2386 38.7614 13 36 13C33.2386 13 31 15.2386 31 18C31 20.7614 33.2386 23 36 23Z" fill="#444CE7"/>
+<path d="M0 18L11 18" stroke="#444CE7" stroke-width="1.5"/>
+<path d="M21 18L30 18" stroke="#444CE7" stroke-width="1.5"/>
+<path opacity="0.7" d="M-0.00160408 15C-0.00160408 15 -6.00089 15 1.12411 15C8.24911 15 8.24908 8.25 14.9991 8.25" stroke="#444CE7" stroke-width="1.5"/>
+<path opacity="0.7" d="M0.000488281 21C0.000488281 21 -5.92692 21 1.17228 21C8.27148 21 8.27423 27.75 14.9998 27.75" stroke="#444CE7" stroke-width="1.5"/>
+</g>
+<defs>
+<clipPath id="clip0_13429_43700">
+<rect width="36" height="36" rx="8" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/notion.svg b/app/components/base/icons/assets/public/common/notion.svg
new file mode 100644
index 0000000..eeda894
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/notion.svg
@@ -0,0 +1,12 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5364_42310)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.5725 18.2611L1.4229 15.5832C0.905706 14.9389 0.625 14.1466 0.625 13.3312V3.63437C0.625 2.4129 1.60224 1.39936 2.86295 1.31328L12.8326 0.632614C13.5569 0.583164 14.2768 0.775682 14.8717 1.17794L18.3745 3.5462C19.0015 3.97012 19.375 4.66312 19.375 5.40266V16.427C19.375 17.6223 18.4141 18.6121 17.1798 18.688L6.11458 19.3692C5.12958 19.4298 4.17749 19.0148 3.5725 18.2611Z" fill="white"/>
+<path d="M7.03006 8.48663V8.35968C7.03006 8.03787 7.28779 7.77098 7.61997 7.7488L10.0396 7.58726L13.3857 12.5146V8.19003L12.5244 8.07522V8.01492C12.5244 7.68933 12.788 7.42068 13.1244 7.40344L15.326 7.29066V7.60749C15.326 7.75622 15.2154 7.88343 15.0638 7.90907L14.534 7.99868V15.0022L13.8691 15.2309C13.3136 15.4219 12.6952 15.2174 12.3772 14.7376L9.12879 9.83568V14.5143L10.1287 14.7056L10.1147 14.7984C10.0711 15.0889 9.82028 15.3086 9.51687 15.3221L7.03006 15.4328C6.99718 15.1204 7.23132 14.8409 7.55431 14.807L7.88143 14.7726V8.53447L7.03006 8.48663Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.9218 1.85418L2.95217 2.53485C2.35499 2.57562 1.89209 3.05572 1.89209 3.63431V13.3311C1.89209 13.8748 2.07923 14.4029 2.42402 14.8325L4.57362 17.5104C4.92117 17.9433 5.46812 18.1817 6.03397 18.1469L17.0991 17.4658C17.6663 17.4309 18.1078 16.9761 18.1078 16.4269V5.4026C18.1078 5.06281 17.9362 4.74441 17.6481 4.54963L14.1453 2.18137C13.7883 1.94002 13.3564 1.82451 12.9218 1.85418ZM3.44654 3.78556C3.30788 3.6829 3.37387 3.46903 3.54806 3.45654L12.9889 2.77938C13.2897 2.75781 13.5886 2.84064 13.8318 3.01299L15.7261 4.35502C15.798 4.40597 15.7642 4.51596 15.6752 4.5208L5.67742 5.06454C5.37485 5.081 5.0762 4.99211 4.83563 4.814L3.44654 3.78556ZM5.20848 6.76913C5.20848 6.44433 5.47088 6.17604 5.80642 6.15777L16.3769 5.5821C16.7039 5.56429 16.9792 5.81577 16.9792 6.13232V15.6782C16.9792 16.0024 16.7177 16.2705 16.3829 16.2895L5.8793 16.8871C5.51537 16.9079 5.20848 16.6282 5.20848 16.2759V6.76913Z" fill="black"/>
+</g>
+<defs>
+<clipPath id="clip0_5364_42310">
+<rect width="20" height="20" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/soc2.svg b/app/components/base/icons/assets/public/common/soc2.svg
new file mode 100644
index 0000000..226d99c
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/soc2.svg
@@ -0,0 +1,103 @@
+<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Group 7">
+<path id="Vector" d="M14 28C21.732 28 28 21.732 28 14C28 6.26801 21.732 0 14 0C6.26801 0 0 6.26801 0 14C0 21.732 6.26801 28 14 28Z" fill="url(#paint0_linear_6186_11887)"/>
+<path id="Vector_2" d="M13.9999 24.8636C19.9997 24.8636 24.8636 19.9997 24.8636 13.9999C24.8636 8.00006 19.9997 3.13623 13.9999 3.13623C8.00006 3.13623 3.13623 8.00006 3.13623 13.9999C3.13623 19.9997 8.00006 24.8636 13.9999 24.8636Z" fill="url(#paint1_linear_6186_11887)"/>
+<g id="Group">
+<path id="Vector_3" d="M5.43048 23.2492C5.46819 23.2107 5.48424 23.1666 5.47862 23.1177C5.473 23.0687 5.44412 22.9997 5.39197 22.909C5.33901 22.8192 5.30772 22.7462 5.29809 22.69C5.28365 22.6106 5.30291 22.5432 5.35586 22.4878C5.40721 22.4341 5.4714 22.4124 5.54762 22.4212C5.62384 22.43 5.69605 22.4678 5.76425 22.5344C5.81079 22.5793 5.84368 22.6282 5.86294 22.6812C5.8822 22.7341 5.88621 22.7871 5.87578 22.8384C5.86535 22.8898 5.84048 22.9355 5.80277 22.9748L5.74339 22.9171C5.78993 22.8689 5.80999 22.8152 5.80597 22.755C5.80116 22.6948 5.77147 22.6379 5.71692 22.5841C5.66316 22.5327 5.6094 22.5031 5.55484 22.4966C5.50028 22.4902 5.45455 22.5055 5.41684 22.544C5.38234 22.5793 5.3687 22.6226 5.37512 22.6724C5.38154 22.7221 5.40802 22.7863 5.45455 22.8641C5.50028 22.9419 5.53077 23.0053 5.54521 23.0551C5.55966 23.1048 5.56287 23.1497 5.55404 23.1915C5.54522 23.2332 5.52435 23.2709 5.49066 23.3054C5.4377 23.3608 5.37271 23.3832 5.29649 23.3736C5.22027 23.364 5.14645 23.3247 5.07424 23.2557C5.0253 23.2083 4.98839 23.1554 4.96432 23.0984C4.94025 23.0414 4.93303 22.9861 4.94186 22.9339C4.95148 22.8818 4.97555 22.8352 5.01487 22.7943L5.07424 22.8513C5.0269 22.9002 5.00765 22.9572 5.01647 23.0214C5.0261 23.0856 5.0606 23.1465 5.12158 23.2059C5.17614 23.2581 5.2315 23.2885 5.28686 23.2966C5.34303 23.3046 5.39036 23.2885 5.42888 23.2492H5.43048Z" fill="white"/>
+<path id="Vector_4" d="M6.31617 23.7556C6.2584 23.8238 6.19662 23.8744 6.12923 23.9065C6.06183 23.9386 5.99524 23.9498 5.92784 23.941C5.86044 23.9321 5.79786 23.9033 5.74009 23.8551C5.65344 23.7821 5.60931 23.6922 5.60771 23.5855C5.6061 23.4788 5.65023 23.3721 5.73849 23.267L5.80268 23.19C5.85964 23.1226 5.92223 23.072 5.98962 23.0399C6.05702 23.0078 6.12522 22.9958 6.19261 23.0046C6.26001 23.0135 6.32259 23.0415 6.37956 23.0897C6.43652 23.1378 6.47584 23.194 6.4967 23.2582C6.51756 23.3224 6.51836 23.3898 6.49991 23.4604C6.48145 23.531 6.44455 23.6 6.38999 23.6666L6.31537 23.7556H6.31617ZM6.32099 23.6224C6.39641 23.5326 6.43492 23.4459 6.43652 23.3609C6.43893 23.2758 6.40443 23.2044 6.33382 23.145C6.26482 23.0873 6.1886 23.0664 6.10436 23.0825C6.02091 23.0993 5.94068 23.1531 5.86365 23.2437L5.79866 23.3216C5.72485 23.4098 5.68634 23.4965 5.68393 23.5823C5.68152 23.6682 5.71522 23.7404 5.78583 23.7998C5.85724 23.8591 5.93426 23.8808 6.0161 23.8631C6.09874 23.8455 6.17817 23.7917 6.25439 23.7003L6.32018 23.6216L6.32099 23.6224Z" fill="white"/>
+<path id="Vector_5" d="M6.97267 24.3966C6.90367 24.4728 6.82825 24.5153 6.74641 24.5226C6.66457 24.5306 6.58113 24.5041 6.49769 24.4439C6.43912 24.4022 6.3982 24.3501 6.37413 24.2883C6.35006 24.2265 6.34524 24.1599 6.35969 24.0893C6.37413 24.0187 6.40542 23.9481 6.45516 23.8791L6.52898 23.7772C6.57953 23.7074 6.63649 23.6536 6.69988 23.6175C6.76326 23.5814 6.82905 23.5646 6.89565 23.5686C6.96304 23.5726 7.02643 23.5959 7.0866 23.6392C7.17085 23.7002 7.2214 23.7708 7.23744 23.8518C7.25349 23.9328 7.23664 24.0155 7.1869 24.1021L7.1195 24.054C7.19973 23.908 7.17486 23.7892 7.04649 23.6961C6.97508 23.6448 6.89886 23.6304 6.81782 23.6536C6.73678 23.6769 6.66217 23.7347 6.59477 23.8293L6.52497 23.9256C6.45918 24.0163 6.42788 24.1037 6.43029 24.188C6.4327 24.2722 6.4688 24.3388 6.53941 24.3902C6.60921 24.4407 6.6734 24.4616 6.73277 24.4536C6.79215 24.4455 6.84991 24.411 6.90608 24.3509L6.97347 24.399L6.97267 24.3966Z" fill="white"/>
+<path id="Vector_6" d="M7.31909 24.9735L7.65768 24.4119L7.55578 24.3501L7.58948 24.2939L7.69138 24.3557L7.73631 24.2811C7.77482 24.2177 7.81975 24.1792 7.87271 24.1648C7.92566 24.1503 7.98022 24.1607 8.03799 24.1952C8.06366 24.2105 8.08613 24.2289 8.10458 24.249L8.06527 24.3028C8.04922 24.2867 8.02996 24.2723 8.0075 24.2586C7.96979 24.2362 7.93368 24.2297 7.89838 24.241C7.86308 24.2522 7.83259 24.2787 7.80691 24.322L7.76038 24.399L7.90801 24.4881L7.87431 24.5443L7.72668 24.4552L7.38809 25.0168L7.31989 24.9751L7.31909 24.9735Z" fill="white"/>
+<path id="Vector_7" d="M7.82238 24.8435C7.85528 24.7825 7.8962 24.7336 7.94675 24.6975C7.99649 24.6614 8.05105 24.6413 8.10882 24.6373C8.16659 24.6333 8.22275 24.6461 8.27811 24.6758C8.36236 24.7216 8.41531 24.7874 8.43617 24.8756C8.45703 24.9631 8.44099 25.0561 8.38803 25.154L8.38001 25.1685C8.34711 25.2302 8.30539 25.2792 8.25565 25.3153C8.2059 25.3514 8.15214 25.3715 8.09438 25.3755C8.03661 25.3787 7.98044 25.3658 7.92589 25.3361C7.84164 25.2912 7.78949 25.2246 7.76863 25.1372C7.74777 25.0497 7.76381 24.9566 7.81597 24.8588L7.82319 24.8443L7.82238 24.8435ZM7.88256 24.9013C7.84164 24.9775 7.828 25.0505 7.84084 25.1203C7.85367 25.1901 7.89219 25.2423 7.95637 25.2768C8.01976 25.3105 8.08395 25.3137 8.14974 25.2864C8.21553 25.2591 8.26929 25.2054 8.31261 25.1251L8.31983 25.1115C8.34631 25.0634 8.36075 25.0136 8.36476 24.9639C8.36878 24.9141 8.35995 24.8692 8.33909 24.8291C8.31823 24.7898 8.28694 24.7585 8.24522 24.736C8.18263 24.7023 8.11845 24.6991 8.05265 24.7272C7.98686 24.7553 7.9323 24.809 7.88978 24.8884L7.88256 24.9013Z" fill="white"/>
+<path id="Vector_8" d="M8.97134 25.1115C8.9577 25.101 8.94166 25.0922 8.92481 25.0842C8.87988 25.0625 8.83575 25.0577 8.79242 25.0673C8.7491 25.0778 8.70978 25.1034 8.67368 25.1452L8.46106 25.5929L8.38965 25.5592L8.69855 24.9069L8.76915 24.9406L8.72101 25.0449C8.79563 24.9855 8.87506 24.9767 8.95931 25.016C8.97937 25.0256 8.99381 25.036 9.00344 25.0465L8.97054 25.1115H8.97134Z" fill="white"/>
+<path id="Vector_9" d="M9.77199 25.8825C9.79124 25.832 9.78883 25.7854 9.76476 25.7429C9.74069 25.7004 9.68614 25.6474 9.60269 25.5857C9.51925 25.5239 9.46148 25.4685 9.43019 25.4212C9.38526 25.3538 9.37643 25.284 9.40371 25.2126C9.43019 25.1436 9.47994 25.0978 9.55375 25.0762C9.62757 25.0545 9.7086 25.0609 9.79766 25.0946C9.85784 25.1179 9.90758 25.15 9.94609 25.1909C9.98461 25.2326 10.0095 25.2784 10.0199 25.3305C10.0303 25.3819 10.0255 25.4332 10.0063 25.4846L9.92924 25.4549C9.95251 25.3931 9.95091 25.3345 9.92283 25.2808C9.89474 25.227 9.845 25.1861 9.77359 25.1596C9.70459 25.1331 9.64281 25.1275 9.58986 25.1428C9.5369 25.158 9.5008 25.1909 9.48234 25.2407C9.46469 25.2872 9.4687 25.3313 9.49518 25.3746C9.52085 25.418 9.5706 25.4661 9.64361 25.5191C9.71663 25.572 9.76958 25.6186 9.80247 25.6587C9.83537 25.6988 9.85623 25.7389 9.86426 25.7806C9.87228 25.8224 9.86827 25.8649 9.85142 25.9106C9.82414 25.982 9.77359 26.0286 9.70058 26.0502C9.62676 26.0719 9.54332 26.0647 9.45025 26.0294C9.38606 26.0053 9.3315 25.9716 9.28737 25.9283C9.24244 25.8849 9.21436 25.8376 9.20233 25.7862C9.19029 25.7349 9.1943 25.6819 9.21436 25.629L9.29139 25.6579C9.26732 25.7221 9.27213 25.7814 9.30583 25.8368C9.33953 25.8922 9.39569 25.9347 9.47512 25.9652C9.54573 25.9916 9.60831 25.9981 9.66287 25.9828C9.71743 25.9676 9.75433 25.9347 9.77439 25.8833L9.77199 25.8825Z" fill="white"/>
+<path id="Vector_10" d="M10.2131 26.2917C10.1545 26.2733 10.1064 26.2428 10.0679 26.1995C10.0294 26.1561 10.0053 26.104 9.99485 26.0446C9.98442 25.9844 9.98924 25.9226 10.0093 25.8585L10.0181 25.8312C10.039 25.7646 10.0703 25.7092 10.112 25.6643C10.1537 25.6194 10.2027 25.5889 10.258 25.5728C10.3134 25.5568 10.3679 25.5568 10.4209 25.5728C10.5043 25.5985 10.5621 25.6482 10.5934 25.7205C10.6247 25.7927 10.6247 25.8785 10.5942 25.9772L10.5806 26.0197L10.0887 25.8673L10.0839 25.8817C10.0598 25.9596 10.0623 26.0318 10.0903 26.0976C10.1192 26.1633 10.1674 26.2067 10.2356 26.2283C10.2765 26.2412 10.315 26.2444 10.3503 26.2396C10.3856 26.2348 10.4217 26.2195 10.4578 26.1946L10.4939 26.246C10.4129 26.3094 10.319 26.3246 10.2123 26.2917H10.2131ZM10.4008 25.6378C10.3439 25.6202 10.2885 25.6258 10.2364 25.6563C10.1842 25.686 10.1425 25.7349 10.112 25.8031L10.5252 25.9315L10.5276 25.9234C10.5461 25.8569 10.5437 25.7967 10.5212 25.7437C10.4987 25.6908 10.4578 25.6555 10.4008 25.6378Z" fill="white"/>
+<path id="Vector_11" d="M11.1407 25.856C11.1254 25.8488 11.1078 25.8424 11.0893 25.8384C11.0412 25.8255 10.997 25.8287 10.9561 25.8472C10.916 25.8657 10.8823 25.8985 10.8542 25.9459L10.7299 26.4257L10.6528 26.4056L10.8334 25.7068L10.9088 25.726L10.8815 25.8376C10.9441 25.7654 11.0203 25.7413 11.1102 25.7646C11.1318 25.7702 11.1479 25.7774 11.1591 25.7862L11.139 25.856H11.1407Z" fill="white"/>
+<path id="Vector_12" d="M11.3831 26.4659L11.7233 25.9123L11.8036 25.9292L11.392 26.5807L11.3286 26.5678L11.2114 25.8064L11.2917 25.8232L11.3831 26.4667V26.4659Z" fill="white"/>
+<path id="Vector_13" d="M11.895 26.6737L11.8164 26.66L11.936 25.9484L12.0146 25.962L11.895 26.6737ZM11.9568 25.7406C11.9592 25.7261 11.9664 25.7141 11.9777 25.7053C11.9889 25.6964 12.0034 25.694 12.0194 25.6964C12.0362 25.6996 12.0483 25.7069 12.0563 25.7181C12.0643 25.7301 12.0675 25.743 12.0651 25.7582C12.0627 25.7727 12.0555 25.7847 12.0443 25.7927C12.033 25.8007 12.0186 25.804 12.0017 25.8007C11.9849 25.7983 11.9729 25.7911 11.9648 25.7791C11.9568 25.767 11.9544 25.7542 11.9568 25.7398V25.7406Z" fill="white"/>
+<path id="Vector_14" d="M12.4061 26.6929C12.4615 26.7002 12.5096 26.6905 12.5505 26.664C12.5915 26.6376 12.6171 26.5999 12.626 26.5509L12.7022 26.5605C12.6942 26.6039 12.6757 26.6424 12.646 26.6745C12.6163 26.7074 12.5794 26.7314 12.5353 26.7459C12.4912 26.7603 12.4454 26.7651 12.3973 26.7595C12.3034 26.7475 12.2328 26.7058 12.1863 26.6336C12.1398 26.5613 12.1229 26.4699 12.1373 26.36L12.1406 26.3359C12.1494 26.2653 12.1694 26.2043 12.2015 26.153C12.2328 26.1016 12.2737 26.0647 12.3235 26.0406C12.3732 26.0166 12.4294 26.0085 12.4912 26.0166C12.5698 26.0262 12.6316 26.0583 12.6765 26.1112C12.7214 26.1642 12.7407 26.2292 12.7351 26.3062L12.6589 26.2966C12.6621 26.2404 12.6476 26.1923 12.6155 26.153C12.5826 26.1136 12.5385 26.0912 12.4823 26.084C12.4109 26.0751 12.3524 26.0936 12.3058 26.1401C12.2601 26.1867 12.2312 26.2565 12.2192 26.3495L12.216 26.3728C12.2047 26.4643 12.216 26.5381 12.2481 26.5942C12.281 26.6504 12.3339 26.6833 12.4053 26.6921L12.4061 26.6929Z" fill="white"/>
+<path id="Vector_15" d="M13.1466 26.8301C13.0856 26.8261 13.0311 26.8068 12.9837 26.7739C12.9364 26.7402 12.9011 26.6961 12.877 26.6399C12.8529 26.5846 12.8433 26.5228 12.8481 26.4562L12.8497 26.4273C12.8545 26.3583 12.8722 26.2965 12.9027 26.2428C12.9332 26.189 12.9733 26.1481 13.0238 26.12C13.0744 26.0919 13.1265 26.0791 13.1827 26.0831C13.2702 26.0887 13.3376 26.1232 13.3849 26.1866C13.4322 26.25 13.4523 26.3326 13.4451 26.4361L13.4419 26.4811L12.9284 26.4458V26.461C12.9219 26.5429 12.9404 26.6119 12.9837 26.6696C13.027 26.7274 13.084 26.7587 13.1546 26.7635C13.1971 26.7667 13.2357 26.7611 13.2694 26.7483C13.3031 26.7354 13.3343 26.7122 13.3632 26.6801L13.4106 26.721C13.3464 26.802 13.2581 26.8381 13.1474 26.8309L13.1466 26.8301ZM13.1779 26.1505C13.1177 26.1465 13.0664 26.165 13.0222 26.2059C12.9781 26.2468 12.9492 26.3046 12.9356 26.3776L13.3672 26.4073V26.3984C13.3704 26.3294 13.3544 26.2717 13.3199 26.2251C13.2854 26.1794 13.2381 26.1537 13.1779 26.1497V26.1505Z" fill="white"/>
+<path id="Vector_16" d="M14.6863 26.3993C14.6887 26.4884 14.6751 26.5678 14.6454 26.636C14.6165 26.7042 14.5732 26.7571 14.517 26.7949C14.4608 26.8326 14.395 26.8526 14.3196 26.8542C14.2065 26.8566 14.1134 26.8189 14.042 26.7395C13.9706 26.6601 13.9329 26.5517 13.9297 26.4137L13.9273 26.3135C13.9249 26.2252 13.9385 26.1466 13.9682 26.0776C13.9979 26.0086 14.0412 25.9548 14.0974 25.9171C14.1535 25.8794 14.2193 25.8593 14.2939 25.8569C14.3686 25.8553 14.4352 25.8714 14.4929 25.9059C14.5507 25.9404 14.5964 25.9901 14.6293 26.0551C14.6622 26.1201 14.6799 26.1963 14.6839 26.283L14.6871 26.3993H14.6863ZM14.602 26.2958C14.5988 26.1787 14.5707 26.088 14.5162 26.023C14.4616 25.958 14.3886 25.9267 14.2963 25.9291C14.2065 25.9315 14.1351 25.966 14.0829 26.0342C14.0308 26.1024 14.0067 26.1955 14.0091 26.3143L14.0115 26.4154C14.0147 26.5301 14.0436 26.6207 14.0982 26.6873C14.1535 26.7531 14.2265 26.7852 14.318 26.7828C14.4111 26.7804 14.4825 26.7459 14.533 26.6777C14.5836 26.6095 14.6069 26.5164 14.6044 26.3985L14.602 26.2958Z" fill="white"/>
+<path id="Vector_17" d="M15.1989 26.1353C15.182 26.1337 15.1636 26.1337 15.1443 26.1353C15.0946 26.1393 15.0536 26.1562 15.0216 26.1866C14.9895 26.2171 14.9678 26.2597 14.9582 26.3134L14.9983 26.8077L14.9189 26.8141L14.8611 26.0952L14.9389 26.0888L14.9493 26.2027C14.9846 26.1144 15.0488 26.0663 15.1419 26.0591C15.1644 26.0575 15.182 26.0591 15.1949 26.0639L15.1989 26.1361V26.1353Z" fill="white"/>
+<path id="Vector_18" d="M15.3144 26.4129C15.3 26.3005 15.3136 26.2091 15.3545 26.1369C15.3955 26.0646 15.4588 26.0237 15.5439 26.0125C15.641 25.9997 15.7204 26.0293 15.7814 26.0999L15.7718 25.9964L15.8456 25.9868L15.9362 26.6881C15.9483 26.7803 15.9314 26.8565 15.8873 26.9167C15.8424 26.9769 15.7766 27.013 15.6883 27.0242C15.6386 27.0307 15.5896 27.0258 15.5415 27.009C15.4933 26.9921 15.454 26.9673 15.4235 26.9336L15.4621 26.8798C15.527 26.9416 15.5976 26.9673 15.6755 26.9568C15.7413 26.948 15.791 26.9223 15.8223 26.8782C15.8544 26.8341 15.8664 26.7779 15.8592 26.7081L15.8472 26.6183C15.8055 26.6953 15.7365 26.7402 15.6394 26.753C15.5567 26.7635 15.4853 26.7394 15.4268 26.68C15.3682 26.6207 15.3313 26.534 15.3168 26.4217L15.3152 26.4113L15.3144 26.4129ZM15.3963 26.4161C15.4083 26.5075 15.4356 26.5773 15.4789 26.6247C15.5222 26.6728 15.5776 26.6921 15.6442 26.684C15.7413 26.6712 15.8047 26.6191 15.8343 26.526L15.791 26.193C15.7661 26.1497 15.7357 26.1184 15.6971 26.0983C15.6594 26.0791 15.6161 26.0719 15.5672 26.0783C15.5006 26.0871 15.4524 26.12 15.4219 26.177C15.3914 26.2339 15.3834 26.3134 15.3963 26.4153V26.4161Z" fill="white"/>
+<path id="Vector_19" d="M16.6271 26.5773C16.615 26.5565 16.6038 26.5244 16.5934 26.4811C16.5725 26.522 16.5428 26.5565 16.5043 26.5838C16.4658 26.611 16.4225 26.6295 16.3743 26.6391C16.3061 26.652 16.2476 26.6439 16.1978 26.6142C16.1481 26.5846 16.1184 26.5404 16.1071 26.4827C16.0935 26.4137 16.112 26.3535 16.1617 26.3021C16.2115 26.2508 16.2877 26.2155 16.3904 26.1954L16.5324 26.1681L16.5171 26.0879C16.5075 26.0374 16.4842 26.0005 16.4473 25.9772C16.4104 25.9539 16.3623 25.9483 16.3021 25.9595C16.2476 25.97 16.205 25.9924 16.1745 26.0277C16.1441 26.0622 16.1328 26.1 16.14 26.1393L16.0614 26.1537C16.051 26.0975 16.067 26.0438 16.112 25.9924C16.1561 25.9411 16.2171 25.9082 16.2933 25.8938C16.3719 25.8785 16.4385 25.8865 16.4915 25.917C16.5444 25.9475 16.5789 25.9981 16.5934 26.0687L16.6576 26.404C16.6704 26.4722 16.688 26.5228 16.7089 26.5541L16.7105 26.5621L16.6271 26.5781V26.5773ZM16.3695 26.5685C16.4217 26.5581 16.4666 26.5364 16.5027 26.5035C16.5388 26.4706 16.5629 26.4305 16.5733 26.3848L16.5436 26.2291L16.4032 26.2564C16.3254 26.2725 16.2668 26.2981 16.2283 26.3342C16.1898 26.3703 16.1745 26.4129 16.1842 26.461C16.1922 26.5011 16.2131 26.5308 16.2476 26.5517C16.2821 26.5725 16.323 26.5781 16.3703 26.5685H16.3695Z" fill="white"/>
+<path id="Vector_20" d="M16.8277 25.7934L16.8606 25.9122C16.8759 25.8624 16.8999 25.8215 16.9336 25.7886C16.9673 25.7557 17.0074 25.7333 17.0548 25.7212C17.1294 25.702 17.1912 25.7092 17.2385 25.7421C17.2859 25.775 17.3204 25.8336 17.3428 25.9178L17.46 26.3767L17.3829 26.3968L17.265 25.9379C17.2489 25.8753 17.2233 25.8328 17.1896 25.8087C17.1559 25.7846 17.1101 25.7798 17.0532 25.7951C17.005 25.8071 16.9665 25.8328 16.9376 25.8721C16.9088 25.9114 16.8919 25.9587 16.8871 26.0141L17.0099 26.4931L16.9328 26.5131L16.7539 25.8143L16.8277 25.7951V25.7934Z" fill="white"/>
+<path id="Vector_21" d="M17.4094 25.4204C17.4054 25.406 17.4062 25.3923 17.4126 25.3795C17.4191 25.3667 17.4303 25.3578 17.4463 25.353C17.4624 25.3482 17.4768 25.349 17.4897 25.3562C17.5025 25.3634 17.5105 25.3739 17.5153 25.3883C17.5194 25.4028 17.5186 25.4164 17.5121 25.4284C17.5057 25.4413 17.4937 25.4501 17.4776 25.4549C17.4616 25.4597 17.4471 25.4589 17.4351 25.4517C17.4231 25.4445 17.4142 25.434 17.4102 25.4196L17.4094 25.4204ZM17.7689 26.2837L17.6927 26.307L17.4832 25.6162L17.5595 25.5929L17.7689 26.2837Z" fill="white"/>
+<path id="Vector_22" d="M18.0281 26.1313L18.471 25.9772L18.4935 26.0406L17.9575 26.2267L17.9382 26.1714L18.1565 25.4669L17.7561 25.6057L17.7336 25.5399L18.2295 25.3674L18.2495 25.4244L18.0297 26.1297L18.0281 26.1313Z" fill="white"/>
+<path id="Vector_23" d="M19.0799 25.8031C19.0639 25.7854 19.0462 25.7558 19.027 25.7156C19.0149 25.7598 18.9925 25.7999 18.9604 25.8344C18.9283 25.8689 18.889 25.8962 18.844 25.9146C18.7799 25.9411 18.7205 25.9443 18.6659 25.925C18.6114 25.9058 18.5728 25.8689 18.5504 25.8143C18.5239 25.7493 18.5295 25.6868 18.568 25.6266C18.6065 25.5664 18.6739 25.5167 18.7702 25.4765L18.9042 25.4212L18.8729 25.345C18.8529 25.2976 18.8232 25.2655 18.7823 25.2511C18.7413 25.2366 18.6932 25.2398 18.637 25.2631C18.5857 25.284 18.5488 25.3153 18.5255 25.3554C18.503 25.3955 18.499 25.434 18.5143 25.4709L18.4397 25.5006C18.418 25.4477 18.4236 25.3915 18.4565 25.3321C18.4902 25.2727 18.5424 25.2286 18.6146 25.1989C18.6892 25.1684 18.755 25.1628 18.8135 25.1821C18.8721 25.2013 18.9154 25.2447 18.9443 25.3105L19.0743 25.6258C19.1008 25.69 19.1281 25.7357 19.1545 25.7622L19.1578 25.7694L19.0791 25.8023L19.0799 25.8031ZM18.8264 25.8456C18.8761 25.8256 18.9146 25.7951 18.9435 25.755C18.9724 25.7148 18.9877 25.6715 18.9885 25.6242L18.9283 25.4773L18.7967 25.5319C18.7237 25.5632 18.6715 25.6001 18.641 25.6434C18.6106 25.6868 18.6041 25.7309 18.6234 25.7766C18.6386 25.8143 18.6659 25.8392 18.7036 25.8528C18.7413 25.8657 18.7831 25.8633 18.8272 25.8448L18.8264 25.8456Z" fill="white"/>
+<path id="Vector_24" d="M19.083 24.8058L19.1616 24.9727L19.2964 24.9093L19.3245 24.9687L19.1897 25.032L19.3943 25.4677C19.4112 25.5038 19.4304 25.5279 19.4521 25.5391C19.4737 25.5504 19.4994 25.5496 19.5299 25.5351C19.5419 25.5295 19.5604 25.5183 19.5853 25.5014L19.6157 25.5584C19.5997 25.5744 19.5756 25.5897 19.5435 25.6049C19.4938 25.6282 19.4513 25.6306 19.4152 25.6129C19.3791 25.5945 19.3478 25.5576 19.3213 25.5022L19.1167 25.0665L18.9963 25.1227L18.9683 25.0633L19.0886 25.0072L19.01 24.8403L19.0822 24.8066L19.083 24.8058Z" fill="white"/>
+<path id="Vector_25" d="M19.3438 24.6526C19.3374 24.639 19.3358 24.6254 19.3398 24.6117C19.3438 24.5981 19.3535 24.5876 19.3687 24.5796C19.384 24.5716 19.3984 24.5708 19.412 24.5756C19.4257 24.5804 19.4361 24.5893 19.4425 24.6029C19.449 24.6165 19.4506 24.6294 19.4465 24.643C19.4425 24.6566 19.4329 24.6671 19.4177 24.6751C19.4024 24.6831 19.388 24.6839 19.3751 24.6799C19.3623 24.6759 19.3519 24.6663 19.3446 24.6526H19.3438ZM19.8493 25.4389L19.7779 25.475L19.4506 24.8316L19.522 24.7955L19.8493 25.4389Z" fill="white"/>
+<path id="Vector_26" d="M19.8461 25.0264C19.8115 24.9663 19.7931 24.9053 19.7891 24.8435C19.7851 24.7817 19.7971 24.7256 19.8244 24.6742C19.8517 24.6229 19.8926 24.5819 19.9471 24.5515C20.0306 24.5041 20.1148 24.4953 20.1999 24.525C20.2849 24.5547 20.3547 24.6172 20.4093 24.7143L20.4173 24.7288C20.4518 24.7897 20.4711 24.8507 20.4751 24.9125C20.4791 24.9743 20.4671 25.0304 20.4398 25.081C20.4125 25.1315 20.3708 25.1717 20.3162 25.2029C20.2328 25.2503 20.1485 25.2591 20.0635 25.2294C19.9784 25.2005 19.9086 25.1372 19.8533 25.0401L19.8452 25.0264H19.8461ZM19.9271 25.0064C19.9696 25.0818 20.0242 25.1323 20.09 25.158C20.1558 25.1837 20.2207 25.1797 20.2841 25.1436C20.3467 25.1083 20.3844 25.0553 20.3957 24.9855C20.4069 24.9157 20.3908 24.8411 20.3459 24.7617L20.3387 24.748C20.3114 24.6999 20.2777 24.6614 20.2376 24.6317C20.1975 24.602 20.155 24.5851 20.11 24.5811C20.0659 24.5771 20.0226 24.5876 19.9808 24.6108C19.9191 24.6461 19.8822 24.6983 19.8701 24.7697C19.8581 24.8403 19.8749 24.9149 19.9191 24.9935L19.9263 25.0064H19.9271Z" fill="white"/>
+<path id="Vector_27" d="M20.4318 24.2803L20.5016 24.3822C20.5 24.3301 20.5096 24.2835 20.5313 24.2418C20.5521 24.2001 20.5834 24.1664 20.6244 24.1391C20.6893 24.0966 20.7495 24.0838 20.8049 24.0998C20.8602 24.1159 20.9116 24.16 20.9597 24.233L21.2173 24.6302L21.1507 24.6735L20.8923 24.2755C20.857 24.2218 20.8193 24.1889 20.7792 24.1768C20.7391 24.1648 20.695 24.1752 20.6452 24.2073C20.6035 24.2346 20.5754 24.2707 20.561 24.3172C20.5465 24.3638 20.5449 24.4143 20.5586 24.4681L20.8281 24.8829L20.7616 24.9262L20.3684 24.3213L20.4318 24.2795V24.2803Z" fill="white"/>
+<path id="Vector_28" d="M21.6546 24.0886C21.6313 24.0565 21.5993 24.0404 21.5599 24.0404C21.5198 24.0404 21.4701 24.0532 21.4107 24.0805C21.3513 24.1078 21.3016 24.1247 21.2631 24.1311C21.2246 24.1383 21.1901 24.1359 21.1612 24.1263C21.1323 24.1166 21.1074 24.0966 21.0858 24.0677C21.0521 24.022 21.0432 23.9698 21.0593 23.912C21.0753 23.8543 21.1138 23.8029 21.1732 23.7588C21.2382 23.7115 21.3016 23.689 21.3642 23.6922C21.4267 23.6954 21.4773 23.7227 21.515 23.774L21.4508 23.8214C21.4259 23.7877 21.3906 23.7692 21.3457 23.7676C21.3008 23.766 21.2567 23.7813 21.2133 23.8133C21.1708 23.8446 21.1443 23.8791 21.1323 23.9168C21.1203 23.9546 21.1259 23.9883 21.1475 24.0187C21.1692 24.0476 21.1965 24.0621 21.2294 24.0629C21.2623 24.0629 21.312 24.0492 21.3778 24.0212C21.4436 23.9931 21.4966 23.9762 21.5359 23.9706C21.5752 23.965 21.6089 23.9674 21.6386 23.9786C21.6675 23.9899 21.6931 24.0099 21.7156 24.0404C21.7517 24.0894 21.7605 24.1431 21.7429 24.2017C21.7252 24.2603 21.6843 24.3132 21.6201 24.3597C21.5527 24.4095 21.4853 24.4336 21.4195 24.432C21.3529 24.4303 21.3016 24.4039 21.2647 24.3541L21.3289 24.3068C21.3594 24.3429 21.3963 24.3605 21.4412 24.3597C21.4861 24.3589 21.5319 24.3413 21.58 24.306C21.6249 24.2731 21.6538 24.2362 21.6666 24.1969C21.6795 24.1575 21.6755 24.1214 21.653 24.0918L21.6546 24.0886Z" fill="white"/>
+<path id="Vector_29" d="M22.7023 23.6914L22.6518 23.7363L21.8848 22.8778L21.9353 22.8329L22.7023 23.6914Z" fill="white"/>
+<path id="Vector_30" d="M23.418 22.3659C23.3868 22.337 23.3523 22.3258 23.3145 22.3322C23.2776 22.3386 23.2239 22.3627 23.1533 22.4044C23.0827 22.4461 23.0217 22.4742 22.9687 22.4886C22.8684 22.5159 22.785 22.4999 22.7192 22.4397C22.6614 22.3867 22.6358 22.3193 22.6414 22.2383C22.647 22.1573 22.6847 22.0786 22.7529 22.004C22.7986 21.9543 22.8484 21.9182 22.9029 21.8957C22.9567 21.8732 23.0113 21.8668 23.0658 21.8756C23.1204 21.8845 23.1677 21.9077 23.2094 21.9454L23.0955 22.069C23.0586 22.0345 23.0185 22.0193 22.9752 22.0241C22.9326 22.0281 22.8909 22.0522 22.8516 22.0955C22.8147 22.1364 22.7938 22.1757 22.7906 22.2142C22.7874 22.2527 22.801 22.2864 22.8323 22.3145C22.8588 22.3386 22.8917 22.3466 22.931 22.3386C22.9711 22.3306 23.0241 22.3057 23.0923 22.2656C23.1597 22.2255 23.2199 22.1974 23.272 22.1829C23.3242 22.1685 23.3707 22.1661 23.4124 22.1757C23.4541 22.1853 23.4935 22.2062 23.5304 22.2399C23.5897 22.2945 23.6162 22.3611 23.6098 22.4389C23.6034 22.5167 23.5641 22.5953 23.4919 22.6732C23.4445 22.7253 23.3916 22.7638 23.3322 22.7895C23.2736 22.8152 23.2159 22.8248 23.1597 22.8176C23.1035 22.8104 23.0538 22.7871 23.0089 22.7454L23.1228 22.621C23.1637 22.6579 23.207 22.674 23.2544 22.6675C23.3009 22.6611 23.3474 22.633 23.394 22.5825C23.4333 22.5392 23.455 22.4991 23.4574 22.4605C23.4598 22.4228 23.4469 22.3907 23.418 22.3643V22.3659Z" fill="white"/>
+<path id="Vector_31" d="M24.0366 22.0386C23.9724 22.1188 23.8946 22.1629 23.8039 22.1718C23.7133 22.1806 23.6266 22.1517 23.5424 22.0843L23.5271 22.0715C23.471 22.0265 23.43 21.9752 23.4028 21.9182C23.3763 21.8612 23.3659 21.8027 23.3731 21.7441C23.3803 21.6855 23.4028 21.6318 23.4413 21.5836C23.5031 21.5074 23.5753 21.4681 23.6571 21.4657C23.7389 21.4633 23.8256 21.4978 23.9147 21.57L23.9652 21.6109L23.6691 21.9776C23.7189 22.0113 23.7678 22.0249 23.8168 22.0201C23.8657 22.0145 23.9066 21.9912 23.9403 21.9503C23.9869 21.8925 24.0013 21.8267 23.9845 21.7529L24.104 21.7369C24.1193 21.7866 24.1217 21.8372 24.1096 21.8901C24.0976 21.9423 24.0735 21.992 24.0358 22.0386H24.0366ZM23.5432 21.6655C23.5151 21.7 23.5047 21.7377 23.5119 21.7786C23.5191 21.8195 23.5416 21.8604 23.5801 21.9014L23.7742 21.6607L23.7646 21.6534C23.7205 21.6221 23.6788 21.6077 23.6419 21.6101C23.6042 21.6125 23.5713 21.631 23.5432 21.6663V21.6655Z" fill="white"/>
+<path id="Vector_32" d="M24.0584 21.0357C24.0432 21.0509 24.0287 21.0678 24.0151 21.0862C23.9718 21.1464 23.9653 21.2034 23.9958 21.2579L24.3946 21.5484L24.2991 21.6791L23.7158 21.2547L23.8065 21.1295L23.8739 21.1737C23.8466 21.1055 23.853 21.0429 23.8939 20.9867C23.9076 20.9683 23.9212 20.9546 23.9349 20.9458L24.0576 21.0357H24.0584Z" fill="white"/>
+<path id="Vector_33" d="M24.5717 20.9305L24.2243 20.5197L24.3166 20.3801L24.7827 20.9851L24.7057 21.103L23.9644 20.9177L24.0566 20.7773L24.5733 20.9313L24.5717 20.9305Z" fill="white"/>
+<path id="Vector_34" d="M24.2029 20.1997C24.1812 20.1868 24.1676 20.1692 24.1619 20.1475C24.1555 20.1258 24.1603 20.1018 24.1756 20.0769C24.1908 20.052 24.2093 20.0368 24.2318 20.0312C24.2542 20.0255 24.2759 20.0296 24.2975 20.0424C24.3184 20.0552 24.332 20.0721 24.3377 20.0945C24.3433 20.117 24.3385 20.1403 24.324 20.1652C24.3088 20.19 24.2903 20.2053 24.2687 20.2109C24.247 20.2157 24.2253 20.2125 24.2045 20.1997H24.2029ZM25.071 20.5182L24.9876 20.657L24.3681 20.2863L24.4516 20.1475L25.071 20.5182Z" fill="white"/>
+<path id="Vector_35" d="M25.2146 20.0271C25.2339 19.9918 25.2395 19.9565 25.2315 19.922C25.2235 19.8875 25.205 19.861 25.1745 19.8426L25.2475 19.7086C25.286 19.7318 25.3165 19.7639 25.3382 19.8056C25.3599 19.8474 25.3703 19.8931 25.3687 19.9436C25.3671 19.9942 25.3542 20.0423 25.3294 20.0881C25.2812 20.1771 25.2146 20.2317 25.1288 20.2525C25.0429 20.2734 24.9499 20.2566 24.8488 20.202L24.8343 20.194C24.738 20.1418 24.6747 20.0744 24.6442 19.991C24.6137 19.9075 24.6233 19.8217 24.6715 19.7326C24.7124 19.6572 24.7677 19.6075 24.8375 19.5842C24.9073 19.5601 24.9788 19.5665 25.0518 19.6035L24.9788 19.7374C24.9418 19.719 24.9049 19.7158 24.8688 19.7262C24.8327 19.7366 24.8054 19.7599 24.7854 19.796C24.7605 19.8426 24.7581 19.8867 24.7782 19.93C24.7982 19.9733 24.8416 20.0134 24.9098 20.0504L24.933 20.0624C25.002 20.0993 25.0598 20.1153 25.1071 20.1081C25.1545 20.1009 25.1906 20.0744 25.2162 20.0279L25.2146 20.0271Z" fill="white"/>
+<path id="Vector_36" d="M25.6743 19.398C25.6309 19.4911 25.5659 19.5529 25.4809 19.5834C25.3959 19.6139 25.3036 19.6066 25.2065 19.5609L25.188 19.5521C25.1231 19.5216 25.0701 19.4815 25.0308 19.4325C24.9915 19.3836 24.9674 19.329 24.9602 19.2705C24.953 19.2119 24.9618 19.1541 24.9883 19.098C25.03 19.0089 25.0902 18.9535 25.1696 18.9311C25.249 18.9086 25.3405 18.9222 25.4448 18.9704L25.5042 18.9977L25.3052 19.4253C25.3614 19.4462 25.4127 19.4478 25.4584 19.4309C25.505 19.4141 25.5387 19.3812 25.5611 19.3338C25.5924 19.2664 25.5908 19.199 25.5563 19.1316L25.6686 19.0875C25.6951 19.1316 25.7096 19.1814 25.7104 19.2352C25.7112 19.2889 25.6991 19.3427 25.6743 19.3972V19.398ZM25.1054 19.1541C25.087 19.1942 25.0853 19.2335 25.1022 19.2713C25.119 19.309 25.1511 19.3435 25.1977 19.374L25.3285 19.0939L25.3172 19.0891C25.2667 19.0691 25.2234 19.0651 25.1872 19.0763C25.1511 19.0875 25.1239 19.1132 25.1046 19.1541H25.1054Z" fill="white"/>
+<path id="Vector_37" d="M25.8155 17.7453C25.9054 17.7774 25.9784 17.8199 26.0354 17.8753C26.0923 17.9306 26.1284 17.9932 26.1445 18.063C26.1605 18.1328 26.1549 18.2059 26.1284 18.2813C26.102 18.3551 26.061 18.4153 26.0041 18.4602C25.9471 18.5051 25.8797 18.5324 25.8019 18.5404C25.7232 18.5485 25.6406 18.5372 25.5532 18.5067L25.5018 18.4883C25.4127 18.457 25.3389 18.4129 25.282 18.3575C25.225 18.3013 25.1881 18.2387 25.172 18.1681C25.156 18.0975 25.1616 18.0253 25.1881 17.9507C25.2146 17.8761 25.2555 17.8159 25.3116 17.771C25.3678 17.7261 25.4352 17.6996 25.5138 17.6924C25.5925 17.6843 25.6759 17.6964 25.7658 17.7277L25.8163 17.7453H25.8155ZM25.712 17.8873C25.6109 17.8512 25.5259 17.8432 25.4585 17.8625C25.3911 17.8817 25.3445 17.9266 25.3197 17.9972C25.2956 18.0662 25.3036 18.1296 25.3437 18.1874C25.3839 18.2452 25.4529 18.2917 25.5515 18.3278L25.6045 18.3463C25.7048 18.3816 25.7898 18.3896 25.8588 18.3695C25.9278 18.3495 25.9744 18.3053 25.9993 18.2355C26.0241 18.1649 26.0161 18.1015 25.976 18.0446C25.9359 17.9876 25.8637 17.9411 25.761 17.905L25.7128 17.8881L25.712 17.8873Z" fill="white"/>
+<path id="Vector_38" d="M25.8541 17.1956C25.8444 17.2149 25.8372 17.2357 25.8308 17.2574C25.8099 17.3288 25.8236 17.385 25.8709 17.4251L26.3451 17.5615L26.3002 17.7171L25.6069 17.5173L25.6495 17.3689L25.7281 17.3874C25.6783 17.332 25.6639 17.2718 25.6832 17.2052C25.6896 17.1828 25.6976 17.1651 25.708 17.1531L25.8541 17.1956Z" fill="white"/>
+<path id="Vector_39" d="M26.0747 17.182C25.9656 17.1563 25.8846 17.1106 25.8316 17.044C25.7787 16.9774 25.7618 16.902 25.7819 16.8169C25.8003 16.7367 25.8437 16.6805 25.9102 16.6477L25.8412 16.6236L25.8749 16.4816L26.5561 16.6412C26.6484 16.6629 26.7142 16.7086 26.7543 16.7784C26.7944 16.8482 26.8024 16.9317 26.78 17.0296C26.7679 17.0809 26.7455 17.1291 26.7126 17.1732C26.6797 17.2173 26.6428 17.2478 26.6019 17.2655L26.5248 17.1684C26.5938 17.1331 26.6364 17.0801 26.6532 17.0095C26.6652 16.9574 26.6612 16.9124 26.6396 16.8755C26.6179 16.8386 26.5802 16.8137 26.5248 16.8009L26.4775 16.7897C26.5176 16.8466 26.5289 16.9132 26.5112 16.9894C26.4919 17.0713 26.4438 17.1315 26.366 17.1684C26.2881 17.2053 26.1919 17.2101 26.0763 17.1828L26.0747 17.182ZM26.1253 17.028C26.1959 17.0448 26.2545 17.0432 26.3018 17.0239C26.3491 17.0047 26.3788 16.9694 26.3908 16.918C26.4061 16.8547 26.3892 16.8009 26.3419 16.7576L26.033 16.6854C25.9728 16.703 25.9351 16.7431 25.9199 16.8065C25.9078 16.8587 25.9191 16.9036 25.9536 16.9421C25.9881 16.9806 26.045 17.0095 26.1253 17.028Z" fill="white"/>
+<path id="Vector_40" d="M26.6877 16.0219C26.6733 16.0267 26.65 16.0291 26.6179 16.0291C26.662 16.0892 26.6781 16.1558 26.6661 16.2297C26.654 16.3011 26.6235 16.3556 26.5754 16.3941C26.5273 16.4326 26.4727 16.4463 26.4125 16.4359C26.3371 16.423 26.2833 16.3853 26.252 16.3219C26.2208 16.2585 26.2143 16.1751 26.232 16.07L26.2488 15.9721L26.2023 15.9641C26.1654 15.9577 26.1341 15.9633 26.1084 15.9801C26.0828 15.997 26.0667 16.0267 26.0595 16.0684C26.0531 16.1045 26.0571 16.1358 26.0715 16.1623C26.086 16.1887 26.1068 16.204 26.1349 16.2088L26.1076 16.3685C26.0683 16.362 26.0346 16.3428 26.0049 16.3115C25.9752 16.2802 25.9544 16.2401 25.9431 16.1927C25.9311 16.1446 25.9303 16.0941 25.9399 16.0387C25.9544 15.9553 25.9865 15.8927 26.0362 15.8502C26.0868 15.8076 26.1493 15.7924 26.2256 15.8036L26.5465 15.8582C26.6107 15.8694 26.6628 15.8686 26.7046 15.8574L26.7158 15.859L26.6885 16.0219H26.6877ZM26.5433 16.1783C26.5489 16.147 26.5457 16.1157 26.5353 16.0852C26.5248 16.0547 26.508 16.0307 26.4839 16.0122L26.3499 15.9898L26.3355 16.0756C26.3259 16.135 26.3283 16.1807 26.3435 16.2144C26.3588 16.2481 26.386 16.2674 26.4237 16.2738C26.4542 16.2786 26.4807 16.273 26.5024 16.2553C26.524 16.2377 26.5377 16.212 26.5433 16.1783Z" fill="white"/>
+<path id="Vector_41" d="M26.0384 15.453L26.1219 15.457C26.0633 15.3968 26.0392 15.3238 26.0481 15.2379C26.0641 15.0887 26.158 15.0213 26.3289 15.0374L26.8031 15.0879L26.7862 15.2492L26.3217 15.1994C26.2759 15.1946 26.2414 15.201 26.2174 15.2179C26.1933 15.2355 26.1788 15.266 26.174 15.3109C26.1668 15.3759 26.1909 15.4273 26.247 15.4658L26.7573 15.5204L26.7405 15.6816L26.0232 15.6046L26.0392 15.453H26.0384Z" fill="white"/>
+<path id="Vector_42" d="M25.9078 14.8416C25.883 14.84 25.8629 14.8312 25.8477 14.8143C25.8324 14.7975 25.8252 14.7742 25.8276 14.7453C25.8292 14.7165 25.8388 14.694 25.8565 14.6787C25.8741 14.6635 25.895 14.6571 25.9199 14.6587C25.9439 14.6603 25.964 14.6691 25.9792 14.6868C25.9945 14.7036 26.0009 14.7269 25.9993 14.7566C25.9977 14.7855 25.9881 14.8079 25.9712 14.8224C25.9544 14.8368 25.9335 14.844 25.9086 14.8424L25.9078 14.8416ZM26.8257 14.7261L26.8161 14.8882L26.0956 14.8432L26.1052 14.6812L26.8257 14.7261Z" fill="white"/>
+<path id="Vector_43" d="M26.7116 14.3489L26.7196 13.9646L26.8488 13.967L26.8368 14.5527L26.7309 14.5503L26.2535 14.1748L26.2463 14.5343L26.1155 14.5319L26.1267 13.967L26.2294 13.9694L26.7116 14.3497V14.3489Z" fill="white"/>
+<path id="Vector_44" d="M26.8312 13.3741C26.8176 13.3813 26.7951 13.3885 26.7646 13.395C26.82 13.4447 26.8497 13.5065 26.8521 13.5811C26.8545 13.6533 26.8361 13.7135 26.7967 13.7608C26.7574 13.8082 26.7069 13.833 26.6459 13.8354C26.5689 13.8386 26.5087 13.8122 26.4662 13.756C26.4229 13.7006 26.3996 13.6196 26.3956 13.5137L26.3916 13.4142L26.3442 13.4158C26.3065 13.4174 26.2776 13.4287 26.256 13.4503C26.2343 13.472 26.2247 13.5041 26.2255 13.5466C26.2271 13.5835 26.2375 13.6132 26.2568 13.6365C26.276 13.6597 26.3001 13.6702 26.3282 13.6694L26.3338 13.8314C26.2945 13.833 26.2568 13.821 26.2215 13.7961C26.1862 13.7712 26.1581 13.7367 26.1364 13.6918C26.1156 13.6477 26.1035 13.5971 26.1019 13.5418C26.0987 13.4575 26.1172 13.3893 26.1581 13.3372C26.199 13.285 26.2576 13.2578 26.3338 13.2529L26.6587 13.2409C26.7237 13.2385 26.7751 13.2273 26.8128 13.208H26.824L26.8304 13.3725L26.8312 13.3741ZM26.7213 13.5562C26.7205 13.5241 26.7117 13.4944 26.6948 13.4672C26.678 13.4399 26.6563 13.419 26.6299 13.4062L26.4943 13.411L26.4975 13.4985C26.4999 13.5586 26.5119 13.6028 26.5336 13.6324C26.5552 13.6621 26.5857 13.6758 26.6242 13.6742C26.6555 13.6734 26.6796 13.6621 26.6973 13.6405C26.7149 13.6188 26.7229 13.5915 26.7221 13.5562H26.7213Z" fill="white"/>
+<path id="Vector_45" d="M25.8997 12.9119L26.0746 12.8967L26.0641 12.7699L26.1837 12.7595L26.1941 12.8862L26.5953 12.8517C26.6226 12.8493 26.6418 12.8421 26.6531 12.8301C26.6643 12.818 26.6691 12.798 26.6667 12.7707C26.6651 12.7522 26.6611 12.7338 26.6555 12.7145L26.7806 12.7041C26.7943 12.7402 26.8023 12.7747 26.8047 12.8092C26.8151 12.9336 26.7517 13.001 26.6153 13.013L26.2078 13.0475L26.2182 13.1654L26.0986 13.1759L26.0882 13.0579L25.9133 13.0732L25.8997 12.9119Z" fill="white"/>
+<path id="Vector_46" d="M25.8638 12.672C25.8389 12.6752 25.8172 12.6696 25.7996 12.656C25.7819 12.6423 25.7707 12.6207 25.7675 12.5918C25.7643 12.5629 25.7699 12.5388 25.7843 12.5212C25.7988 12.5035 25.818 12.4931 25.8429 12.4899C25.867 12.4867 25.8886 12.4923 25.9063 12.5067C25.9239 12.5212 25.9352 12.542 25.9384 12.5717C25.9416 12.6014 25.9368 12.6239 25.9223 12.6415C25.9079 12.6592 25.8886 12.6696 25.8646 12.672H25.8638ZM26.7463 12.3944L26.7656 12.5557L26.0491 12.6407L26.0298 12.4795L26.7463 12.3944Z" fill="white"/>
+<path id="Vector_47" d="M26.365 12.2814C26.2952 12.2926 26.2302 12.2894 26.17 12.2709C26.1098 12.2525 26.0601 12.2212 26.0216 12.1755C25.9831 12.1305 25.959 12.0752 25.9478 12.0102C25.9317 11.9139 25.9502 11.8312 26.0015 11.7606C26.0537 11.6908 26.1299 11.6443 26.2318 11.6226L26.2695 11.6154C26.3401 11.6042 26.4043 11.6066 26.4645 11.625C26.5246 11.6427 26.5736 11.6748 26.6121 11.7197C26.6506 11.7647 26.6755 11.8208 26.6859 11.8866C26.7028 11.9869 26.6827 12.0728 26.6257 12.1442C26.5688 12.2156 26.4845 12.2605 26.373 12.279L26.365 12.2806V12.2814ZM26.3521 12.1193C26.4251 12.1073 26.4805 12.0824 26.5166 12.0455C26.5535 12.0086 26.5672 11.9628 26.5575 11.9091C26.5487 11.8553 26.5206 11.8168 26.4733 11.7935C26.426 11.7703 26.3618 11.7655 26.2807 11.7791C26.2085 11.7911 26.154 11.816 26.1171 11.8537C26.0801 11.8914 26.0657 11.9372 26.0745 11.9901C26.0834 12.0423 26.1106 12.08 26.1572 12.104C26.2037 12.1281 26.2679 12.1329 26.3505 12.1193H26.3521Z" fill="white"/>
+<path id="Vector_48" d="M25.8461 11.4036L25.9263 11.3803C25.8517 11.3426 25.8044 11.2816 25.7851 11.1974C25.7514 11.0513 25.818 10.9575 25.9849 10.9157L26.4494 10.8082L26.4855 10.9663L26.0298 11.0714C25.9849 11.0818 25.9544 11.0987 25.9375 11.1235C25.9207 11.1476 25.9175 11.1821 25.9271 11.2254C25.9416 11.2888 25.9817 11.3297 26.0467 11.3474L26.5473 11.2319L26.5842 11.3899L25.8814 11.552L25.8469 11.4036H25.8461Z" fill="white"/>
+<path id="Vector_49" d="M26.0946 10.2811C26.0665 10.2891 26.0489 10.3068 26.0416 10.3341C26.0336 10.3613 26.032 10.4031 26.0368 10.4592C26.0416 10.5154 26.04 10.5635 26.0336 10.6044C26.0192 10.6935 25.9758 10.7481 25.9052 10.7689C25.8459 10.7866 25.7881 10.7761 25.7335 10.7376C25.679 10.6991 25.6397 10.6414 25.6164 10.5635C25.5923 10.4809 25.5923 10.4079 25.6188 10.3445C25.6445 10.2811 25.6902 10.2402 25.7552 10.2209L25.8009 10.3766C25.7712 10.3854 25.7496 10.4039 25.7359 10.4319C25.7223 10.46 25.7215 10.4921 25.7319 10.529C25.7424 10.5635 25.7584 10.5884 25.7801 10.6052C25.8025 10.6221 25.8266 10.6269 25.8531 10.6189C25.8772 10.6117 25.8924 10.5964 25.8996 10.5724C25.9068 10.5483 25.9084 10.5042 25.9036 10.4392C25.8988 10.3742 25.9012 10.322 25.9093 10.2811C25.9173 10.241 25.9325 10.2089 25.9534 10.184C25.9742 10.1591 26.0031 10.1415 26.0408 10.1311C26.1034 10.1126 26.1612 10.1238 26.2149 10.164C26.2687 10.2041 26.308 10.2659 26.3329 10.3493C26.3497 10.4063 26.3545 10.4592 26.3465 10.5098C26.3393 10.5603 26.3208 10.6028 26.2928 10.6381C26.2639 10.6734 26.2294 10.6975 26.1877 10.7095L26.1427 10.5587C26.1788 10.5459 26.2029 10.5234 26.2149 10.4921C26.227 10.4608 26.227 10.4239 26.2149 10.3814C26.2029 10.3405 26.1861 10.3116 26.1644 10.2947C26.1427 10.2779 26.1187 10.2731 26.0938 10.2811H26.0946Z" fill="white"/>
+</g>
+<g id="Group_2">
+<g id="Group_3">
+<path id="Vector_50" d="M8.9457 10.9173H6.97035L6.52184 12.1393H6.13672L7.78312 7.78821H8.13294L9.77933 12.1393H9.39662L8.9457 10.9173ZM7.08428 10.6068H8.82937L7.95642 8.23672L7.08348 10.6068H7.08428Z" fill="white"/>
+<path id="Vector_51" d="M10.8064 12.1401H10.439V7.78906H10.8064V12.1401Z" fill="white"/>
+<path id="Vector_52" d="M15.0067 10.7833C14.9569 11.2415 14.7933 11.5921 14.5149 11.8352C14.2364 12.0783 13.8666 12.1995 13.4044 12.1995C13.0819 12.1995 12.7962 12.1184 12.5483 11.9572C12.3004 11.7959 12.1086 11.5672 11.973 11.2712C11.8375 10.9751 11.7685 10.6373 11.7668 10.2562V9.69135C11.7668 9.30462 11.8342 8.96202 11.9698 8.66355C12.1054 8.36508 12.3004 8.13401 12.5539 7.97194C12.8083 7.80987 13.1003 7.72803 13.4309 7.72803C13.8971 7.72803 14.2653 7.85319 14.5349 8.10432C14.8045 8.35546 14.9618 8.70287 15.0059 9.14736H14.6352C14.5437 8.40841 14.1418 8.03853 13.4309 8.03853C13.0361 8.03853 12.7224 8.18616 12.4881 8.48142C12.2539 8.77668 12.1367 9.18427 12.1367 9.70499V10.2377C12.1367 10.74 12.2507 11.1412 12.4785 11.4396C12.7064 11.7389 13.0153 11.8882 13.4036 11.8882C13.7919 11.8882 14.0776 11.7959 14.2733 11.6113C14.4683 11.4268 14.5895 11.1508 14.6352 10.7817H15.0059L15.0067 10.7833Z" fill="white"/>
+<path id="Vector_53" d="M16.2061 10.3678V12.1401H15.8386V7.78906H17.3205C17.7731 7.78906 18.1301 7.9046 18.3917 8.13567C18.654 8.36675 18.7848 8.68447 18.7848 9.08885C18.7848 9.49323 18.6588 9.81256 18.4069 10.0348C18.155 10.2571 17.7899 10.3678 17.3117 10.3678H16.2061ZM16.2061 10.0573H17.3205C17.6768 10.0573 17.9488 9.97222 18.1365 9.80293C18.3235 9.63364 18.4173 9.39695 18.4173 9.09366C18.4173 8.79038 18.3243 8.55209 18.1381 8.37397C17.952 8.19505 17.6872 8.10438 17.3446 8.10037H16.2061V10.0581V10.0573Z" fill="white"/>
+<path id="Vector_54" d="M21.4823 10.9173H19.507L19.0585 12.1393H18.6733L20.3197 7.78821H20.6696L22.316 12.1393H21.9332L21.4823 10.9173ZM19.6201 10.6068H21.3652L20.4922 8.23672L19.6193 10.6068H19.6201Z" fill="white"/>
+<path id="Vector_55" d="M11.4289 18.1368C11.4289 17.8961 11.3438 17.7051 11.1745 17.5647C11.0052 17.4243 10.6955 17.2911 10.2454 17.1643C9.79532 17.0376 9.46636 16.8996 9.25936 16.7503C8.9641 16.5393 8.81727 16.2625 8.81727 15.9199C8.81727 15.5773 8.95447 15.3165 9.22807 15.1087C9.50167 14.9009 9.85229 14.7966 10.2783 14.7966C10.5672 14.7966 10.8255 14.8528 11.0542 14.9643C11.2821 15.0758 11.4594 15.2315 11.5845 15.4305C11.7097 15.6295 11.7731 15.8517 11.7731 16.0972H11.4024C11.4024 15.7996 11.3005 15.5605 11.0975 15.3791C10.8945 15.1978 10.6217 15.1079 10.2783 15.1079C9.93493 15.1079 9.68059 15.1826 9.48321 15.331C9.28584 15.4794 9.18715 15.6736 9.18715 15.9135C9.18715 16.1349 9.27541 16.3155 9.45272 16.4551C9.63004 16.5947 9.91407 16.7182 10.304 16.8249C10.6947 16.9317 10.99 17.0424 11.1914 17.1571C11.3928 17.2718 11.5444 17.4082 11.6455 17.5679C11.7474 17.7276 11.798 17.9153 11.798 18.1328C11.798 18.4754 11.6608 18.7506 11.3872 18.9576C11.1136 19.1646 10.7525 19.2681 10.304 19.2681C9.99751 19.2681 9.71589 19.2135 9.45994 19.1036C9.204 18.9937 9.00983 18.8404 8.87745 18.643C8.74506 18.4457 8.67847 18.2194 8.67847 17.9651H9.04594C9.04594 18.2716 9.16067 18.5139 9.38934 18.6912C9.618 18.8685 9.92289 18.9568 10.304 18.9568C10.6426 18.9568 10.9146 18.8821 11.12 18.7329C11.3254 18.5837 11.4281 18.3855 11.4281 18.1384L11.4289 18.1368Z" fill="white"/>
+<path id="Vector_56" d="M15.7455 17.267C15.7455 17.6673 15.6765 18.0188 15.5377 18.3221C15.3989 18.6245 15.2015 18.858 14.9448 19.0217C14.688 19.1854 14.3911 19.2664 14.0542 19.2664C13.5463 19.2664 13.1355 19.0843 12.8234 18.7208C12.5105 18.3574 12.354 17.8663 12.354 17.2493V16.8008C12.354 16.4045 12.4246 16.053 12.565 15.7473C12.7054 15.4417 12.9044 15.2066 13.1612 15.0421C13.4179 14.8776 13.714 14.7958 14.0485 14.7958C14.3831 14.7958 14.6784 14.8768 14.9343 15.0381C15.1903 15.1994 15.3876 15.4272 15.5273 15.7225C15.6669 16.0177 15.7391 16.3587 15.7455 16.7479V17.2678V17.267ZM15.378 16.7944C15.378 16.2705 15.2593 15.8597 15.0226 15.5628C14.7851 15.2659 14.4609 15.1175 14.0485 15.1175C13.6361 15.1175 13.3216 15.2667 13.0817 15.5644C12.8418 15.8621 12.7215 16.2785 12.7215 16.8121V17.2662C12.7215 17.7821 12.841 18.1913 13.0801 18.4929C13.3192 18.7946 13.6442 18.9455 14.0542 18.9455C14.4642 18.9455 14.7955 18.7962 15.0282 18.4986C15.2617 18.2009 15.378 17.7861 15.378 17.2541V16.7936V16.7944Z" fill="white"/>
+<path id="Vector_57" d="M19.6922 17.8495C19.6425 18.3076 19.4788 18.6583 19.2004 18.9014C18.922 19.1445 18.5521 19.2656 18.09 19.2656C17.7674 19.2656 17.4818 19.1846 17.2339 19.0233C16.9859 18.862 16.7942 18.6334 16.6586 18.3373C16.523 18.0413 16.454 17.7035 16.4524 17.3224V16.7575C16.4524 16.3708 16.5198 16.0282 16.6554 15.7297C16.791 15.4312 16.9859 15.2002 17.2395 15.0381C17.4938 14.876 17.7859 14.7942 18.1164 14.7942C18.5826 14.7942 18.9509 14.9194 19.2205 15.1705C19.49 15.4216 19.6473 15.769 19.6914 16.2135H19.3208C19.2293 15.4746 18.8273 15.1047 18.1164 15.1047C17.7217 15.1047 17.408 15.2523 17.1737 15.5476C16.9394 15.8428 16.8223 16.2504 16.8223 16.7712V17.3039C16.8223 17.8062 16.9362 18.2073 17.1641 18.5058C17.3919 18.8051 17.7008 18.9543 18.0892 18.9543C18.4775 18.9543 18.7631 18.862 18.9589 18.6775C19.1539 18.493 19.275 18.217 19.3208 17.8479H19.6914L19.6922 17.8495Z" fill="white"/>
+</g>
+<path id="Vector_58" d="M6.00195 13.5538H22.5871" stroke="white" stroke-width="0.111926" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<g id="Group_4">
+<path id="Vector_59" d="M8.72524 21.7257C8.71722 21.7089 8.71 21.68 8.70518 21.6374C8.63859 21.7064 8.55916 21.7409 8.46609 21.7409C8.38345 21.7409 8.31525 21.7177 8.26229 21.6711C8.20934 21.6246 8.18286 21.5652 8.18286 21.493C8.18286 21.4056 8.21576 21.3382 8.28235 21.2892C8.34895 21.2411 8.44202 21.217 8.56237 21.217H8.70197V21.1512C8.70197 21.1015 8.68673 21.0614 8.65704 21.0317C8.62736 21.002 8.58323 20.9868 8.52466 20.9868C8.47331 20.9868 8.43078 20.9996 8.39628 21.0253C8.36178 21.0509 8.34413 21.0822 8.34413 21.1191H8.19971C8.19971 21.0774 8.21496 21.0365 8.24464 20.998C8.27433 20.9587 8.31444 20.9282 8.36579 20.9057C8.41634 20.8833 8.47251 20.8712 8.53348 20.8712C8.63057 20.8712 8.70599 20.8953 8.76055 20.9434C8.8151 20.9916 8.84399 21.0582 8.84559 21.1432V21.5291C8.84559 21.6062 8.85522 21.6671 8.87528 21.7129V21.7249H8.72444L8.72524 21.7257ZM8.48695 21.6166C8.53188 21.6166 8.5744 21.6046 8.61452 21.5821C8.65464 21.5588 8.68432 21.5283 8.70197 21.4914V21.3189H8.58965C8.41393 21.3189 8.32568 21.3703 8.32568 21.473C8.32568 21.5179 8.34092 21.5532 8.37061 21.5781C8.4003 21.6037 8.43881 21.6158 8.48615 21.6158L8.48695 21.6166Z" fill="white"/>
+<path id="Vector_60" d="M9.03174 20.6642C9.03174 20.6409 9.03896 20.6209 9.0534 20.6056C9.06784 20.5904 9.0887 20.5815 9.11679 20.5815C9.14487 20.5815 9.16573 20.5896 9.18017 20.6056C9.19461 20.6217 9.20183 20.6409 9.20183 20.6642C9.20183 20.6875 9.19461 20.7067 9.18017 20.722C9.16573 20.7372 9.14487 20.7452 9.11679 20.7452C9.0887 20.7452 9.06784 20.7372 9.0534 20.722C9.03896 20.7067 9.03174 20.6866 9.03174 20.6642ZM9.18659 21.7257H9.04297V20.8864H9.18659V21.7257Z" fill="white"/>
+<path id="Vector_61" d="M9.71276 21.6246C9.76411 21.6246 9.80824 21.6094 9.84675 21.5781C9.88526 21.5468 9.90612 21.5083 9.91013 21.4618H10.0457C10.0433 21.5099 10.0265 21.5556 9.99598 21.599C9.96549 21.6423 9.92457 21.6768 9.87403 21.7025C9.82348 21.7281 9.76892 21.741 9.71276 21.741C9.59882 21.741 9.50736 21.7025 9.43996 21.6262C9.37257 21.55 9.33887 21.4457 9.33887 21.3133V21.2893C9.33887 21.2074 9.35411 21.1352 9.3838 21.071C9.41348 21.0076 9.45681 20.9579 9.51297 20.9226C9.56914 20.8873 9.63573 20.8696 9.71195 20.8696C9.80583 20.8696 9.88446 20.8977 9.94624 20.9539C10.0088 21.01 10.0417 21.0831 10.0457 21.1737H9.91013C9.90612 21.1192 9.88526 21.075 9.84835 21.0397C9.81144 21.0052 9.76571 20.9876 9.71115 20.9876C9.63814 20.9876 9.58198 21.0141 9.54186 21.0662C9.50174 21.1184 9.48168 21.1946 9.48168 21.2941V21.3213C9.48168 21.4184 9.50174 21.4922 9.54106 21.5444C9.58117 21.5965 9.63814 21.623 9.71195 21.623L9.71276 21.6246Z" fill="white"/>
+<path id="Vector_62" d="M10.877 21.3156C10.877 21.4432 10.8481 21.5459 10.7895 21.6245C10.731 21.7024 10.6523 21.7417 10.552 21.7417C10.4518 21.7417 10.3699 21.7096 10.3113 21.6446V22.049H10.1677V20.8872H10.2985L10.3057 20.9803C10.3643 20.9081 10.4453 20.8719 10.5488 20.8719C10.6523 20.8719 10.7294 20.9097 10.7879 20.9859C10.8465 21.0621 10.8762 21.168 10.8762 21.3028V21.3156H10.877ZM10.7334 21.2996C10.7334 21.2049 10.7133 21.1303 10.6732 21.0757C10.6331 21.0212 10.5777 20.9939 10.5071 20.9939C10.4205 20.9939 10.3555 21.0324 10.3113 21.1094V21.5106C10.3547 21.5868 10.4197 21.6253 10.5087 21.6253C10.5777 21.6253 10.6323 21.5981 10.6724 21.5435C10.7133 21.4889 10.7334 21.4079 10.7334 21.3004V21.2996Z" fill="white"/>
+<path id="Vector_63" d="M11.5373 21.7257C11.5292 21.7089 11.522 21.68 11.5172 21.6374C11.4506 21.7064 11.3712 21.7409 11.2781 21.7409C11.1955 21.7409 11.1273 21.7177 11.0743 21.6711C11.0214 21.6246 10.9949 21.5652 10.9949 21.493C10.9949 21.4056 11.0278 21.3382 11.0944 21.2892C11.161 21.2411 11.254 21.217 11.3744 21.217H11.514V21.1512C11.514 21.1015 11.4987 21.0614 11.4691 21.0317C11.4394 21.002 11.3952 20.9868 11.3367 20.9868C11.2853 20.9868 11.2428 20.9996 11.2083 21.0253C11.1738 21.0509 11.1561 21.0822 11.1561 21.1191H11.0117C11.0117 21.0774 11.027 21.0365 11.0567 20.998C11.0863 20.9587 11.1265 20.9282 11.1778 20.9057C11.2284 20.8833 11.2845 20.8712 11.3455 20.8712C11.4426 20.8712 11.518 20.8953 11.5726 20.9434C11.6271 20.9916 11.656 21.0582 11.6576 21.1432V21.5291C11.6576 21.6062 11.6672 21.6671 11.6873 21.7129V21.7249H11.5365L11.5373 21.7257ZM11.299 21.6166C11.3439 21.6166 11.3864 21.6046 11.4265 21.5821C11.4666 21.5588 11.4963 21.5283 11.514 21.4914V21.3189H11.4017C11.2259 21.3189 11.1377 21.3703 11.1377 21.473C11.1377 21.5179 11.1529 21.5532 11.1826 21.5781C11.2123 21.6037 11.2508 21.6158 11.2982 21.6158L11.299 21.6166Z" fill="white"/>
+<path id="Vector_64" d="M11.8462 21.6511C11.8462 21.6262 11.8534 21.6054 11.8687 21.5893C11.8839 21.5733 11.9056 21.5645 11.9353 21.5645C11.9649 21.5645 11.9874 21.5725 12.0026 21.5893C12.0179 21.6062 12.0259 21.6262 12.0259 21.6511C12.0259 21.676 12.0179 21.6944 12.0026 21.7105C11.9874 21.7265 11.9649 21.7346 11.9353 21.7346C11.9056 21.7346 11.8839 21.7265 11.8687 21.7105C11.8534 21.6944 11.8462 21.6744 11.8462 21.6511Z" fill="white"/>
+<path id="Vector_65" d="M12.1841 21.2988C12.1841 21.217 12.2001 21.1423 12.2322 21.0773C12.2643 21.0124 12.3092 20.961 12.367 20.9257C12.4248 20.8904 12.4906 20.8719 12.5644 20.8719C12.6783 20.8719 12.7714 20.9113 12.842 20.9907C12.9126 21.0701 12.9479 21.1752 12.9479 21.306V21.3164C12.9479 21.3983 12.9327 21.4713 12.9014 21.5363C12.8701 21.6013 12.8252 21.6518 12.7674 21.6879C12.7088 21.724 12.6422 21.7425 12.5668 21.7425C12.4529 21.7425 12.3606 21.7032 12.29 21.6237C12.2194 21.5443 12.1841 21.44 12.1841 21.31V21.2996V21.2988ZM12.3277 21.3156C12.3277 21.4087 12.3494 21.4833 12.3927 21.5395C12.436 21.5957 12.4938 21.6237 12.566 21.6237C12.6382 21.6237 12.6968 21.5949 12.7393 21.5379C12.7818 21.4809 12.8035 21.4007 12.8035 21.298C12.8035 21.2057 12.7818 21.1311 12.7377 21.0741C12.6944 21.0172 12.6358 20.9883 12.5636 20.9883C12.4914 20.9883 12.436 21.0164 12.3919 21.0725C12.3478 21.1287 12.3269 21.2097 12.3269 21.3148L12.3277 21.3156Z" fill="white"/>
+<path id="Vector_66" d="M13.4936 21.0156C13.472 21.0124 13.4487 21.01 13.423 21.01C13.3292 21.01 13.265 21.0501 13.2313 21.1304V21.7257H13.0876V20.8865H13.2273L13.2297 20.9835C13.277 20.9089 13.3436 20.8712 13.4294 20.8712C13.4575 20.8712 13.4784 20.8744 13.4928 20.8824V21.0156H13.4936Z" fill="white"/>
+<path id="Vector_67" d="M13.5361 21.2996C13.5361 21.1688 13.5666 21.0645 13.6268 20.9875C13.687 20.9105 13.7672 20.8719 13.8675 20.8719C13.9678 20.8719 14.0496 20.9081 14.1074 20.9803L14.1146 20.8872H14.2454V21.7064C14.2454 21.8147 14.2133 21.9005 14.1491 21.9631C14.0849 22.0257 13.9983 22.057 13.89 22.057C13.8298 22.057 13.7704 22.0442 13.7126 22.0185C13.6549 21.9928 13.6107 21.9575 13.5803 21.9126L13.6549 21.8267C13.7167 21.903 13.7913 21.9407 13.8803 21.9407C13.9501 21.9407 14.0047 21.9206 14.0432 21.8821C14.0825 21.8428 14.1018 21.7874 14.1018 21.716V21.6438C14.044 21.7104 13.9662 21.7433 13.8667 21.7433C13.7672 21.7433 13.6894 21.704 13.6284 21.6245C13.5674 21.5451 13.5369 21.4376 13.5369 21.3012L13.5361 21.2996ZM13.6806 21.3156C13.6806 21.4103 13.6998 21.4849 13.7391 21.5387C13.7776 21.5924 13.8322 21.6197 13.902 21.6197C13.9927 21.6197 14.0593 21.5788 14.101 21.4962V21.1135C14.0568 21.0332 13.9911 20.9931 13.9036 20.9931C13.8338 20.9931 13.7792 21.0204 13.7399 21.0749C13.7006 21.1295 13.6814 21.2097 13.6814 21.3164L13.6806 21.3156Z" fill="white"/>
+<path id="Vector_68" d="M14.4505 21.8228H14.3269L14.7987 20.5968H14.9214L14.4505 21.8228Z" fill="white"/>
+<path id="Vector_69" d="M15.5251 21.5035C15.5251 21.4649 15.5107 21.4345 15.481 21.4128C15.4521 21.3911 15.4008 21.3727 15.3286 21.3574C15.2556 21.3422 15.1986 21.3229 15.1553 21.3013C15.1127 21.2796 15.0815 21.2539 15.0606 21.2234C15.0405 21.1938 15.0301 21.1577 15.0301 21.1167C15.0301 21.0477 15.059 20.99 15.1176 20.9426C15.1761 20.8953 15.2499 20.8712 15.3406 20.8712C15.4361 20.8712 15.5131 20.8961 15.5717 20.945C15.6311 20.994 15.6607 21.0574 15.6607 21.1336H15.5163C15.5163 21.0943 15.4995 21.0606 15.4666 21.0317C15.4337 21.0028 15.3912 20.9892 15.3406 20.9892C15.2901 20.9892 15.2475 21.0004 15.2179 21.0237C15.1882 21.0461 15.1737 21.0758 15.1737 21.1127C15.1737 21.1472 15.1874 21.1737 15.2146 21.1913C15.2419 21.209 15.2917 21.2258 15.3631 21.2419C15.4345 21.2579 15.4931 21.2772 15.5372 21.2997C15.5813 21.3221 15.6142 21.3486 15.6359 21.3799C15.6575 21.4112 15.668 21.4489 15.668 21.4946C15.668 21.5692 15.6383 21.6294 15.5781 21.6752C15.5179 21.7201 15.4401 21.7434 15.3446 21.7434C15.2772 21.7434 15.2179 21.7313 15.1665 21.7081C15.1152 21.684 15.0742 21.6511 15.0453 21.6086C15.0165 21.566 15.0012 21.5195 15.0012 21.4698H15.1448C15.1472 21.5179 15.1665 21.5556 15.2026 21.5845C15.2387 21.6134 15.2861 21.627 15.3446 21.627C15.3992 21.627 15.4425 21.6158 15.4754 21.5941C15.5083 21.5725 15.5243 21.5428 15.5243 21.5059L15.5251 21.5035Z" fill="white"/>
+<path id="Vector_70" d="M15.7778 21.2988C15.7778 21.217 15.7939 21.1423 15.826 21.0773C15.8581 21.0124 15.903 20.961 15.9608 20.9257C16.0185 20.8904 16.0843 20.8719 16.1581 20.8719C16.2721 20.8719 16.3651 20.9113 16.4358 20.9907C16.5064 21.0701 16.5417 21.1752 16.5417 21.306V21.3164C16.5417 21.3983 16.5264 21.4713 16.4951 21.5363C16.4638 21.6013 16.4189 21.6518 16.3611 21.6879C16.3026 21.724 16.236 21.7425 16.1605 21.7425C16.0466 21.7425 15.9543 21.7032 15.8837 21.6237C15.8131 21.5443 15.7778 21.44 15.7778 21.31V21.2996V21.2988ZM15.9223 21.3156C15.9223 21.4087 15.9439 21.4833 15.9872 21.5395C16.0306 21.5957 16.0883 21.6237 16.1605 21.6237C16.2328 21.6237 16.2913 21.5949 16.3339 21.5379C16.3764 21.4809 16.398 21.4007 16.398 21.298C16.398 21.2057 16.3764 21.1311 16.3322 21.0741C16.2889 21.0172 16.2304 20.9883 16.1581 20.9883C16.0859 20.9883 16.0306 21.0164 15.9864 21.0725C15.9423 21.1287 15.9215 21.2097 15.9215 21.3148L15.9223 21.3156Z" fill="white"/>
+<path id="Vector_71" d="M17.0182 21.6246C17.0695 21.6246 17.1137 21.6094 17.1522 21.5781C17.1907 21.5468 17.2115 21.5083 17.2156 21.4618H17.3511C17.3487 21.5099 17.3319 21.5556 17.3014 21.599C17.2709 21.6423 17.23 21.6768 17.1794 21.7025C17.1289 21.7281 17.0743 21.741 17.0182 21.741C16.9042 21.741 16.8128 21.7025 16.7454 21.6262C16.678 21.55 16.6443 21.4457 16.6443 21.3133V21.2893C16.6443 21.2074 16.6595 21.1352 16.6892 21.071C16.7189 21.0076 16.7622 20.9579 16.8184 20.9226C16.8746 20.8873 16.9412 20.8696 17.0174 20.8696C17.1112 20.8696 17.1899 20.8977 17.2517 20.9539C17.3142 21.01 17.3471 21.0831 17.3511 21.1737H17.2156C17.2115 21.1192 17.1907 21.075 17.1538 21.0397C17.1169 21.0052 17.0711 20.9876 17.0166 20.9876C16.9436 20.9876 16.8874 21.0141 16.8473 21.0662C16.8072 21.1184 16.7871 21.1946 16.7871 21.2941V21.3213C16.7871 21.4184 16.8072 21.4922 16.8465 21.5444C16.8866 21.5965 16.9436 21.623 17.0174 21.623L17.0182 21.6246Z" fill="white"/>
+<path id="Vector_72" d="M18.0637 21.3469H18.2202V21.4641H18.0637V21.7264H17.9193V21.4641H17.405V21.3798L17.9105 20.5975H18.0629V21.3477L18.0637 21.3469ZM17.5687 21.3469H17.9201V20.7933L17.9033 20.8246L17.5687 21.3469Z" fill="white"/>
+<path id="Vector_73" d="M18.814 21.5035C18.814 21.4649 18.7995 21.4345 18.7698 21.4128C18.7402 21.3911 18.6896 21.3727 18.6174 21.3574C18.5444 21.3422 18.4874 21.3229 18.4441 21.3013C18.4016 21.2796 18.3703 21.2539 18.3494 21.2234C18.3294 21.1938 18.3189 21.1577 18.3189 21.1167C18.3189 21.0477 18.3478 20.99 18.4064 20.9426C18.4649 20.8953 18.5388 20.8712 18.6294 20.8712C18.7249 20.8712 18.8019 20.8961 18.8605 20.945C18.9199 20.994 18.9496 21.0574 18.9496 21.1336H18.8051C18.8051 21.0943 18.7883 21.0606 18.7554 21.0317C18.7217 21.0036 18.68 20.9892 18.6294 20.9892C18.5789 20.9892 18.5364 21.0004 18.5067 21.0237C18.477 21.0461 18.4625 21.0758 18.4625 21.1127C18.4625 21.1472 18.4762 21.1737 18.5035 21.1913C18.5307 21.209 18.5805 21.2258 18.6519 21.2419C18.7233 21.2579 18.7819 21.2772 18.826 21.2997C18.8701 21.3221 18.903 21.3486 18.9247 21.3799C18.9464 21.4112 18.9568 21.4489 18.9568 21.4946C18.9568 21.5692 18.9271 21.6294 18.8669 21.6752C18.8067 21.7201 18.7289 21.7434 18.6334 21.7434C18.566 21.7434 18.5067 21.7313 18.4553 21.7081C18.404 21.684 18.3631 21.6511 18.3342 21.6086C18.3053 21.566 18.29 21.5195 18.29 21.4698H18.4337C18.4361 21.5179 18.4553 21.5556 18.4914 21.5845C18.5275 21.6126 18.5749 21.627 18.6334 21.627C18.688 21.627 18.7313 21.6158 18.7642 21.5941C18.7971 21.5725 18.8132 21.5428 18.8132 21.5059L18.814 21.5035Z" fill="white"/>
+<path id="Vector_74" d="M19.0664 21.2988C19.0664 21.217 19.0825 21.1423 19.1145 21.0773C19.1466 21.0116 19.1916 20.961 19.2493 20.9257C19.3071 20.8904 19.3729 20.8719 19.4467 20.8719C19.5606 20.8719 19.6537 20.9113 19.7243 20.9907C19.7949 21.0701 19.8302 21.1752 19.8302 21.306V21.3164C19.8302 21.3983 19.815 21.4713 19.7837 21.5363C19.7524 21.6013 19.7075 21.6518 19.6497 21.6879C19.5911 21.724 19.5245 21.7425 19.4491 21.7425C19.3352 21.7425 19.2429 21.7032 19.1723 21.6237C19.1017 21.5443 19.0664 21.44 19.0664 21.31V21.2996V21.2988ZM19.21 21.3156C19.21 21.4087 19.2317 21.4833 19.275 21.5395C19.3183 21.5957 19.3761 21.6237 19.4483 21.6237C19.5205 21.6237 19.5791 21.5949 19.6216 21.5379C19.665 21.4809 19.6858 21.4007 19.6858 21.298C19.6858 21.2057 19.6641 21.1311 19.62 21.0741C19.5767 21.0172 19.5181 20.9883 19.4459 20.9883C19.3737 20.9883 19.3183 21.0164 19.2742 21.0725C19.2301 21.1287 19.2092 21.2097 19.2092 21.3148L19.21 21.3156Z" fill="white"/>
+</g>
+<path id="Vector_75" d="M25.8569 25.0298V25.1269H25.67V25.6147H25.5536V25.1269H25.3667V25.0298H25.8569ZM26.4892 25.6147L26.4675 25.2713C26.4651 25.2264 26.4651 25.1702 26.4635 25.1076H26.4571C26.4418 25.159 26.425 25.228 26.4073 25.2817L26.3022 25.6059H26.1819L26.0768 25.2729C26.0663 25.228 26.0487 25.159 26.0358 25.1076H26.0294C26.0294 25.1614 26.027 25.2175 26.0254 25.2713L26.0038 25.6147H25.8922L25.9356 25.0306H26.1097L26.2108 25.3162C26.2236 25.3612 26.234 25.4045 26.2493 25.4647H26.2517C26.2669 25.4109 26.2798 25.3612 26.2926 25.3186L26.3937 25.0306H26.5614L26.6063 25.6147H26.49H26.4892Z" fill="#231F20"/>
+</g>
+<defs>
+<linearGradient id="paint0_linear_6186_11887" x1="28" y1="14" x2="0" y2="14" gradientUnits="userSpaceOnUse">
+<stop stop-color="#2161AD"/>
+<stop offset="0.18" stop-color="#1F69B3"/>
+<stop offset="0.47" stop-color="#1C82C4"/>
+<stop offset="0.84" stop-color="#16A9E1"/>
+<stop offset="1" stop-color="#14BDEF"/>
+</linearGradient>
+<linearGradient id="paint1_linear_6186_11887" x1="3.13623" y1="13.9999" x2="24.8636" y2="13.9999" gradientUnits="userSpaceOnUse">
+<stop stop-color="#2161AD"/>
+<stop offset="0.18" stop-color="#1F69B3"/>
+<stop offset="0.47" stop-color="#1C82C4"/>
+<stop offset="0.84" stop-color="#16A9E1"/>
+<stop offset="1" stop-color="#14BDEF"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/common/sparkles-soft.svg b/app/components/base/icons/assets/public/common/sparkles-soft.svg
new file mode 100644
index 0000000..37f3072
--- /dev/null
+++ b/app/components/base/icons/assets/public/common/sparkles-soft.svg
@@ -0,0 +1,6 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="sparkles-soft">
+<path id="Vector" opacity="0.5" d="M10.9963 1.36798C10.9839 1.25339 10.8909 1.16677 10.7802 1.16666C10.6695 1.16654 10.5763 1.25295 10.5636 1.36752C10.5045 1.90085 10.3525 2.26673 10.1143 2.5149C9.87599 2.76307 9.52476 2.92145 9.01275 2.98296C8.90277 2.99618 8.81983 3.09324 8.81995 3.20856C8.82006 3.32388 8.90322 3.42076 9.0132 3.43373C9.51653 3.49312 9.87583 3.65148 10.1201 3.90135C10.3631 4.14986 10.518 4.51523 10.563 5.04321C10.573 5.16035 10.6673 5.25012 10.7802 5.24999C10.8931 5.24986 10.9872 5.15987 10.9969 5.0427C11.0401 4.52364 11.1949 4.15004 11.4394 3.89528C11.684 3.64052 12.0426 3.47926 12.5409 3.43433C12.6534 3.42419 12.7398 3.32619 12.7399 3.20858C12.7401 3.09097 12.6539 2.99277 12.5414 2.98236C12.0346 2.93546 11.6838 2.77407 11.4452 2.52098C11.2054 2.2665 11.0533 1.89229 10.9963 1.36798Z" fill="#F5F8FF"/>
+<path id="Vector_2" d="M7.13646 2.85102C7.10442 2.55638 6.8653 2.33365 6.5806 2.33334C6.29595 2.33304 6.05633 2.55526 6.02374 2.84984C5.87186 4.22127 5.48089 5.1621 4.86827 5.80025C4.25565 6.43838 3.35245 6.84566 2.03587 7.00386C1.75307 7.03781 1.53975 7.28742 1.54004 7.58393C1.54033 7.88049 1.75415 8.12958 2.03701 8.16294C3.33132 8.31566 4.25509 8.72289 4.88328 9.36543C5.50807 10.0045 5.90647 10.9439 6.02222 12.3016C6.04793 12.6029 6.29035 12.8337 6.58066 12.8333C6.87102 12.833 7.11294 12.6016 7.13797 12.3003C7.24885 10.9656 7.64695 10.0049 8.27583 9.34979C8.90477 8.69471 9.82698 8.28002 11.1083 8.16452C11.3976 8.13844 11.6197 7.88644 11.62 7.58399C11.6204 7.28159 11.3988 7.02906 11.1096 7.00229C9.8062 6.88171 8.90432 6.46673 8.29084 5.81589C7.674 5.16152 7.28306 4.19926 7.13646 2.85102Z" fill="#F5F8FF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/education/triangle.svg b/app/components/base/icons/assets/public/education/triangle.svg
new file mode 100644
index 0000000..e52c5c5
--- /dev/null
+++ b/app/components/base/icons/assets/public/education/triangle.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="22" viewBox="0 0 16 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path id="Rectangle 979" d="M0 0H16L9.91493 16.7339C8.76529 19.8955 5.76063 22 2.39658 22H0V0Z" fill="white"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/csv.svg b/app/components/base/icons/assets/public/files/csv.svg
new file mode 100644
index 0000000..b108404
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/csv.svg
@@ -0,0 +1,24 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="File Icons/csv">
+<g id="sharp" filter="url(#filter0_d_6816_769)">
+<path d="M4 7.73398C4 5.49377 4 4.37367 4.43597 3.51802C4.81947 2.76537 5.43139 2.15345 6.18404 1.76996C7.03969 1.33398 8.15979 1.33398 10.4 1.33398H18.6667L28 10.6673V24.2673C28 26.5075 28 27.6276 27.564 28.4833C27.1805 29.2359 26.5686 29.8478 25.816 30.2313C24.9603 30.6673 23.8402 30.6673 21.6 30.6673H10.4C8.15979 30.6673 7.03969 30.6673 6.18404 30.2313C5.43139 29.8478 4.81947 29.2359 4.43597 28.4833C4 27.6276 4 26.5075 4 24.2673V7.73398Z" fill="#169951"/>
+</g>
+<g id="CSV" opacity="0.96">
+<path d="M13.0846 21.8908C12.8419 23.3562 11.8246 24.0562 10.5646 24.0562C9.78992 24.0562 9.20192 23.7948 8.71659 23.3095C8.01659 22.6095 8.04459 21.6762 8.04459 20.6775C8.04459 19.6788 8.01659 18.7455 8.71659 18.0455C9.20192 17.5602 9.78992 17.2988 10.5646 17.2988C11.8246 17.2988 12.8419 17.9988 13.0846 19.4642H11.4233C11.3206 19.0908 11.1153 18.7548 10.5739 18.7548C10.2753 18.7548 10.0513 18.8762 9.92992 19.0348C9.78059 19.2308 9.67792 19.4642 9.67792 20.6775C9.67792 21.8908 9.78059 22.1242 9.92992 22.3202C10.0513 22.4788 10.2753 22.6002 10.5739 22.6002C11.1153 22.6002 11.3206 22.2642 11.4233 21.8908H13.0846Z" fill="white"/>
+<path d="M18.4081 21.9655C18.4081 23.3188 17.2414 24.0562 15.8414 24.0562C14.8241 24.0562 13.9934 23.8695 13.3214 23.1788L14.3668 22.1335C14.7121 22.4788 15.3188 22.6002 15.8508 22.6002C16.4948 22.6002 16.8028 22.3855 16.8028 22.0028C16.8028 21.8442 16.7654 21.7135 16.6721 21.6108C16.5881 21.5268 16.4481 21.4615 16.2334 21.4335L15.4308 21.3215C14.8428 21.2375 14.3948 21.0415 14.0961 20.7335C13.7881 20.4162 13.6388 19.9682 13.6388 19.3988C13.6388 18.1855 14.5534 17.2988 16.0654 17.2988C17.0174 17.2988 17.7361 17.5228 18.3054 18.0922L17.2788 19.1188C16.8588 18.6988 16.3081 18.7268 16.0188 18.7268C15.4494 18.7268 15.2161 19.0535 15.2161 19.3428C15.2161 19.4268 15.2441 19.5482 15.3468 19.6508C15.4308 19.7348 15.5708 19.8188 15.8041 19.8468L16.6068 19.9588C17.2041 20.0428 17.6334 20.2295 17.9134 20.5095C18.2681 20.8548 18.4081 21.3495 18.4081 21.9655Z" fill="white"/>
+<path d="M24.4166 17.3548L22.214 24.0002H21.0006L18.8073 17.3548H20.4966L21.6166 21.0695L22.718 17.3548H24.4166Z" fill="white"/>
+</g>
+<path id="bevel" opacity="0.5" d="M18.6667 1.33398L28.0001 10.6673H21.3334C19.8607 10.6673 18.6667 9.47341 18.6667 8.00065V1.33398Z" fill="white"/>
+</g>
+<defs>
+<filter id="filter0_d_6816_769" x="2" y="0.333984" width="28" height="33.334" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6816_769"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6816_769" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/doc.svg b/app/components/base/icons/assets/public/files/doc.svg
new file mode 100644
index 0000000..9a8aef5
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/doc.svg
@@ -0,0 +1,22 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_17194_49206)">
+<path d="M4 7.73301C4 5.4928 4 4.37269 4.43597 3.51705C4.81947 2.7644 5.43139 2.15248 6.18404 1.76898C7.03969 1.33301 8.15979 1.33301 10.4 1.33301H18.6667L28 10.6663V24.2663C28 26.5066 28 27.6267 27.564 28.4823C27.1805 29.2349 26.5686 29.8469 25.816 30.2304C24.9603 30.6663 23.8402 30.6663 21.6 30.6663H10.4C8.15979 30.6663 7.03969 30.6663 6.18404 30.2304C5.43139 29.8469 4.81947 29.2349 4.43597 28.4823C4 27.6267 4 26.5066 4 24.2663V7.73301Z" fill="#2349A9"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.33301L27.9998 10.6663H21.3332C19.8604 10.6663 18.6665 9.47243 18.6665 7.99967V1.33301Z" fill="white"/>
+<g opacity="0.96">
+<path d="M13.6329 21.4112C13.6329 22.2603 13.7059 22.9501 13.0326 23.5793C12.6351 23.9508 12.0754 24.11 11.4751 24.11H9.3335V18.7125H11.4751C12.0754 18.7125 12.6351 18.8717 13.0326 19.2431C13.7059 19.8723 13.6329 20.5622 13.6329 21.4112ZM12.2133 21.4112C12.2133 20.5015 12.1727 20.3499 12.0591 20.1983C11.9293 20.0164 11.7347 19.8951 11.3777 19.8951H10.7531V22.9274H11.3777C11.7347 22.9274 11.9293 22.8061 12.0591 22.6242C12.1727 22.4725 12.2133 22.3285 12.2133 21.4112Z" fill="white"/>
+<path d="M18.8275 21.4112C18.8275 22.2224 18.8519 22.9805 18.2435 23.549C17.8217 23.9432 17.3349 24.1555 16.6292 24.1555C15.9234 24.1555 15.4367 23.9432 15.0149 23.549C14.4065 22.9805 14.4308 22.2224 14.4308 21.4112C14.4308 20.6001 14.4065 19.842 15.0149 19.2735C15.4367 18.8793 15.9234 18.667 16.6292 18.667C17.3349 18.667 17.8217 18.8793 18.2435 19.2735C18.8519 19.842 18.8275 20.6001 18.8275 21.4112ZM17.4079 21.4112C17.4079 20.4257 17.3268 20.2438 17.197 20.0846C17.0916 19.9557 16.8888 19.8496 16.6292 19.8496C16.3696 19.8496 16.1668 19.9557 16.0613 20.0846C15.9316 20.2438 15.8504 20.4257 15.8504 21.4112C15.8504 22.3967 15.9316 22.5711 16.0613 22.7303C16.1668 22.8592 16.3696 22.9729 16.6292 22.9729C16.8888 22.9729 17.0916 22.8592 17.197 22.7303C17.3268 22.5711 17.4079 22.3967 17.4079 21.4112Z" fill="white"/>
+<path d="M24.0002 22.3967C23.7893 23.5869 22.905 24.1555 21.8099 24.1555C21.1366 24.1555 20.6256 23.9432 20.2037 23.549C19.5953 22.9805 19.6197 22.2224 19.6197 21.4112C19.6197 20.6001 19.5953 19.842 20.2037 19.2735C20.6256 18.8793 21.1366 18.667 21.8099 18.667C22.905 18.667 23.7893 19.2356 24.0002 20.4257H22.5562C22.467 20.1225 22.2885 19.8496 21.818 19.8496C21.5584 19.8496 21.3638 19.9481 21.2583 20.077C21.1285 20.2362 21.0393 20.4257 21.0393 21.4112C21.0393 22.3967 21.1285 22.5863 21.2583 22.7455C21.3638 22.8743 21.5584 22.9729 21.818 22.9729C22.2885 22.9729 22.467 22.7 22.5562 22.3967H24.0002Z" fill="white"/>
+</g>
+<defs>
+<filter id="filter0_d_17194_49206" x="2" y="0.333008" width="28" height="33.333" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_17194_49206"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_17194_49206" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/docx.svg b/app/components/base/icons/assets/public/files/docx.svg
new file mode 100644
index 0000000..5f8fa51
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/docx.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_10291_62253)">
+<path d="M4 7.73301C4 5.4928 4 4.37269 4.43597 3.51705C4.81947 2.7644 5.43139 2.15248 6.18404 1.76898C7.03969 1.33301 8.15979 1.33301 10.4 1.33301H18.6667L28 10.6663V24.2663C28 26.5065 28 27.6267 27.564 28.4823C27.1805 29.2349 26.5686 29.8469 25.816 30.2304C24.9603 30.6663 23.8402 30.6663 21.6 30.6663H10.4C8.15979 30.6663 7.03969 30.6663 6.18404 30.2304C5.43139 29.8469 4.81947 29.2349 4.43597 28.4823C4 27.6267 4 26.5065 4 24.2663V7.73301Z" fill="#2349A9"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.33301L27.9998 10.6663H21.3332C19.8604 10.6663 18.6665 9.47243 18.6665 7.99967V1.33301Z" fill="white"/>
+<g opacity="0.96">
+<path d="M10.8443 21.3337C10.8443 22.1587 10.9153 22.8291 10.261 23.4405C9.87477 23.8014 9.33086 23.9561 8.74754 23.9561H6.6665V18.7112H8.74754C9.33086 18.7112 9.87477 18.8659 10.261 19.2268C10.9153 19.8383 10.8443 20.5086 10.8443 21.3337ZM9.46487 21.3337C9.46487 20.4497 9.42545 20.3024 9.31509 20.155C9.18897 19.9782 8.99979 19.8604 8.65295 19.8604H8.04598V22.807H8.65295C8.99979 22.807 9.18897 22.6891 9.31509 22.5123C9.42545 22.365 9.46487 22.225 9.46487 21.3337Z" fill="white"/>
+<path d="M15.8922 21.3337C15.8922 22.1219 15.9158 22.8585 15.3246 23.411C14.9147 23.7941 14.4418 24.0003 13.756 24.0003C13.0702 24.0003 12.5972 23.7941 12.1873 23.411C11.5961 22.8585 11.6197 22.1219 11.6197 21.3337C11.6197 20.5454 11.5961 19.8088 12.1873 19.2563C12.5972 18.8733 13.0702 18.667 13.756 18.667C14.4418 18.667 14.9147 18.8733 15.3246 19.2563C15.9158 19.8088 15.8922 20.5454 15.8922 21.3337ZM14.5127 21.3337C14.5127 20.376 14.4339 20.1992 14.3077 20.0445C14.2053 19.9193 14.0082 19.8162 13.756 19.8162C13.5037 19.8162 13.3066 19.9193 13.2042 20.0445C13.078 20.1992 12.9992 20.376 12.9992 21.3337C12.9992 22.2913 13.078 22.4607 13.2042 22.6154C13.3066 22.7407 13.5037 22.8512 13.756 22.8512C14.0082 22.8512 14.2053 22.7407 14.3077 22.6154C14.4339 22.4607 14.5127 22.2913 14.5127 21.3337Z" fill="white"/>
+<path d="M20.9186 22.2913C20.7136 23.4478 19.8544 24.0003 18.7902 24.0003C18.136 24.0003 17.6394 23.7941 17.2295 23.411C16.6383 22.8585 16.6619 22.1219 16.6619 21.3337C16.6619 20.5454 16.6383 19.8088 17.2295 19.2563C17.6394 18.8733 18.136 18.667 18.7902 18.667C19.8544 18.667 20.7136 19.2195 20.9186 20.376H19.5154C19.4287 20.0814 19.2553 19.8162 18.7981 19.8162C18.5459 19.8162 18.3567 19.9119 18.2542 20.0372C18.1281 20.1919 18.0414 20.376 18.0414 21.3337C18.0414 22.2913 18.1281 22.4755 18.2542 22.6302C18.3567 22.7554 18.5459 22.8512 18.7981 22.8512C19.2553 22.8512 19.4287 22.586 19.5154 22.2913H20.9186Z" fill="white"/>
+<path d="M25.9998 23.9561H24.4233L23.501 22.3429L22.5787 23.9561H21.0022L22.7522 21.2674L21.1126 18.7112H22.6812L23.501 20.1919L24.3208 18.7112H25.8895L24.2499 21.2674L25.9998 23.9561Z" fill="white"/>
+</g>
+<defs>
+<filter id="filter0_d_10291_62253" x="2" y="0.333008" width="28" height="33.333" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_10291_62253"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_10291_62253" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/html.svg b/app/components/base/icons/assets/public/files/html.svg
new file mode 100644
index 0000000..f4db500
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/html.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14424)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#EC5B27"/>
+</g>
+<g opacity="0.96">
+<path d="M10.2704 24.0002V18.3042H8.87042V20.4962H7.38242V18.3042H5.98242V24.0002H7.38242V21.7442H8.87042V24.0002H10.2704Z" fill="white"/>
+<path d="M15.2839 19.5522V18.3042H11.0839V19.5522H12.4839V24.0002H13.8839V19.5522H15.2839Z" fill="white"/>
+<path d="M21.4116 24.0002V18.3042H20.0356L18.7556 20.8162L17.4756 18.3042H16.0996V24.0002H17.4996V21.2722L18.3076 22.6802H19.2036L20.0116 21.2722V24.0002H21.4116Z" fill="white"/>
+<path d="M26.3525 24.0002V22.7522H23.9605V18.3042H22.5605V24.0002H26.3525Z" fill="white"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14424" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14424"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14424" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/json.svg b/app/components/base/icons/assets/public/files/json.svg
new file mode 100644
index 0000000..0876828
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/json.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14428)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#2D2D2E"/>
+</g>
+<g opacity="0.96">
+<path d="M9.83907 22.0479V18.3039H8.43907V22.0159C8.43907 22.5599 8.12707 22.7999 7.69507 22.7999C7.38307 22.7999 7.23907 22.6879 7.06307 22.5119L6.14307 23.4239C6.60707 23.8879 7.03107 24.0479 7.69507 24.0479C8.76707 24.0479 9.83907 23.3999 9.83907 22.0479Z" fill="white"/>
+<path d="M14.7321 22.2559C14.7321 21.7279 14.6121 21.3039 14.3081 21.0079C14.0681 20.7679 13.7001 20.6079 13.1881 20.5359L12.5001 20.4399C12.3001 20.4159 12.1801 20.3439 12.1081 20.2719C12.0201 20.1839 11.9961 20.0799 11.9961 20.0079C11.9961 19.7599 12.1961 19.4799 12.6841 19.4799C12.9321 19.4799 13.4041 19.4559 13.7641 19.8159L14.6441 18.9359C14.1561 18.4479 13.5401 18.2559 12.7241 18.2559C11.4281 18.2559 10.6441 19.0159 10.6441 20.0559C10.6441 20.5439 10.7721 20.9279 11.0361 21.1999C11.2921 21.4639 11.6761 21.6319 12.1801 21.7039L12.8681 21.7999C13.0521 21.8239 13.1721 21.8799 13.2441 21.9519C13.3241 22.0399 13.3561 22.1519 13.3561 22.2879C13.3561 22.6159 13.0921 22.7999 12.5401 22.7999C12.0841 22.7999 11.5641 22.6959 11.2681 22.3999L10.3721 23.2959C10.9481 23.8879 11.6601 24.0479 12.5321 24.0479C13.7321 24.0479 14.7321 23.4159 14.7321 22.2559Z" fill="white"/>
+<path d="M19.8023 21.1519C19.8023 20.2959 19.8263 19.4959 19.2263 18.8959C18.8103 18.4799 18.3303 18.2559 17.6343 18.2559C16.9383 18.2559 16.4583 18.4799 16.0423 18.8959C15.4423 19.4959 15.4663 20.2959 15.4663 21.1519C15.4663 22.0079 15.4423 22.8079 16.0423 23.4079C16.4583 23.8239 16.9383 24.0479 17.6343 24.0479C18.3303 24.0479 18.8103 23.8239 19.2263 23.4079C19.8263 22.8079 19.8023 22.0079 19.8023 21.1519ZM18.4023 21.1519C18.4023 22.1919 18.3223 22.3759 18.1943 22.5439C18.0903 22.6799 17.8903 22.7999 17.6343 22.7999C17.3783 22.7999 17.1783 22.6799 17.0743 22.5439C16.9463 22.3759 16.8663 22.1919 16.8663 21.1519C16.8663 20.1119 16.9463 19.9199 17.0743 19.7519C17.1783 19.6159 17.3783 19.5039 17.6343 19.5039C17.8903 19.5039 18.0903 19.6159 18.1943 19.7519C18.3223 19.9199 18.4023 20.1119 18.4023 21.1519Z" fill="white"/>
+<path d="M25.2154 23.9999V18.3039H23.8154V21.1679L21.9914 18.3039H20.7674V23.9999H22.1674V21.1359L23.9914 23.9999H25.2154Z" fill="white"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14428" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14428"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14428" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/md.svg b/app/components/base/icons/assets/public/files/md.svg
new file mode 100644
index 0000000..d730b5a
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/md.svg
@@ -0,0 +1,18 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3777_37339)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#309BEC"/>
+</g>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M21.9904 25.3335H10.0096C9.45202 25.3335 9 24.9138 9 24.396V18.271C9 17.7532 9.45202 17.3335 10.0096 17.3335H21.9904C22.548 17.3335 23 17.7532 23 18.271V24.396C23 24.9138 22.548 25.3335 21.9904 25.3335ZM12.3654 23.4585V21.021L13.7115 22.5835L15.0577 21.021V23.4585H16.4038V19.2085H15.0577L13.7115 20.771L12.3654 19.2085H11.0192V23.4585H12.3654ZM20.0385 21.3335H21.3846L19.3654 23.521L17.3462 21.3335H18.6923V19.2085H20.0385V21.3335Z" fill="white"/>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3777_37339" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3777_37339"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3777_37339" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/pdf.svg b/app/components/base/icons/assets/public/files/pdf.svg
new file mode 100644
index 0000000..bc63229
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/pdf.svg
@@ -0,0 +1,22 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14420)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#DD3633"/>
+</g>
+<g opacity="0.96">
+<path d="M13.2801 20.1362C13.2801 19.2002 12.6001 18.3042 11.3361 18.3042H9.08008V24.0002H10.4801V21.9682H11.3361C12.6001 21.9682 13.2801 21.0722 13.2801 20.1362ZM11.8801 20.1362C11.8801 20.4322 11.6561 20.7122 11.2721 20.7122H10.4801V19.5602H11.2721C11.6561 19.5602 11.8801 19.8402 11.8801 20.1362Z" fill="white"/>
+<path d="M18.3357 21.1522C18.3357 20.2562 18.4077 19.5282 17.7437 18.8642C17.3517 18.4722 16.7997 18.3042 16.2077 18.3042H14.0957V24.0002H16.2077C16.7997 24.0002 17.3517 23.8322 17.7437 23.4402C18.4077 22.7762 18.3357 22.0482 18.3357 21.1522ZM16.9357 21.1522C16.9357 22.1202 16.8957 22.2722 16.7837 22.4322C16.6557 22.6242 16.4637 22.7522 16.1117 22.7522H15.4957V19.5522H16.1117C16.4637 19.5522 16.6557 19.6802 16.7837 19.8722C16.8957 20.0322 16.9357 20.1922 16.9357 21.1522Z" fill="white"/>
+<path d="M23.1786 19.5522V18.3042H19.3066V24.0002H20.7066V21.8002H22.8186V20.5522H20.7066V19.5522H23.1786Z" fill="white"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14420" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14420"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14420" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/txt.svg b/app/components/base/icons/assets/public/files/txt.svg
new file mode 100644
index 0000000..d1b6a8c
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/txt.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14432)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#E3E5E8"/>
+<path d="M4.25 7.73349C4.25 6.60926 4.25019 5.78113 4.30367 5.12666C4.3569 4.47511 4.46169 4.01774 4.65873 3.63103C5.01825 2.92542 5.59193 2.35175 6.29754 1.99222C6.68424 1.79518 7.14162 1.6904 7.79317 1.63716C8.44763 1.58369 9.27577 1.5835 10.4 1.5835H18.5631L27.75 10.7704V24.2668C27.75 25.3911 27.7498 26.2192 27.6963 26.8737C27.6431 27.5252 27.5383 27.9826 27.3413 28.3693C26.9817 29.0749 26.4081 29.6486 25.7025 30.0081C25.3158 30.2051 24.8584 30.3099 24.2068 30.3632C23.5524 30.4166 22.7242 30.4168 21.6 30.4168H10.4C9.27577 30.4168 8.44763 30.4166 7.79317 30.3632C7.14162 30.3099 6.68424 30.2051 6.29754 30.0081C5.59193 29.6486 5.01825 29.0749 4.65873 28.3693C4.46169 27.9826 4.3569 27.5252 4.30367 26.8737C4.25019 26.2192 4.25 25.3911 4.25 24.2668V7.73349Z" stroke="black" stroke-opacity="0.03" stroke-width="0.5"/>
+</g>
+<g opacity="0.96">
+<path d="M13.2254 19.5522V18.3042H9.02539V19.5522H10.4254V24.0002H11.8254V19.5522H13.2254Z" fill="#667085"/>
+<path d="M18.5371 24.0002L16.7611 21.0802L18.4251 18.3042H16.8331L16.0011 19.9122L15.1691 18.3042H13.5771L15.2411 21.0802L13.4651 24.0002H15.0651L16.0011 22.2482L16.9371 24.0002H18.5371Z" fill="#667085"/>
+<path d="M22.9754 19.5522V18.3042H18.7754V19.5522H20.1754V24.0002H21.5754V19.5522H22.9754Z" fill="#667085"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14432" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14432"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14432" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/unknown.svg b/app/components/base/icons/assets/public/files/unknown.svg
new file mode 100644
index 0000000..6daa243
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/unknown.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14436)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#E3E5E8"/>
+<path d="M4.25 7.73349C4.25 6.60926 4.25019 5.78113 4.30367 5.12666C4.3569 4.47511 4.46169 4.01774 4.65873 3.63103C5.01825 2.92542 5.59193 2.35175 6.29754 1.99222C6.68424 1.79518 7.14162 1.6904 7.79317 1.63716C8.44763 1.58369 9.27577 1.5835 10.4 1.5835H18.5631L27.75 10.7704V24.2668C27.75 25.3911 27.7498 26.2192 27.6963 26.8737C27.6431 27.5252 27.5383 27.9826 27.3413 28.3693C26.9817 29.0749 26.4081 29.6486 25.7025 30.0081C25.3158 30.2051 24.8584 30.3099 24.2068 30.3632C23.5524 30.4166 22.7242 30.4168 21.6 30.4168H10.4C9.27577 30.4168 8.44763 30.4166 7.79317 30.3632C7.14162 30.3099 6.68424 30.2051 6.29754 30.0081C5.59193 29.6486 5.01825 29.0749 4.65873 28.3693C4.46169 27.9826 4.3569 27.5252 4.30367 26.8737C4.25019 26.2192 4.25 25.3911 4.25 24.2668V7.73349Z" stroke="black" stroke-opacity="0.03" stroke-width="0.5"/>
+</g>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9998 23.1992C15.8014 23.1992 15.6039 23.1968 15.4077 23.1924V24.0549C15.4077 24.3819 15.6728 24.647 15.9998 24.647C16.3268 24.647 16.592 24.3819 16.592 24.0549V23.1924C16.3957 23.1968 16.1983 23.1992 15.9998 23.1992Z" fill="#98A2B3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0984 22.8838L11.757 23.8593C11.649 24.168 11.8117 24.5058 12.1203 24.6138C12.185 24.6364 12.251 24.6472 12.3159 24.6472C12.5605 24.6472 12.7894 24.4944 12.8747 24.2505L13.2936 23.0534C12.8807 23.0073 12.481 22.9506 12.0984 22.8838Z" fill="#98A2B3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M20.2431 23.8593L19.9018 22.8838C19.5192 22.9506 19.1195 23.0073 18.7065 23.0534L19.1254 24.2505C19.2108 24.4944 19.4396 24.6472 19.6843 24.6472C19.7491 24.6472 19.8151 24.6364 19.8798 24.6138C20.1885 24.5058 20.3511 24.168 20.2431 23.8593Z" fill="#98A2B3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M20.1624 17.2634C20.2697 17.6416 20.3254 18.0369 20.3254 18.4409C20.3254 18.9087 20.05 19.3327 19.6226 19.5228C19.5564 19.5522 17.9801 20.2436 16.0359 20.2436C14.0917 20.2436 12.5153 19.5522 12.4492 19.5228C12.0218 19.3327 11.7464 18.9086 11.7464 18.4409C11.7464 18.0312 11.8037 17.6305 11.914 17.2476C10.3343 17.5645 8.5 18.2009 8.5 19.4464C8.5 20.2859 9.32512 20.9477 10.9525 21.4134C11.4194 21.547 11.9381 21.66 12.4949 21.7506C12.8783 21.813 13.28 21.8648 13.6953 21.9056C14.2455 21.9597 14.8197 21.9942 15.4079 22.0082C15.6039 22.0128 15.8013 22.0153 16 22.0153C16.1987 22.0153 16.3962 22.0128 16.5921 22.0082C17.1803 21.9943 17.7545 21.9596 18.3047 21.9056C18.72 21.8648 19.1217 21.8131 19.5051 21.7506C20.062 21.66 20.5807 21.547 21.0476 21.4134C22.6749 20.9477 23.5 20.2859 23.5 19.4464C23.5 18.2187 21.7108 17.5833 20.1624 17.2634Z" fill="#98A2B3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M18.8441 17.1144C18.7585 16.9335 18.6559 16.7622 18.5384 16.6025C18.4174 16.4382 18.2809 16.286 18.1307 16.1486C17.5784 15.6437 16.8433 15.3354 16.036 15.3354C15.2318 15.3354 14.499 15.6411 13.9476 16.1426C13.7974 16.2791 13.6609 16.4303 13.5399 16.5937C13.4217 16.753 13.3185 16.924 13.2322 17.1048C13.039 17.5095 12.9307 17.9624 12.9307 18.4407C12.9307 18.4407 14.321 19.0592 16.036 19.0592C17.751 19.0592 19.1412 18.4407 19.1412 18.4407C19.1412 17.9662 19.0344 17.5167 18.8441 17.1144Z" fill="#98A2B3"/>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14436" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14436"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14436" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/xlsx.svg b/app/components/base/icons/assets/public/files/xlsx.svg
new file mode 100644
index 0000000..2cdf42c
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/xlsx.svg
@@ -0,0 +1,18 @@
+<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_5938_927)">
+<path d="M3 5.8C3 4.11984 3 3.27976 3.32698 2.63803C3.6146 2.07354 4.07354 1.6146 4.63803 1.32698C5.27976 1 6.11984 1 7.8 1H14L21 8V18.2C21 19.8802 21 20.7202 20.673 21.362C20.3854 21.9265 19.9265 22.3854 19.362 22.673C18.7202 23 17.8802 23 16.2 23H7.8C6.11984 23 5.27976 23 4.63803 22.673C4.07354 22.3854 3.6146 21.9265 3.32698 21.362C3 20.7202 3 19.8802 3 18.2V5.8Z" fill="#169951"/>
+</g>
+<path opacity="0.5" d="M14 1L21 8H16C14.8954 8 14 7.10457 14 6V1Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M17 12C17.5523 12 18 12.4477 18 13V18C18 18.5523 17.5523 19 17 19H7C6.44772 19 6 18.5523 6 18V13C6 12.4477 6.44772 12 7 12H17ZM11.5 13H7L7 15H11.5V13ZM12.5 18H17V16H12.5V18ZM11.5 16V18H7L7 16H11.5ZM12.5 15H17V13H12.5V15Z" fill="white" fill-opacity="0.96"/>
+<defs>
+<filter id="filter0_d_5938_927" x="1" y="0" width="22" height="26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5938_927"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5938_927" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/files/yaml.svg b/app/components/base/icons/assets/public/files/yaml.svg
new file mode 100644
index 0000000..c7c3f54
--- /dev/null
+++ b/app/components/base/icons/assets/public/files/yaml.svg
@@ -0,0 +1 @@
+<svg fill="none" height="26" viewBox="0 0 24 26" width="24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><filter id="a" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="26" width="22" x="1" y="0"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" result="hardAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dy="1"/><feGaussianBlur stdDeviation="1"/><feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/><feBlend in2="BackgroundImageFix" mode="normal" result="effect1_dropShadow_7605_8828"/><feBlend in="SourceGraphic" in2="effect1_dropShadow_7605_8828" mode="normal" result="shape"/></filter><g filter="url(#a)"><path d="m3 5.8c0-1.68016 0-2.52024.32698-3.16197.28762-.56449.74656-1.02343 1.31105-1.31105.64173-.32698 1.48181-.32698 3.16197-.32698h6.2l7 7v10.2c0 1.6802 0 2.5202-.327 3.162-.2876.5645-.7465 1.0234-1.311 1.311-.6418.327-1.4818.327-3.162.327h-8.4c-1.68016 0-2.52024 0-3.16197-.327-.56449-.2876-1.02343-.7465-1.31105-1.311-.32698-.6418-.32698-1.4818-.32698-3.162z" fill="#e8eaed"/><path d="m16.2 22.75h-8.4c-.8442 0-1.46232-.0002-1.95004-.04-.48479-.0397-.81868-.1172-1.09843-.2597-.51745-.2637-.93815-.6844-1.2018-1.2018-.14254-.2798-.22008-.6137-.25969-1.0985-.03985-.4877-.04004-1.1058-.04004-1.95v-12.4c0-.8442.00019-1.46232.04004-1.95004.03961-.48479.11715-.81868.25969-1.09843.26365-.51745.68435-.93815 1.2018-1.2018.27975-.14254.61364-.22008 1.09843-.25969.48772-.03985 1.10584-.04004 1.95004-.04004h6.0964l6.8536 6.85355v10.09645c0 .8442-.0002 1.4623-.04 1.95-.0397.4848-.1172.8187-.2597 1.0985-.2637.5174-.6844.9381-1.2018 1.2018-.2798.1425-.6137.22-1.0985.2597-.4877.0398-1.1058.04-1.95.04z" stroke="#000" stroke-opacity=".03" stroke-width=".5"/></g><path d="m14 1 7 7h-5c-1.1046 0-2-.89543-2-2z" fill="#fff" opacity=".5"/><path d="m11.5264 9-2.15191 3.2267v2.0455h-1.31897v-2.0455l-2.05552-3.2267h1.48242l1.30707 2.0776 1.31781-2.0776z" fill="#000"/><path d="m13.7426 13.1121h-2.3874l-.4855 1.1724h-1.0572l2.2355-5.27223h1.0813l2.1448 5.27223h-1.1297zm-.3966-1.0526-.7318-1.9348-.8165 1.9348z" fill="#cb171e"/><g fill="#000"><path d="m8.05469 14.8635v5.1673h1.10866v-3.5643l1.16025 2.3957h.8727l1.1999-2.4799v3.6474h1.0636v-5.1662h-1.4522l-1.2885 2.3369-1.22722-2.3369z"/><path d="m17.9994 18.9079h-2.7272v-4.0456h-1.1296v5.1451h3.8568z"/></g></svg>
\ No newline at end of file
diff --git a/app/components/base/icons/assets/public/knowledge/chunk.svg b/app/components/base/icons/assets/public/knowledge/chunk.svg
new file mode 100644
index 0000000..1dc0494
--- /dev/null
+++ b/app/components/base/icons/assets/public/knowledge/chunk.svg
@@ -0,0 +1,13 @@
+<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Group">
+<path id="Vector" d="M2.5 10H0V7.5H2.5V10Z" fill="#676F83"/>
+<path id="Vector_2" d="M6.25 6.25H3.75V3.75H6.25V6.25Z" fill="#676F83"/>
+<path id="Vector_3" d="M2.5 6.25H0V3.75H2.5V6.25Z" fill="#676F83"/>
+<path id="Vector_4" d="M6.25 2.5H3.75V0H6.25V2.5Z" fill="#676F83"/>
+<path id="Vector_5" d="M2.5 2.5H0V0H2.5V2.5Z" fill="#676F83"/>
+<path id="Vector_6" d="M10 2.5H7.5V0H10V2.5Z" fill="#676F83"/>
+<path id="Vector_7" d="M9.58342 7.91663H7.91675V9.58329H9.58342V7.91663Z" fill="#676F83"/>
+<path id="Vector_8" d="M9.58342 4.16663H7.91675V5.83329H9.58342V4.16663Z" fill="#676F83"/>
+<path id="Vector_9" d="M5.83341 7.91663H4.16675V9.58329H5.83341V7.91663Z" fill="#676F83"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/knowledge/collapse.svg b/app/components/base/icons/assets/public/knowledge/collapse.svg
new file mode 100644
index 0000000..b54e046
--- /dev/null
+++ b/app/components/base/icons/assets/public/knowledge/collapse.svg
@@ -0,0 +1,9 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon L">
+<g id="Vector">
+<path d="M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z" fill="#354052"/>
+<path d="M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z" fill="#354052"/>
+<path d="M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z" fill="#354052"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/knowledge/general-type.svg b/app/components/base/icons/assets/public/knowledge/general-type.svg
new file mode 100644
index 0000000..779df5f
--- /dev/null
+++ b/app/components/base/icons/assets/public/knowledge/general-type.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon L">
+<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M6 0.5C6.27615 0.5 6.5 0.72386 6.5 1V1.52755C6.95855 1.57831 7.3967 1.69804 7.80355 1.87619L8.067 1.41997C8.20505 1.18083 8.51085 1.09889 8.75 1.23696C8.98915 1.37503 9.07105 1.68082 8.933 1.91998L8.6692 2.37685C9.033 2.64523 9.3548 2.96707 9.6232 3.33084L10.0801 3.06703C10.3193 2.92896 10.6251 3.0109 10.7632 3.25005C10.9012 3.4892 10.8193 3.79499 10.5801 3.93306L10.1238 4.19649C10.302 4.60333 10.4218 5.0415 10.4725 5.50005H11C11.2761 5.50005 11.5 5.7239 11.5 6.00005C11.5 6.2762 11.2761 6.50005 11 6.50005H10.4725C10.4218 6.9586 10.302 7.3968 10.1238 7.80365L10.5801 8.0671C10.8193 8.20515 10.9012 8.51095 10.7632 8.7501C10.6251 8.98925 10.3193 9.0712 10.0801 8.9331L9.6232 8.6693C9.3548 9.03305 9.03295 9.3549 8.6692 9.62325L8.933 10.0802C9.07105 10.3193 8.98915 10.6251 8.75 10.7632C8.51085 10.9012 8.20505 10.8193 8.067 10.5802L7.80355 10.1239C7.3967 10.3021 6.95855 10.4218 6.5 10.4726V11C6.5 11.2761 6.27615 11.5 6 11.5C5.72385 11.5 5.5 11.2761 5.5 11V10.4726C5.04145 10.4218 4.60328 10.3021 4.19644 10.1239L3.933 10.5802C3.79493 10.8194 3.48914 10.9013 3.24999 10.7633C3.01084 10.6252 2.92891 10.3194 3.06698 10.0802L3.3308 9.62325C2.96702 9.3549 2.64517 9.03305 2.37678 8.66925L1.91986 8.93305C1.68071 9.07115 1.37492 8.9892 1.23685 8.75005C1.09878 8.5109 1.18072 8.2051 1.41986 8.06705L1.87612 7.8036C1.69797 7.39675 1.57824 6.9586 1.52749 6.50005L0.999975 6.5C0.723835 6.5 0.499987 6.2761 0.5 6C0.500015 5.72385 0.72388 5.5 1.00003 5.5L1.5275 5.50005C1.57825 5.0415 1.69796 4.60335 1.87611 4.19652L1.41987 3.93312C1.18072 3.79504 1.09878 3.48925 1.23685 3.2501C1.37492 3.01095 1.68071 2.92901 1.91985 3.06709L2.37675 3.33086C2.64514 2.96708 2.967 2.64524 3.33078 2.37684L3.06698 1.91992C2.92891 1.68077 3.01084 1.37498 3.24999 1.23691C3.48914 1.09884 3.79493 1.18077 3.933 1.41992L4.19642 1.87619C4.60327 1.69803 5.04145 1.57831 5.5 1.52755V1C5.5 0.72386 5.72385 0.5 6 0.5ZM3.83484 3.24991C3.48643 3.52463 3.19141 3.86415 2.96808 4.25014C2.67048 4.7645 2.49999 5.3616 2.49999 6.00005C2.49999 6.6385 2.67048 7.2356 2.96809 7.75C3.19142 8.13595 3.48645 8.4755 3.83486 8.7502L4.8599 6.97475C4.63581 6.71285 4.49999 6.37245 4.49999 6.00005C4.49999 5.62765 4.63581 5.28725 4.8599 5.02535L3.83484 3.24991ZM5.7258 4.52514L4.70041 2.74911C5.10185 2.58847 5.5402 2.50005 6 2.50005C6.63845 2.50005 7.23555 2.67054 7.74995 2.96816C8.28125 3.27557 8.7245 3.71882 9.0319 4.25012C9.2503 4.62764 9.4003 5.04975 9.4646 5.50005H7.41465C7.2087 4.91745 6.6531 4.50005 6 4.50005C5.9065 4.50005 5.8148 4.50865 5.7258 4.52514ZM7.41465 6.50005C7.2087 7.08265 6.6531 7.50005 6 7.50005C5.9065 7.50005 5.8148 7.49145 5.7258 7.47495L4.70043 9.251C5.10185 9.41165 5.5402 9.50005 6 9.50005C6.63845 9.50005 7.23555 9.32955 7.7499 9.03195C8.2812 8.72455 8.72445 8.2813 9.03185 7.75C9.2503 7.3725 9.4003 6.95035 9.4646 6.50005H7.41465Z" fill="#676F83"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/knowledge/layout-right-2-line-mod.svg b/app/components/base/icons/assets/public/knowledge/layout-right-2-line-mod.svg
new file mode 100644
index 0000000..188f9b5
--- /dev/null
+++ b/app/components/base/icons/assets/public/knowledge/layout-right-2-line-mod.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon L">
+<path id="Vector" d="M14.0002 2C14.3684 2 14.6668 2.29848 14.6668 2.66667V13.3333C14.6668 13.7015 14.3684 14 14.0002 14H2.00016C1.63198 14 1.3335 13.7015 1.3335 13.3333V2.66667C1.3335 2.29848 1.63198 2 2.00016 2H14.0002ZM13.3335 3.33333H2.66683V12.6667H13.3335V3.33333ZM14.0002 2.66667V13.3333H10.0002V2.66667H14.0002Z" fill="#354052"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/knowledge/parent-child-type.svg b/app/components/base/icons/assets/public/knowledge/parent-child-type.svg
new file mode 100644
index 0000000..bc596b6
--- /dev/null
+++ b/app/components/base/icons/assets/public/knowledge/parent-child-type.svg
@@ -0,0 +1,7 @@
+<svg width="10" height="11" viewBox="0 0 10 11" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Group">
+<path id="Vector" d="M2.70833 3.87501C3.51375 3.87501 4.16666 3.22209 4.16666 2.41668C4.16666 1.61126 3.51375 0.958344 2.70833 0.958344C1.90292 0.958344 1.25 1.61126 1.25 2.41668C1.25 3.22209 1.90292 3.87501 2.70833 3.87501Z" fill="#676F83"/>
+<path id="Vector_2" d="M7.29158 3.87501C8.097 3.87501 8.74992 3.22209 8.74992 2.41668C8.74992 1.61126 8.097 0.958344 7.29158 0.958344C6.48617 0.958344 5.83325 1.61126 5.83325 2.41668C5.83325 3.22209 6.48617 3.87501 7.29158 3.87501Z" fill="#676F83"/>
+<path id="Vector_3" d="M7.29167 4.70835C6.83771 4.70886 6.39118 4.82363 5.99324 5.04208C5.59529 5.26053 5.25874 5.57563 5.01459 5.95835C5.34482 5.9622 5.66011 6.09658 5.89159 6.33215C6.12306 6.56771 6.25191 6.8853 6.24998 7.21555C6.24805 7.5458 6.11551 7.86187 5.8813 8.09472C5.6471 8.32756 5.33026 8.45826 5 8.45826C4.66975 8.45826 4.35291 8.32756 4.1187 8.09472C3.8845 7.86187 3.75195 7.5458 3.75003 7.21555C3.7481 6.8853 3.87695 6.56771 4.10842 6.33215C4.3399 6.09658 4.65519 5.9622 4.98542 5.95835C4.67086 5.46415 4.20432 5.08546 3.656 4.87926C3.10767 4.67306 2.50721 4.6505 1.94496 4.81497C1.3827 4.97944 0.889064 5.32205 0.538306 5.79125C0.187547 6.26045 -0.00135882 6.83086 7.35834e-06 7.41668V10.125C7.35834e-06 10.2355 0.043906 10.3415 0.122046 10.4196C0.200186 10.4978 0.306167 10.5417 0.416674 10.5417H3.33334V9.50001L1.83334 8.37501C1.78957 8.34218 1.75269 8.30105 1.72481 8.25397C1.69693 8.20688 1.6786 8.15477 1.67086 8.1006C1.65523 7.99121 1.6837 7.88008 1.75001 7.79168C1.81631 7.70327 1.91502 7.64483 2.02441 7.6292C2.13381 7.61357 2.24493 7.64204 2.33334 7.70835L3.88875 8.87501H6.11125L7.66667 7.70835C7.75507 7.64204 7.8662 7.61357 7.97559 7.6292C8.08499 7.64483 8.1837 7.70327 8.25 7.79168C8.31631 7.88008 8.34478 7.99121 8.32915 8.1006C8.31352 8.21 8.25507 8.30871 8.16667 8.37501L6.66667 9.50001V10.5417H9.58333C9.69384 10.5417 9.79982 10.4978 9.87796 10.4196C9.9561 10.3415 10 10.2355 10 10.125V7.41668C9.99912 6.69866 9.71349 6.01029 9.20577 5.50257C8.69805 4.99485 8.00969 4.70923 7.29167 4.70835Z" fill="#676F83"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/knowledge/selection-mod.svg b/app/components/base/icons/assets/public/knowledge/selection-mod.svg
new file mode 100644
index 0000000..ae3c9c5
--- /dev/null
+++ b/app/components/base/icons/assets/public/knowledge/selection-mod.svg
@@ -0,0 +1,13 @@
+<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Group">
+<path id="Vector" d="M2.5 10H0V7.5H2.5V10Z" fill="#676F83"/>
+<path id="Vector_2" d="M6.25 6.25H3.75V3.75H6.25V6.25Z" fill="#676F83"/>
+<path id="Vector_3" d="M2.5 6.25H0V3.75H2.5V6.25Z" fill="#676F83"/>
+<path id="Vector_4" d="M6.25 2.5H3.75V0H6.25V2.5Z" fill="#676F83"/>
+<path id="Vector_5" d="M2.5 2.5H0V0H2.5V2.5Z" fill="#676F83"/>
+<path id="Vector_6" d="M10 2.5H7.5V0H10V2.5Z" fill="#676F83"/>
+<path id="Vector_7" d="M9.58332 7.91663H7.91666V9.58329H9.58332V7.91663Z" fill="#676F83"/>
+<path id="Vector_8" d="M9.58332 4.16663H7.91666V5.83329H9.58332V4.16663Z" fill="#676F83"/>
+<path id="Vector_9" d="M5.83332 7.91663H4.16666V9.58329H5.83332V7.91663Z" fill="#676F83"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/Anthropic-dark.svg b/app/components/base/icons/assets/public/llm/Anthropic-dark.svg
new file mode 100644
index 0000000..57abb73
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/Anthropic-dark.svg
@@ -0,0 +1,186 @@
+<svg width="90" height="10" viewBox="0 0 90 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Anthropic" clip-path="url(#clip0_5981_49007)">
+<g id="Clip path group">
+<mask id="mask0_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_2">
+<path id="Vector" d="M89.375 -0.00195312H0V9.99805H89.375V-0.00195312Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask0_5981_49007)">
+<g id="Group">
+<g id="Clip path group_2">
+<mask id="mask1_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_4">
+<path id="Vector_2" d="M0 -0.00390625H89.375V9.99609H0V-0.00390625Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask1_5981_49007)">
+<g id="Group_2">
+<g id="Clip path group_3">
+<mask id="mask2_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_12">
+<path id="Vector_3" d="M0 -0.00585938H89.375V9.99414H0V-0.00585938Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask2_5981_49007)">
+<g id="Group_3">
+<g id="Clip path group_4">
+<mask id="mask3_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_89">
+<path id="Vector_4" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask3_5981_49007)">
+<g id="Group_4">
+<g id="Group_5">
+<g id="Group_6">
+<path id="Vector_5" d="M18.1273 6.92438L13.7773 0.15625H11.4297V9.82501H13.4321V3.05688L17.7821 9.82501H20.1297V0.15625H18.1273V6.92438Z" fill="black" fill-opacity="0.95"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_5">
+<mask id="mask4_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_80">
+<path id="Vector_6" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask4_5981_49007)">
+<g id="Group_7">
+<g id="Group_8">
+<g id="Group_9">
+<path id="Vector_7" d="M21.7969 2.02094H25.0423V9.82501H27.1139V2.02094H30.3594V0.15625H21.7969V2.02094Z" fill="black" fill-opacity="0.95"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_6">
+<mask id="mask5_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_71">
+<path id="Vector_8" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask5_5981_49007)">
+<g id="Group_10">
+<g id="Group_11">
+<g id="Group_12">
+<path id="Vector_9" d="M38.6442 4.00994H34.0871V0.15625H32.0156V9.82501H34.0871V5.87463H38.6442V9.82501H40.7156V0.15625H38.6442V4.00994Z" fill="black" fill-opacity="0.95"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_7">
+<mask id="mask6_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_62">
+<path id="Vector_10" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask6_5981_49007)">
+<g id="Group_13">
+<g id="Group_14">
+<g id="Group_15">
+<path id="Vector_11" d="M45.3376 2.02094H47.893C48.9152 2.02094 49.4539 2.39387 49.4539 3.09831C49.4539 3.80275 48.9152 4.17569 47.893 4.17569H45.3376V2.02094ZM51.5259 3.09831C51.5259 1.27506 50.186 0.15625 47.9897 0.15625H43.2656V9.82501H45.3376V6.04037H47.6443L49.7164 9.82501H52.0094L49.715 5.75211C50.8666 5.30941 51.5259 4.37721 51.5259 3.09831Z" fill="black" fill-opacity="0.95"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_8">
+<mask id="mask7_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_53">
+<path id="Vector_12" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask7_5981_49007)">
+<g id="Group_16">
+<g id="Group_17">
+<g id="Group_18">
+<path id="Vector_13" d="M57.8732 8.05653C56.2438 8.05653 55.2496 6.89631 55.2496 5.00404C55.2496 3.08416 56.2438 1.92394 57.8732 1.92394C59.4887 1.92394 60.4691 3.08416 60.4691 5.00404C60.4691 6.89631 59.4887 8.05653 57.8732 8.05653ZM57.8732 -0.00976562C55.0839 -0.00976562 53.1094 2.06206 53.1094 5.00404C53.1094 7.91841 55.0839 9.99023 57.8732 9.99023C60.6486 9.99023 62.6094 7.91841 62.6094 5.00404C62.6094 2.06206 60.6486 -0.00976562 57.8732 -0.00976562Z" fill="black" fill-opacity="0.95"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_9">
+<mask id="mask8_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_44">
+<path id="Vector_14" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask8_5981_49007)">
+<g id="Group_19">
+<g id="Group_20">
+<g id="Group_21">
+<path id="Vector_15" d="M69.1794 4.45194H66.6233V2.02094H69.1794C70.2019 2.02094 70.7407 2.43532 70.7407 3.23644C70.7407 4.03756 70.2019 4.45194 69.1794 4.45194ZM69.2762 0.15625H64.5508V9.82501H66.6233V6.31662H69.2762C71.473 6.31662 72.8133 5.15637 72.8133 3.23644C72.8133 1.3165 71.473 0.15625 69.2762 0.15625Z" fill="black" fill-opacity="0.95"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_10">
+<mask id="mask9_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_35">
+<path id="Vector_16" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask9_5981_49007)">
+<g id="Group_22">
+<g id="Group_23">
+<g id="Group_24">
+<path id="Vector_17" d="M86.8413 6.57863C86.4823 7.51786 85.7642 8.05653 84.7837 8.05653C83.1542 8.05653 82.16 6.89631 82.16 5.00404C82.16 3.08416 83.1542 1.92394 84.7837 1.92394C85.7642 1.92394 86.4823 2.46261 86.8413 3.40183H89.0369C88.4984 1.33002 86.8827 -0.00976562 84.7837 -0.00976562C81.9942 -0.00976562 80.0195 2.06206 80.0195 5.00404C80.0195 7.91841 81.9942 9.99023 84.7837 9.99023C86.8965 9.99023 88.5122 8.63664 89.0508 6.57863H86.8413Z" fill="black" fill-opacity="0.95"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_11">
+<mask id="mask10_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_26">
+<path id="Vector_18" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask10_5981_49007)">
+<g id="Group_25">
+<g id="Group_26">
+<g id="Group_27">
+<path id="Vector_19" d="M73.6484 0.15625L77.5033 9.82501H79.6172L75.7624 0.15625H73.6484Z" fill="black" fill-opacity="0.95"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_12">
+<mask id="mask11_5981_49007" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_17">
+<path id="Vector_20" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask11_5981_49007)">
+<g id="Group_28">
+<g id="Group_29">
+<g id="Group_30">
+<path id="Vector_21" d="M3.64038 5.99893L4.95938 2.60106L6.27838 5.99893H3.64038ZM3.85422 0.15625L0 9.82501H2.15505L2.9433 7.79456H6.97558L7.76371 9.82501H9.91875L6.06453 0.15625H3.85422Z" fill="black" fill-opacity="0.95"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_5981_49007">
+<rect width="89.375" height="10" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/Anthropic-light.svg b/app/components/base/icons/assets/public/llm/Anthropic-light.svg
new file mode 100644
index 0000000..3e587cc
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/Anthropic-light.svg
@@ -0,0 +1,186 @@
+<svg width="90" height="10" viewBox="0 0 90 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Anthropic" clip-path="url(#clip0_5981_52010)">
+<g id="Clip path group">
+<mask id="mask0_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_2">
+<path id="Vector" d="M89.375 -0.00195312H0V9.99805H89.375V-0.00195312Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask0_5981_52010)">
+<g id="Group">
+<g id="Clip path group_2">
+<mask id="mask1_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_4">
+<path id="Vector_2" d="M0 -0.00390625H89.375V9.99609H0V-0.00390625Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask1_5981_52010)">
+<g id="Group_2">
+<g id="Clip path group_3">
+<mask id="mask2_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_12">
+<path id="Vector_3" d="M0 -0.00585938H89.375V9.99414H0V-0.00585938Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask2_5981_52010)">
+<g id="Group_3">
+<g id="Clip path group_4">
+<mask id="mask3_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_89">
+<path id="Vector_4" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask3_5981_52010)">
+<g id="Group_4">
+<g id="Group_5">
+<g id="Group_6">
+<path id="Vector_5" d="M18.1273 6.92438L13.7773 0.15625H11.4297V9.82501H13.4321V3.05688L17.7821 9.82501H20.1297V0.15625H18.1273V6.92438Z" fill="white" fill-opacity="0.8"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_5">
+<mask id="mask4_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_80">
+<path id="Vector_6" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask4_5981_52010)">
+<g id="Group_7">
+<g id="Group_8">
+<g id="Group_9">
+<path id="Vector_7" d="M21.7969 2.02094H25.0423V9.82501H27.1139V2.02094H30.3594V0.15625H21.7969V2.02094Z" fill="white" fill-opacity="0.8"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_6">
+<mask id="mask5_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_71">
+<path id="Vector_8" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask5_5981_52010)">
+<g id="Group_10">
+<g id="Group_11">
+<g id="Group_12">
+<path id="Vector_9" d="M38.6442 4.00994H34.0871V0.15625H32.0156V9.82501H34.0871V5.87463H38.6442V9.82501H40.7156V0.15625H38.6442V4.00994Z" fill="white" fill-opacity="0.8"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_7">
+<mask id="mask6_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_62">
+<path id="Vector_10" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask6_5981_52010)">
+<g id="Group_13">
+<g id="Group_14">
+<g id="Group_15">
+<path id="Vector_11" d="M45.3376 2.02094H47.893C48.9152 2.02094 49.4539 2.39387 49.4539 3.09831C49.4539 3.80275 48.9152 4.17569 47.893 4.17569H45.3376V2.02094ZM51.5259 3.09831C51.5259 1.27506 50.186 0.15625 47.9897 0.15625H43.2656V9.82501H45.3376V6.04037H47.6443L49.7164 9.82501H52.0094L49.715 5.75211C50.8666 5.30941 51.5259 4.37721 51.5259 3.09831Z" fill="white" fill-opacity="0.8"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_8">
+<mask id="mask7_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_53">
+<path id="Vector_12" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask7_5981_52010)">
+<g id="Group_16">
+<g id="Group_17">
+<g id="Group_18">
+<path id="Vector_13" d="M57.8732 8.05653C56.2438 8.05653 55.2496 6.89631 55.2496 5.00404C55.2496 3.08416 56.2438 1.92394 57.8732 1.92394C59.4887 1.92394 60.4691 3.08416 60.4691 5.00404C60.4691 6.89631 59.4887 8.05653 57.8732 8.05653ZM57.8732 -0.00976562C55.0839 -0.00976562 53.1094 2.06206 53.1094 5.00404C53.1094 7.91841 55.0839 9.99023 57.8732 9.99023C60.6486 9.99023 62.6094 7.91841 62.6094 5.00404C62.6094 2.06206 60.6486 -0.00976562 57.8732 -0.00976562Z" fill="white" fill-opacity="0.8"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_9">
+<mask id="mask8_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_44">
+<path id="Vector_14" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask8_5981_52010)">
+<g id="Group_19">
+<g id="Group_20">
+<g id="Group_21">
+<path id="Vector_15" d="M69.1794 4.45194H66.6233V2.02094H69.1794C70.2019 2.02094 70.7407 2.43532 70.7407 3.23644C70.7407 4.03756 70.2019 4.45194 69.1794 4.45194ZM69.2762 0.15625H64.5508V9.82501H66.6233V6.31662H69.2762C71.473 6.31662 72.8133 5.15637 72.8133 3.23644C72.8133 1.3165 71.473 0.15625 69.2762 0.15625Z" fill="white" fill-opacity="0.8"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_10">
+<mask id="mask9_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_35">
+<path id="Vector_16" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask9_5981_52010)">
+<g id="Group_22">
+<g id="Group_23">
+<g id="Group_24">
+<path id="Vector_17" d="M86.8413 6.57863C86.4823 7.51786 85.7642 8.05653 84.7837 8.05653C83.1542 8.05653 82.16 6.89631 82.16 5.00404C82.16 3.08416 83.1542 1.92394 84.7837 1.92394C85.7642 1.92394 86.4823 2.46261 86.8413 3.40183H89.0369C88.4984 1.33002 86.8827 -0.00976562 84.7837 -0.00976562C81.9942 -0.00976562 80.0195 2.06206 80.0195 5.00404C80.0195 7.91841 81.9942 9.99023 84.7837 9.99023C86.8965 9.99023 88.5122 8.63664 89.0508 6.57863H86.8413Z" fill="white" fill-opacity="0.8"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_11">
+<mask id="mask10_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_26">
+<path id="Vector_18" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask10_5981_52010)">
+<g id="Group_25">
+<g id="Group_26">
+<g id="Group_27">
+<path id="Vector_19" d="M73.6484 0.15625L77.5033 9.82501H79.6172L75.7624 0.15625H73.6484Z" fill="white" fill-opacity="0.8"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<g id="Clip path group_12">
+<mask id="mask11_5981_52010" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="90" height="11">
+<g id="__lottie_element_17">
+<path id="Vector_20" d="M0 -0.0078125H89.375V9.99219H0V-0.0078125Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask11_5981_52010)">
+<g id="Group_28">
+<g id="Group_29">
+<g id="Group_30">
+<path id="Vector_21" d="M3.64038 5.99893L4.95938 2.60106L6.27838 5.99893H3.64038ZM3.85422 0.15625L0 9.82501H2.15505L2.9433 7.79456H6.97558L7.76371 9.82501H9.91875L6.06453 0.15625H3.85422Z" fill="white" fill-opacity="0.8"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_5981_52010">
+<rect width="89.375" height="10" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/anthropic-text.svg b/app/components/base/icons/assets/public/llm/anthropic-text.svg
new file mode 100644
index 0000000..cace17d
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/anthropic-text.svg
@@ -0,0 +1,78 @@
+<svg width="90" height="20" viewBox="0 0 90 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_8587_60274)">
+<mask id="mask0_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M89.375 4.99805H0V14.998H89.375V4.99805Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_8587_60274)">
+<mask id="mask1_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99609H89.375V14.9961H0V4.99609Z" fill="white"/>
+</mask>
+<g mask="url(#mask1_8587_60274)">
+<mask id="mask2_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99414H89.375V14.9941H0V4.99414Z" fill="white"/>
+</mask>
+<g mask="url(#mask2_8587_60274)">
+<mask id="mask3_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask3_8587_60274)">
+<path d="M18.1273 11.9244L13.7773 5.15625H11.4297V14.825H13.4321V8.05688L17.7821 14.825H20.1297V5.15625H18.1273V11.9244Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask4_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask4_8587_60274)">
+<path d="M21.7969 7.02094H25.0423V14.825H27.1139V7.02094H30.3594V5.15625H21.7969V7.02094Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask5_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask5_8587_60274)">
+<path d="M38.6442 9.00994H34.0871V5.15625H32.0156V14.825H34.0871V10.8746H38.6442V14.825H40.7156V5.15625H38.6442V9.00994Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask6_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask6_8587_60274)">
+<path d="M45.3376 7.02094H47.893C48.9152 7.02094 49.4539 7.39387 49.4539 8.09831C49.4539 8.80275 48.9152 9.17569 47.893 9.17569H45.3376V7.02094ZM51.5259 8.09831C51.5259 6.27506 50.186 5.15625 47.9897 5.15625H43.2656V14.825H45.3376V11.0404H47.6443L49.7164 14.825H52.0094L49.715 10.7521C50.8666 10.3094 51.5259 9.37721 51.5259 8.09831Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask7_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask7_8587_60274)">
+<path d="M57.8732 13.0565C56.2438 13.0565 55.2496 11.8963 55.2496 10.004C55.2496 8.08416 56.2438 6.92394 57.8732 6.92394C59.4887 6.92394 60.4691 8.08416 60.4691 10.004C60.4691 11.8963 59.4887 13.0565 57.8732 13.0565ZM57.8732 4.99023C55.0839 4.99023 53.1094 7.06206 53.1094 10.004C53.1094 12.9184 55.0839 14.9902 57.8732 14.9902C60.6486 14.9902 62.6094 12.9184 62.6094 10.004C62.6094 7.06206 60.6486 4.99023 57.8732 4.99023Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask8_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask8_8587_60274)">
+<path d="M69.1794 9.45194H66.6233V7.02094H69.1794C70.2019 7.02094 70.7407 7.43532 70.7407 8.23644C70.7407 9.03756 70.2019 9.45194 69.1794 9.45194ZM69.2762 5.15625H64.5508V14.825H66.6233V11.3166H69.2762C71.473 11.3166 72.8133 10.1564 72.8133 8.23644C72.8133 6.3165 71.473 5.15625 69.2762 5.15625Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask9_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask9_8587_60274)">
+<path d="M86.8413 11.5786C86.4823 12.5179 85.7642 13.0565 84.7837 13.0565C83.1542 13.0565 82.16 11.8963 82.16 10.004C82.16 8.08416 83.1542 6.92394 84.7837 6.92394C85.7642 6.92394 86.4823 7.46261 86.8413 8.40183H89.0369C88.4984 6.33002 86.8827 4.99023 84.7837 4.99023C81.9942 4.99023 80.0195 7.06206 80.0195 10.004C80.0195 12.9184 81.9942 14.9902 84.7837 14.9902C86.8965 14.9902 88.5122 13.6366 89.0508 11.5786H86.8413Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask10_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask10_8587_60274)">
+<path d="M73.6484 5.15625L77.5033 14.825H79.6172L75.7624 5.15625H73.6484Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask11_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask11_8587_60274)">
+<path d="M3.64038 10.9989L4.95938 7.60106L6.27838 10.9989H3.64038ZM3.85422 5.15625L0 14.825H2.15505L2.9433 12.7946H6.97558L7.76371 14.825H9.91875L6.06453 5.15625H3.85422Z" fill="black" fill-opacity="0.92"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_8587_60274">
+<rect width="89.375" height="10" fill="white" transform="translate(0 5)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/anthropic.svg b/app/components/base/icons/assets/public/llm/anthropic.svg
new file mode 100644
index 0000000..d852f04
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/anthropic.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="#CA9F7B"/>
+<path d="M15.3843 6.43481H12.9687L17.3739 17.5652H19.7896L15.3843 6.43481ZM8.40522 6.43481L4 17.5652H6.4633L7.36417 15.2279H11.9729L12.8737 17.5652H15.337L10.9318 6.43481H8.40522ZM8.16104 13.1607L9.66852 9.24907L11.176 13.1607H8.16104Z" fill="#191918"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/azure-openai-service-text.svg b/app/components/base/icons/assets/public/llm/azure-openai-service-text.svg
new file mode 100644
index 0000000..7485c44
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/azure-openai-service-text.svg
@@ -0,0 +1,25 @@
+<svg width="212" height="24" viewBox="0 0 212 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="2" y="1.5" width="10" height="10" fill="#EF4F21"/>
+<rect x="2" y="12.5" width="10" height="10" fill="#03A4EE"/>
+<rect x="13" y="1.5" width="10" height="10" fill="#7EB903"/>
+<rect x="13" y="12.5" width="10" height="10" fill="#FBB604"/>
+<path d="M52.276 10.0045C52.7751 8.50639 52.6033 6.86529 51.8051 5.50264C50.6048 3.41259 48.1917 2.33732 45.835 2.84333C44.7866 1.66218 43.2803 0.990477 41.7011 1.0001C39.2922 0.994602 37.1548 2.54563 36.4137 4.83781C34.8661 5.15475 33.5304 6.12346 32.7487 7.49643C31.5394 9.58097 31.8151 12.2087 33.4307 13.9962C32.9316 15.4943 33.1034 17.1354 33.9016 18.498C35.1019 20.5881 37.515 21.6634 39.8717 21.1573C40.9195 22.3385 42.4264 23.0102 44.0056 22.9999C46.4159 23.0061 48.554 21.4537 49.2951 19.1594C50.8426 18.8425 52.1784 17.8738 52.9601 16.5008C54.168 14.4163 53.8916 11.7906 52.2767 10.0031L52.276 10.0045ZM44.007 21.5623C43.0424 21.5637 42.1081 21.2261 41.3677 20.608C41.4014 20.5901 41.4598 20.5578 41.4976 20.5345L45.8783 18.0044C46.1024 17.8772 46.2399 17.6386 46.2385 17.3808V11.2049L48.0899 12.274C48.1099 12.2836 48.1229 12.3028 48.1257 12.3248V17.4393C48.1229 19.7136 46.2812 21.5575 44.007 21.5623ZM35.1494 17.7789C34.6661 16.9443 34.4921 15.9659 34.6578 15.0165C34.6901 15.0357 34.7472 15.0708 34.7878 15.0942L39.1684 17.6242C39.3905 17.7541 39.6655 17.7541 39.8882 17.6242L45.2362 14.5359V16.6741C45.2376 16.6961 45.2272 16.7174 45.2101 16.7311L40.782 19.288C38.8096 20.4238 36.2906 19.7486 35.1501 17.7789H35.1494ZM33.9965 8.21626C34.4777 7.38024 35.2374 6.74085 36.1421 6.40878C36.1421 6.44659 36.1401 6.51328 36.1401 6.56003V11.6208C36.1387 11.878 36.2762 12.1165 36.4996 12.2437L41.8476 15.3313L39.9962 16.4004C39.9776 16.4128 39.9542 16.4149 39.9336 16.4059L35.5048 13.847C33.5365 12.7071 32.8614 10.1887 33.9958 8.21694L33.9965 8.21626ZM49.2078 11.7563L43.8598 8.66795L45.7112 7.59956C45.7298 7.58718 45.7532 7.58512 45.7738 7.59406L50.2026 10.1509C52.1743 11.2901 52.8501 13.8126 51.7109 15.7844C51.229 16.6191 50.47 17.2584 49.566 17.5912V12.3792C49.568 12.122 49.4312 11.8841 49.2085 11.7563H49.2078ZM51.0502 8.98284C51.0179 8.9629 50.9609 8.92852 50.9203 8.90515L46.5397 6.37509C46.3176 6.24515 46.0426 6.24515 45.8199 6.37509L40.4719 9.46341V7.32524C40.4705 7.30324 40.4808 7.28192 40.498 7.26817L44.9261 4.71337C46.8985 3.57553 49.4202 4.25273 50.5573 6.2259C51.0379 7.05917 51.2118 8.03475 51.0489 8.98284H51.0502ZM39.4654 12.7937L37.6133 11.7246C37.5934 11.715 37.5803 11.6958 37.5776 11.6738V6.55935C37.579 4.2823 39.4262 2.43701 41.7032 2.43838C42.6664 2.43838 43.5986 2.77664 44.339 3.39265C44.3053 3.41053 44.2476 3.44284 44.2091 3.46622L39.8284 5.99627C39.6043 6.12346 39.4668 6.36134 39.4682 6.61916L39.4654 12.7924V12.7937ZM40.4712 10.6253L42.8534 9.24959L45.2355 10.6246V13.3754L42.8534 14.7504L40.4712 13.3754V10.6253Z" fill="black"/>
+<path d="M64.0195 17.0001H62.0508L65.6353 6.81824H67.9123L71.5018 17.0001H69.533L66.8136 8.90631H66.734L64.0195 17.0001ZM64.0842 13.0079H69.4535V14.4894H64.0842V13.0079Z" fill="#1D2939"/>
+<path d="M72.6639 17.0001V15.8566L76.6014 10.9198V10.8552H72.7931V9.36369H78.8038V10.5917L75.0552 15.4439V15.5086H78.9331V17.0001H72.6639Z" fill="#1D2939"/>
+<path d="M85.4918 13.7884V9.36369H87.2915V17.0001H85.5465V15.6428H85.467C85.2946 16.0704 85.0112 16.42 84.6168 16.6918C84.2257 16.9636 83.7435 17.0995 83.1701 17.0995C82.6696 17.0995 82.2272 16.9885 81.8427 16.7664C81.4615 16.541 81.1632 16.2145 80.9478 15.787C80.7324 15.3561 80.6246 14.8358 80.6246 14.2259V9.36369H82.4244V13.9475C82.4244 14.4314 82.5569 14.8159 82.8221 15.1009C83.0872 15.3859 83.4352 15.5285 83.8661 15.5285C84.1313 15.5285 84.3881 15.4638 84.6367 15.3346C84.8853 15.2053 85.0891 15.0131 85.2482 14.7579C85.4106 14.4993 85.4918 14.1762 85.4918 13.7884Z" fill="#1D2939"/>
+<path d="M89.1422 17.0001V9.36369H90.8873V10.6364H90.9668C91.106 10.1956 91.3446 9.85588 91.6827 9.61724C92.0241 9.37529 92.4135 9.25432 92.851 9.25432C92.9505 9.25432 93.0615 9.25929 93.1841 9.26923C93.3101 9.27586 93.4145 9.28746 93.4973 9.30403V10.9596C93.4211 10.9331 93.3001 10.9099 93.1344 10.89C92.972 10.8668 92.8146 10.8552 92.6621 10.8552C92.334 10.8552 92.039 10.9264 91.7772 11.0689C91.5186 11.2082 91.3148 11.402 91.1657 11.6506C91.0165 11.8992 90.9419 12.1859 90.9419 12.5107V17.0001H89.1422Z" fill="#1D2939"/>
+<path d="M97.7592 17.1492C96.9936 17.1492 96.3324 16.9901 95.7756 16.6719C95.2221 16.3504 94.7962 15.8964 94.4979 15.3097C94.1996 14.7198 94.0504 14.0254 94.0504 13.2266C94.0504 12.4411 94.1996 11.7517 94.4979 11.1584C94.7995 10.5618 95.2204 10.0978 95.7607 9.76639C96.3009 9.43164 96.9356 9.26426 97.6648 9.26426C98.1354 9.26426 98.5795 9.34049 98.9972 9.49295C99.4181 9.6421 99.7893 9.87411 100.111 10.189C100.436 10.5038 100.691 10.9049 100.876 11.3921C101.062 11.876 101.155 12.4527 101.155 13.1222V13.6741H94.8956V12.461H99.4297C99.4264 12.1163 99.3518 11.8097 99.206 11.5412C99.0601 11.2695 98.8563 11.0557 98.5945 10.8999C98.3359 10.7441 98.0343 10.6662 97.6896 10.6662C97.3217 10.6662 96.9986 10.7557 96.7202 10.9347C96.4418 11.1104 96.2247 11.3424 96.0689 11.6307C95.9164 11.9158 95.8385 12.229 95.8352 12.5704V13.6293C95.8352 14.0734 95.9164 14.4546 96.0788 14.7728C96.2412 15.0877 96.4683 15.3296 96.7599 15.4986C97.0516 15.6644 97.393 15.7472 97.7841 15.7472C98.0459 15.7472 98.2829 15.7108 98.495 15.6378C98.7071 15.5616 98.8911 15.4506 99.0469 15.3047C99.2027 15.1589 99.3203 14.9783 99.3999 14.7628L101.08 14.9518C100.974 15.3959 100.772 15.7837 100.474 16.1151C100.179 16.4432 99.8009 16.6984 99.3402 16.8807C98.8795 17.0597 98.3525 17.1492 97.7592 17.1492Z" fill="#1D2939"/>
+<path d="M115.328 11.9091C115.328 13.0062 115.122 13.9458 114.711 14.728C114.303 15.5069 113.747 16.1035 113.041 16.5178C112.338 16.9321 111.541 17.1393 110.649 17.1393C109.758 17.1393 108.959 16.9321 108.253 16.5178C107.55 16.1002 106.994 15.5019 106.583 14.7231C106.175 13.9409 105.971 13.0029 105.971 11.9091C105.971 10.8121 106.175 9.87411 106.583 9.09523C106.994 8.31303 107.55 7.71478 108.253 7.30048C108.959 6.88618 109.758 6.67903 110.649 6.67903C111.541 6.67903 112.338 6.88618 113.041 7.30048C113.747 7.71478 114.303 8.31303 114.711 9.09523C115.122 9.87411 115.328 10.8121 115.328 11.9091ZM113.473 11.9091C113.473 11.1369 113.352 10.4856 113.11 9.95531C112.872 9.42169 112.54 9.019 112.116 8.74721C111.692 8.47212 111.203 8.33457 110.649 8.33457C110.096 8.33457 109.607 8.47212 109.183 8.74721C108.758 9.019 108.425 9.42169 108.183 9.95531C107.945 10.4856 107.825 11.1369 107.825 11.9091C107.825 12.6814 107.945 13.3343 108.183 13.868C108.425 14.3983 108.758 14.801 109.183 15.076C109.607 15.3478 110.096 15.4837 110.649 15.4837C111.203 15.4837 111.692 15.3478 112.116 15.076C112.54 14.801 112.872 14.3983 113.11 13.868C113.352 13.3343 113.473 12.6814 113.473 11.9091Z" fill="#1D2939"/>
+<path d="M116.992 19.8637V9.36369H118.762V10.6265H118.866C118.959 10.4409 119.09 10.2437 119.259 10.0349C119.428 9.82274 119.657 9.6421 119.945 9.49295C120.233 9.34049 120.601 9.26426 121.049 9.26426C121.639 9.26426 122.171 9.41507 122.645 9.71667C123.122 10.015 123.5 10.4574 123.778 11.0441C124.06 11.6274 124.201 12.3433 124.201 13.1918C124.201 14.0304 124.063 14.743 123.788 15.3296C123.513 15.9162 123.138 16.3637 122.664 16.6719C122.19 16.9802 121.654 17.1343 121.054 17.1343C120.616 17.1343 120.253 17.0614 119.965 16.9155C119.676 16.7697 119.444 16.594 119.269 16.3885C119.096 16.1797 118.962 15.9825 118.866 15.7969H118.792V19.8637H116.992ZM118.757 13.1819C118.757 13.6757 118.826 14.1082 118.966 14.4795C119.108 14.8507 119.312 15.1407 119.577 15.3495C119.846 15.555 120.17 15.6577 120.551 15.6577C120.949 15.6577 121.282 15.5517 121.551 15.3395C121.819 15.1241 122.021 14.8308 122.157 14.4596C122.297 14.085 122.366 13.6591 122.366 13.1819C122.366 12.7079 122.298 12.287 122.162 11.9191C122.026 11.5512 121.824 11.2628 121.556 11.054C121.287 10.8452 120.953 10.7408 120.551 10.7408C120.167 10.7408 119.841 10.8419 119.572 11.0441C119.304 11.2463 119.1 11.5296 118.961 11.8942C118.825 12.2588 118.757 12.688 118.757 13.1819Z" fill="#1D2939"/>
+<path d="M129.123 17.1492C128.357 17.1492 127.696 16.9901 127.139 16.6719C126.585 16.3504 126.159 15.8964 125.861 15.3097C125.563 14.7198 125.414 14.0254 125.414 13.2266C125.414 12.4411 125.563 11.7517 125.861 11.1584C126.163 10.5618 126.584 10.0978 127.124 9.76639C127.664 9.43164 128.299 9.26426 129.028 9.26426C129.499 9.26426 129.943 9.34049 130.36 9.49295C130.781 9.6421 131.153 9.87411 131.474 10.189C131.799 10.5038 132.054 10.9049 132.24 11.3921C132.425 11.876 132.518 12.4527 132.518 13.1222V13.6741H126.259V12.461H130.793C130.79 12.1163 130.715 11.8097 130.569 11.5412C130.423 11.2695 130.22 11.0557 129.958 10.8999C129.699 10.7441 129.398 10.6662 129.053 10.6662C128.685 10.6662 128.362 10.7557 128.083 10.9347C127.805 11.1104 127.588 11.3424 127.432 11.6307C127.28 11.9158 127.202 12.229 127.199 12.5704V13.6293C127.199 14.0734 127.28 14.4546 127.442 14.7728C127.605 15.0877 127.832 15.3296 128.123 15.4986C128.415 15.6644 128.756 15.7472 129.147 15.7472C129.409 15.7472 129.646 15.7108 129.858 15.6378C130.07 15.5616 130.254 15.4506 130.41 15.3047C130.566 15.1589 130.684 14.9783 130.763 14.7628L132.444 14.9518C132.337 15.3959 132.135 15.7837 131.837 16.1151C131.542 16.4432 131.164 16.6984 130.703 16.8807C130.243 17.0597 129.716 17.1492 129.123 17.1492Z" fill="#1D2939"/>
+<path d="M135.84 12.5256V17.0001H134.041V9.36369H135.761V10.6613H135.85C136.026 10.2337 136.306 9.894 136.691 9.6421C137.078 9.39021 137.557 9.26426 138.127 9.26426C138.654 9.26426 139.113 9.37695 139.504 9.60233C139.899 9.82771 140.204 10.1542 140.419 10.5817C140.638 11.0093 140.746 11.528 140.742 12.1378V17.0001H138.943V12.4162C138.943 11.9058 138.81 11.5064 138.545 11.2181C138.283 10.9297 137.92 10.7856 137.456 10.7856C137.141 10.7856 136.861 10.8552 136.616 10.9944C136.374 11.1303 136.183 11.3275 136.044 11.586C135.908 11.8445 135.84 12.1577 135.84 12.5256Z" fill="#1D2939"/>
+<path d="M143.959 17.0001H141.99L145.575 6.81824H147.852L151.441 17.0001H149.472L146.753 8.90631H146.673L143.959 17.0001ZM144.024 13.0079H149.393V14.4894H144.024V13.0079Z" fill="#1D2939"/>
+<path d="M154.627 6.81824V17.0001H152.782V6.81824H154.627Z" fill="#1D2939"/>
+<path d="M165.63 9.61724C165.584 9.18306 165.388 8.84499 165.044 8.60304C164.702 8.36109 164.258 8.24011 163.711 8.24011C163.327 8.24011 162.997 8.29811 162.722 8.41412C162.447 8.53012 162.236 8.68756 162.09 8.88642C161.945 9.08528 161.87 9.31232 161.867 9.56753C161.867 9.77965 161.915 9.9636 162.011 10.1194C162.11 10.2752 162.244 10.4077 162.414 10.5171C162.583 10.6232 162.77 10.7127 162.975 10.7856C163.181 10.8585 163.388 10.9198 163.597 10.9695L164.551 11.2082C164.936 11.2976 165.305 11.4186 165.66 11.5711C166.018 11.7235 166.338 11.9158 166.619 12.1478C166.905 12.3798 167.13 12.6599 167.296 12.988C167.461 13.3161 167.544 13.7006 167.544 14.1414C167.544 14.738 167.392 15.2633 167.087 15.7174C166.782 16.1681 166.341 16.5211 165.764 16.7763C165.191 17.0282 164.497 17.1542 163.681 17.1542C162.889 17.1542 162.201 17.0315 161.618 16.7863C161.038 16.541 160.584 16.1831 160.256 15.7124C159.931 15.2418 159.755 14.6684 159.729 13.9922H161.544C161.57 14.3469 161.679 14.6419 161.872 14.8772C162.064 15.1125 162.314 15.2882 162.622 15.4042C162.934 15.5202 163.282 15.5782 163.666 15.5782C164.067 15.5782 164.419 15.5185 164.72 15.3992C165.025 15.2766 165.264 15.1075 165.436 14.8921C165.609 14.6734 165.696 14.4181 165.7 14.1265C165.696 13.8613 165.619 13.6426 165.466 13.4702C165.314 13.2946 165.1 13.1487 164.825 13.0327C164.553 12.9134 164.235 12.8073 163.87 12.7145L162.712 12.4162C161.873 12.2008 161.21 11.8743 160.723 11.4368C160.239 10.996 159.997 10.411 159.997 9.68187C159.997 9.08197 160.16 8.55664 160.485 8.10588C160.813 7.65512 161.258 7.30545 161.822 7.05687C162.385 6.80498 163.023 6.67903 163.736 6.67903C164.459 6.67903 165.092 6.80498 165.635 7.05687C166.182 7.30545 166.611 7.65181 166.923 8.09594C167.234 8.53675 167.395 9.04385 167.405 9.61724H165.63Z" fill="#1D2939"/>
+<path d="M172.49 17.1492C171.724 17.1492 171.063 16.9901 170.506 16.6719C169.953 16.3504 169.527 15.8964 169.228 15.3097C168.93 14.7198 168.781 14.0254 168.781 13.2266C168.781 12.4411 168.93 11.7517 169.228 11.1584C169.53 10.5618 169.951 10.0978 170.491 9.76639C171.031 9.43164 171.666 9.26426 172.395 9.26426C172.866 9.26426 173.31 9.34049 173.728 9.49295C174.149 9.6421 174.52 9.87411 174.841 10.189C175.166 10.5038 175.421 10.9049 175.607 11.3921C175.792 11.876 175.885 12.4527 175.885 13.1222V13.6741H169.626V12.461H174.16C174.157 12.1163 174.082 11.8097 173.936 11.5412C173.791 11.2695 173.587 11.0557 173.325 10.8999C173.066 10.7441 172.765 10.6662 172.42 10.6662C172.052 10.6662 171.729 10.7557 171.451 10.9347C171.172 11.1104 170.955 11.3424 170.799 11.6307C170.647 11.9158 170.569 12.229 170.566 12.5704V13.6293C170.566 14.0734 170.647 14.4546 170.809 14.7728C170.972 15.0877 171.199 15.3296 171.49 15.4986C171.782 15.6644 172.123 15.7472 172.515 15.7472C172.776 15.7472 173.013 15.7108 173.225 15.6378C173.438 15.5616 173.622 15.4506 173.777 15.3047C173.933 15.1589 174.051 14.9783 174.13 14.7628L175.811 14.9518C175.705 15.3959 175.502 15.7837 175.204 16.1151C174.909 16.4432 174.531 16.6984 174.071 16.8807C173.61 17.0597 173.083 17.1492 172.49 17.1492Z" fill="#1D2939"/>
+<path d="M177.408 17.0001V9.36369H179.153V10.6364H179.232C179.372 10.1956 179.61 9.85588 179.948 9.61724C180.29 9.37529 180.679 9.25432 181.117 9.25432C181.216 9.25432 181.327 9.25929 181.45 9.26923C181.576 9.27586 181.68 9.28746 181.763 9.30403V10.9596C181.687 10.9331 181.566 10.9099 181.4 10.89C181.238 10.8668 181.08 10.8552 180.928 10.8552C180.6 10.8552 180.305 10.9264 180.043 11.0689C179.784 11.2082 179.58 11.402 179.431 11.6506C179.282 11.8992 179.208 12.1859 179.208 12.5107V17.0001H177.408Z" fill="#1D2939"/>
+<path d="M190.012 9.36369L187.293 17.0001H185.304L182.585 9.36369H184.504L186.259 15.0363H186.338L188.098 9.36369H190.012Z" fill="#1D2939"/>
+<path d="M191.257 17.0001V9.36369H193.057V17.0001H191.257ZM192.162 8.27989C191.877 8.27989 191.632 8.18542 191.426 7.9965C191.221 7.80427 191.118 7.57392 191.118 7.30545C191.118 7.03367 191.221 6.80332 191.426 6.6144C191.632 6.42217 191.877 6.32605 192.162 6.32605C192.451 6.32605 192.696 6.42217 192.898 6.6144C193.104 6.80332 193.206 7.03367 193.206 7.30545C193.206 7.57392 193.104 7.80427 192.898 7.9965C192.696 8.18542 192.451 8.27989 192.162 8.27989Z" fill="#1D2939"/>
+<path d="M198.239 17.1492C197.477 17.1492 196.822 16.9818 196.275 16.6471C195.731 16.3123 195.312 15.85 195.017 15.26C194.726 14.6667 194.58 13.984 194.58 13.2117C194.58 12.4361 194.729 11.7517 195.027 11.1584C195.325 10.5618 195.746 10.0978 196.29 9.76639C196.837 9.43164 197.483 9.26426 198.229 9.26426C198.849 9.26426 199.397 9.37861 199.874 9.6073C200.355 9.83268 200.738 10.1525 201.023 10.5668C201.308 10.9778 201.47 11.4584 201.51 12.0086H199.79C199.72 11.6407 199.555 11.3341 199.293 11.0888C199.034 10.8403 198.688 10.716 198.254 10.716C197.886 10.716 197.563 10.8154 197.284 11.0143C197.006 11.2098 196.789 11.4915 196.633 11.8594C196.481 12.2273 196.404 12.6681 196.404 13.1819C196.404 13.7022 196.481 14.1497 196.633 14.5242C196.785 14.8954 196.999 15.1821 197.274 15.3843C197.553 15.5832 197.879 15.6826 198.254 15.6826C198.519 15.6826 198.756 15.6329 198.965 15.5334C199.177 15.4307 199.354 15.2832 199.497 15.091C199.639 14.8987 199.737 14.6651 199.79 14.39H201.51C201.467 14.9302 201.308 15.4091 201.033 15.8268C200.758 16.2411 200.383 16.5659 199.909 16.8012C199.435 17.0332 198.878 17.1492 198.239 17.1492Z" fill="#1D2939"/>
+<path d="M206.369 17.1492C205.603 17.1492 204.942 16.9901 204.385 16.6719C203.831 16.3504 203.406 15.8964 203.107 15.3097C202.809 14.7198 202.66 14.0254 202.66 13.2266C202.66 12.4411 202.809 11.7517 203.107 11.1584C203.409 10.5618 203.83 10.0978 204.37 9.76639C204.91 9.43164 205.545 9.26426 206.274 9.26426C206.745 9.26426 207.189 9.34049 207.607 9.49295C208.027 9.6421 208.399 9.87411 208.72 10.189C209.045 10.5038 209.3 10.9049 209.486 11.3921C209.671 11.876 209.764 12.4527 209.764 13.1222V13.6741H203.505V12.461H208.039C208.036 12.1163 207.961 11.8097 207.815 11.5412C207.67 11.2695 207.466 11.0557 207.204 10.8999C206.945 10.7441 206.644 10.6662 206.299 10.6662C205.931 10.6662 205.608 10.7557 205.33 10.9347C205.051 11.1104 204.834 11.3424 204.678 11.6307C204.526 11.9158 204.448 12.229 204.445 12.5704V13.6293C204.445 14.0734 204.526 14.4546 204.688 14.7728C204.851 15.0877 205.078 15.3296 205.369 15.4986C205.661 15.6644 206.002 15.7472 206.393 15.7472C206.655 15.7472 206.892 15.7108 207.104 15.6378C207.317 15.5616 207.5 15.4506 207.656 15.3047C207.812 15.1589 207.93 14.9783 208.009 14.7628L209.69 14.9518C209.584 15.3959 209.381 15.7837 209.083 16.1151C208.788 16.4432 208.41 16.6984 207.95 16.8807C207.489 17.0597 206.962 17.1492 206.369 17.1492Z" fill="#1D2939"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/azure-openai-service.svg b/app/components/base/icons/assets/public/llm/azure-openai-service.svg
new file mode 100644
index 0000000..6a541fc
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/azure-openai-service.svg
@@ -0,0 +1,7 @@
+<svg width="56" height="24" viewBox="0 0 56 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="2" y="1.5" width="10" height="10" fill="#EF4F21"/>
+<rect x="2" y="12.5" width="10" height="10" fill="#03A4EE"/>
+<rect x="13" y="1.5" width="10" height="10" fill="#7EB903"/>
+<rect x="13" y="12.5" width="10" height="10" fill="#FBB604"/>
+<path d="M52.276 10.0045C52.7751 8.50639 52.6033 6.86529 51.8051 5.50264C50.6048 3.41259 48.1917 2.33732 45.835 2.84333C44.7866 1.66218 43.2803 0.990477 41.7011 1.0001C39.2922 0.994602 37.1548 2.54563 36.4137 4.83781C34.8661 5.15475 33.5304 6.12346 32.7487 7.49643C31.5394 9.58097 31.8151 12.2087 33.4307 13.9962C32.9316 15.4943 33.1034 17.1354 33.9016 18.498C35.1019 20.5881 37.515 21.6634 39.8717 21.1573C40.9195 22.3385 42.4264 23.0102 44.0056 22.9999C46.4159 23.0061 48.554 21.4537 49.2951 19.1594C50.8426 18.8425 52.1784 17.8738 52.9601 16.5008C54.168 14.4163 53.8916 11.7906 52.2767 10.0031L52.276 10.0045ZM44.007 21.5623C43.0424 21.5637 42.1081 21.2261 41.3677 20.608C41.4014 20.5901 41.4598 20.5578 41.4976 20.5345L45.8783 18.0044C46.1024 17.8772 46.2399 17.6386 46.2385 17.3808V11.2049L48.0899 12.274C48.1099 12.2836 48.1229 12.3028 48.1257 12.3248V17.4393C48.1229 19.7136 46.2812 21.5575 44.007 21.5623ZM35.1494 17.7789C34.6661 16.9443 34.4921 15.9659 34.6578 15.0165C34.6901 15.0357 34.7472 15.0708 34.7878 15.0942L39.1684 17.6242C39.3905 17.7541 39.6655 17.7541 39.8882 17.6242L45.2362 14.5359V16.6741C45.2376 16.6961 45.2272 16.7174 45.2101 16.7311L40.782 19.288C38.8096 20.4238 36.2906 19.7486 35.1501 17.7789H35.1494ZM33.9965 8.21626C34.4777 7.38024 35.2374 6.74085 36.1421 6.40878C36.1421 6.44659 36.1401 6.51328 36.1401 6.56003V11.6208C36.1387 11.878 36.2762 12.1165 36.4996 12.2437L41.8476 15.3313L39.9962 16.4004C39.9776 16.4128 39.9542 16.4149 39.9336 16.4059L35.5048 13.847C33.5365 12.7071 32.8614 10.1887 33.9958 8.21694L33.9965 8.21626ZM49.2078 11.7563L43.8598 8.66795L45.7112 7.59956C45.7298 7.58718 45.7532 7.58512 45.7738 7.59406L50.2026 10.1509C52.1743 11.2901 52.8501 13.8126 51.7109 15.7844C51.229 16.6191 50.47 17.2584 49.566 17.5912V12.3792C49.568 12.122 49.4312 11.8841 49.2085 11.7563H49.2078ZM51.0502 8.98284C51.0179 8.9629 50.9609 8.92852 50.9203 8.90515L46.5397 6.37509C46.3176 6.24515 46.0426 6.24515 45.8199 6.37509L40.4719 9.46341V7.32524C40.4705 7.30324 40.4808 7.28192 40.498 7.26817L44.9261 4.71337C46.8985 3.57553 49.4202 4.25273 50.5573 6.2259C51.0379 7.05917 51.2118 8.03475 51.0489 8.98284H51.0502ZM39.4654 12.7937L37.6133 11.7246C37.5934 11.715 37.5803 11.6958 37.5776 11.6738V6.55935C37.579 4.2823 39.4262 2.43701 41.7032 2.43838C42.6664 2.43838 43.5986 2.77664 44.339 3.39265C44.3053 3.41053 44.2476 3.44284 44.2091 3.46622L39.8284 5.99627C39.6043 6.12346 39.4668 6.36134 39.4682 6.61916L39.4654 12.7924V12.7937ZM40.4712 10.6253L42.8534 9.24959L45.2355 10.6246V13.3754L42.8534 14.7504L40.4712 13.3754V10.6253Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/azureai-text.svg b/app/components/base/icons/assets/public/llm/azureai-text.svg
new file mode 100644
index 0000000..0bbbeee
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/azureai-text.svg
@@ -0,0 +1,30 @@
+<svg width="92" height="24" viewBox="0 0 92 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.63655 2.50023H15.6036L9.40921 20.8535C9.34555 21.0421 9.22434 21.206 9.06266 21.3221C8.90097 21.4382 8.70695 21.5006 8.5079 21.5007H3.86407C3.71326 21.5007 3.56461 21.4648 3.43042 21.396C3.29623 21.3271 3.18036 21.2273 3.09239 21.1048C3.00442 20.9823 2.94689 20.8406 2.92454 20.6915C2.9022 20.5424 2.91569 20.39 2.9639 20.2471L8.73501 3.1474C8.79864 2.95872 8.91987 2.79477 9.0816 2.67863C9.24334 2.56249 9.43743 2.50024 9.63655 2.50023Z" fill="url(#paint0_linear_8587_60561)"/>
+<path d="M18.307 14.8105H8.84467C8.7567 14.8104 8.67074 14.8368 8.59799 14.8863C8.52524 14.9358 8.46906 15.006 8.43679 15.0878C8.40451 15.1697 8.39763 15.2593 8.41704 15.3451C8.43645 15.4309 8.48125 15.5089 8.54561 15.5689L14.6259 21.2439C14.8029 21.4091 15.036 21.5009 15.2781 21.5008H20.636L18.307 14.8105Z" fill="#0078D4"/>
+<path d="M9.63533 2.50001C9.43405 2.49923 9.23778 2.56284 9.07521 2.68154C8.91265 2.80024 8.79229 2.96781 8.73173 3.15978L2.96979 20.2313C2.91834 20.3747 2.90219 20.5284 2.9227 20.6794C2.94321 20.8304 2.99979 20.9742 3.08764 21.0987C3.17549 21.2232 3.29203 21.3247 3.42741 21.3946C3.56278 21.4646 3.71301 21.5009 3.86538 21.5004H8.62906C8.80648 21.4687 8.97231 21.3905 9.1096 21.2738C9.2469 21.157 9.35074 21.0059 9.41052 20.8359L10.5596 17.4495L14.6639 21.2777C14.8359 21.42 15.0517 21.4986 15.2749 21.5004H20.6129L18.2717 14.8102L11.4469 14.8118L15.6239 2.50001H9.63533Z" fill="url(#paint1_linear_8587_60561)"/>
+<path d="M17.2574 3.14625C17.1938 2.95788 17.0728 2.7942 16.9113 2.67826C16.7498 2.56233 16.556 2.49998 16.3572 2.5H9.70703C9.90582 2.50001 10.0996 2.56237 10.2611 2.67831C10.4226 2.79424 10.5436 2.9579 10.6072 3.14625L16.3785 20.2467C16.4268 20.3896 16.4403 20.542 16.418 20.6911C16.3957 20.8403 16.3381 20.9821 16.2502 21.1046C16.1622 21.2271 16.0463 21.327 15.9121 21.3959C15.7779 21.4647 15.6292 21.5007 15.4784 21.5007H22.1288C22.2796 21.5006 22.4283 21.4647 22.5624 21.3958C22.6966 21.3269 22.8125 21.2271 22.9004 21.1045C22.9884 20.982 23.0459 20.8403 23.0682 20.6911C23.0905 20.5419 23.077 20.3896 23.0287 20.2467L17.2574 3.14625Z" fill="url(#paint2_linear_8587_60561)"/>
+<path d="M34.312 17.0001H32.3433L35.9278 6.81824H38.2048L41.7943 17.0001H39.8255L37.106 8.90631H37.0265L34.312 17.0001ZM34.3766 13.0079H39.746V14.4894H34.3766V13.0079Z" fill="#1D2939"/>
+<path d="M42.9564 17.0001V15.8566L46.8939 10.9198V10.8552H43.0856V9.36369H49.0963V10.5917L45.3477 15.4439V15.5086H49.2255V17.0001H42.9564Z" fill="#1D2939"/>
+<path d="M55.7843 13.7884V9.36369H57.584V17.0001H55.839V15.6428H55.7595C55.5871 16.0704 55.3037 16.42 54.9093 16.6918C54.5182 16.9636 54.036 17.0995 53.4626 17.0995C52.9621 17.0995 52.5196 16.9885 52.1352 16.7664C51.754 16.541 51.4557 16.2145 51.2403 15.787C51.0248 15.3561 50.9171 14.8358 50.9171 14.2259V9.36369H52.7168V13.9475C52.7168 14.4314 52.8494 14.8159 53.1146 15.1009C53.3797 15.3859 53.7277 15.5285 54.1586 15.5285C54.4238 15.5285 54.6806 15.4638 54.9292 15.3346C55.1778 15.2053 55.3816 15.0131 55.5407 14.7579C55.7031 14.4993 55.7843 14.1762 55.7843 13.7884Z" fill="#1D2939"/>
+<path d="M59.4347 17.0001V9.36369H61.1797V10.6364H61.2593C61.3985 10.1956 61.6371 9.85588 61.9752 9.61724C62.3166 9.37529 62.706 9.25432 63.1435 9.25432C63.2429 9.25432 63.354 9.25929 63.4766 9.26923C63.6026 9.27586 63.707 9.28746 63.7898 9.30403V10.9596C63.7136 10.9331 63.5926 10.9099 63.4269 10.89C63.2645 10.8668 63.1071 10.8552 62.9546 10.8552C62.6265 10.8552 62.3315 10.9264 62.0696 11.0689C61.8111 11.2082 61.6073 11.402 61.4581 11.6506C61.309 11.8992 61.2344 12.1859 61.2344 12.5107V17.0001H59.4347Z" fill="#1D2939"/>
+<path d="M68.0517 17.1492C67.2861 17.1492 66.6249 16.9901 66.068 16.6719C65.5145 16.3504 65.0886 15.8964 64.7903 15.3097C64.4921 14.7198 64.3429 14.0254 64.3429 13.2266C64.3429 12.4411 64.4921 11.7517 64.7903 11.1584C65.092 10.5618 65.5129 10.0978 66.0531 9.76639C66.5934 9.43164 67.2281 9.26426 67.9573 9.26426C68.4279 9.26426 68.872 9.34049 69.2896 9.49295C69.7106 9.6421 70.0818 9.87411 70.4033 10.189C70.7281 10.5038 70.9833 10.9049 71.1689 11.3921C71.3545 11.876 71.4473 12.4527 71.4473 13.1222V13.6741H65.1881V12.461H69.7222C69.7189 12.1163 69.6443 11.8097 69.4984 11.5412C69.3526 11.2695 69.1488 11.0557 68.8869 10.8999C68.6284 10.7441 68.3268 10.6662 67.9821 10.6662C67.6142 10.6662 67.2911 10.7557 67.0126 10.9347C66.7342 11.1104 66.5171 11.3424 66.3614 11.6307C66.2089 11.9158 66.131 12.229 66.1277 12.5704V13.6293C66.1277 14.0734 66.2089 14.4546 66.3713 14.7728C66.5337 15.0877 66.7608 15.3296 67.0524 15.4986C67.3441 15.6644 67.6855 15.7472 68.0766 15.7472C68.3384 15.7472 68.5754 15.7108 68.7875 15.6378C68.9996 15.5616 69.1836 15.4506 69.3394 15.3047C69.4951 15.1589 69.6128 14.9783 69.6923 14.7628L71.3727 14.9518C71.2667 15.3959 71.0645 15.7837 70.7662 16.1151C70.4712 16.4432 70.0934 16.6984 69.6327 16.8807C69.172 17.0597 68.645 17.1492 68.0517 17.1492Z" fill="#1D2939"/>
+<path d="M77.8296 17.0001H75.8608L79.4454 6.81824H81.7223L85.3118 17.0001H83.3431L80.6236 8.90631H80.5441L77.8296 17.0001ZM77.8942 13.0079H83.2635V14.4894H77.8942V13.0079Z" fill="#1D2939"/>
+<path d="M88.4974 6.81824V17.0001H86.6529V6.81824H88.4974Z" fill="#1D2939"/>
+<defs>
+<linearGradient id="paint0_linear_8587_60561" x1="11.8113" y1="3.90823" x2="5.61444" y2="22.2154" gradientUnits="userSpaceOnUse">
+<stop stop-color="#114A8B"/>
+<stop offset="1" stop-color="#0669BC"/>
+</linearGradient>
+<linearGradient id="paint1_linear_8587_60561" x1="13.7459" y1="12.4397" x2="12.3125" y2="12.9243" gradientUnits="userSpaceOnUse">
+<stop stop-opacity="0.3"/>
+<stop offset="0.071" stop-opacity="0.2"/>
+<stop offset="0.321" stop-opacity="0.1"/>
+<stop offset="0.623" stop-opacity="0.05"/>
+<stop offset="1" stop-opacity="0"/>
+</linearGradient>
+<linearGradient id="paint2_linear_8587_60561" x1="12.9582" y1="3.37404" x2="19.7606" y2="21.4968" gradientUnits="userSpaceOnUse">
+<stop stop-color="#3CCBF4"/>
+<stop offset="1" stop-color="#2892DF"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/azureai.svg b/app/components/base/icons/assets/public/llm/azureai.svg
new file mode 100644
index 0000000..93c9b59
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/azureai.svg
@@ -0,0 +1,23 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.41642 1.13526H14.9266L8.16839 21.1596C8.09893 21.3654 7.96669 21.5442 7.79029 21.6708C7.61389 21.7975 7.4022 21.8657 7.18504 21.8657H2.11851C1.95397 21.8657 1.79179 21.8266 1.64539 21.7515C1.49898 21.6764 1.37257 21.5675 1.27659 21.4338C1.18062 21.3002 1.11784 21.1456 1.09347 20.9829C1.06909 20.8201 1.08381 20.6539 1.13641 20.498L7.43281 1.84135C7.50224 1.6355 7.6345 1.45662 7.81096 1.3299C7.98742 1.20319 8.19918 1.13527 8.41642 1.13526Z" fill="url(#paint0_linear_8587_60253)"/>
+<path d="M17.8761 14.5664H7.55255C7.45657 14.5663 7.36278 14.5951 7.28341 14.6491C7.20403 14.703 7.14275 14.7796 7.10754 14.8689C7.07232 14.9582 7.06482 15.056 7.08599 15.1496C7.10717 15.2433 7.15605 15.3283 7.22626 15.3938L13.86 21.5856C14.0531 21.7657 14.3074 21.8659 14.5715 21.8659H20.4171L17.8761 14.5664Z" fill="#0078D4"/>
+<path d="M8.41509 1.13502C8.19548 1.13417 7.98136 1.20358 7.80399 1.33308C7.62663 1.46259 7.49532 1.64542 7.42924 1.85486L1.14283 20.4808C1.0867 20.6373 1.06907 20.805 1.09145 20.9697C1.11383 21.1344 1.17556 21.2913 1.2714 21.4272C1.36725 21.563 1.4944 21.6737 1.6421 21.75C1.7898 21.8263 1.9537 21.8659 2.11994 21.8655H7.31723C7.5108 21.8309 7.69172 21.7455 7.84151 21.6181C7.9913 21.4907 8.10459 21.3259 8.16982 21.1404L9.42345 17.4456L13.9014 21.6224C14.0891 21.7776 14.3245 21.8635 14.568 21.8655H20.3918L17.8376 14.566L10.3916 14.5678L14.9488 1.13502H8.41509Z" fill="url(#paint1_linear_8587_60253)"/>
+<path d="M16.7308 1.8401C16.6614 1.63458 16.5294 1.456 16.3532 1.3295C16.177 1.20301 15.9656 1.13498 15.7487 1.13501H8.49316C8.71005 1.13502 8.92147 1.20306 9.09765 1.32955C9.27383 1.45604 9.4059 1.6346 9.47527 1.8401L15.7719 20.4975C15.8246 20.6535 15.8393 20.8197 15.815 20.9825C15.7906 21.1452 15.7278 21.2999 15.6319 21.4336C15.5359 21.5673 15.4095 21.6762 15.263 21.7514C15.1166 21.8265 14.9544 21.8657 14.7898 21.8657H22.0456C22.2101 21.8657 22.3723 21.8264 22.5187 21.7513C22.6651 21.6761 22.7915 21.5672 22.8875 21.4335C22.9834 21.2998 23.0461 21.1452 23.0705 20.9824C23.0948 20.8197 23.0801 20.6534 23.0274 20.4975L16.7308 1.8401Z" fill="url(#paint2_linear_8587_60253)"/>
+<defs>
+<linearGradient id="paint0_linear_8587_60253" x1="10.7892" y1="2.67146" x2="4.0279" y2="22.6454" gradientUnits="userSpaceOnUse">
+<stop stop-color="#114A8B"/>
+<stop offset="1" stop-color="#0669BC"/>
+</linearGradient>
+<linearGradient id="paint1_linear_8587_60253" x1="12.8998" y1="11.9797" x2="11.3359" y2="12.5085" gradientUnits="userSpaceOnUse">
+<stop stop-opacity="0.3"/>
+<stop offset="0.071" stop-opacity="0.2"/>
+<stop offset="0.321" stop-opacity="0.1"/>
+<stop offset="0.623" stop-opacity="0.05"/>
+<stop offset="1" stop-opacity="0"/>
+</linearGradient>
+<linearGradient id="paint2_linear_8587_60253" x1="12.0403" y1="2.08863" x2="19.4621" y2="21.8613" gradientUnits="userSpaceOnUse">
+<stop stop-color="#3CCBF4"/>
+<stop offset="1" stop-color="#2892DF"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/baichuan-text.svg b/app/components/base/icons/assets/public/llm/baichuan-text.svg
new file mode 100644
index 0000000..7ff6b5a
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/baichuan-text.svg
@@ -0,0 +1,19 @@
+<svg width="130" height="24" viewBox="0 0 130 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.58154 1.7793H6.52779L4.34655 6.20409V17.7335L1.91602 22.2206H7.21333L9.58154 17.7335V1.7793ZM11.5761 1.7793H16.8111V22.2206H11.5761V1.7793ZM23.9166 1.7793H18.6816V6.01712H23.9166V1.7793ZM23.9166 7.38818H18.6816V22.2206H23.9166V7.38818Z" fill="url(#paint0_radial_11622_96091)"/>
+<path d="M129.722 6.83203V18H127.482V6.83203H129.722Z" fill="#FF6A34"/>
+<path d="M123.196 15.872H118.748L118.012 18H115.66L119.676 6.81604H122.284L126.3 18H123.932L123.196 15.872ZM122.588 14.08L120.972 9.40804L119.356 14.08H122.588Z" fill="#FF6A34"/>
+<path d="M110.962 18H108.722L103.65 10.336V18H101.41V6.81598H103.65L108.722 14.496V6.81598H110.962V18Z" fill="#FF6A34"/>
+<path d="M97.1258 15.872H92.6778L91.9418 18H89.5898L93.6058 6.81604H96.2138L100.23 18H97.8618L97.1258 15.872ZM96.5178 14.08L94.9018 9.40804L93.2858 14.08H96.5178Z" fill="#FF6A34"/>
+<path d="M81.6482 6.83203V13.744C81.6482 14.5014 81.8455 15.0827 82.2402 15.488C82.6349 15.8827 83.1895 16.08 83.9042 16.08C84.6295 16.08 85.1895 15.8827 85.5842 15.488C85.9789 15.0827 86.1762 14.5014 86.1762 13.744V6.83203H88.4322V13.728C88.4322 14.6774 88.2242 15.4827 87.8082 16.144C87.4029 16.7947 86.8535 17.2854 86.1602 17.616C85.4775 17.9467 84.7149 18.112 83.8722 18.112C83.0402 18.112 82.2829 17.9467 81.6002 17.616C80.9282 17.2854 80.3949 16.7947 80.0002 16.144C79.6055 15.4827 79.4082 14.6774 79.4082 13.728V6.83203H81.6482Z" fill="#FF6A34"/>
+<path d="M77.557 6.83203V18H75.317V13.248H70.533V18H68.293V6.83203H70.533V11.424H75.317V6.83203H77.557Z" fill="#FF6A34"/>
+<path d="M55.7871 12.4C55.7871 11.3013 56.0324 10.32 56.5231 9.45599C57.0244 8.58132 57.7018 7.90399 58.5551 7.42399C59.4191 6.93332 60.3844 6.68799 61.4511 6.68799C62.6991 6.68799 63.7924 7.00799 64.7311 7.64799C65.6698 8.28799 66.3258 9.17332 66.6991 10.304H64.1231C63.8671 9.77065 63.5044 9.37065 63.0351 9.10399C62.5764 8.83732 62.0431 8.70399 61.4351 8.70399C60.7844 8.70399 60.2031 8.85865 59.6911 9.16799C59.1898 9.46665 58.7951 9.89332 58.5071 10.448C58.2298 11.0027 58.0911 11.6533 58.0911 12.4C58.0911 13.136 58.2298 13.7867 58.5071 14.352C58.7951 14.9067 59.1898 15.3387 59.6911 15.648C60.2031 15.9467 60.7844 16.096 61.4351 16.096C62.0431 16.096 62.5764 15.9627 63.0351 15.696C63.5044 15.4187 63.8671 15.0133 64.1231 14.48H66.6991C66.3258 15.6213 65.6698 16.512 64.7311 17.152C63.8031 17.7813 62.7098 18.096 61.4511 18.096C60.3844 18.096 59.4191 17.856 58.5551 17.376C57.7018 16.8853 57.0244 16.208 56.5231 15.344C56.0324 14.48 55.7871 13.4987 55.7871 12.4Z" fill="#FF6A34"/>
+<path d="M54.4373 6.83203V18H52.1973V6.83203H54.4373Z" fill="#FF6A34"/>
+<path d="M47.913 15.872H43.465L42.729 18H40.377L44.393 6.81598H47.001L51.017 18H48.649L47.913 15.872ZM47.305 14.08L45.689 9.40798L44.073 14.08H47.305Z" fill="#FF6A34"/>
+<path d="M37.4395 12.272C38.0688 12.3893 38.5862 12.704 38.9915 13.216C39.3968 13.728 39.5995 14.3146 39.5995 14.976C39.5995 15.5733 39.4502 16.1013 39.1515 16.56C38.8635 17.008 38.4422 17.36 37.8875 17.616C37.3328 17.872 36.6768 18 35.9195 18H31.1035V6.83197H35.7115C36.4688 6.83197 37.1195 6.95464 37.6635 7.19997C38.2182 7.4453 38.6342 7.78664 38.9115 8.22397C39.1995 8.6613 39.3435 9.1573 39.3435 9.71197C39.3435 10.3626 39.1675 10.9066 38.8155 11.344C38.4742 11.7813 38.0155 12.0906 37.4395 12.272ZM33.3435 11.44H35.3915C35.9248 11.44 36.3355 11.3226 36.6235 11.088C36.9115 10.8426 37.0555 10.496 37.0555 10.048C37.0555 9.59997 36.9115 9.2533 36.6235 9.00797C36.3355 8.76264 35.9248 8.63997 35.3915 8.63997H33.3435V11.44ZM35.5995 16.176C36.1435 16.176 36.5648 16.048 36.8635 15.792C37.1728 15.536 37.3275 15.1733 37.3275 14.704C37.3275 14.224 37.1675 13.8506 36.8475 13.584C36.5275 13.3066 36.0955 13.168 35.5515 13.168H33.3435V16.176H35.5995Z" fill="#FF6A34"/>
+<defs>
+<radialGradient id="paint0_radial_11622_96091" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(6.5 5.5) rotate(45) scale(20.5061 22.0704)">
+<stop stop-color="#FEBD3F"/>
+<stop offset="0.77608" stop-color="#FF6933"/>
+</radialGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/baichuan.svg b/app/components/base/icons/assets/public/llm/baichuan.svg
new file mode 100644
index 0000000..4ddcd26
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/baichuan.svg
@@ -0,0 +1,11 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Baichuan">
+<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M8.58154 1.7793H5.52779L3.34655 6.20409V17.7335L0.916016 22.2206H6.21333L8.58154 17.7335V1.7793ZM10.5761 1.7793H15.8111V22.2206H10.5761V1.7793ZM22.9166 1.7793H17.6816V6.01712H22.9166V1.7793ZM22.9166 7.38818H17.6816V22.2206H22.9166V7.38818Z" fill="url(#paint0_radial_11622_96084)"/>
+</g>
+<defs>
+<radialGradient id="paint0_radial_11622_96084" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(5.5 5.5) rotate(45) scale(20.5061 22.0704)">
+<stop stop-color="#FEBD3F"/>
+<stop offset="0.77608" stop-color="#FF6933"/>
+</radialGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/chatglm-text.svg b/app/components/base/icons/assets/public/llm/chatglm-text.svg
new file mode 100644
index 0000000..dc7924c
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/chatglm-text.svg
@@ -0,0 +1,16 @@
+<svg width="100" height="24" viewBox="0 0 100 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M56.5415 9.49683C56.3371 9.38235 56.1222 9.28491 55.8984 9.20565C55.4497 9.04653 54.9672 8.95911 54.4654 8.95911C52.0893 8.95911 50.1562 10.9044 50.1562 13.2955C50.1562 15.6867 52.0893 17.6313 54.4654 17.6313C54.9672 17.6313 55.4497 17.5438 55.8984 17.3847C55.9178 17.3778 55.9378 17.3703 55.9572 17.3627C57.2065 16.8986 58.1845 15.8659 58.582 14.5785V12.0125C58.2489 10.9333 57.5083 10.0333 56.5415 9.49683ZM55.9578 13.9446C55.9397 13.986 55.9197 14.0269 55.8991 14.0665C55.6247 14.5804 55.0854 14.9307 54.466 14.9307C53.5698 14.9307 52.8411 14.1973 52.8411 13.2955C52.8411 12.3936 53.5698 11.6603 54.466 11.6603C55.0854 11.6603 55.6241 12.01 55.8991 12.5244C55.9203 12.5647 55.9403 12.6049 55.9578 12.6471C56.0434 12.8458 56.0909 13.0653 56.0909 13.2955C56.0909 13.5257 56.0434 13.7452 55.9578 13.9446Z" fill="#1A2029"/>
+<path d="M58.6419 9.49683V17.596H55.959V13.9445C56.0446 13.7458 56.0921 13.5256 56.0921 13.2955C56.0921 13.0653 56.0446 12.8458 55.959 12.6471V9.49683H58.6419Z" fill="#1A2029"/>
+<path d="M63.4475 7.46912H60.7637V17.6142H63.4475V7.46912Z" fill="#1A2029"/>
+<path d="M64.8417 9.49683H59.3789V12.1974H64.3659C64.3587 12.0773 64.3545 11.9559 64.3545 11.8339C64.3545 11.0031 64.5285 10.2125 64.8417 9.49683Z" fill="#1A2029"/>
+<path d="M35.3555 14.908C34.2412 14.908 33.2644 14.3087 32.7257 13.4137C32.4444 12.947 32.2832 12.3999 32.2832 11.8163C32.2832 11.2326 32.4444 10.6849 32.7257 10.2188C33.2644 9.32448 34.2412 8.72448 35.3555 8.72448C36.4699 8.72448 37.4461 9.32388 37.9847 10.2188L40.2809 8.82324C39.2716 7.14714 37.441 6.02454 35.3555 6.02454C33.27 6.02454 31.4388 7.14714 30.4296 8.82324C29.9027 9.69744 29.5996 10.7219 29.5996 11.8169C29.5996 12.9118 29.9027 13.9363 30.4296 14.8105C31.4388 16.4866 33.2694 17.6092 35.3555 17.6092C37.4417 17.6092 39.2716 16.4866 40.2809 14.8105L37.9847 13.415C37.4461 14.3093 36.4692 14.9093 35.3555 14.9093V14.908Z" fill="#1A2029"/>
+<path d="M79.4097 14.9232H85.1781V17.6237H77.5179V17.6124H76.7265V6.04407H79.4097V14.9232ZM96.7581 6.04971H93.8625L91.4631 10.1371L89.0631 6.04971H86.0763V17.6181H88.7601V10.5352L91.4637 15.1389L94.0749 10.6918V17.6181H96.7581V6.12141V6.04971ZM70.7661 13.2169H73.1445V13.9779C72.5841 14.581 71.7867 14.959 70.9023 14.959C70.0179 14.959 69.2121 14.5773 68.6511 13.9691C68.5089 13.815 68.3811 13.6458 68.2725 13.4647C67.9911 12.998 67.8297 12.4509 67.8297 11.8672C67.8297 11.2836 67.9911 10.7358 68.2725 10.2697C68.8113 9.37545 69.7881 8.77545 70.9023 8.77545C71.7087 8.77545 72.4425 9.08931 72.9909 9.60249L74.8881 7.69311C73.8537 6.69123 72.4479 6.07491 70.9023 6.07491C68.8161 6.07491 66.9855 7.19751 65.9763 8.87355C65.4495 9.74775 65.1465 10.7723 65.1465 11.8672C65.1465 12.9622 65.4495 13.9867 65.9763 14.8609C66.1983 15.2288 66.4587 15.5703 66.7539 15.8791C67.8027 16.9765 69.2751 17.6596 70.9029 17.6596C72.9885 17.6596 74.8191 16.537 75.8283 14.8609V10.5175H70.7661V13.2181V13.2169Z" fill="#1A2029"/>
+<path d="M49.4752 12.5477V17.6174H46.7954V13.1156C46.7954 12.2603 46.106 11.5666 45.2561 11.5666C44.4061 11.5666 43.7168 12.2597 43.7168 13.1156V17.6174H41.0332V6H43.7168V9.8811C44.3343 9.3333 45.1473 9.00186 46.0373 9.00942C47.9484 9.02514 49.4752 10.6244 49.4752 12.5477Z" fill="#1A2029"/>
+<mask id="mask0_8587_60467" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="2" y="1" width="23" height="22">
+<path d="M24.8 1.80005H2V22.2H24.8V1.80005Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_8587_60467)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4.86378 14.2544C4.86378 12.8981 5.67438 11.5371 7.25923 10.4634C8.83827 9.39369 11.0864 8.69373 13.6282 8.69373C16.17 8.69373 18.4182 9.39369 19.9972 10.4634C20.7966 11.005 21.399 11.6196 21.7998 12.27C22.2873 11.3803 22.4969 10.4351 22.3835 9.49257C22.3759 9.42933 22.3824 9.36771 22.4005 9.31065C22.0758 9.01857 21.7259 8.74629 21.3558 8.49561C19.3272 7.12131 16.5915 6.30969 13.6282 6.30969C10.665 6.30969 7.92918 7.12131 5.90058 8.49561C3.8778 9.86595 2.45703 11.8813 2.45703 14.2544C2.45703 16.6275 3.8778 18.6429 5.90058 20.0132C7.92918 21.3875 10.665 22.1991 13.6282 22.1991C16.5915 22.1991 19.3272 21.3875 21.3558 20.0132C23.3786 18.6429 24.7994 16.6275 24.7994 14.2544C24.7994 12.7455 24.225 11.3813 23.2868 10.2356C23.2377 11.2918 22.8621 12.3073 22.238 13.2301C22.3409 13.5687 22.3926 13.9117 22.3926 14.2544C22.3926 15.6107 21.582 16.9718 19.9972 18.0454C18.4182 19.1151 16.17 19.8151 13.6282 19.8151C11.0864 19.8151 8.83827 19.1151 7.25923 18.0454C5.67438 16.9718 4.86378 15.6107 4.86378 14.2544Z" fill="#3762FF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4.84445 11.4838C4.20239 13.2886 4.35368 14.9157 5.18868 16.0839C6.02368 17.2521 7.52281 17.9339 9.45459 17.9334C11.3826 17.933 13.6296 17.24 15.6939 15.7923C17.7581 14.3445 19.1643 12.4753 19.8052 10.674C20.4473 8.86925 20.2959 7.24211 19.461 6.07397C18.626 4.90576 17.1269 4.22394 15.1951 4.22436C13.267 4.22479 11.0201 4.91779 8.95575 6.36557C6.89152 7.81337 5.48529 9.68255 4.84445 11.4838ZM2.53559 10.6778C3.36374 8.35007 5.11254 6.08981 7.54117 4.3865C9.96981 2.68317 12.7029 1.8 15.1945 1.79944C17.6825 1.79889 20.0426 2.69125 21.4589 4.67268C22.8752 6.65411 22.941 9.15569 22.1141 11.48C21.2859 13.8077 19.5371 16.068 17.1085 17.7713C14.6798 19.4747 11.9468 20.3579 9.45513 20.3584C6.9672 20.3589 4.60706 19.4666 3.19075 17.4851C1.77445 15.5037 1.70868 13.0022 2.53559 10.6778Z" fill="#1041F3"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/chatglm.svg b/app/components/base/icons/assets/public/llm/chatglm.svg
new file mode 100644
index 0000000..cb04297
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/chatglm.svg
@@ -0,0 +1,9 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<mask id="mask0_8587_60212" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="1" y="2" width="23" height="21">
+<path d="M23.8 2H1V22.4H23.8V2Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_8587_60212)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.86378 14.4544C3.86378 13.0981 4.67438 11.737 6.25923 10.6634C7.83827 9.59364 10.0864 8.89368 12.6282 8.89368C15.17 8.89368 17.4182 9.59364 18.9972 10.6634C19.7966 11.2049 20.399 11.8196 20.7998 12.4699C21.2873 11.5802 21.4969 10.6351 21.3835 9.69252C21.3759 9.62928 21.3824 9.56766 21.4005 9.5106C21.0758 9.21852 20.7259 8.94624 20.3558 8.69556C18.3272 7.32126 15.5915 6.50964 12.6282 6.50964C9.66497 6.50964 6.92918 7.32126 4.90058 8.69556C2.8778 10.0659 1.45703 12.0812 1.45703 14.4544C1.45703 16.8275 2.8778 18.8428 4.90058 20.2132C6.92918 21.5875 9.66497 22.3991 12.6282 22.3991C15.5915 22.3991 18.3272 21.5875 20.3558 20.2132C22.3786 18.8428 23.7994 16.8275 23.7994 14.4544C23.7994 12.9455 23.225 11.5813 22.2868 10.4355C22.2377 11.4917 21.8621 12.5072 21.238 13.43C21.3409 13.7686 21.3926 14.1116 21.3926 14.4544C21.3926 15.8107 20.582 17.1717 18.9972 18.2453C17.4182 19.3151 15.17 20.015 12.6282 20.015C10.0864 20.015 7.83827 19.3151 6.25923 18.2453C4.67438 17.1717 3.86378 15.8107 3.86378 14.4544Z" fill="#3762FF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.84445 11.6838C3.20239 13.4885 3.35368 15.1156 4.18868 16.2838C5.02368 17.452 6.52281 18.1339 8.45459 18.1334C10.3826 18.133 12.6296 17.44 14.6939 15.9922C16.7581 14.5444 18.1643 12.6753 18.8052 10.8739C19.4473 9.0692 19.2959 7.44206 18.461 6.27392C17.626 5.10572 16.1269 4.42389 14.1951 4.42431C12.267 4.42475 10.0201 5.11774 7.95575 6.56552C5.89152 8.01332 4.48529 9.8825 3.84445 11.6838ZM1.53559 10.8778C2.36374 8.55002 4.11254 6.28976 6.54117 4.58645C8.96981 2.88312 11.7029 1.99995 14.1945 1.99939C16.6825 1.99884 19.0426 2.8912 20.4589 4.87263C21.8752 6.85406 21.941 9.35564 21.1141 11.6799C20.2859 14.0077 18.5371 16.2679 16.1085 17.9713C13.6798 19.6746 10.9468 20.5578 8.45513 20.5584C5.9672 20.5589 3.60706 19.6665 2.19075 17.6851C0.774446 15.7036 0.708677 13.2021 1.53559 10.8778Z" fill="#1041F3"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/cohere-text.svg b/app/components/base/icons/assets/public/llm/cohere-text.svg
new file mode 100644
index 0000000..9c17689
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/cohere-text.svg
@@ -0,0 +1,11 @@
+<svg width="120" height="24" viewBox="0 0 120 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M34.4917 21.9129C37.4378 21.9129 40.0162 20.4398 41.0355 17.4656C41.2334 16.8701 40.9496 16.4743 40.384 16.4743H39.2787C38.7689 16.4743 38.4292 16.7002 38.2013 17.1818C37.3239 18.9108 36.1047 19.5324 34.5757 19.5324C31.8553 19.5324 30.1844 17.6335 30.1844 14.4616C30.1844 11.2896 31.9133 9.39083 34.5177 9.39083C36.1046 9.39083 37.4079 10.0704 38.2293 11.6854C38.4852 12.1671 38.795 12.3929 39.3067 12.3929H40.412C40.9776 12.3929 41.2614 12.0251 41.0635 11.4855C39.8742 8.25556 37.2099 7.01035 34.4917 7.01035C30.3843 7.01035 27.3242 10.0424 27.3242 14.4616C27.3242 18.8808 30.2424 21.9129 34.4917 21.9129ZM108.627 13.1584C108.995 10.75 110.638 9.24892 112.876 9.24892C115.115 9.24892 116.786 10.7779 116.983 13.1584H108.627ZM112.99 21.9129C115.596 21.9129 118.203 20.6956 119.478 17.9474C119.79 17.2958 119.506 16.8421 118.94 16.8421H117.892C117.383 16.8421 117.071 17.0679 116.816 17.5216C115.966 19.0227 114.493 19.6463 112.992 19.6463C110.414 19.6463 108.743 17.8894 108.545 15.0292H118.943C119.508 15.0292 119.878 14.7174 119.878 14.1219C119.764 9.67465 116.876 7.01235 112.88 7.01235C108.885 7.01235 105.713 9.90251 105.713 14.4636C105.713 19.0247 108.801 21.9148 112.994 21.9148L112.99 21.9129ZM96.5025 14.8313H97.4378C98.0035 14.8313 98.3152 14.5196 98.4012 13.9239C98.9409 10.0964 101.182 9.5887 103.564 9.70264C104.074 9.72661 104.491 9.33487 104.491 8.82319V7.94575C104.491 7.38012 104.208 7.03833 103.642 7.01035C101.533 6.9304 99.6525 7.65393 98.5651 9.70264C98.5052 9.81455 98.3373 9.78458 98.3233 9.65866L98.1474 8.11365C98.0915 7.54801 97.7796 7.26418 97.212 7.26418H92.9347C92.435 7.26418 92.0272 7.66993 92.0272 8.17161V8.6533C92.0272 9.15298 92.433 9.56072 92.9347 9.56072H94.6916C95.1912 9.56072 95.599 9.96646 95.599 10.4681V13.9239C95.599 14.4236 96.0048 14.8313 96.5064 14.8313H96.5025ZM92.6788 21.631H101.545C102.111 21.631 102.453 21.2913 102.453 20.7236V20.2418C102.453 19.6762 102.113 19.3345 101.545 19.3345H99.2787C98.7131 19.3345 98.3712 18.9947 98.3712 18.4271V16.8681C98.3712 16.3024 98.0315 15.9606 97.4638 15.9606H96.5005C95.9348 15.9606 95.593 16.3004 95.593 16.8681V18.4271C95.593 18.9927 95.2532 19.3345 94.6856 19.3345H92.6749C92.1092 19.3345 91.7674 19.6743 91.7674 20.2418V20.7236C91.7674 21.2893 92.1073 21.631 92.6749 21.631H92.6788ZM78.9955 13.1604C79.3633 10.752 81.0062 9.25092 83.2449 9.25092C85.4834 9.25092 87.1544 10.7799 87.3522 13.1604H78.9955ZM83.3587 21.9148C85.9651 21.9148 88.5714 20.6977 89.8466 17.9493C90.1585 17.2978 89.8746 16.844 89.309 16.844H88.2617C87.7519 16.844 87.4402 17.0699 87.1844 17.5236C86.3349 19.0247 84.8618 19.6482 83.3607 19.6482C80.7824 19.6482 79.1115 17.8914 78.9136 15.0313H89.311C89.8766 15.0313 90.2464 14.7194 90.2464 14.1238C90.1324 9.67665 87.2443 7.01434 83.2488 7.01434C79.2533 7.01434 76.0814 9.9045 76.0814 14.4656C76.0814 19.0266 79.1694 21.9168 83.3628 21.9168L83.3587 21.9148ZM50.5835 21.9148C54.8329 21.9148 57.8649 18.7708 57.8649 14.4636C57.8649 10.1563 54.8329 7.01235 50.5835 7.01235C46.3342 7.01235 43.3022 10.2143 43.3022 14.4636C43.3022 15.455 43.472 16.5602 43.9816 17.7775C44.2375 18.3731 44.7192 18.4571 45.2289 18.0892L46.0504 17.4936C46.4761 17.1818 46.588 16.8141 46.4461 16.2765C46.2202 15.5689 46.1623 14.9453 46.1623 14.4076C46.1623 11.4335 47.9472 9.39283 50.5815 9.39283C53.2159 9.39283 55.0007 11.4035 55.0007 14.4636C55.0007 17.5236 53.2439 19.5344 50.6375 19.5344C49.7301 19.5344 48.8806 19.3645 47.8612 18.5989C47.4355 18.2592 47.0397 18.2032 46.586 18.5429L45.9624 18.9967C45.4527 19.3645 45.3968 19.8741 45.8764 20.2718C47.3496 21.4611 49.0485 21.9148 50.5795 21.9148H50.5835ZM61.4606 21.631H62.3961C62.8957 21.631 63.3035 21.2252 63.3035 20.7236V13.9539C63.3035 11.0937 64.8324 9.39283 67.213 9.39283C69.3656 9.39283 70.6128 10.8099 70.6128 13.4163V20.7255C70.6128 21.2252 71.0186 21.633 71.5203 21.633H72.4836C72.9833 21.633 73.391 21.2272 73.391 20.7255V12.9625C73.391 9.13899 71.4363 7.01434 68.1224 7.01434C65.8659 7.01434 64.5327 7.93776 63.5373 9.22294C63.4613 9.32088 63.3075 9.26691 63.3075 9.14499V2.99092C63.3014 2.48924 62.8957 2.0835 62.3961 2.0835H61.4606C60.9609 2.0835 60.5532 2.48924 60.5532 2.99092V20.7236C60.5532 21.2232 60.959 21.631 61.4606 21.631Z" fill="#39594D"/>
+<mask id="mask0_13223_52628" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="1" y="2" width="20" height="20">
+<path d="M20.8354 2.08319H1.00195V21.9165H20.8354V2.08319Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_13223_52628)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.42768 13.8921C7.96151 13.8921 9.02342 13.8628 10.4912 13.2585C12.2017 12.5542 15.6047 11.2758 18.0597 9.96274C19.7765 9.04432 20.5291 7.82964 20.5291 6.19387C20.5291 3.92362 18.6887 2.08319 16.4185 2.08319H6.90643C3.64547 2.08319 1.00195 4.72669 1.00195 7.98763C1.00195 11.2486 3.47706 13.8921 7.42768 13.8921Z" fill="#39594D"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.03711 17.958C9.03711 16.3596 9.99942 14.9184 11.4758 14.3057L14.4713 13.0625C17.5013 11.805 20.8364 14.0316 20.8364 17.3123C20.8364 19.8539 18.7755 21.9141 16.2338 21.9134L12.9906 21.9126C10.807 21.912 9.03711 20.1417 9.03711 17.958Z" fill="#D18EE2"/>
+<path d="M4.40571 14.6705C2.5259 14.6705 1.00195 16.1943 1.00195 18.0741V18.515C1.00195 20.3947 2.52584 21.9186 4.40565 21.9186C6.28547 21.9186 7.80941 20.3947 7.80941 18.515V18.0741C7.80941 16.1943 6.28552 14.6705 4.40571 14.6705Z" fill="#FF7759"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/cohere.svg b/app/components/base/icons/assets/public/llm/cohere.svg
new file mode 100644
index 0000000..28fe96d
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/cohere.svg
@@ -0,0 +1,16 @@
+<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Clip path group">
+<mask id="mask0_13224_9519" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="22" height="22">
+<g id="clip0_2207_90691">
+<path id="Vector" d="M21.5 0.5H0.5V21.5H21.5V0.5Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask0_13224_9519)">
+<g id="Group">
+<path id="Vector_2" fill-rule="evenodd" clip-rule="evenodd" d="M7.30367 13.0035C7.8689 13.0035 8.99327 12.9725 10.5474 12.3326C12.3585 11.587 15.9617 10.2334 18.561 8.84305C20.3788 7.8706 21.1757 6.58448 21.1757 4.85248C21.1757 2.44869 19.2271 0.5 16.8233 0.5H6.75176C3.299 0.5 0.5 3.299 0.5 6.75176C0.5 10.2045 3.12069 13.0035 7.30367 13.0035Z" fill="#39594D"/>
+<path id="Vector_3" fill-rule="evenodd" clip-rule="evenodd" d="M9.00732 17.3086C9.00732 15.6162 10.0262 14.0902 11.5894 13.4414L14.7612 12.1251C17.9694 10.7936 21.5006 13.1513 21.5006 16.6249C21.5006 19.316 19.3185 21.4974 16.6273 21.4967L13.1933 21.4958C10.8813 21.4952 9.00732 19.6207 9.00732 17.3086Z" fill="#D18EE2"/>
+<path id="Vector_4" d="M4.10396 13.8277C2.11358 13.8277 0.5 15.4411 0.5 17.4315V17.8984C0.5 19.8887 2.11352 21.5022 4.1039 21.5022C6.09428 21.5022 7.70785 19.8887 7.70785 17.8984V17.4315C7.70785 15.4411 6.09434 13.8277 4.10396 13.8277Z" fill="#FF7759"/>
+</g>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/gpt-3.svg b/app/components/base/icons/assets/public/llm/gpt-3.svg
new file mode 100644
index 0000000..514215f
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/gpt-3.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="#19C37D"/>
+<path d="M19.6451 11.6028C19.8209 11.995 19.9325 12.4142 19.9781 12.8419C20.0221 13.2696 20.0001 13.7024 19.9088 14.1234C19.8192 14.5443 19.6637 14.9484 19.4473 15.3203C19.3053 15.5688 19.1379 15.8021 18.9452 16.0168C18.7542 16.2298 18.5412 16.4225 18.3096 16.5916C18.0763 16.7606 17.8278 16.9027 17.564 17.0193C17.302 17.1343 17.0281 17.2222 16.7475 17.2796C16.6156 17.6888 16.4195 18.0759 16.1659 18.4242C15.914 18.7724 15.6081 19.0784 15.2598 19.3303C14.9115 19.5839 14.5261 19.78 14.117 19.9118C13.7079 20.0454 13.2802 20.1113 12.8491 20.1113C12.5634 20.113 12.276 20.0826 11.9953 20.0251C11.7164 19.9659 11.4425 19.8763 11.1805 19.7597C10.9184 19.643 10.6699 19.4977 10.4383 19.3286C10.2084 19.1595 9.99541 18.9651 9.80606 18.7504C9.38342 18.8417 8.95064 18.8637 8.52293 18.8197C8.09522 18.7741 7.67596 18.6625 7.28206 18.4867C6.88985 18.3126 6.52638 18.0759 6.20687 17.7868C5.88735 17.4977 5.61517 17.1596 5.40047 16.7877C5.25677 16.5392 5.13843 16.2771 5.04883 16.005C4.95924 15.7328 4.90007 15.4522 4.86964 15.1665C4.83921 14.8824 4.8409 14.595 4.87133 14.3093C4.90176 14.0253 4.96431 13.7447 5.05391 13.4725C4.76651 13.153 4.52983 12.7895 4.35402 12.3973C4.17989 12.0034 4.06662 11.5859 4.02267 11.1581C3.97702 10.7304 4.00069 10.2976 4.09029 9.8767C4.17989 9.45575 4.33542 9.05171 4.55181 8.67978C4.69382 8.43127 4.86118 8.19628 5.05222 7.98327C5.24325 7.77026 5.45795 7.57754 5.68956 7.40848C5.92116 7.23943 6.17136 7.09573 6.4334 6.98077C6.69713 6.86412 6.971 6.77791 7.25163 6.72043C7.38349 6.30962 7.5796 5.92417 7.83149 5.57592C8.08508 5.22766 8.39107 4.92167 8.73932 4.66809C9.08758 4.4162 9.47302 4.22009 9.88214 4.08654C10.2913 3.95467 10.719 3.88705 11.1501 3.88874C11.4358 3.88705 11.7232 3.91579 12.0038 3.97496C12.2844 4.03413 12.5583 4.12204 12.8203 4.23869C13.0824 4.35703 13.3309 4.50072 13.5625 4.66978C13.7941 4.84053 14.0071 5.03325 14.1964 5.24795C14.6174 5.15835 15.0502 5.13637 15.4779 5.18033C15.9056 5.22428 16.3232 5.33755 16.7171 5.51168C17.1093 5.6875 17.4727 5.92248 17.7923 6.21157C18.1118 6.49896 18.384 6.83538 18.5987 7.209C18.7423 7.45582 18.8607 7.71786 18.9503 7.99173C19.0399 8.26391 19.1007 8.54454 19.1295 8.83024C19.1599 9.11595 19.1599 9.40334 19.1278 9.68905C19.0974 9.97475 19.0348 10.2554 18.9452 10.5276C19.2343 10.8471 19.4693 11.2089 19.6451 11.6028ZM14.0122 18.8197C14.3807 18.6676 14.7154 18.4428 14.9978 18.1604C15.2801 17.8781 15.5049 17.5434 15.6571 17.1731C15.8092 16.8046 15.8887 16.409 15.8887 16.01V12.2401C15.8876 12.2367 15.8864 12.2328 15.8853 12.2283C15.8842 12.2249 15.8825 12.2215 15.8802 12.2181C15.878 12.2147 15.8752 12.2119 15.8718 12.2097C15.8684 12.2063 15.865 12.204 15.8616 12.2029L14.4974 11.4151V15.9695C14.4974 16.0151 14.4906 16.0624 14.4788 16.1064C14.4669 16.152 14.45 16.1943 14.4264 16.2349C14.4027 16.2755 14.3756 16.3126 14.3418 16.3448C14.309 16.3775 14.272 16.4059 14.2319 16.4293L11.0013 18.294C10.9742 18.3109 10.9286 18.3346 10.9049 18.3481C11.0385 18.4613 11.1839 18.5611 11.336 18.649C11.4899 18.7369 11.6488 18.8113 11.8144 18.8722C11.9801 18.9313 12.1509 18.977 12.3233 19.0074C12.4974 19.0378 12.6732 19.053 12.8491 19.053C13.248 19.053 13.6436 18.9736 14.0122 18.8197ZM6.31844 16.2602C6.51962 16.6068 6.78504 16.9077 7.10117 17.1512C7.419 17.3946 7.77908 17.5721 8.16453 17.6752C8.54998 17.7784 8.95233 17.8054 9.34792 17.753C9.74351 17.7006 10.1239 17.5721 10.4705 17.3726L13.7366 15.4877L13.7451 15.4792C13.7473 15.477 13.749 15.4736 13.7501 15.4691C13.7524 15.4657 13.7541 15.4623 13.7552 15.4589V13.8698L9.81283 16.1504C9.77225 16.174 9.72999 16.1909 9.68603 16.2045C9.64039 16.2163 9.59474 16.2214 9.54741 16.2214C9.50176 16.2214 9.45612 16.2163 9.41047 16.2045C9.36652 16.1909 9.32256 16.174 9.28199 16.1504L6.05133 14.284C6.0226 14.2671 5.98033 14.2417 5.95666 14.2265C5.92623 14.4006 5.91102 14.5764 5.91102 14.7523C5.91102 14.9281 5.92792 15.1039 5.95835 15.278C5.98878 15.4505 6.03612 15.6212 6.09529 15.7869C6.15615 15.9526 6.23053 16.1115 6.31844 16.2636V16.2602ZM5.46978 9.21062C5.2703 9.55718 5.14182 9.93925 5.08941 10.3348C5.037 10.7304 5.06405 11.1311 5.16717 11.5182C5.2703 11.9037 5.44781 12.2638 5.69125 12.5816C5.93469 12.8977 6.2373 13.1631 6.58217 13.3626L9.84664 15.2493C9.85002 15.2504 9.85396 15.2515 9.85847 15.2527H9.8703C9.87481 15.2527 9.87876 15.2515 9.88214 15.2493C9.88552 15.2482 9.8889 15.2465 9.89228 15.2442L11.2616 14.453L7.31925 12.1775C7.28037 12.1539 7.24318 12.1251 7.20937 12.093C7.17661 12.0602 7.1482 12.0232 7.12484 11.9831C7.10286 11.9426 7.08427 11.9003 7.07243 11.8547C7.0606 11.8107 7.05384 11.7651 7.05553 11.7177V7.87846C6.88985 7.93932 6.72925 8.0137 6.5771 8.10161C6.42495 8.19121 6.28125 8.29265 6.14601 8.40591C6.01245 8.51918 5.88735 8.64428 5.77408 8.77953C5.66082 8.91308 5.56107 9.05847 5.47316 9.21062H5.46978ZM16.6832 11.8208C16.7238 11.8445 16.761 11.8716 16.7948 11.9054C16.8269 11.9375 16.8557 11.9747 16.8794 12.0153C16.9013 12.0558 16.9199 12.0998 16.9318 12.1437C16.9419 12.1894 16.9487 12.235 16.947 12.2824V16.1216C17.4896 15.9221 17.963 15.5722 18.3129 15.1124C18.6646 14.6525 18.8759 14.1031 18.9249 13.5283C18.974 12.9535 18.859 12.3753 18.5919 11.8631C18.3248 11.3509 17.9174 10.9248 17.417 10.6374L14.1525 8.75079C14.1491 8.74966 14.1452 8.74853 14.1407 8.74741H14.1288C14.1254 8.74853 14.1215 8.74966 14.117 8.75079C14.1136 8.75191 14.1102 8.7536 14.1068 8.75586L12.7443 9.54366L16.6866 11.8208H16.6832ZM18.0441 9.77526H18.0425V9.77695L18.0441 9.77526ZM18.0425 9.77357C18.1405 9.20555 18.0746 8.62061 17.8514 8.08809C17.63 7.55556 17.2597 7.09742 16.7864 6.76607C16.313 6.43641 15.7551 6.24707 15.1787 6.22171C14.6005 6.19804 14.0291 6.33836 13.5287 6.62575L10.2642 8.51073C10.2608 8.51298 10.258 8.5158 10.2558 8.51918L10.249 8.52932C10.2479 8.5327 10.2467 8.53665 10.2456 8.54116C10.2445 8.54454 10.2439 8.54848 10.2439 8.55299V10.1286L14.1863 7.85141C14.2269 7.82774 14.2708 7.81084 14.3148 7.79731C14.3604 7.78548 14.4061 7.78041 14.4517 7.78041C14.499 7.78041 14.5447 7.78548 14.5903 7.79731C14.6343 7.81084 14.6766 7.82774 14.7171 7.85141L17.9478 9.71778C17.9765 9.73469 18.0188 9.75836 18.0425 9.77357ZM9.50007 8.02892C9.50007 7.98327 9.50683 7.93763 9.51867 7.89198C9.5305 7.84803 9.54741 7.80407 9.57108 7.7635C9.59474 7.72462 9.62179 7.68743 9.6556 7.65361C9.68772 7.62149 9.72492 7.59275 9.76549 7.57078L12.9961 5.70609C13.0266 5.6875 13.0688 5.66383 13.0925 5.65199C12.6496 5.28176 12.1086 5.04508 11.5355 4.97239C10.9624 4.89801 10.3809 4.9893 9.85847 5.23443C9.3344 5.47956 8.89147 5.87008 8.5821 6.35696C8.27273 6.84553 8.10874 7.41017 8.10874 7.98834V11.7583C8.10987 11.7628 8.111 11.7667 8.11212 11.7701C8.11325 11.7735 8.11494 11.7769 8.1172 11.7803C8.11945 11.7836 8.12227 11.787 8.12565 11.7904C8.1279 11.7927 8.13128 11.7949 8.13579 11.7972L9.50007 12.585V8.02892ZM10.2405 13.011L11.997 14.0253L13.7535 13.011V10.984L11.9987 9.96968L10.2422 10.984L10.2405 13.011Z" fill="white"/>
+<rect x="0.5" y="0.5" width="23" height="23" rx="5.5" stroke="black" stroke-opacity="0.05"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/gpt-4.svg b/app/components/base/icons/assets/public/llm/gpt-4.svg
new file mode 100644
index 0000000..63abb1e
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/gpt-4.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="#AB68FF"/>
+<path d="M19.6451 11.6028C19.8209 11.995 19.9325 12.4142 19.9781 12.8419C20.0221 13.2696 20.0001 13.7024 19.9088 14.1234C19.8192 14.5443 19.6637 14.9484 19.4473 15.3203C19.3053 15.5688 19.1379 15.8021 18.9452 16.0168C18.7542 16.2298 18.5412 16.4225 18.3096 16.5916C18.0763 16.7606 17.8278 16.9027 17.564 17.0193C17.302 17.1343 17.0281 17.2222 16.7475 17.2796C16.6156 17.6888 16.4195 18.0759 16.1659 18.4242C15.914 18.7724 15.6081 19.0784 15.2598 19.3303C14.9115 19.5839 14.5261 19.78 14.117 19.9118C13.7079 20.0454 13.2802 20.1113 12.8491 20.1113C12.5634 20.113 12.276 20.0826 11.9953 20.0251C11.7164 19.9659 11.4425 19.8763 11.1805 19.7597C10.9184 19.643 10.6699 19.4977 10.4383 19.3286C10.2084 19.1595 9.99541 18.9651 9.80606 18.7504C9.38342 18.8417 8.95064 18.8637 8.52293 18.8197C8.09522 18.7741 7.67596 18.6625 7.28206 18.4867C6.88985 18.3126 6.52638 18.0759 6.20687 17.7868C5.88735 17.4977 5.61517 17.1596 5.40047 16.7877C5.25677 16.5392 5.13843 16.2771 5.04883 16.005C4.95924 15.7328 4.90007 15.4522 4.86964 15.1665C4.83921 14.8824 4.8409 14.595 4.87133 14.3093C4.90176 14.0253 4.96431 13.7447 5.05391 13.4725C4.76651 13.153 4.52983 12.7895 4.35402 12.3973C4.17989 12.0034 4.06662 11.5859 4.02267 11.1581C3.97702 10.7304 4.00069 10.2976 4.09029 9.8767C4.17989 9.45575 4.33542 9.05171 4.55181 8.67978C4.69382 8.43127 4.86118 8.19628 5.05222 7.98327C5.24325 7.77026 5.45795 7.57754 5.68956 7.40848C5.92116 7.23943 6.17136 7.09573 6.4334 6.98077C6.69713 6.86412 6.971 6.77791 7.25163 6.72043C7.38349 6.30962 7.5796 5.92417 7.83149 5.57592C8.08508 5.22766 8.39107 4.92167 8.73932 4.66809C9.08758 4.4162 9.47302 4.22009 9.88214 4.08654C10.2913 3.95467 10.719 3.88705 11.1501 3.88874C11.4358 3.88705 11.7232 3.91579 12.0038 3.97496C12.2844 4.03413 12.5583 4.12204 12.8203 4.23869C13.0824 4.35703 13.3309 4.50072 13.5625 4.66978C13.7941 4.84053 14.0071 5.03325 14.1964 5.24795C14.6174 5.15835 15.0502 5.13637 15.4779 5.18033C15.9056 5.22428 16.3232 5.33755 16.7171 5.51168C17.1093 5.6875 17.4727 5.92248 17.7923 6.21157C18.1118 6.49896 18.384 6.83538 18.5987 7.209C18.7423 7.45582 18.8607 7.71786 18.9503 7.99173C19.0399 8.26391 19.1007 8.54454 19.1295 8.83024C19.1599 9.11595 19.1599 9.40334 19.1278 9.68905C19.0974 9.97475 19.0348 10.2554 18.9452 10.5276C19.2343 10.8471 19.4693 11.2089 19.6451 11.6028ZM14.0122 18.8197C14.3807 18.6676 14.7154 18.4428 14.9978 18.1604C15.2801 17.8781 15.5049 17.5434 15.6571 17.1731C15.8092 16.8046 15.8887 16.409 15.8887 16.01V12.2401C15.8876 12.2367 15.8864 12.2328 15.8853 12.2283C15.8842 12.2249 15.8825 12.2215 15.8802 12.2181C15.878 12.2147 15.8752 12.2119 15.8718 12.2097C15.8684 12.2063 15.865 12.204 15.8616 12.2029L14.4974 11.4151V15.9695C14.4974 16.0151 14.4906 16.0624 14.4788 16.1064C14.4669 16.152 14.45 16.1943 14.4264 16.2349C14.4027 16.2755 14.3756 16.3126 14.3418 16.3448C14.309 16.3775 14.272 16.4059 14.2319 16.4293L11.0013 18.294C10.9742 18.3109 10.9286 18.3346 10.9049 18.3481C11.0385 18.4613 11.1839 18.5611 11.336 18.649C11.4899 18.7369 11.6488 18.8113 11.8144 18.8722C11.9801 18.9313 12.1509 18.977 12.3233 19.0074C12.4974 19.0378 12.6732 19.053 12.8491 19.053C13.248 19.053 13.6436 18.9736 14.0122 18.8197ZM6.31844 16.2602C6.51962 16.6068 6.78504 16.9077 7.10117 17.1512C7.419 17.3946 7.77908 17.5721 8.16453 17.6752C8.54998 17.7784 8.95233 17.8054 9.34792 17.753C9.74351 17.7006 10.1239 17.5721 10.4705 17.3726L13.7366 15.4877L13.7451 15.4792C13.7473 15.477 13.749 15.4736 13.7501 15.4691C13.7524 15.4657 13.7541 15.4623 13.7552 15.4589V13.8698L9.81283 16.1504C9.77225 16.174 9.72999 16.1909 9.68603 16.2045C9.64039 16.2163 9.59474 16.2214 9.54741 16.2214C9.50176 16.2214 9.45612 16.2163 9.41047 16.2045C9.36652 16.1909 9.32256 16.174 9.28199 16.1504L6.05133 14.284C6.0226 14.2671 5.98033 14.2417 5.95666 14.2265C5.92623 14.4006 5.91102 14.5764 5.91102 14.7523C5.91102 14.9281 5.92792 15.1039 5.95835 15.278C5.98878 15.4505 6.03612 15.6212 6.09529 15.7869C6.15615 15.9526 6.23053 16.1115 6.31844 16.2636V16.2602ZM5.46978 9.21062C5.2703 9.55718 5.14182 9.93925 5.08941 10.3348C5.037 10.7304 5.06405 11.1311 5.16717 11.5182C5.2703 11.9037 5.44781 12.2638 5.69125 12.5816C5.93469 12.8977 6.2373 13.1631 6.58217 13.3626L9.84664 15.2493C9.85002 15.2504 9.85396 15.2515 9.85847 15.2527H9.8703C9.87481 15.2527 9.87876 15.2515 9.88214 15.2493C9.88552 15.2482 9.8889 15.2465 9.89228 15.2442L11.2616 14.453L7.31925 12.1775C7.28037 12.1539 7.24318 12.1251 7.20937 12.093C7.17661 12.0602 7.1482 12.0232 7.12484 11.9831C7.10286 11.9426 7.08427 11.9003 7.07243 11.8547C7.0606 11.8107 7.05384 11.7651 7.05553 11.7177V7.87846C6.88985 7.93932 6.72925 8.0137 6.5771 8.10161C6.42495 8.19121 6.28125 8.29265 6.14601 8.40591C6.01245 8.51918 5.88735 8.64428 5.77408 8.77953C5.66082 8.91308 5.56107 9.05847 5.47316 9.21062H5.46978ZM16.6832 11.8208C16.7238 11.8445 16.761 11.8716 16.7948 11.9054C16.8269 11.9375 16.8557 11.9747 16.8794 12.0153C16.9013 12.0558 16.9199 12.0998 16.9318 12.1437C16.9419 12.1894 16.9487 12.235 16.947 12.2824V16.1216C17.4896 15.9221 17.963 15.5722 18.3129 15.1124C18.6646 14.6525 18.8759 14.1031 18.9249 13.5283C18.974 12.9535 18.859 12.3753 18.5919 11.8631C18.3248 11.3509 17.9174 10.9248 17.417 10.6374L14.1525 8.75079C14.1491 8.74966 14.1452 8.74853 14.1407 8.74741H14.1288C14.1254 8.74853 14.1215 8.74966 14.117 8.75079C14.1136 8.75191 14.1102 8.7536 14.1068 8.75586L12.7443 9.54366L16.6866 11.8208H16.6832ZM18.0441 9.77526H18.0425V9.77695L18.0441 9.77526ZM18.0425 9.77357C18.1405 9.20555 18.0746 8.62061 17.8514 8.08809C17.63 7.55556 17.2597 7.09742 16.7864 6.76607C16.313 6.43641 15.7551 6.24707 15.1787 6.22171C14.6005 6.19804 14.0291 6.33836 13.5287 6.62575L10.2642 8.51073C10.2608 8.51298 10.258 8.5158 10.2558 8.51918L10.249 8.52932C10.2479 8.5327 10.2467 8.53665 10.2456 8.54116C10.2445 8.54454 10.2439 8.54848 10.2439 8.55299V10.1286L14.1863 7.85141C14.2269 7.82774 14.2708 7.81084 14.3148 7.79731C14.3604 7.78548 14.4061 7.78041 14.4517 7.78041C14.499 7.78041 14.5447 7.78548 14.5903 7.79731C14.6343 7.81084 14.6766 7.82774 14.7171 7.85141L17.9478 9.71778C17.9765 9.73469 18.0188 9.75836 18.0425 9.77357ZM9.50007 8.02892C9.50007 7.98327 9.50683 7.93763 9.51867 7.89198C9.5305 7.84803 9.54741 7.80407 9.57108 7.7635C9.59474 7.72462 9.62179 7.68743 9.6556 7.65361C9.68772 7.62149 9.72492 7.59275 9.76549 7.57078L12.9961 5.70609C13.0266 5.6875 13.0688 5.66383 13.0925 5.65199C12.6496 5.28176 12.1086 5.04508 11.5355 4.97239C10.9624 4.89801 10.3809 4.9893 9.85847 5.23443C9.3344 5.47956 8.89147 5.87008 8.5821 6.35696C8.27273 6.84553 8.10874 7.41017 8.10874 7.98834V11.7583C8.10987 11.7628 8.111 11.7667 8.11212 11.7701C8.11325 11.7735 8.11494 11.7769 8.1172 11.7803C8.11945 11.7836 8.12227 11.787 8.12565 11.7904C8.1279 11.7927 8.13128 11.7949 8.13579 11.7972L9.50007 12.585V8.02892ZM10.2405 13.011L11.997 14.0253L13.7535 13.011V10.984L11.9987 9.96968L10.2422 10.984L10.2405 13.011Z" fill="white"/>
+<rect x="0.5" y="0.5" width="23" height="23" rx="5.5" stroke="black" stroke-opacity="0.05"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/huggingface-text-hub.svg b/app/components/base/icons/assets/public/llm/huggingface-text-hub.svg
new file mode 100644
index 0000000..a6b85be
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/huggingface-text-hub.svg
@@ -0,0 +1,45 @@
+<svg width="151" height="24" viewBox="0 0 151 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_8587_60397)">
+<g clip-path="url(#clip1_8587_60397)">
+<path d="M12.9267 20.2062C17.7747 20.2062 21.7049 16.2761 21.7049 11.428C21.7049 6.57993 17.7747 2.64978 12.9267 2.64978C8.07858 2.64978 4.14844 6.57993 4.14844 11.428C4.14844 16.2761 8.07858 20.2062 12.9267 20.2062Z" fill="#FFD21E"/>
+<path d="M21.7075 11.4326C21.7075 6.58451 17.7774 2.65436 12.9293 2.65436C8.08123 2.65436 4.15108 6.58451 4.15108 11.4326C4.15108 16.2807 8.08123 20.2108 12.9293 20.2108C17.7774 20.2108 21.7075 16.2807 21.7075 11.4326ZM3.14062 11.4326C3.14062 6.02647 7.52316 1.64392 12.9293 1.64392C18.3354 1.64392 22.718 6.02647 22.718 11.4326C22.718 16.8387 18.3354 21.2213 12.9293 21.2213C7.52316 21.2213 3.14062 16.8387 3.14062 11.4326Z" fill="#FF9D0B"/>
+<path d="M15.7803 9.03703C16.1022 9.1507 16.2303 9.81254 16.5555 9.6396C17.1714 9.31212 17.4052 8.54734 17.0777 7.93142C16.7503 7.31553 15.9855 7.08172 15.3696 7.4092C14.7536 7.73669 14.5198 8.50147 14.8473 9.11738C15.0019 9.40809 15.4925 8.9354 15.7803 9.03703Z" fill="#3A3B45"/>
+<path d="M9.83227 9.03703C9.51034 9.1507 9.38227 9.81254 9.05706 9.6396C8.44114 9.31212 8.20733 8.54734 8.53481 7.93142C8.8623 7.31553 9.62708 7.08172 10.243 7.4092C10.8589 7.73669 11.0927 8.50147 10.7652 9.11738C10.6107 9.40809 10.12 8.9354 9.83227 9.03703Z" fill="#3A3B45"/>
+<path d="M12.866 15.1044C15.3487 15.1044 16.1499 12.8908 16.1499 11.7541C16.1499 11.1633 15.7528 11.3492 15.1167 11.6641C14.5289 11.9551 13.7371 12.3563 12.866 12.3563C11.0523 12.3563 9.58203 10.6173 9.58203 11.7541C9.58203 12.8908 10.3832 15.1044 12.866 15.1044Z" fill="#3A3B45"/>
+<mask id="mask0_8587_60397" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="9" y="11" width="8" height="5">
+<path d="M12.8543 15.1005C15.337 15.1005 16.1382 12.8869 16.1382 11.7502C16.1382 11.1594 15.7411 11.3453 15.105 11.6602C14.5172 11.9512 13.7253 12.3524 12.8543 12.3524C11.0406 12.3524 9.57031 10.6134 9.57031 11.7502C9.57031 12.8869 10.3715 15.1005 12.8543 15.1005Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_8587_60397)">
+<path d="M12.9175 17.6824C14.1274 17.6824 15.1083 16.7016 15.1083 15.4916C15.1083 14.5491 14.5133 13.7457 13.6783 13.4364C13.6476 13.425 13.6166 13.4143 13.5852 13.4043C13.3747 13.337 13.1503 14.0606 12.9175 14.0606C12.6999 14.0606 12.4897 13.3324 12.2913 13.3915C11.3864 13.6609 10.7266 14.4991 10.7266 15.4916C10.7266 16.7016 11.7075 17.6824 12.9175 17.6824Z" fill="#F94040"/>
+</g>
+<path d="M18.8679 10.2273C19.3213 10.2273 19.6888 9.85972 19.6888 9.40631C19.6888 8.9529 19.3213 8.58533 18.8679 8.58533C18.4144 8.58533 18.0469 8.9529 18.0469 9.40631C18.0469 9.85972 18.4144 10.2273 18.8679 10.2273Z" fill="#FF9D0B"/>
+<path d="M7.11786 10.2273C7.57127 10.2273 7.93885 9.85972 7.93885 9.40631C7.93885 8.9529 7.57127 8.58533 7.11786 8.58533C6.66442 8.58533 6.29688 8.9529 6.29688 9.40631C6.29688 9.85972 6.66442 10.2273 7.11786 10.2273Z" fill="#FF9D0B"/>
+<path d="M5.4272 13.0092C5.01822 13.0092 4.6527 13.1771 4.39781 13.4818C4.24018 13.6705 4.07548 13.9746 4.06209 14.4301C3.89057 14.3808 3.72561 14.3533 3.57152 14.3533C3.17997 14.3533 2.82632 14.5033 2.57623 14.7759C2.25491 15.1258 2.11219 15.5557 2.17433 15.9859C2.20389 16.1908 2.27234 16.3744 2.37465 16.5444C2.15892 16.719 2.00003 16.962 1.92323 17.2543C1.86311 17.4834 1.80148 17.9606 2.1233 18.4522C2.10284 18.4842 2.08364 18.5176 2.06571 18.5517C1.87221 18.919 1.85983 19.334 2.03059 19.7205C2.28952 20.3063 2.93292 20.7678 4.18233 21.2632C4.95962 21.5714 5.67072 21.7684 5.67703 21.7702C6.70465 22.0367 7.63401 22.1721 8.43858 22.1721C9.91736 22.1721 10.9761 21.7192 11.5854 20.8259C12.566 19.3876 12.4258 18.072 11.1569 16.8039C10.4547 16.1021 9.98784 15.0674 9.89058 14.8403C9.69456 14.1679 9.1762 13.4204 8.31454 13.4204C8.24205 13.4204 8.16854 13.4262 8.09629 13.4376C7.71889 13.4969 7.38898 13.7142 7.15329 14.0411C6.89891 13.7248 6.65186 13.4732 6.4283 13.3312C6.09132 13.1175 5.75459 13.0092 5.4272 13.0092ZM5.4272 14.0196C5.55603 14.0196 5.71341 14.0744 5.88695 14.1846C6.42577 14.5263 7.46552 16.3136 7.8462 17.0087C7.97377 17.2417 8.19178 17.3402 8.38805 17.3402C8.77758 17.3402 9.08172 16.9529 8.42367 16.4608C7.4342 15.7204 7.78128 14.5102 8.25366 14.4356C8.27438 14.4324 8.29484 14.4308 8.31454 14.4308C8.74398 14.4308 8.93344 15.171 8.93344 15.171C8.93344 15.171 9.48868 16.5654 10.4425 17.5185C11.3964 18.4719 11.4457 19.237 10.7505 20.2566C10.2763 20.9517 9.36869 21.1617 8.43858 21.1617C7.47386 21.1617 6.48488 20.9358 5.93066 20.7921C5.90337 20.785 2.53279 19.8329 2.9597 19.0226C3.03144 18.8864 3.14966 18.8318 3.29845 18.8318C3.89966 18.8318 4.99322 19.7266 5.46332 19.7266C5.56841 19.7266 5.64243 19.6819 5.67274 19.5727C5.87306 18.8541 2.62701 18.5519 2.90059 17.5109C2.94884 17.3268 3.07969 17.252 3.26359 17.2523C4.05805 17.2523 5.84047 18.6495 6.21408 18.6495C6.24263 18.6495 6.26309 18.6411 6.27421 18.6234C6.46139 18.3213 6.35883 18.1104 5.03944 17.3119C3.72006 16.5131 2.79398 16.0327 3.32068 15.4592C3.38131 15.393 3.46719 15.3637 3.57152 15.3637C4.37255 15.364 6.26511 17.0863 6.26511 17.0863C6.26511 17.0863 6.77589 17.6175 7.08483 17.6175C7.15582 17.6175 7.21619 17.5895 7.25711 17.5203C7.47613 17.151 5.22284 15.4433 5.09578 14.7388C5.00964 14.2613 5.15615 14.0196 5.4272 14.0196Z" fill="#FF9D0B"/>
+<path d="M10.7569 20.2539C11.4521 19.2344 11.4028 18.4692 10.4489 17.5159C9.49509 16.5628 8.93985 15.1684 8.93985 15.1684C8.93985 15.1684 8.73245 14.3585 8.26007 14.433C7.78769 14.5075 7.44085 15.7178 8.43033 16.4582C9.41981 17.1984 8.2333 17.7013 7.85261 17.0061C7.47193 16.3109 6.43243 14.5237 5.89336 14.1819C5.35454 13.8402 4.97512 14.0316 5.10218 14.7362C5.22925 15.4407 7.48279 17.1483 7.26352 17.5179C7.04426 17.8872 6.27152 17.0837 6.27152 17.0837C6.27152 17.0837 3.85353 14.8832 3.32707 15.4566C2.80063 16.03 3.72646 16.5105 5.04585 17.3093C6.36549 18.1078 6.4678 18.3187 6.28061 18.6208C6.09317 18.9229 3.18056 16.4673 2.90698 17.5083C2.63365 18.5493 5.87947 18.8514 5.67915 19.5701C5.47883 20.2891 3.39275 18.2098 2.96609 19.0199C2.53918 19.8303 5.90978 20.7824 5.93706 20.7895C7.02582 21.0719 9.79089 21.6703 10.7569 20.2539Z" fill="#FFD21E"/>
+<path d="M20.5549 13.0092C20.9639 13.0092 21.3294 13.1771 21.5843 13.4818C21.7419 13.6705 21.9066 13.9746 21.92 14.4301C22.0915 14.3808 22.2565 14.3533 22.4106 14.3533C22.8021 14.3533 23.1558 14.5033 23.4058 14.7759C23.7272 15.1258 23.8699 15.5557 23.8078 15.9859C23.7782 16.1908 23.7097 16.3744 23.6074 16.5444C23.8232 16.719 23.9821 16.962 24.0588 17.2543C24.119 17.4834 24.1806 17.9606 23.8588 18.4522C23.8792 18.4842 23.8984 18.5176 23.9164 18.5517C24.1099 18.919 24.1223 19.334 23.9515 19.7205C23.6926 20.3063 23.0492 20.7678 21.7997 21.2632C21.0225 21.5714 20.3114 21.7684 20.305 21.7702C19.2774 22.0367 18.3481 22.1721 17.5435 22.1721C16.0647 22.1721 15.006 21.7192 14.3967 20.8259C13.4161 19.3876 13.5563 18.072 14.8252 16.8039C15.5274 16.1021 15.9942 15.0674 16.0915 14.8403C16.2875 14.1679 16.8059 13.4204 17.6675 13.4204C17.74 13.4204 17.8135 13.4262 17.8858 13.4376C18.2632 13.4969 18.5931 13.7142 18.8288 14.0411C19.0832 13.7248 19.3302 13.4732 19.5538 13.3312C19.8908 13.1175 20.2275 13.0092 20.5549 13.0092ZM20.5549 14.0196C20.4261 14.0196 20.2687 14.0744 20.0951 14.1846C19.5563 14.5263 18.5166 16.3136 18.1359 17.0087C18.0083 17.2417 17.7903 17.3402 17.594 17.3402C17.2045 17.3402 16.9004 16.9529 17.5584 16.4608C18.5479 15.7204 18.2008 14.5102 17.7284 14.4356C17.7077 14.4324 17.6872 14.4308 17.6675 14.4308C17.2381 14.4308 17.0486 15.171 17.0486 15.171C17.0486 15.171 16.4934 16.5654 15.5395 17.5185C14.5857 18.4719 14.5364 19.237 15.2316 20.2566C15.7058 20.9517 16.6134 21.1617 17.5435 21.1617C18.5082 21.1617 19.4972 20.9358 20.0514 20.7921C20.0787 20.785 23.4493 19.8329 23.0224 19.0226C22.9506 18.8864 22.8324 18.8318 22.6836 18.8318C22.0824 18.8318 20.9889 19.7266 20.5188 19.7266C20.4137 19.7266 20.3397 19.6819 20.3093 19.5727C20.109 18.8541 23.3551 18.5519 23.0815 17.5109C23.0332 17.3268 22.9024 17.252 22.7185 17.2523C21.924 17.2523 20.1416 18.6495 19.768 18.6495C19.7395 18.6495 19.719 18.6411 19.7079 18.6234C19.5207 18.3213 19.6233 18.1104 20.9426 17.3119C22.262 16.5131 23.1881 16.0327 22.6614 15.4592C22.6008 15.393 22.5149 15.3637 22.4106 15.3637C21.6095 15.364 19.717 17.0863 19.717 17.0863C19.717 17.0863 19.2062 17.6175 18.8972 17.6175C18.8263 17.6175 18.7659 17.5895 18.725 17.5203C18.506 17.151 20.7592 15.4433 20.8863 14.7388C20.9724 14.2613 20.8259 14.0196 20.5549 14.0196Z" fill="#FF9D0B"/>
+<path d="M15.2334 20.2539C14.5382 19.2344 14.5875 18.4692 15.5414 17.5159C16.4952 16.5628 17.0505 15.1684 17.0505 15.1684C17.0505 15.1684 17.2578 14.3585 17.7302 14.433C18.2026 14.5075 18.5494 15.7178 17.56 16.4582C16.5705 17.1984 17.757 17.7013 18.1377 17.0061C18.5184 16.3109 19.5579 14.5237 20.0969 14.1819C20.6358 13.8402 21.0152 14.0316 20.8881 14.7362C20.7611 15.4407 18.5075 17.1483 18.7268 17.5179C18.946 17.8872 19.7188 17.0837 19.7188 17.0837C19.7188 17.0837 22.1368 14.8832 22.6632 15.4566C23.1897 16.03 22.2638 16.5105 20.9445 17.3093C19.6248 18.1078 19.5225 18.3187 19.7097 18.6208C19.8971 18.9229 22.8097 16.4673 23.0833 17.5083C23.3566 18.5493 20.1108 18.8514 20.3112 19.5701C20.5115 20.2891 22.5975 18.2098 23.0242 19.0199C23.4511 19.8303 20.0805 20.7824 20.0532 20.7895C18.9645 21.0719 16.1994 21.6703 15.2334 20.2539Z" fill="#FFD21E"/>
+</g>
+<path d="M34.1509 17V7.22003H36.3559V10.985H39.7309V7.22003H41.9509V17H39.7309V12.92H36.3559V17H34.1509Z" fill="#1D2939"/>
+<path d="M46.3133 17.18C45.5033 17.18 44.9133 16.915 44.5433 16.385C44.1833 15.845 44.0033 15.11 44.0033 14.18V9.56003H46.2083V13.895C46.2083 14.425 46.2833 14.795 46.4333 15.005C46.5833 15.205 46.8183 15.305 47.1383 15.305C47.4183 15.305 47.6533 15.24 47.8433 15.11C48.0333 14.98 48.2383 14.77 48.4583 14.48V9.56003H50.6633V17H48.8633L48.6983 15.965H48.6533C48.3433 16.335 48.0033 16.63 47.6333 16.85C47.2633 17.07 46.8233 17.18 46.3133 17.18Z" fill="#1D2939"/>
+<path d="M55.2587 20.165C54.6787 20.165 54.1537 20.1 53.6837 19.97C53.2137 19.84 52.8387 19.635 52.5587 19.355C52.2787 19.075 52.1387 18.715 52.1387 18.275C52.1387 17.675 52.4937 17.175 53.2037 16.775V16.715C53.0137 16.585 52.8487 16.42 52.7087 16.22C52.5787 16.02 52.5137 15.765 52.5137 15.455C52.5137 15.185 52.5937 14.925 52.7537 14.675C52.9137 14.425 53.1137 14.22 53.3537 14.06V14C53.0937 13.82 52.8587 13.56 52.6487 13.22C52.4487 12.88 52.3487 12.495 52.3487 12.065C52.3487 11.465 52.4937 10.97 52.7837 10.58C53.0737 10.18 53.4537 9.88003 53.9237 9.68003C54.3937 9.48003 54.8937 9.38003 55.4237 9.38003C55.8637 9.38003 56.2487 9.44003 56.5787 9.56003H59.2937V11.165H58.1087C58.1787 11.275 58.2337 11.415 58.2737 11.585C58.3237 11.755 58.3487 11.94 58.3487 12.14C58.3487 12.71 58.2187 13.18 57.9587 13.55C57.6987 13.92 57.3487 14.195 56.9087 14.375C56.4687 14.555 55.9737 14.645 55.4237 14.645C55.1337 14.645 54.8337 14.595 54.5237 14.495C54.3437 14.645 54.2537 14.83 54.2537 15.05C54.2537 15.24 54.3387 15.38 54.5087 15.47C54.6787 15.56 54.9687 15.605 55.3787 15.605H56.5787C57.4987 15.605 58.1987 15.755 58.6787 16.055C59.1687 16.345 59.4137 16.825 59.4137 17.495C59.4137 18.005 59.2437 18.46 58.9037 18.86C58.5637 19.27 58.0837 19.59 57.4637 19.82C56.8437 20.05 56.1087 20.165 55.2587 20.165ZM55.4237 13.31C55.7137 13.31 55.9537 13.205 56.1437 12.995C56.3437 12.785 56.4437 12.475 56.4437 12.065C56.4437 11.675 56.3437 11.38 56.1437 11.18C55.9537 10.97 55.7137 10.865 55.4237 10.865C55.1337 10.865 54.8887 10.965 54.6887 11.165C54.4987 11.365 54.4037 11.665 54.4037 12.065C54.4037 12.475 54.4987 12.785 54.6887 12.995C54.8887 13.205 55.1337 13.31 55.4237 13.31ZM55.6037 18.785C56.1037 18.785 56.5137 18.695 56.8337 18.515C57.1537 18.335 57.3137 18.12 57.3137 17.87C57.3137 17.64 57.2137 17.485 57.0137 17.405C56.8237 17.325 56.5437 17.285 56.1737 17.285H55.4087C55.1587 17.285 54.9487 17.275 54.7787 17.255C54.6187 17.245 54.4787 17.225 54.3587 17.195C54.0887 17.435 53.9537 17.68 53.9537 17.93C53.9537 18.21 54.1037 18.42 54.4037 18.56C54.7137 18.71 55.1137 18.785 55.6037 18.785Z" fill="#1D2939"/>
+<path d="M63.2714 20.165C62.6914 20.165 62.1664 20.1 61.6964 19.97C61.2264 19.84 60.8514 19.635 60.5714 19.355C60.2914 19.075 60.1514 18.715 60.1514 18.275C60.1514 17.675 60.5064 17.175 61.2164 16.775V16.715C61.0264 16.585 60.8614 16.42 60.7214 16.22C60.5914 16.02 60.5264 15.765 60.5264 15.455C60.5264 15.185 60.6064 14.925 60.7664 14.675C60.9264 14.425 61.1264 14.22 61.3664 14.06V14C61.1064 13.82 60.8714 13.56 60.6614 13.22C60.4614 12.88 60.3614 12.495 60.3614 12.065C60.3614 11.465 60.5064 10.97 60.7964 10.58C61.0864 10.18 61.4664 9.88003 61.9364 9.68003C62.4064 9.48003 62.9064 9.38003 63.4364 9.38003C63.8764 9.38003 64.2614 9.44003 64.5914 9.56003H67.3064V11.165H66.1214C66.1914 11.275 66.2464 11.415 66.2864 11.585C66.3364 11.755 66.3614 11.94 66.3614 12.14C66.3614 12.71 66.2314 13.18 65.9714 13.55C65.7114 13.92 65.3614 14.195 64.9214 14.375C64.4814 14.555 63.9864 14.645 63.4364 14.645C63.1464 14.645 62.8464 14.595 62.5364 14.495C62.3564 14.645 62.2664 14.83 62.2664 15.05C62.2664 15.24 62.3514 15.38 62.5214 15.47C62.6914 15.56 62.9814 15.605 63.3914 15.605H64.5914C65.5114 15.605 66.2114 15.755 66.6914 16.055C67.1814 16.345 67.4264 16.825 67.4264 17.495C67.4264 18.005 67.2564 18.46 66.9164 18.86C66.5764 19.27 66.0964 19.59 65.4764 19.82C64.8564 20.05 64.1214 20.165 63.2714 20.165ZM63.4364 13.31C63.7264 13.31 63.9664 13.205 64.1564 12.995C64.3564 12.785 64.4564 12.475 64.4564 12.065C64.4564 11.675 64.3564 11.38 64.1564 11.18C63.9664 10.97 63.7264 10.865 63.4364 10.865C63.1464 10.865 62.9014 10.965 62.7014 11.165C62.5114 11.365 62.4164 11.665 62.4164 12.065C62.4164 12.475 62.5114 12.785 62.7014 12.995C62.9014 13.205 63.1464 13.31 63.4364 13.31ZM63.6164 18.785C64.1164 18.785 64.5264 18.695 64.8464 18.515C65.1664 18.335 65.3264 18.12 65.3264 17.87C65.3264 17.64 65.2264 17.485 65.0264 17.405C64.8364 17.325 64.5564 17.285 64.1864 17.285H63.4214C63.1714 17.285 62.9614 17.275 62.7914 17.255C62.6314 17.245 62.4914 17.225 62.3714 17.195C62.1014 17.435 61.9664 17.68 61.9664 17.93C61.9664 18.21 62.1164 18.42 62.4164 18.56C62.7264 18.71 63.1264 18.785 63.6164 18.785Z" fill="#1D2939"/>
+<path d="M68.6291 17V9.56003H70.8341V17H68.6291ZM69.7241 8.46503C69.3541 8.46503 69.0541 8.36003 68.8241 8.15003C68.5941 7.94003 68.4791 7.66003 68.4791 7.31003C68.4791 6.96003 68.5941 6.68003 68.8241 6.47003C69.0541 6.26003 69.3541 6.15503 69.7241 6.15503C70.0941 6.15503 70.3941 6.26003 70.6241 6.47003C70.8541 6.68003 70.9691 6.96003 70.9691 7.31003C70.9691 7.66003 70.8541 7.94003 70.6241 8.15003C70.3941 8.36003 70.0941 8.46503 69.7241 8.46503Z" fill="#1D2939"/>
+<path d="M72.7746 17V9.56003H74.5746L74.7246 10.505H74.7846C75.1046 10.205 75.4546 9.94503 75.8346 9.72503C76.2246 9.49503 76.6696 9.38003 77.1696 9.38003C77.9796 9.38003 78.5646 9.65003 78.9246 10.19C79.2946 10.72 79.4796 11.45 79.4796 12.38V17H77.2746V12.665C77.2746 12.125 77.1996 11.755 77.0496 11.555C76.9096 11.355 76.6796 11.255 76.3596 11.255C76.0796 11.255 75.8396 11.32 75.6396 11.45C75.4396 11.57 75.2196 11.745 74.9796 11.975V17H72.7746Z" fill="#1D2939"/>
+<path d="M84.0136 20.165C83.4336 20.165 82.9086 20.1 82.4386 19.97C81.9686 19.84 81.5936 19.635 81.3136 19.355C81.0336 19.075 80.8936 18.715 80.8936 18.275C80.8936 17.675 81.2486 17.175 81.9586 16.775V16.715C81.7686 16.585 81.6036 16.42 81.4636 16.22C81.3336 16.02 81.2686 15.765 81.2686 15.455C81.2686 15.185 81.3486 14.925 81.5086 14.675C81.6686 14.425 81.8686 14.22 82.1086 14.06V14C81.8486 13.82 81.6136 13.56 81.4036 13.22C81.2036 12.88 81.1036 12.495 81.1036 12.065C81.1036 11.465 81.2486 10.97 81.5386 10.58C81.8286 10.18 82.2086 9.88003 82.6786 9.68003C83.1486 9.48003 83.6486 9.38003 84.1786 9.38003C84.6186 9.38003 85.0036 9.44003 85.3336 9.56003H88.0486V11.165H86.8636C86.9336 11.275 86.9886 11.415 87.0286 11.585C87.0786 11.755 87.1036 11.94 87.1036 12.14C87.1036 12.71 86.9736 13.18 86.7136 13.55C86.4536 13.92 86.1036 14.195 85.6636 14.375C85.2236 14.555 84.7286 14.645 84.1786 14.645C83.8886 14.645 83.5886 14.595 83.2786 14.495C83.0986 14.645 83.0086 14.83 83.0086 15.05C83.0086 15.24 83.0936 15.38 83.2636 15.47C83.4336 15.56 83.7236 15.605 84.1336 15.605H85.3336C86.2536 15.605 86.9536 15.755 87.4336 16.055C87.9236 16.345 88.1686 16.825 88.1686 17.495C88.1686 18.005 87.9986 18.46 87.6586 18.86C87.3186 19.27 86.8386 19.59 86.2186 19.82C85.5986 20.05 84.8636 20.165 84.0136 20.165ZM84.1786 13.31C84.4686 13.31 84.7086 13.205 84.8986 12.995C85.0986 12.785 85.1986 12.475 85.1986 12.065C85.1986 11.675 85.0986 11.38 84.8986 11.18C84.7086 10.97 84.4686 10.865 84.1786 10.865C83.8886 10.865 83.6436 10.965 83.4436 11.165C83.2536 11.365 83.1586 11.665 83.1586 12.065C83.1586 12.475 83.2536 12.785 83.4436 12.995C83.6436 13.205 83.8886 13.31 84.1786 13.31ZM84.3586 18.785C84.8586 18.785 85.2686 18.695 85.5886 18.515C85.9086 18.335 86.0686 18.12 86.0686 17.87C86.0686 17.64 85.9686 17.485 85.7686 17.405C85.5786 17.325 85.2986 17.285 84.9286 17.285H84.1636C83.9136 17.285 83.7036 17.275 83.5336 17.255C83.3736 17.245 83.2336 17.225 83.1136 17.195C82.8436 17.435 82.7086 17.68 82.7086 17.93C82.7086 18.21 82.8586 18.42 83.1586 18.56C83.4686 18.71 83.8686 18.785 84.3586 18.785Z" fill="#1D2939"/>
+<path d="M92.5542 17V7.22003H98.7192V9.08003H94.7592V11.345H98.1492V13.205H94.7592V17H92.5542Z" fill="#1D2939"/>
+<path d="M101.544 17.18C100.864 17.18 100.324 16.965 99.9241 16.535C99.5241 16.095 99.3241 15.56 99.3241 14.93C99.3241 14.15 99.6541 13.54 100.314 13.1C100.974 12.66 102.039 12.365 103.509 12.215C103.489 11.885 103.389 11.625 103.209 11.435C103.039 11.235 102.749 11.135 102.339 11.135C102.029 11.135 101.714 11.195 101.394 11.315C101.074 11.435 100.734 11.6 100.374 11.81L99.5791 10.355C100.049 10.065 100.549 9.83003 101.079 9.65003C101.619 9.47003 102.179 9.38003 102.759 9.38003C103.709 9.38003 104.439 9.65503 104.949 10.205C105.459 10.755 105.714 11.6 105.714 12.74V17H103.914L103.764 16.235H103.704C103.394 16.515 103.059 16.745 102.699 16.925C102.349 17.095 101.964 17.18 101.544 17.18ZM102.294 15.47C102.544 15.47 102.759 15.415 102.939 15.305C103.129 15.185 103.319 15.03 103.509 14.84V13.535C102.729 13.635 102.189 13.795 101.889 14.015C101.589 14.225 101.439 14.475 101.439 14.765C101.439 15.005 101.514 15.185 101.664 15.305C101.824 15.415 102.034 15.47 102.294 15.47Z" fill="#1D2939"/>
+<path d="M110.819 17.18C110.129 17.18 109.504 17.03 108.944 16.73C108.394 16.42 107.954 15.975 107.624 15.395C107.304 14.805 107.144 14.1 107.144 13.28C107.144 12.45 107.324 11.745 107.684 11.165C108.044 10.585 108.519 10.145 109.109 9.84503C109.699 9.53503 110.334 9.38003 111.014 9.38003C111.474 9.38003 111.879 9.45503 112.229 9.60503C112.589 9.75503 112.909 9.94503 113.189 10.175L112.154 11.6C111.804 11.31 111.469 11.165 111.149 11.165C110.619 11.165 110.194 11.355 109.874 11.735C109.564 12.115 109.409 12.63 109.409 13.28C109.409 13.92 109.564 14.435 109.874 14.825C110.194 15.205 110.594 15.395 111.074 15.395C111.314 15.395 111.549 15.345 111.779 15.245C112.009 15.135 112.219 15.005 112.409 14.855L113.279 16.295C112.909 16.615 112.509 16.845 112.079 16.985C111.649 17.115 111.229 17.18 110.819 17.18Z" fill="#1D2939"/>
+<path d="M117.486 17.18C116.776 17.18 116.136 17.025 115.566 16.715C114.996 16.405 114.546 15.96 114.216 15.38C113.886 14.8 113.721 14.1 113.721 13.28C113.721 12.47 113.886 11.775 114.216 11.195C114.556 10.615 114.996 10.17 115.536 9.86003C116.076 9.54003 116.641 9.38003 117.231 9.38003C117.941 9.38003 118.526 9.54003 118.986 9.86003C119.456 10.17 119.806 10.595 120.036 11.135C120.276 11.665 120.396 12.27 120.396 12.95C120.396 13.14 120.386 13.33 120.366 13.52C120.346 13.7 120.326 13.835 120.306 13.925H115.851C115.951 14.465 116.176 14.865 116.526 15.125C116.876 15.375 117.296 15.5 117.786 15.5C118.316 15.5 118.851 15.335 119.391 15.005L120.126 16.34C119.746 16.6 119.321 16.805 118.851 16.955C118.381 17.105 117.926 17.18 117.486 17.18ZM115.836 12.47H118.521C118.521 12.06 118.421 11.725 118.221 11.465C118.031 11.195 117.716 11.06 117.276 11.06C116.936 11.06 116.631 11.18 116.361 11.42C116.091 11.65 115.916 12 115.836 12.47Z" fill="#1D2939"/>
+<path d="M125.103 17V7.22003H127.308V10.985H130.683V7.22003H132.903V17H130.683V12.92H127.308V17H125.103Z" fill="#1D2939"/>
+<path d="M137.265 17.18C136.455 17.18 135.865 16.915 135.495 16.385C135.135 15.845 134.955 15.11 134.955 14.18V9.56003H137.16V13.895C137.16 14.425 137.235 14.795 137.385 15.005C137.535 15.205 137.77 15.305 138.09 15.305C138.37 15.305 138.605 15.24 138.795 15.11C138.985 14.98 139.19 14.77 139.41 14.48V9.56003H141.615V17H139.815L139.65 15.965H139.605C139.295 16.335 138.955 16.63 138.585 16.85C138.215 17.07 137.775 17.18 137.265 17.18Z" fill="#1D2939"/>
+<path d="M147.456 17.18C147.126 17.18 146.791 17.1 146.451 16.94C146.121 16.77 145.811 16.525 145.521 16.205H145.461L145.281 17H143.556V6.48503H145.761V9.06503L145.701 10.205C145.991 9.94503 146.306 9.74503 146.646 9.60503C146.986 9.45503 147.326 9.38003 147.666 9.38003C148.266 9.38003 148.786 9.53503 149.226 9.84503C149.666 10.155 150.001 10.595 150.231 11.165C150.471 11.725 150.591 12.385 150.591 13.145C150.591 13.995 150.441 14.725 150.141 15.335C149.841 15.935 149.451 16.395 148.971 16.715C148.501 17.025 147.996 17.18 147.456 17.18ZM146.946 15.38C147.326 15.38 147.651 15.205 147.921 14.855C148.191 14.505 148.326 13.95 148.326 13.19C148.326 11.85 147.896 11.18 147.036 11.18C146.596 11.18 146.171 11.405 145.761 11.855V14.9C145.961 15.08 146.161 15.205 146.361 15.275C146.561 15.345 146.756 15.38 146.946 15.38Z" fill="#1D2939"/>
+</g>
+<defs>
+<clipPath id="clip0_8587_60397">
+<rect x="0.998047" width="150" height="24" rx="6" fill="white"/>
+</clipPath>
+<clipPath id="clip1_8587_60397">
+<rect width="23.998" height="22.2298" fill="white" transform="translate(0.998047 0.885132)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/huggingface-text.svg b/app/components/base/icons/assets/public/llm/huggingface-text.svg
new file mode 100644
index 0000000..70135a0
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/huggingface-text.svg
@@ -0,0 +1,42 @@
+<svg width="120" height="24" viewBox="0 0 120 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_8587_60377)">
+<g clip-path="url(#clip1_8587_60377)">
+<path d="M11.9286 20.2062C16.7767 20.2062 20.7069 16.2761 20.7069 11.428C20.7069 6.57993 16.7767 2.64978 11.9286 2.64978C7.08054 2.64978 3.15039 6.57993 3.15039 11.428C3.15039 16.2761 7.08054 20.2062 11.9286 20.2062Z" fill="#FFD21E"/>
+<path d="M20.7095 11.4326C20.7095 6.58451 16.7793 2.65436 11.9313 2.65436C7.08318 2.65436 3.15303 6.58451 3.15303 11.4326C3.15303 16.2807 7.08318 20.2108 11.9313 20.2108C16.7793 20.2108 20.7095 16.2807 20.7095 11.4326ZM2.14258 11.4326C2.14258 6.02647 6.52511 1.64392 11.9313 1.64392C17.3374 1.64392 21.7199 6.02647 21.7199 11.4326C21.7199 16.8387 17.3374 21.2213 11.9313 21.2213C6.52511 21.2213 2.14258 16.8387 2.14258 11.4326Z" fill="#FF9D0B"/>
+<path d="M14.7822 9.03703C15.1041 9.1507 15.2322 9.81254 15.5574 9.6396C16.1734 9.31212 16.4072 8.54734 16.0797 7.93142C15.7522 7.31553 14.9874 7.08172 14.3715 7.4092C13.7556 7.73669 13.5218 8.50147 13.8493 9.11738C14.0038 9.40809 14.4944 8.9354 14.7822 9.03703Z" fill="#3A3B45"/>
+<path d="M8.83422 9.03703C8.5123 9.1507 8.38422 9.81254 8.05901 9.6396C7.4431 9.31212 7.20928 8.54734 7.53676 7.93142C7.86425 7.31553 8.62903 7.08172 9.24494 7.4092C9.86086 7.73669 10.0947 8.50147 9.76719 9.11738C9.61262 9.40809 9.122 8.9354 8.83422 9.03703Z" fill="#3A3B45"/>
+<path d="M11.8679 15.1044C14.3507 15.1044 15.1519 12.8908 15.1519 11.7541C15.1519 11.1633 14.7547 11.3492 14.1187 11.6641C13.5309 11.9551 12.739 12.3563 11.8679 12.3563C10.0543 12.3563 8.58398 10.6173 8.58398 11.7541C8.58398 12.8908 9.38514 15.1044 11.8679 15.1044Z" fill="#3A3B45"/>
+<mask id="mask0_8587_60377" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="8" y="11" width="8" height="5">
+<path d="M11.8562 15.1005C14.339 15.1005 15.1402 12.8869 15.1402 11.7502C15.1402 11.1594 14.743 11.3453 14.1069 11.6602C13.5191 11.9512 12.7273 12.3524 11.8562 12.3524C10.0425 12.3524 8.57227 10.6134 8.57227 11.7502C8.57227 12.8869 9.37342 15.1005 11.8562 15.1005Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_8587_60377)">
+<path d="M11.9194 17.6824C13.1294 17.6824 14.1103 16.7016 14.1103 15.4916C14.1103 14.5491 13.5152 13.7457 12.6803 13.4364C12.6496 13.425 12.6185 13.4143 12.5872 13.4043C12.3766 13.337 12.1523 14.0606 11.9194 14.0606C11.7018 14.0606 11.4917 13.3324 11.2933 13.3915C10.3884 13.6609 9.72852 14.4991 9.72852 15.4916C9.72852 16.7016 10.7094 17.6824 11.9194 17.6824Z" fill="#F94040"/>
+</g>
+<path d="M17.8698 10.2273C18.3232 10.2273 18.6908 9.85972 18.6908 9.40631C18.6908 8.9529 18.3232 8.58533 17.8698 8.58533C17.4164 8.58533 17.0488 8.9529 17.0488 9.40631C17.0488 9.85972 17.4164 10.2273 17.8698 10.2273Z" fill="#FF9D0B"/>
+<path d="M6.11981 10.2273C6.57323 10.2273 6.9408 9.85972 6.9408 9.40631C6.9408 8.9529 6.57323 8.58533 6.11981 8.58533C5.66638 8.58533 5.29883 8.9529 5.29883 9.40631C5.29883 9.85972 5.66638 10.2273 6.11981 10.2273Z" fill="#FF9D0B"/>
+<path d="M4.42915 13.0092C4.02018 13.0092 3.65465 13.1771 3.39976 13.4818C3.24214 13.6705 3.07743 13.9746 3.06404 14.4301C2.89252 14.3808 2.72757 14.3533 2.57347 14.3533C2.18193 14.3533 1.82827 14.5033 1.57819 14.7759C1.25687 15.1258 1.11414 15.5557 1.17628 15.9859C1.20584 16.1908 1.2743 16.3744 1.3766 16.5444C1.16087 16.719 1.00198 16.962 0.925188 17.2543C0.865067 17.4834 0.803429 17.9606 1.12526 18.4522C1.10479 18.4842 1.0856 18.5176 1.06766 18.5517C0.874161 18.919 0.861783 19.334 1.03255 19.7205C1.29147 20.3063 1.93487 20.7678 3.18429 21.2632C3.96157 21.5714 4.67267 21.7684 4.67899 21.7702C5.70661 22.0367 6.63596 22.1721 7.44053 22.1721C8.91931 22.1721 9.97801 21.7192 10.5873 20.8259C11.5679 19.3876 11.4277 18.072 10.1589 16.8039C9.45662 16.1021 8.98979 15.0674 8.89254 14.8403C8.69651 14.1679 8.17815 13.4204 7.3165 13.4204C7.244 13.4204 7.17049 13.4262 7.09824 13.4376C6.72084 13.4969 6.39093 13.7142 6.15525 14.0411C5.90087 13.7248 5.65381 13.4732 5.43025 13.3312C5.09327 13.1175 4.75654 13.0092 4.42915 13.0092ZM4.42915 14.0196C4.55799 14.0196 4.71536 14.0744 4.88891 14.1846C5.42773 14.5263 6.46747 16.3136 6.84816 17.0087C6.97573 17.2417 7.19373 17.3402 7.39001 17.3402C7.77953 17.3402 8.08368 16.9529 7.42563 16.4608C6.43615 15.7204 6.78324 14.5102 7.25562 14.4356C7.27633 14.4324 7.29679 14.4308 7.3165 14.4308C7.74594 14.4308 7.93539 15.171 7.93539 15.171C7.93539 15.171 8.49063 16.5654 9.44449 17.5185C10.3984 18.4719 10.4476 19.237 9.75243 20.2566C9.27828 20.9517 8.37064 21.1617 7.44053 21.1617C6.47581 21.1617 5.48684 20.9358 4.93261 20.7921C4.90533 20.785 1.53474 19.8329 1.96165 19.0226C2.03339 18.8864 2.15161 18.8318 2.3004 18.8318C2.90162 18.8318 3.99517 19.7266 4.46528 19.7266C4.57036 19.7266 4.64438 19.6819 4.67469 19.5727C4.87501 18.8541 1.62896 18.5519 1.90254 17.5109C1.95079 17.3268 2.08164 17.252 2.26554 17.2523C3.06 17.2523 4.84243 18.6495 5.21604 18.6495C5.24458 18.6495 5.26504 18.6411 5.27616 18.6234C5.46334 18.3213 5.36078 18.1104 4.0414 17.3119C2.72201 16.5131 1.79594 16.0327 2.32263 15.4592C2.38326 15.393 2.46915 15.3637 2.57347 15.3637C3.3745 15.364 5.26706 17.0863 5.26706 17.0863C5.26706 17.0863 5.77784 17.6175 6.08679 17.6175C6.15777 17.6175 6.21814 17.5895 6.25907 17.5203C6.47808 17.151 4.22479 15.4433 4.09773 14.7388C4.01159 14.2613 4.1581 14.0196 4.42915 14.0196Z" fill="#FF9D0B"/>
+<path d="M9.75883 20.2539C10.454 19.2344 10.4048 18.4692 9.4509 17.5159C8.49704 16.5628 7.9418 15.1684 7.9418 15.1684C7.9418 15.1684 7.73441 14.3585 7.26203 14.433C6.78964 14.5075 6.44281 15.7178 7.43228 16.4582C8.42176 17.1984 7.23525 17.7013 6.85456 17.0061C6.47388 16.3109 5.43438 14.5237 4.89531 14.1819C4.35649 13.8402 3.97707 14.0316 4.10414 14.7362C4.2312 15.4407 6.48474 17.1483 6.26547 17.5179C6.04621 17.8872 5.27347 17.0837 5.27347 17.0837C5.27347 17.0837 2.85548 14.8832 2.32903 15.4566C1.80258 16.03 2.72842 16.5105 4.0478 17.3093C5.36744 18.1078 5.46975 18.3187 5.28257 18.6208C5.09513 18.9229 2.18251 16.4673 1.90893 17.5083C1.63561 18.5493 4.88142 18.8514 4.6811 19.5701C4.48078 20.2891 2.3947 18.2098 1.96804 19.0199C1.54113 19.8303 4.91173 20.7824 4.93901 20.7895C6.02777 21.0719 8.79285 21.6703 9.75883 20.2539Z" fill="#FFD21E"/>
+<path d="M19.5568 13.0092C19.9658 13.0092 20.3313 13.1771 20.5862 13.4818C20.7439 13.6705 20.9086 13.9746 20.9219 14.4301C21.0935 14.3808 21.2584 14.3533 21.4125 14.3533C21.8041 14.3533 22.1577 14.5033 22.4078 14.7759C22.7291 15.1258 22.8718 15.5557 22.8097 15.9859C22.7802 16.1908 22.7117 16.3744 22.6094 16.5444C22.8251 16.719 22.984 16.962 23.0608 17.2543C23.1209 17.4834 23.1826 17.9606 22.8607 18.4522C22.8812 18.4842 22.9004 18.5176 22.9183 18.5517C23.1118 18.919 23.1242 19.334 22.9534 19.7205C22.6945 20.3063 22.0511 20.7678 20.8017 21.2632C20.0244 21.5714 19.3133 21.7684 19.307 21.7702C18.2794 22.0367 17.35 22.1721 16.5455 22.1721C15.0667 22.1721 14.008 21.7192 13.3987 20.8259C12.418 19.3876 12.5582 18.072 13.8271 16.8039C14.5294 16.1021 14.9962 15.0674 15.0935 14.8403C15.2895 14.1679 15.8078 13.4204 16.6695 13.4204C16.742 13.4204 16.8155 13.4262 16.8877 13.4376C17.2651 13.4969 17.5951 13.7142 17.8307 14.0411C18.0851 13.7248 18.3322 13.4732 18.5557 13.3312C18.8927 13.1175 19.2295 13.0092 19.5568 13.0092ZM19.5568 14.0196C19.428 14.0196 19.2706 14.0744 19.0971 14.1846C18.5583 14.5263 17.5185 16.3136 17.1378 17.0087C17.0103 17.2417 16.7923 17.3402 16.596 17.3402C16.2065 17.3402 15.9023 16.9529 16.5604 16.4608C17.5498 15.7204 17.2028 14.5102 16.7304 14.4356C16.7097 14.4324 16.6892 14.4308 16.6695 14.4308C16.2401 14.4308 16.0506 15.171 16.0506 15.171C16.0506 15.171 15.4954 16.5654 14.5415 17.5185C13.5876 18.4719 13.5384 19.237 14.2336 20.2566C14.7077 20.9517 15.6153 21.1617 16.5455 21.1617C17.5102 21.1617 18.4992 20.9358 19.0534 20.7921C19.0807 20.785 22.4513 19.8329 22.0243 19.0226C21.9526 18.8864 21.8344 18.8318 21.6856 18.8318C21.0844 18.8318 19.9908 19.7266 19.5207 19.7266C19.4156 19.7266 19.3416 19.6819 19.3113 19.5727C19.111 18.8541 22.357 18.5519 22.0835 17.5109C22.0352 17.3268 21.9043 17.252 21.7204 17.2523C20.926 17.2523 19.1436 18.6495 18.77 18.6495C18.7414 18.6495 18.7209 18.6411 18.7098 18.6234C18.5226 18.3213 18.6252 18.1104 19.9446 17.3119C21.264 16.5131 22.1901 16.0327 21.6634 15.4592C21.6027 15.393 21.5168 15.3637 21.4125 15.3637C20.6115 15.364 18.7189 17.0863 18.7189 17.0863C18.7189 17.0863 18.2081 17.6175 17.8992 17.6175C17.8282 17.6175 17.7678 17.5895 17.7269 17.5203C17.5079 17.151 19.7612 15.4433 19.8883 14.7388C19.9744 14.2613 19.8279 14.0196 19.5568 14.0196Z" fill="#FF9D0B"/>
+<path d="M14.2354 20.2539C13.5402 19.2344 13.5895 18.4692 14.5433 17.5159C15.4972 16.5628 16.0524 15.1684 16.0524 15.1684C16.0524 15.1684 16.2598 14.3585 16.7322 14.433C17.2046 14.5075 17.5514 15.7178 16.5619 16.4582C15.5724 17.1984 16.759 17.7013 17.1396 17.0061C17.5203 16.3109 18.5598 14.5237 19.0989 14.1819C19.6377 13.8402 20.0171 14.0316 19.8901 14.7362C19.763 15.4407 17.5095 17.1483 17.7287 17.5179C17.948 17.8872 18.7207 17.0837 18.7207 17.0837C18.7207 17.0837 21.1387 14.8832 21.6652 15.4566C22.1916 16.03 21.2658 16.5105 19.9464 17.3093C18.6268 18.1078 18.5245 18.3187 18.7116 18.6208C18.8991 18.9229 21.8117 16.4673 22.0853 17.5083C22.3586 18.5493 19.1128 18.8514 19.3131 19.5701C19.5134 20.2891 21.5995 18.2098 22.0262 19.0199C22.4531 19.8303 19.0825 20.7824 19.0552 20.7895C17.9664 21.0719 15.2014 21.6703 14.2354 20.2539Z" fill="#FFD21E"/>
+</g>
+<path d="M33.1528 17V7.22003H35.3578V10.985H38.7328V7.22003H40.9528V17H38.7328V12.92H35.3578V17H33.1528Z" fill="#1D2939"/>
+<path d="M45.3153 17.18C44.5053 17.18 43.9153 16.915 43.5453 16.385C43.1853 15.845 43.0053 15.11 43.0053 14.18V9.56003H45.2103V13.895C45.2103 14.425 45.2853 14.795 45.4353 15.005C45.5853 15.205 45.8203 15.305 46.1403 15.305C46.4203 15.305 46.6553 15.24 46.8453 15.11C47.0353 14.98 47.2403 14.77 47.4603 14.48V9.56003H49.6653V17H47.8653L47.7003 15.965H47.6553C47.3453 16.335 47.0053 16.63 46.6353 16.85C46.2653 17.07 45.8253 17.18 45.3153 17.18Z" fill="#1D2939"/>
+<path d="M54.2606 20.165C53.6806 20.165 53.1556 20.1 52.6856 19.97C52.2156 19.84 51.8406 19.635 51.5606 19.355C51.2806 19.075 51.1406 18.715 51.1406 18.275C51.1406 17.675 51.4956 17.175 52.2056 16.775V16.715C52.0156 16.585 51.8506 16.42 51.7106 16.22C51.5806 16.02 51.5156 15.765 51.5156 15.455C51.5156 15.185 51.5956 14.925 51.7556 14.675C51.9156 14.425 52.1156 14.22 52.3556 14.06V14C52.0956 13.82 51.8606 13.56 51.6506 13.22C51.4506 12.88 51.3506 12.495 51.3506 12.065C51.3506 11.465 51.4956 10.97 51.7856 10.58C52.0756 10.18 52.4556 9.88003 52.9256 9.68003C53.3956 9.48003 53.8956 9.38003 54.4256 9.38003C54.8656 9.38003 55.2506 9.44003 55.5806 9.56003H58.2956V11.165H57.1106C57.1806 11.275 57.2356 11.415 57.2756 11.585C57.3256 11.755 57.3506 11.94 57.3506 12.14C57.3506 12.71 57.2206 13.18 56.9606 13.55C56.7006 13.92 56.3506 14.195 55.9106 14.375C55.4706 14.555 54.9756 14.645 54.4256 14.645C54.1356 14.645 53.8356 14.595 53.5256 14.495C53.3456 14.645 53.2556 14.83 53.2556 15.05C53.2556 15.24 53.3406 15.38 53.5106 15.47C53.6806 15.56 53.9706 15.605 54.3806 15.605H55.5806C56.5006 15.605 57.2006 15.755 57.6806 16.055C58.1706 16.345 58.4156 16.825 58.4156 17.495C58.4156 18.005 58.2456 18.46 57.9056 18.86C57.5656 19.27 57.0856 19.59 56.4656 19.82C55.8456 20.05 55.1106 20.165 54.2606 20.165ZM54.4256 13.31C54.7156 13.31 54.9556 13.205 55.1456 12.995C55.3456 12.785 55.4456 12.475 55.4456 12.065C55.4456 11.675 55.3456 11.38 55.1456 11.18C54.9556 10.97 54.7156 10.865 54.4256 10.865C54.1356 10.865 53.8906 10.965 53.6906 11.165C53.5006 11.365 53.4056 11.665 53.4056 12.065C53.4056 12.475 53.5006 12.785 53.6906 12.995C53.8906 13.205 54.1356 13.31 54.4256 13.31ZM54.6056 18.785C55.1056 18.785 55.5156 18.695 55.8356 18.515C56.1556 18.335 56.3156 18.12 56.3156 17.87C56.3156 17.64 56.2156 17.485 56.0156 17.405C55.8256 17.325 55.5456 17.285 55.1756 17.285H54.4106C54.1606 17.285 53.9506 17.275 53.7806 17.255C53.6206 17.245 53.4806 17.225 53.3606 17.195C53.0906 17.435 52.9556 17.68 52.9556 17.93C52.9556 18.21 53.1056 18.42 53.4056 18.56C53.7156 18.71 54.1156 18.785 54.6056 18.785Z" fill="#1D2939"/>
+<path d="M62.2733 20.165C61.6933 20.165 61.1683 20.1 60.6983 19.97C60.2283 19.84 59.8533 19.635 59.5733 19.355C59.2933 19.075 59.1533 18.715 59.1533 18.275C59.1533 17.675 59.5083 17.175 60.2183 16.775V16.715C60.0283 16.585 59.8633 16.42 59.7233 16.22C59.5933 16.02 59.5283 15.765 59.5283 15.455C59.5283 15.185 59.6083 14.925 59.7683 14.675C59.9283 14.425 60.1283 14.22 60.3683 14.06V14C60.1083 13.82 59.8733 13.56 59.6633 13.22C59.4633 12.88 59.3633 12.495 59.3633 12.065C59.3633 11.465 59.5083 10.97 59.7983 10.58C60.0883 10.18 60.4683 9.88003 60.9383 9.68003C61.4083 9.48003 61.9083 9.38003 62.4383 9.38003C62.8783 9.38003 63.2633 9.44003 63.5933 9.56003H66.3083V11.165H65.1233C65.1933 11.275 65.2483 11.415 65.2883 11.585C65.3383 11.755 65.3633 11.94 65.3633 12.14C65.3633 12.71 65.2333 13.18 64.9733 13.55C64.7133 13.92 64.3633 14.195 63.9233 14.375C63.4833 14.555 62.9883 14.645 62.4383 14.645C62.1483 14.645 61.8483 14.595 61.5383 14.495C61.3583 14.645 61.2683 14.83 61.2683 15.05C61.2683 15.24 61.3533 15.38 61.5233 15.47C61.6933 15.56 61.9833 15.605 62.3933 15.605H63.5933C64.5133 15.605 65.2133 15.755 65.6933 16.055C66.1833 16.345 66.4283 16.825 66.4283 17.495C66.4283 18.005 66.2583 18.46 65.9183 18.86C65.5783 19.27 65.0983 19.59 64.4783 19.82C63.8583 20.05 63.1233 20.165 62.2733 20.165ZM62.4383 13.31C62.7283 13.31 62.9683 13.205 63.1583 12.995C63.3583 12.785 63.4583 12.475 63.4583 12.065C63.4583 11.675 63.3583 11.38 63.1583 11.18C62.9683 10.97 62.7283 10.865 62.4383 10.865C62.1483 10.865 61.9033 10.965 61.7033 11.165C61.5133 11.365 61.4183 11.665 61.4183 12.065C61.4183 12.475 61.5133 12.785 61.7033 12.995C61.9033 13.205 62.1483 13.31 62.4383 13.31ZM62.6183 18.785C63.1183 18.785 63.5283 18.695 63.8483 18.515C64.1683 18.335 64.3283 18.12 64.3283 17.87C64.3283 17.64 64.2283 17.485 64.0283 17.405C63.8383 17.325 63.5583 17.285 63.1883 17.285H62.4233C62.1733 17.285 61.9633 17.275 61.7933 17.255C61.6333 17.245 61.4933 17.225 61.3733 17.195C61.1033 17.435 60.9683 17.68 60.9683 17.93C60.9683 18.21 61.1183 18.42 61.4183 18.56C61.7283 18.71 62.1283 18.785 62.6183 18.785Z" fill="#1D2939"/>
+<path d="M67.631 17V9.56003H69.836V17H67.631ZM68.726 8.46503C68.356 8.46503 68.056 8.36003 67.826 8.15003C67.596 7.94003 67.481 7.66003 67.481 7.31003C67.481 6.96003 67.596 6.68003 67.826 6.47003C68.056 6.26003 68.356 6.15503 68.726 6.15503C69.096 6.15503 69.396 6.26003 69.626 6.47003C69.856 6.68003 69.971 6.96003 69.971 7.31003C69.971 7.66003 69.856 7.94003 69.626 8.15003C69.396 8.36003 69.096 8.46503 68.726 8.46503Z" fill="#1D2939"/>
+<path d="M71.7765 17V9.56003H73.5765L73.7265 10.505H73.7865C74.1065 10.205 74.4565 9.94503 74.8365 9.72503C75.2265 9.49503 75.6715 9.38003 76.1715 9.38003C76.9815 9.38003 77.5665 9.65003 77.9265 10.19C78.2965 10.72 78.4815 11.45 78.4815 12.38V17H76.2765V12.665C76.2765 12.125 76.2015 11.755 76.0515 11.555C75.9115 11.355 75.6815 11.255 75.3615 11.255C75.0815 11.255 74.8415 11.32 74.6415 11.45C74.4415 11.57 74.2215 11.745 73.9815 11.975V17H71.7765Z" fill="#1D2939"/>
+<path d="M83.0155 20.165C82.4355 20.165 81.9105 20.1 81.4405 19.97C80.9705 19.84 80.5955 19.635 80.3155 19.355C80.0355 19.075 79.8955 18.715 79.8955 18.275C79.8955 17.675 80.2505 17.175 80.9605 16.775V16.715C80.7705 16.585 80.6055 16.42 80.4655 16.22C80.3355 16.02 80.2705 15.765 80.2705 15.455C80.2705 15.185 80.3505 14.925 80.5105 14.675C80.6705 14.425 80.8705 14.22 81.1105 14.06V14C80.8505 13.82 80.6155 13.56 80.4055 13.22C80.2055 12.88 80.1055 12.495 80.1055 12.065C80.1055 11.465 80.2505 10.97 80.5405 10.58C80.8305 10.18 81.2105 9.88003 81.6805 9.68003C82.1505 9.48003 82.6505 9.38003 83.1805 9.38003C83.6205 9.38003 84.0055 9.44003 84.3355 9.56003H87.0505V11.165H85.8655C85.9355 11.275 85.9905 11.415 86.0305 11.585C86.0805 11.755 86.1055 11.94 86.1055 12.14C86.1055 12.71 85.9755 13.18 85.7155 13.55C85.4555 13.92 85.1055 14.195 84.6655 14.375C84.2255 14.555 83.7305 14.645 83.1805 14.645C82.8905 14.645 82.5905 14.595 82.2805 14.495C82.1005 14.645 82.0105 14.83 82.0105 15.05C82.0105 15.24 82.0955 15.38 82.2655 15.47C82.4355 15.56 82.7255 15.605 83.1355 15.605H84.3355C85.2555 15.605 85.9555 15.755 86.4355 16.055C86.9255 16.345 87.1705 16.825 87.1705 17.495C87.1705 18.005 87.0005 18.46 86.6605 18.86C86.3205 19.27 85.8405 19.59 85.2205 19.82C84.6005 20.05 83.8655 20.165 83.0155 20.165ZM83.1805 13.31C83.4705 13.31 83.7105 13.205 83.9005 12.995C84.1005 12.785 84.2005 12.475 84.2005 12.065C84.2005 11.675 84.1005 11.38 83.9005 11.18C83.7105 10.97 83.4705 10.865 83.1805 10.865C82.8905 10.865 82.6455 10.965 82.4455 11.165C82.2555 11.365 82.1605 11.665 82.1605 12.065C82.1605 12.475 82.2555 12.785 82.4455 12.995C82.6455 13.205 82.8905 13.31 83.1805 13.31ZM83.3605 18.785C83.8605 18.785 84.2705 18.695 84.5905 18.515C84.9105 18.335 85.0705 18.12 85.0705 17.87C85.0705 17.64 84.9705 17.485 84.7705 17.405C84.5805 17.325 84.3005 17.285 83.9305 17.285H83.1655C82.9155 17.285 82.7055 17.275 82.5355 17.255C82.3755 17.245 82.2355 17.225 82.1155 17.195C81.8455 17.435 81.7105 17.68 81.7105 17.93C81.7105 18.21 81.8605 18.42 82.1605 18.56C82.4705 18.71 82.8705 18.785 83.3605 18.785Z" fill="#1D2939"/>
+<path d="M91.5562 17V7.22003H97.7212V9.08003H93.7612V11.345H97.1512V13.205H93.7612V17H91.5562Z" fill="#1D2939"/>
+<path d="M100.546 17.18C99.8661 17.18 99.3261 16.965 98.9261 16.535C98.5261 16.095 98.3261 15.56 98.3261 14.93C98.3261 14.15 98.6561 13.54 99.3161 13.1C99.9761 12.66 101.041 12.365 102.511 12.215C102.491 11.885 102.391 11.625 102.211 11.435C102.041 11.235 101.751 11.135 101.341 11.135C101.031 11.135 100.716 11.195 100.396 11.315C100.076 11.435 99.7361 11.6 99.3761 11.81L98.5811 10.355C99.0511 10.065 99.5511 9.83003 100.081 9.65003C100.621 9.47003 101.181 9.38003 101.761 9.38003C102.711 9.38003 103.441 9.65503 103.951 10.205C104.461 10.755 104.716 11.6 104.716 12.74V17H102.916L102.766 16.235H102.706C102.396 16.515 102.061 16.745 101.701 16.925C101.351 17.095 100.966 17.18 100.546 17.18ZM101.296 15.47C101.546 15.47 101.761 15.415 101.941 15.305C102.131 15.185 102.321 15.03 102.511 14.84V13.535C101.731 13.635 101.191 13.795 100.891 14.015C100.591 14.225 100.441 14.475 100.441 14.765C100.441 15.005 100.516 15.185 100.666 15.305C100.826 15.415 101.036 15.47 101.296 15.47Z" fill="#1D2939"/>
+<path d="M109.821 17.18C109.131 17.18 108.506 17.03 107.946 16.73C107.396 16.42 106.956 15.975 106.626 15.395C106.306 14.805 106.146 14.1 106.146 13.28C106.146 12.45 106.326 11.745 106.686 11.165C107.046 10.585 107.521 10.145 108.111 9.84503C108.701 9.53503 109.336 9.38003 110.016 9.38003C110.476 9.38003 110.881 9.45503 111.231 9.60503C111.591 9.75503 111.911 9.94503 112.191 10.175L111.156 11.6C110.806 11.31 110.471 11.165 110.151 11.165C109.621 11.165 109.196 11.355 108.876 11.735C108.566 12.115 108.411 12.63 108.411 13.28C108.411 13.92 108.566 14.435 108.876 14.825C109.196 15.205 109.596 15.395 110.076 15.395C110.316 15.395 110.551 15.345 110.781 15.245C111.011 15.135 111.221 15.005 111.411 14.855L112.281 16.295C111.911 16.615 111.511 16.845 111.081 16.985C110.651 17.115 110.231 17.18 109.821 17.18Z" fill="#1D2939"/>
+<path d="M116.488 17.18C115.778 17.18 115.138 17.025 114.568 16.715C113.998 16.405 113.548 15.96 113.218 15.38C112.888 14.8 112.723 14.1 112.723 13.28C112.723 12.47 112.888 11.775 113.218 11.195C113.558 10.615 113.998 10.17 114.538 9.86003C115.078 9.54003 115.643 9.38003 116.233 9.38003C116.943 9.38003 117.528 9.54003 117.988 9.86003C118.458 10.17 118.808 10.595 119.038 11.135C119.278 11.665 119.398 12.27 119.398 12.95C119.398 13.14 119.388 13.33 119.368 13.52C119.348 13.7 119.328 13.835 119.308 13.925H114.853C114.953 14.465 115.178 14.865 115.528 15.125C115.878 15.375 116.298 15.5 116.788 15.5C117.318 15.5 117.853 15.335 118.393 15.005L119.128 16.34C118.748 16.6 118.323 16.805 117.853 16.955C117.383 17.105 116.928 17.18 116.488 17.18ZM114.838 12.47H117.523C117.523 12.06 117.423 11.725 117.223 11.465C117.033 11.195 116.718 11.06 116.278 11.06C115.938 11.06 115.633 11.18 115.363 11.42C115.093 11.65 114.918 12 114.838 12.47Z" fill="#1D2939"/>
+</g>
+<defs>
+<clipPath id="clip0_8587_60377">
+<rect width="119.998" height="24" rx="6" fill="white"/>
+</clipPath>
+<clipPath id="clip1_8587_60377">
+<rect width="23.998" height="22.2298" fill="white" transform="translate(0 0.885132)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/huggingface.svg b/app/components/base/icons/assets/public/llm/huggingface.svg
new file mode 100644
index 0000000..5a444f1
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/huggingface.svg
@@ -0,0 +1,19 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.9286 20.2062C16.7767 20.2062 20.7069 16.2761 20.7069 11.428C20.7069 6.57993 16.7767 2.64978 11.9286 2.64978C7.08054 2.64978 3.15039 6.57993 3.15039 11.428C3.15039 16.2761 7.08054 20.2062 11.9286 20.2062Z" fill="#FFD21E"/>
+<path d="M20.7095 11.4326C20.7095 6.58451 16.7793 2.65436 11.9313 2.65436C7.08318 2.65436 3.15303 6.58451 3.15303 11.4326C3.15303 16.2807 7.08318 20.2108 11.9313 20.2108C16.7793 20.2108 20.7095 16.2807 20.7095 11.4326ZM2.14258 11.4326C2.14258 6.02647 6.52511 1.64392 11.9313 1.64392C17.3374 1.64392 21.7199 6.02647 21.7199 11.4326C21.7199 16.8387 17.3374 21.2213 11.9313 21.2213C6.52511 21.2213 2.14258 16.8387 2.14258 11.4326Z" fill="#FF9D0B"/>
+<path d="M14.7822 9.03703C15.1041 9.1507 15.2322 9.81254 15.5574 9.6396C16.1734 9.31212 16.4072 8.54734 16.0797 7.93142C15.7522 7.31553 14.9874 7.08172 14.3715 7.4092C13.7556 7.73669 13.5218 8.50147 13.8493 9.11738C14.0038 9.40809 14.4944 8.9354 14.7822 9.03703Z" fill="#3A3B45"/>
+<path d="M8.83422 9.03703C8.5123 9.1507 8.38422 9.81254 8.05901 9.6396C7.4431 9.31212 7.20928 8.54734 7.53676 7.93142C7.86425 7.31553 8.62903 7.08172 9.24494 7.4092C9.86086 7.73669 10.0947 8.50147 9.76719 9.11738C9.61262 9.40809 9.122 8.9354 8.83422 9.03703Z" fill="#3A3B45"/>
+<path d="M11.8679 15.1044C14.3507 15.1044 15.1519 12.8908 15.1519 11.7541C15.1519 11.1633 14.7547 11.3492 14.1187 11.6641C13.5309 11.9551 12.739 12.3563 11.8679 12.3563C10.0543 12.3563 8.58398 10.6173 8.58398 11.7541C8.58398 12.8908 9.38514 15.1044 11.8679 15.1044Z" fill="#3A3B45"/>
+<mask id="mask0_8587_60183" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="8" y="11" width="8" height="5">
+<path d="M11.8562 15.1005C14.339 15.1005 15.1402 12.8869 15.1402 11.7502C15.1402 11.1594 14.743 11.3453 14.1069 11.6602C13.5191 11.9512 12.7273 12.3524 11.8562 12.3524C10.0425 12.3524 8.57227 10.6134 8.57227 11.7502C8.57227 12.8869 9.37342 15.1005 11.8562 15.1005Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_8587_60183)">
+<path d="M11.9194 17.6824C13.1294 17.6824 14.1103 16.7016 14.1103 15.4916C14.1103 14.5491 13.5152 13.7457 12.6803 13.4364C12.6496 13.425 12.6185 13.4143 12.5872 13.4043C12.3766 13.337 12.1523 14.0606 11.9194 14.0606C11.7018 14.0606 11.4917 13.3324 11.2933 13.3915C10.3884 13.6609 9.72852 14.4991 9.72852 15.4916C9.72852 16.7016 10.7094 17.6824 11.9194 17.6824Z" fill="#F94040"/>
+</g>
+<path d="M17.8698 10.2273C18.3232 10.2273 18.6908 9.85972 18.6908 9.40631C18.6908 8.9529 18.3232 8.58533 17.8698 8.58533C17.4164 8.58533 17.0488 8.9529 17.0488 9.40631C17.0488 9.85972 17.4164 10.2273 17.8698 10.2273Z" fill="#FF9D0B"/>
+<path d="M6.11981 10.2273C6.57323 10.2273 6.9408 9.85972 6.9408 9.40631C6.9408 8.9529 6.57323 8.58533 6.11981 8.58533C5.66638 8.58533 5.29883 8.9529 5.29883 9.40631C5.29883 9.85972 5.66638 10.2273 6.11981 10.2273Z" fill="#FF9D0B"/>
+<path d="M4.42915 13.0092C4.02018 13.0092 3.65465 13.1771 3.39976 13.4818C3.24214 13.6705 3.07743 13.9746 3.06404 14.4301C2.89252 14.3808 2.72757 14.3533 2.57347 14.3533C2.18193 14.3533 1.82827 14.5033 1.57819 14.7759C1.25687 15.1258 1.11414 15.5557 1.17628 15.9859C1.20584 16.1908 1.2743 16.3744 1.3766 16.5444C1.16087 16.719 1.00198 16.962 0.925188 17.2543C0.865067 17.4834 0.803429 17.9606 1.12526 18.4522C1.10479 18.4842 1.0856 18.5176 1.06766 18.5517C0.874161 18.919 0.861783 19.334 1.03255 19.7205C1.29147 20.3063 1.93487 20.7678 3.18429 21.2632C3.96157 21.5714 4.67267 21.7684 4.67899 21.7702C5.70661 22.0367 6.63596 22.1721 7.44053 22.1721C8.91931 22.1721 9.97801 21.7192 10.5873 20.8259C11.5679 19.3876 11.4277 18.072 10.1589 16.8039C9.45662 16.1021 8.98979 15.0674 8.89254 14.8403C8.69651 14.1679 8.17815 13.4204 7.3165 13.4204C7.244 13.4204 7.17049 13.4262 7.09824 13.4376C6.72084 13.4969 6.39093 13.7142 6.15525 14.0411C5.90087 13.7248 5.65381 13.4732 5.43025 13.3312C5.09327 13.1175 4.75654 13.0092 4.42915 13.0092ZM4.42915 14.0196C4.55799 14.0196 4.71536 14.0744 4.88891 14.1846C5.42773 14.5263 6.46747 16.3136 6.84816 17.0087C6.97573 17.2417 7.19373 17.3402 7.39001 17.3402C7.77953 17.3402 8.08368 16.9529 7.42563 16.4608C6.43615 15.7204 6.78324 14.5102 7.25562 14.4356C7.27633 14.4324 7.29679 14.4308 7.3165 14.4308C7.74594 14.4308 7.93539 15.171 7.93539 15.171C7.93539 15.171 8.49063 16.5654 9.44449 17.5185C10.3984 18.4719 10.4476 19.237 9.75243 20.2566C9.27828 20.9517 8.37064 21.1617 7.44053 21.1617C6.47581 21.1617 5.48684 20.9358 4.93261 20.7921C4.90533 20.785 1.53474 19.8329 1.96165 19.0226C2.03339 18.8864 2.15161 18.8318 2.3004 18.8318C2.90162 18.8318 3.99517 19.7266 4.46528 19.7266C4.57036 19.7266 4.64438 19.6819 4.67469 19.5727C4.87501 18.8541 1.62896 18.5519 1.90254 17.5109C1.95079 17.3268 2.08164 17.252 2.26554 17.2523C3.06 17.2523 4.84243 18.6495 5.21604 18.6495C5.24458 18.6495 5.26504 18.6411 5.27616 18.6234C5.46334 18.3213 5.36078 18.1104 4.0414 17.3119C2.72201 16.5131 1.79594 16.0327 2.32263 15.4592C2.38326 15.393 2.46915 15.3637 2.57347 15.3637C3.3745 15.364 5.26706 17.0863 5.26706 17.0863C5.26706 17.0863 5.77784 17.6175 6.08679 17.6175C6.15777 17.6175 6.21814 17.5895 6.25907 17.5203C6.47808 17.151 4.22479 15.4433 4.09773 14.7388C4.01159 14.2613 4.1581 14.0196 4.42915 14.0196Z" fill="#FF9D0B"/>
+<path d="M9.75883 20.2539C10.454 19.2344 10.4048 18.4692 9.4509 17.5159C8.49704 16.5628 7.9418 15.1684 7.9418 15.1684C7.9418 15.1684 7.73441 14.3585 7.26203 14.433C6.78964 14.5075 6.44281 15.7178 7.43228 16.4582C8.42176 17.1984 7.23525 17.7013 6.85456 17.0061C6.47388 16.3109 5.43438 14.5237 4.89531 14.1819C4.35649 13.8402 3.97707 14.0316 4.10414 14.7362C4.2312 15.4407 6.48474 17.1483 6.26547 17.5179C6.04621 17.8872 5.27347 17.0837 5.27347 17.0837C5.27347 17.0837 2.85548 14.8832 2.32903 15.4566C1.80258 16.03 2.72842 16.5105 4.0478 17.3093C5.36744 18.1078 5.46975 18.3187 5.28257 18.6208C5.09513 18.9229 2.18251 16.4673 1.90893 17.5083C1.63561 18.5493 4.88142 18.8514 4.6811 19.5701C4.48078 20.2891 2.3947 18.2098 1.96804 19.0199C1.54113 19.8303 4.91173 20.7824 4.93901 20.7895C6.02777 21.0719 8.79285 21.6703 9.75883 20.2539Z" fill="#FFD21E"/>
+<path d="M19.5568 13.0092C19.9658 13.0092 20.3313 13.1771 20.5862 13.4818C20.7439 13.6705 20.9086 13.9746 20.9219 14.4301C21.0935 14.3808 21.2584 14.3533 21.4125 14.3533C21.8041 14.3533 22.1577 14.5033 22.4078 14.7759C22.7291 15.1258 22.8718 15.5557 22.8097 15.9859C22.7802 16.1908 22.7117 16.3744 22.6094 16.5444C22.8251 16.719 22.984 16.962 23.0608 17.2543C23.1209 17.4834 23.1826 17.9606 22.8607 18.4522C22.8812 18.4842 22.9004 18.5176 22.9183 18.5517C23.1118 18.919 23.1242 19.334 22.9534 19.7205C22.6945 20.3063 22.0511 20.7678 20.8017 21.2632C20.0244 21.5714 19.3133 21.7684 19.307 21.7702C18.2794 22.0367 17.35 22.1721 16.5455 22.1721C15.0667 22.1721 14.008 21.7192 13.3987 20.8259C12.418 19.3876 12.5582 18.072 13.8271 16.8039C14.5294 16.1021 14.9962 15.0674 15.0935 14.8403C15.2895 14.1679 15.8078 13.4204 16.6695 13.4204C16.742 13.4204 16.8155 13.4262 16.8877 13.4376C17.2651 13.4969 17.5951 13.7142 17.8307 14.0411C18.0851 13.7248 18.3322 13.4732 18.5557 13.3312C18.8927 13.1175 19.2295 13.0092 19.5568 13.0092ZM19.5568 14.0196C19.428 14.0196 19.2706 14.0744 19.0971 14.1846C18.5583 14.5263 17.5185 16.3136 17.1378 17.0087C17.0103 17.2417 16.7923 17.3402 16.596 17.3402C16.2065 17.3402 15.9023 16.9529 16.5604 16.4608C17.5498 15.7204 17.2028 14.5102 16.7304 14.4356C16.7097 14.4324 16.6892 14.4308 16.6695 14.4308C16.2401 14.4308 16.0506 15.171 16.0506 15.171C16.0506 15.171 15.4954 16.5654 14.5415 17.5185C13.5876 18.4719 13.5384 19.237 14.2336 20.2566C14.7077 20.9517 15.6153 21.1617 16.5455 21.1617C17.5102 21.1617 18.4992 20.9358 19.0534 20.7921C19.0807 20.785 22.4513 19.8329 22.0243 19.0226C21.9526 18.8864 21.8344 18.8318 21.6856 18.8318C21.0844 18.8318 19.9908 19.7266 19.5207 19.7266C19.4156 19.7266 19.3416 19.6819 19.3113 19.5727C19.111 18.8541 22.357 18.5519 22.0835 17.5109C22.0352 17.3268 21.9043 17.252 21.7204 17.2523C20.926 17.2523 19.1436 18.6495 18.77 18.6495C18.7414 18.6495 18.7209 18.6411 18.7098 18.6234C18.5226 18.3213 18.6252 18.1104 19.9446 17.3119C21.264 16.5131 22.1901 16.0327 21.6634 15.4592C21.6027 15.393 21.5168 15.3637 21.4125 15.3637C20.6115 15.364 18.7189 17.0863 18.7189 17.0863C18.7189 17.0863 18.2081 17.6175 17.8992 17.6175C17.8282 17.6175 17.7678 17.5895 17.7269 17.5203C17.5079 17.151 19.7612 15.4433 19.8883 14.7388C19.9744 14.2613 19.8279 14.0196 19.5568 14.0196Z" fill="#FF9D0B"/>
+<path d="M14.2354 20.2539C13.5402 19.2344 13.5895 18.4692 14.5433 17.5159C15.4972 16.5628 16.0524 15.1684 16.0524 15.1684C16.0524 15.1684 16.2598 14.3585 16.7322 14.433C17.2046 14.5075 17.5514 15.7178 16.5619 16.4582C15.5724 17.1984 16.759 17.7013 17.1396 17.0061C17.5203 16.3109 18.5598 14.5237 19.0989 14.1819C19.6377 13.8402 20.0171 14.0316 19.8901 14.7362C19.763 15.4407 17.5095 17.1483 17.7287 17.5179C17.948 17.8872 18.7207 17.0837 18.7207 17.0837C18.7207 17.0837 21.1387 14.8832 21.6652 15.4566C22.1916 16.03 21.2658 16.5105 19.9464 17.3093C18.6268 18.1078 18.5245 18.3187 18.7116 18.6208C18.8991 18.9229 21.8117 16.4673 22.0853 17.5083C22.3586 18.5493 19.1128 18.8514 19.3131 19.5701C19.5134 20.2891 21.5995 18.2098 22.0262 19.0199C22.4531 19.8303 19.0825 20.7824 19.0552 20.7895C17.9664 21.0719 15.2014 21.6703 14.2354 20.2539Z" fill="#FFD21E"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/iflytek-spark-text-cn.svg b/app/components/base/icons/assets/public/llm/iflytek-spark-text-cn.svg
new file mode 100644
index 0000000..71d8521
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/iflytek-spark-text-cn.svg
@@ -0,0 +1,11 @@
+<svg width="84" height="24" viewBox="0 0 84 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M34.8763 7.49212H33.1466V11.557H34.4438V13.0273H33.1466V18.7137H31.1574V13.0489H29.752V11.5786H31.179V7.49212H29.8384V6.02185H36.952C37.2547 6.02185 37.4925 6.25969 37.4925 6.56239V17.33H38.4438L37.7736 18.7354L35.4817 18.757L35.4601 8.11915C35.4817 7.7732 35.2222 7.49212 34.8763 7.49212Z" fill="#2B2B2D"/>
+<path d="M26.1832 11.8599H25.3184V10.3896H27.6102C27.9129 10.3896 28.1508 10.6275 28.1508 10.9302L28.1724 17.3086H29.2319L28.5832 18.7356H26.7238C26.4211 18.7356 26.1832 18.4978 26.1832 18.1951V11.8599Z" fill="#2B2B2D"/>
+<path d="M28.1724 6.02185H25.3184V7.55699H28.1724V6.02185Z" fill="#2B2B2D"/>
+<path d="M50.1495 6.02162L45.5873 10.0865H48.6792L52.8306 6.02162H50.1495ZM49.09 11.773H46.1279L49.5873 15.5135H52.5495L49.09 11.773ZM43.4468 17.3514C43.2522 17.3514 43.1225 17.1784 43.1657 16.9838L45.89 6.69189C45.9765 6.34595 45.7171 6 45.3711 6H40.1387V7.44865H43.036C43.3171 7.44865 43.5333 7.72973 43.4468 7.98919L40.7873 18.0216C40.7008 18.3676 40.9603 18.7135 41.3062 18.7135H51.7927L52.5927 17.3297H43.4468V17.3514Z" fill="#2B2B2D"/>
+<path d="M62.2792 16.465H67.1224V15.3406H62.2792V14.2379H67.1224V13.1569H62.2792V12.2271H67.1224V10.4974V6.56227C67.1224 6.25957 66.8845 6.02173 66.5818 6.02173H55.5332V11.665C55.5332 11.9677 55.771 12.2055 56.0737 12.2055H57.0035L55.5332 14.2379H60.1602V15.3406H55.5548V16.465L60.1602 16.4433V17.3515H55.5548V18.7352H67.1008V17.3515H62.2575V16.465H62.2792ZM57.6305 9.78389H63.7927L64.3981 8.61632H57.6305V7.31903H65.0035V10.8866H57.6305V9.78389ZM60.1602 13.1352H58.3224L59.0359 12.2055H60.1602V13.1352Z" fill="#2B2B2D"/>
+<path d="M71.549 6.02173H69.4733L71.0085 12.2271H73.0842L71.549 6.02173ZM79.6788 6.02173L78.1436 12.2488H80.2409L81.776 6.02173H79.6788ZM76.6517 12.3136V6.02173H74.5112V12.3136L69.3652 18.7569H71.9814L75.6355 14.2379L79.3112 18.7785L81.949 18.7569L76.6517 12.3136Z" fill="#2B2B2D"/>
+<path d="M20.8854 16.4979C20.5611 17.6438 20.0206 18.6817 19.3287 19.5898C18.2908 20.8871 14.7233 20.8871 12.5827 20.3249C10.2692 19.6979 8.60434 18.2492 8.47461 18.1411C9.38272 18.8546 10.5287 19.2654 11.7827 19.2654C14.7881 19.2654 17.2097 16.8006 17.2097 13.7735C17.2097 12.8654 16.9935 12.0222 16.6043 11.2654C16.5827 11.2222 16.626 11.179 16.6476 11.2006C18.3557 11.4817 21.7503 13.0817 20.8854 16.4979Z" fill="#2751D0"/>
+<path d="M21.2102 12.6705C21.2102 12.7353 21.1454 12.7569 21.1021 12.6921C20.3021 10.984 18.8967 10.465 17.2102 10.0759C15.9346 9.79478 15.0913 9.36235 14.7238 9.16775C14.6373 9.12451 14.5724 9.05964 14.4859 9.0164C11.8264 7.39478 11.7832 4.60559 11.7832 4.60559V0.562346C11.7832 0.519102 11.8481 0.497481 11.8697 0.519102L18.1616 6.70289L18.6373 7.15694C20.021 8.62721 20.9724 10.5515 21.2102 12.6705Z" fill="#D82F20"/>
+<path d="M19.3286 19.5894C17.5989 21.8596 14.8745 23.3515 11.8043 23.3515C6.57182 23.3515 2.33398 19.0704 2.33398 13.7948C2.33398 11.2218 3.32858 8.90828 4.97182 7.17855L5.4475 6.70288L9.5556 2.65964C9.59885 2.61639 9.66371 2.65964 9.64209 2.70288C9.57723 2.98396 9.46912 3.63261 9.53398 4.49747C9.62047 5.51369 9.9448 6.87585 10.8961 8.38937C11.4799 9.34072 12.3232 10.3353 13.4907 11.3731C13.6205 11.5029 13.7718 11.611 13.9232 11.7407C14.4421 12.2813 14.7448 12.9948 14.7448 13.7948C14.7448 15.4164 13.4259 16.7353 11.8259 16.7353C11.134 16.7353 10.507 16.4975 10.0097 16.0867C9.96642 16.0434 10.0097 15.9786 10.0529 16.0002C10.161 16.0218 10.2691 16.0434 10.3772 16.0434C10.9394 16.0434 11.4151 15.5894 11.4151 15.0056C11.4151 14.6596 11.2421 14.3353 10.9826 14.1623C10.2907 13.6002 9.70695 13.0596 9.20966 12.5191C8.51777 11.7623 7.99885 11.0272 7.63128 10.3137C6.87453 11.265 6.39885 12.4542 6.39885 13.7731C6.39885 15.5461 7.22047 17.1245 8.51777 18.1191C8.6475 18.2272 10.3124 19.6759 12.6259 20.3029C14.7232 20.9083 18.2907 20.8867 19.3286 19.5894Z" fill="#69C5F4"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/iflytek-spark-text.svg b/app/components/base/icons/assets/public/llm/iflytek-spark-text.svg
new file mode 100644
index 0000000..521c68c
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/iflytek-spark-text.svg
@@ -0,0 +1,24 @@
+<svg width="150" height="24" viewBox="0 0 150 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_8587_60507)">
+<path d="M19.6552 16.7993C19.3116 18.0034 18.7389 19.0938 18.0059 20.048C16.9063 21.4111 13.1266 21.4111 10.8588 20.8204C8.40766 20.1616 6.64379 18.6395 6.50635 18.5259C7.46846 19.2756 8.68255 19.7072 10.0112 19.7072C13.1953 19.7072 15.7609 17.1174 15.7609 13.9368C15.7609 12.9826 15.5319 12.0966 15.1195 11.3015C15.0966 11.2561 15.1424 11.2106 15.1653 11.2333C16.975 11.5287 20.5715 13.2098 19.6552 16.7993Z" fill="#2751D0"/>
+<path d="M19.9994 12.7773C19.9994 12.8454 19.9306 12.8682 19.8848 12.8C19.0372 11.0053 17.5483 10.46 15.7615 10.0511C14.4099 9.75577 13.5166 9.3014 13.1271 9.09694C13.0355 9.0515 12.9668 8.98335 12.8751 8.93791C10.0575 7.23404 10.0117 4.30339 10.0117 4.30339V0.0550813C10.0117 0.00964486 10.0804 -0.0130733 10.1034 0.0096449L16.7694 6.50706L17.2734 6.98414C18.7394 8.52898 19.7474 10.5509 19.9994 12.7773Z" fill="#D82F20"/>
+<path d="M18.0052 20.0462C16.1726 22.4316 13.2863 23.9992 10.0334 23.9992C4.48985 23.9992 0 19.501 0 13.9577C0 11.2543 1.05374 8.8234 2.7947 7.00594L3.29866 6.50614L7.65107 2.25783C7.69688 2.2124 7.7656 2.25783 7.7427 2.30327C7.67397 2.59861 7.55944 3.28015 7.62816 4.18888C7.71979 5.25664 8.06341 6.68789 9.07133 8.27817C9.68983 9.27777 10.5832 10.3228 11.8202 11.4133C11.9577 11.5496 12.118 11.6632 12.2784 11.7995C12.8281 12.3674 13.1488 13.1171 13.1488 13.9577C13.1488 15.6616 11.7515 17.0474 10.0563 17.0474C9.32331 17.0474 8.659 16.7975 8.13213 16.3659C8.08631 16.3204 8.13212 16.2523 8.17794 16.275C8.29247 16.2977 8.40701 16.3204 8.52155 16.3204C9.11714 16.3204 9.62111 15.8433 9.62111 15.2299C9.62111 14.8665 9.43785 14.5257 9.16296 14.3439C8.42992 13.7533 7.81142 13.1853 7.28455 12.6173C6.55151 11.8222 6.00174 11.0498 5.61231 10.3001C4.81055 11.2997 4.30659 12.5492 4.30659 13.935C4.30659 15.7979 5.17707 17.4563 6.55152 18.5014C6.68896 18.615 8.45283 20.1371 10.9039 20.7959C13.1259 21.432 16.9057 21.4093 18.0052 20.0462Z" fill="#69C5F4"/>
+<path d="M27 10.0997V16.3997H29.008V10.0997H27ZM27 7.89966V9.29966H29.008V7.89966H27Z" fill="#2B2B2D"/>
+<path d="M39.1482 9.09927V7.49927H31.0156V16.2993H33.2245V12.8993H38.8469V11.2993H33.2245V9.09927H39.1482Z" fill="#2B2B2D"/>
+<path d="M43.367 14.6993V7.49927H41.1582V16.2993H48.2867V14.6993H43.367Z" fill="#2B2B2D"/>
+<path d="M55.2168 7.60083L52.6064 11.3008L49.9959 7.60083H47.2852L51.502 13.1008V16.4008H53.7108V13.1008L57.9277 7.60083H55.2168Z" fill="#2B2B2D"/>
+<path d="M58.9316 7.60083V9.20083H62.2449V16.4008H64.4537V9.20083H67.6666V7.60083H58.9316Z" fill="#2B2B2D"/>
+<path d="M71.8827 14.7993V12.6993H77.7059V11.0993H71.8827V9.09927H77.9067V7.49927H69.6738V16.2993H78.1075V14.6993H71.8827V14.7993Z" fill="#2B2B2D"/>
+<path d="M85.1353 11.3008L89.4526 7.60083H86.6413L82.3241 11.4008V7.60083H80.1152V16.4008H82.3241V13.8008L83.6293 12.7008L87.0429 16.5008H89.9546L85.1353 11.3008Z" fill="#2B2B2D"/>
+<path d="M103.167 11.4C102.866 11.3 102.564 11.2001 101.962 11.1001C101.36 11.0001 99.7532 10.8001 99.1508 10.6001C98.7492 10.5001 98.448 10.3 98.448 9.80005C98.448 8.90005 99.6528 8.80005 99.6528 8.80005C99.954 8.80005 100.255 8.80005 100.356 8.80005C101.159 8.80005 102.163 8.90005 102.665 9.60005C102.765 9.70005 102.765 9.70005 102.866 9.90005L104.974 9.40005C104.773 9.10005 104.673 8.90005 104.372 8.60005C103.97 8.20005 103.468 8.00005 103.267 7.90005C102.665 7.60005 101.862 7.30005 100.356 7.30005C98.7492 7.30005 97.8456 7.70005 97.3436 8.10005C97.0423 8.30005 96.2392 8.90005 96.2392 10.1001C96.2392 11.4001 97.2431 12.0001 97.6447 12.2001C98.3476 12.5001 99.2512 12.7 100.858 12.9C101.661 13 102.263 13.1 102.464 13.3C102.665 13.4 102.765 13.6 102.765 13.9C102.765 14.3 102.464 14.6001 102.364 14.7001C101.761 15.1001 100.657 15.1001 100.556 15.1001C99.452 15.1001 98.1468 14.8001 97.6447 13.7001L95.6367 14.2001C95.7371 14.3001 95.7371 14.4001 95.8375 14.6001C95.9379 14.8001 96.2392 15.3001 96.7412 15.6001C97.0424 15.8001 97.2432 15.9001 97.3436 16.0001C97.946 16.3001 98.8496 16.7001 100.456 16.7001C100.757 16.7001 101.058 16.7001 101.36 16.7001C101.862 16.7001 102.364 16.6 102.765 16.4C104.572 15.8 104.874 14.6 104.874 13.8C104.974 12.1 103.669 11.6 103.167 11.4Z" fill="#2B2B2D"/>
+<path d="M115.318 8.80083C114.816 8.00083 114.012 7.70083 113.109 7.60083C112.908 7.60083 112.607 7.60083 112.406 7.60083H106.984V16.4008H109.193V13.1008H112.306C113.109 13.1008 114.012 13.1008 114.615 12.7008C114.916 12.5008 115.117 12.3008 115.217 12.2008C115.418 12.0008 115.518 11.8008 115.518 11.7008C115.719 11.2008 115.719 10.6008 115.719 10.4008C115.719 9.50083 115.518 9.00083 115.318 8.80083ZM112.908 11.4008C112.607 11.5008 112.205 11.5008 111.804 11.5008H109.093V9.10083H112.205C112.506 9.10083 112.607 9.10083 112.707 9.20083C113.41 9.40083 113.41 10.2008 113.41 10.4008C113.51 10.5008 113.51 11.1008 112.908 11.4008Z" fill="#2B2B2D"/>
+<path d="M122.345 7.60083H119.936L115.719 16.4008H118.128L118.831 14.7008H123.349L124.052 16.4008H126.562L122.345 7.60083ZM119.634 13.1008L121.241 9.70083L122.747 13.1008H119.634Z" fill="#2B2B2D"/>
+<path d="M134.594 12.6993C135.498 12.4993 136.301 12.2993 136.703 11.3993C136.904 10.8993 136.904 10.4993 136.904 10.1993C136.904 8.99926 136.301 8.09926 135.097 7.69926C134.695 7.59926 134.394 7.49927 133.59 7.49927H127.566V16.2993H129.775V12.7993H132.285L134.594 16.2993H137.205L134.594 12.6993ZM133.892 11.1993C133.691 11.1993 133.39 11.1993 133.39 11.1993H129.876V9.09927H133.39C133.791 9.09927 134.293 9.09927 134.594 9.49927C134.795 9.69927 134.795 10.0993 134.795 10.1993C134.695 10.8993 134.193 11.1993 133.892 11.1993Z" fill="#2B2B2D"/>
+<path d="M144.335 11.3008L148.653 7.60083H145.841L141.524 11.4008V7.60083H139.215V16.4008H141.424V13.8008L142.729 12.7008L146.143 16.5008H149.054L144.335 11.3008Z" fill="#2B2B2D"/>
+</g>
+<defs>
+<clipPath id="clip0_8587_60507">
+<rect width="150" height="24" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/iflytek-spark.svg b/app/components/base/icons/assets/public/llm/iflytek-spark.svg
new file mode 100644
index 0000000..ef0a913
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/iflytek-spark.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M21.6547 16.7993C21.3111 18.0034 20.7384 19.0938 20.0054 20.048C18.9058 21.4111 15.1261 21.4111 12.8583 20.8204C10.4072 20.1616 8.6433 18.6395 8.50586 18.5259C9.46797 19.2756 10.6821 19.7072 12.0107 19.7072C15.1948 19.7072 17.7605 17.1174 17.7605 13.9368C17.7605 12.9826 17.5314 12.0966 17.119 11.3015C17.0961 11.2561 17.1419 11.2106 17.1649 11.2333C18.9745 11.5287 22.571 13.2098 21.6547 16.7993Z" fill="#2751D0"/>
+<path d="M21.9994 12.7773C21.9994 12.8454 21.9306 12.8682 21.8848 12.8C21.0372 11.0053 19.5483 10.46 17.7615 10.0511C16.4099 9.75577 15.5166 9.3014 15.1271 9.09694C15.0355 9.0515 14.9668 8.98335 14.8751 8.93791C12.0575 7.23404 12.0117 4.30339 12.0117 4.30339V0.0550813C12.0117 0.00964486 12.0804 -0.0130733 12.1034 0.0096449L18.7694 6.50706L19.2734 6.98414C20.7394 8.52898 21.7474 10.5509 21.9994 12.7773Z" fill="#D82F20"/>
+<path d="M20.0052 20.0462C18.1726 22.4316 15.2863 23.9992 12.0334 23.9992C6.48985 23.9992 2 19.501 2 13.9577C2 11.2543 3.05374 8.8234 4.7947 7.00594L5.29866 6.50614L9.65107 2.25783C9.69688 2.2124 9.7656 2.25783 9.7427 2.30327C9.67397 2.59861 9.55944 3.28015 9.62816 4.18888C9.71979 5.25664 10.0634 6.68789 11.0713 8.27817C11.6898 9.27777 12.5832 10.3228 13.8202 11.4133C13.9577 11.5496 14.118 11.6632 14.2784 11.7995C14.8281 12.3674 15.1488 13.1171 15.1488 13.9577C15.1488 15.6616 13.7515 17.0474 12.0563 17.0474C11.3233 17.0474 10.659 16.7975 10.1321 16.3659C10.0863 16.3204 10.1321 16.2523 10.1779 16.275C10.2925 16.2977 10.407 16.3204 10.5215 16.3204C11.1171 16.3204 11.6211 15.8433 11.6211 15.2299C11.6211 14.8665 11.4378 14.5257 11.163 14.3439C10.4299 13.7533 9.81142 13.1853 9.28455 12.6173C8.55151 11.8222 8.00174 11.0498 7.61231 10.3001C6.81055 11.2997 6.30659 12.5492 6.30659 13.935C6.30659 15.7979 7.17707 17.4563 8.55152 18.5014C8.68896 18.615 10.4528 20.1371 12.9039 20.7959C15.1259 21.432 18.9057 21.4093 20.0052 20.0462Z" fill="#69C5F4"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/jina-text.svg b/app/components/base/icons/assets/public/llm/jina-text.svg
new file mode 100644
index 0000000..6a241fc
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/jina-text.svg
@@ -0,0 +1,12 @@
+<svg width="58" height="24" viewBox="0 0 58 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_13814_61529)">
+<path d="M4.47132 23.952C6.49932 23.952 8.14332 22.308 8.14332 20.28C8.14332 18.252 6.49932 16.608 4.47132 16.608C2.44332 16.608 0.799316 18.252 0.799316 20.28C0.799316 22.308 2.44332 23.952 4.47132 23.952Z" fill="#EB6161"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16.0387 8.71204C16.5187 8.71204 16.9027 9.09604 16.9027 9.57604L16.8547 16.608C16.8547 20.616 13.6387 23.88 9.63074 23.952H9.51074V16.632H9.53474L9.55874 9.60004C9.55874 9.12004 9.94274 8.73604 10.4227 8.73604H16.0387V8.71204ZM27.3187 8.71204C27.7987 8.71204 28.1827 9.09604 28.1827 9.57604V19.416C28.1827 19.896 27.7987 20.28 27.3187 20.28H21.7027C21.2227 20.28 20.8387 19.896 20.8387 19.416V9.57604C20.8387 9.09604 21.2227 8.71204 21.7027 8.71204H27.3187ZM36.1507 8.68804H36.2707C39.8707 8.73604 42.7987 11.64 42.8947 15.24V19.392C42.8947 19.872 42.5107 20.256 42.0307 20.256H32.9587C32.4787 20.256 32.0947 19.872 32.0947 19.392V9.55204C32.0947 9.07204 32.4787 8.68804 32.9587 8.68804H36.1507ZM51.0067 20.16C47.9827 19.968 45.5587 17.448 45.5587 14.376C45.5587 11.184 48.1507 8.59204 51.3427 8.59204C54.4147 8.59204 56.9347 10.992 57.1267 14.04V19.296C57.1267 19.776 56.7427 20.16 56.2627 20.16H51.0067Z" fill="#009191"/>
+<path d="M24.4987 7.344C26.5267 7.344 28.1707 5.7 28.1707 3.672C28.1707 1.644 26.5267 0 24.4987 0C22.4707 0 20.8267 1.644 20.8267 3.672C20.8267 5.7 22.4707 7.344 24.4987 7.344Z" fill="#FBCB67"/>
+</g>
+<defs>
+<clipPath id="clip0_13814_61529">
+<rect width="56.4" height="24" fill="white" transform="translate(0.800781)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/jina.svg b/app/components/base/icons/assets/public/llm/jina.svg
new file mode 100644
index 0000000..2e1b00f
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/jina.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6.56053 21.4486C9.07925 21.4486 11.1211 19.4068 11.1211 16.8882C11.1211 14.3696 9.07925 12.3279 6.56053 12.3279C4.04182 12.3279 2 14.3696 2 16.8882C2 19.4068 4.04182 21.4486 6.56053 21.4486Z" fill="#EB6161"/>
+<path d="M22.0002 3.59467L21.9406 12.3279C21.9406 17.3055 17.9464 21.3591 12.9685 21.4485L12.8789 12.3577L12.8791 3.62447C12.8791 3.02835 13.356 2.55145 13.9522 2.55145H20.9271C21.5233 2.55145 22.0002 2.99854 22.0002 3.59467Z" fill="#009191"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/localai-text.svg b/app/components/base/icons/assets/public/llm/localai-text.svg
new file mode 100644
index 0000000..251a37f
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/localai-text.svg
@@ -0,0 +1,22 @@
+<svg width="90" height="24" viewBox="0 0 90 24" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g clip-path="url(#clip0_10164_6324)">
+<rect width="24" height="24" rx="4" fill="#1E0122"/>
+<rect width="24" height="24" fill="url(#pattern0)"/>
+</g>
+<path d="M33.0242 16.528H36.7842V18H31.2002V6.88003H33.0242V16.528Z" fill="#1C2B33"/>
+<path d="M41.8136 18.144C40.9816 18.144 40.2296 17.9574 39.5576 17.584C38.8856 17.2 38.3576 16.6667 37.9736 15.984C37.5896 15.2907 37.3976 14.4907 37.3976 13.584C37.3976 12.688 37.5949 11.8934 37.9896 11.2C38.3842 10.5067 38.9229 9.97337 39.6056 9.60003C40.2882 9.2267 41.0509 9.04003 41.8936 9.04003C42.7362 9.04003 43.4989 9.2267 44.1816 9.60003C44.8642 9.97337 45.4029 10.5067 45.7976 11.2C46.1922 11.8934 46.3896 12.688 46.3896 13.584C46.3896 14.48 46.1869 15.2747 45.7816 15.968C45.3762 16.6614 44.8216 17.2 44.1176 17.584C43.4242 17.9574 42.6562 18.144 41.8136 18.144ZM41.8136 16.56C42.2829 16.56 42.7202 16.448 43.1256 16.224C43.5416 16 43.8776 15.664 44.1336 15.216C44.3896 14.768 44.5176 14.224 44.5176 13.584C44.5176 12.944 44.3949 12.4054 44.1496 11.968C43.9042 11.52 43.5789 11.184 43.1736 10.96C42.7682 10.736 42.3309 10.624 41.8616 10.624C41.3922 10.624 40.9549 10.736 40.5496 10.96C40.1549 11.184 39.8402 11.52 39.6056 11.968C39.3709 12.4054 39.2536 12.944 39.2536 13.584C39.2536 14.5334 39.4936 15.2694 39.9736 15.792C40.4642 16.304 41.0776 16.56 41.8136 16.56Z" fill="#1C2B33"/>
+<path d="M47.2647 13.584C47.2647 12.6774 47.446 11.8827 47.8087 11.2C48.182 10.5067 48.694 9.97337 49.3447 9.60003C49.9954 9.2267 50.742 9.04003 51.5847 9.04003C52.6514 9.04003 53.5314 9.29603 54.2247 9.80803C54.9287 10.3094 55.4034 11.0294 55.6487 11.968H53.6807C53.5207 11.5307 53.2647 11.1894 52.9127 10.944C52.5607 10.6987 52.118 10.576 51.5847 10.576C50.838 10.576 50.2407 10.8427 49.7927 11.376C49.3554 11.8987 49.1367 12.6347 49.1367 13.584C49.1367 14.5334 49.3554 15.2747 49.7927 15.808C50.2407 16.3414 50.838 16.608 51.5847 16.608C52.6407 16.608 53.3394 16.144 53.6807 15.216H55.6487C55.3927 16.112 54.9127 16.8267 54.2087 17.36C53.5047 17.8827 52.63 18.144 51.5847 18.144C50.742 18.144 49.9954 17.9574 49.3447 17.584C48.694 17.2 48.182 16.6667 47.8087 15.984C47.446 15.2907 47.2647 14.4907 47.2647 13.584Z" fill="#1C2B33"/>
+<path d="M56.5384 13.552C56.5384 12.6667 56.7198 11.8827 57.0824 11.2C57.4558 10.5174 57.9571 9.98937 58.5864 9.61603C59.2264 9.23203 59.9304 9.04003 60.6984 9.04003C61.3918 9.04003 61.9944 9.1787 62.5064 9.45603C63.0291 9.7227 63.4451 10.0587 63.7544 10.464V9.18403H65.5944V18H63.7544V16.688C63.4451 17.104 63.0238 17.4507 62.4904 17.728C61.9571 18.0054 61.3491 18.144 60.6664 18.144C59.9091 18.144 59.2158 17.952 58.5864 17.568C57.9571 17.1734 57.4558 16.6294 57.0824 15.936C56.7198 15.232 56.5384 14.4374 56.5384 13.552ZM63.7544 13.584C63.7544 12.976 63.6264 12.448 63.3704 12C63.1251 11.552 62.7998 11.2107 62.3944 10.976C61.9891 10.7414 61.5518 10.624 61.0824 10.624C60.6131 10.624 60.1758 10.7414 59.7704 10.976C59.3651 11.2 59.0344 11.536 58.7784 11.984C58.5331 12.4214 58.4104 12.944 58.4104 13.552C58.4104 14.16 58.5331 14.6934 58.7784 15.152C59.0344 15.6107 59.3651 15.9627 59.7704 16.208C60.1864 16.4427 60.6238 16.56 61.0824 16.56C61.5518 16.56 61.9891 16.4427 62.3944 16.208C62.7998 15.9734 63.1251 15.632 63.3704 15.184C63.6264 14.7254 63.7544 14.192 63.7544 13.584Z" fill="#1C2B33"/>
+<path d="M69.4942 6.16003V18H67.6702V6.16003H69.4942Z" fill="#1C2B33"/>
+<path d="M78.2729 15.728H73.6169L72.8169 18H70.9129L74.8969 6.86403H77.0089L80.9929 18H79.0729L78.2729 15.728ZM77.7609 14.24L75.9529 9.07203L74.1289 14.24H77.7609Z" fill="#1C2B33"/>
+<path d="M84.2292 6.88003V18H82.4052V6.88003H84.2292Z" fill="#1C2B33"/>
+<defs>
+<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
+<use xlink:href="#image0_10164_6324" transform="scale(0.00390625)"/>
+</pattern>
+<clipPath id="clip0_10164_6324">
+<rect width="24" height="24" rx="4" fill="white"/>
+</clipPath>
+<image id="image0_10164_6324" width="256" height="256" xlink:href="data:image/jpeg;base64,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"/>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/localai.svg b/app/components/base/icons/assets/public/llm/localai.svg
new file mode 100644
index 0000000..9dc6e62
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/localai.svg
@@ -0,0 +1,15 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g clip-path="url(#clip0_10164_6300)">
+<rect width="24" height="24" rx="4" fill="#1C0120"/>
+<rect width="24" height="24" fill="url(#pattern0)"/>
+</g>
+<defs>
+<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
+<use xlink:href="#image0_10164_6300" transform="scale(0.00390625)"/>
+</pattern>
+<clipPath id="clip0_10164_6300">
+<rect width="24" height="24" rx="4" fill="white"/>
+</clipPath>
+<image id="image0_10164_6300" width="256" height="256" xlink:href="data:image/jpeg;base64,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"/>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/microsoft.svg b/app/components/base/icons/assets/public/llm/microsoft.svg
new file mode 100644
index 0000000..df1f54f
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/microsoft.svg
@@ -0,0 +1,8 @@
+<svg width="21" height="22" viewBox="0 0 21 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Microsoft">
+<rect id="Rectangle 1010" y="0.5" width="10" height="10" fill="#EF4F21"/>
+<rect id="Rectangle 1012" y="11.5" width="10" height="10" fill="#03A4EE"/>
+<rect id="Rectangle 1011" x="11" y="0.5" width="10" height="10" fill="#7EB903"/>
+<rect id="Rectangle 1013" x="11" y="11.5" width="10" height="10" fill="#FBB604"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/openai-black.svg b/app/components/base/icons/assets/public/llm/openai-black.svg
new file mode 100644
index 0000000..c8fb1c5
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/openai-black.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="black"/>
+<path d="M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z" fill="white"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/openai-blue.svg b/app/components/base/icons/assets/public/llm/openai-blue.svg
new file mode 100644
index 0000000..ccd75ec
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/openai-blue.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="#03A4EE"/>
+<path d="M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z" fill="white"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/openai-green.svg b/app/components/base/icons/assets/public/llm/openai-green.svg
new file mode 100644
index 0000000..70686f9
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/openai-green.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="#19C37D"/>
+<path d="M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z" fill="white"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/openai-text.svg b/app/components/base/icons/assets/public/llm/openai-text.svg
new file mode 100644
index 0000000..be38813
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/openai-text.svg
@@ -0,0 +1,8 @@
+<svg width="52" height="20" viewBox="0 0 52 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0.00390625 8.70054C0.00390625 12.058 2.16008 14.399 5.14793 14.399C8.13577 14.399 10.2919 12.058 10.2919 8.70054C10.2919 5.34307 8.13577 3.00208 5.14793 3.00208C2.16008 3.00208 0.00390625 5.34307 0.00390625 8.70054ZM8.32058 8.70054C8.32058 11.1031 7.01148 12.6587 5.14793 12.6587C3.28437 12.6587 1.97527 11.1031 1.97527 8.70054C1.97527 6.29794 3.28437 4.74242 5.14793 4.74242C7.01148 4.74242 8.32058 6.29794 8.32058 8.70054Z" fill="black" fill-opacity="0.92"/>
+<path d="M15.8456 14.3975C18.1096 14.3975 19.4033 12.4877 19.4033 10.1929C19.4033 7.89816 18.1096 5.9884 15.8456 5.9884C14.7983 5.9884 14.0283 6.40424 13.52 7.00489V6.14242H11.6719V17.0003H13.52V13.381C14.0283 13.9817 14.7983 14.3975 15.8456 14.3975ZM13.4738 9.96193C13.4738 8.4372 14.3363 7.60554 15.476 7.60554C16.8159 7.60554 17.5398 8.65282 17.5398 10.1929C17.5398 11.7331 16.8159 12.7804 15.476 12.7804C14.3363 12.7804 13.4738 11.9333 13.4738 10.4394V9.96193Z" fill="black" fill-opacity="0.92"/>
+<path d="M24.4039 14.3975C26.021 14.3975 27.2993 13.5504 27.8692 12.1335L26.2828 11.5329C26.0364 12.3645 25.3126 12.8266 24.4039 12.8266C23.218 12.8266 22.3863 11.9795 22.2477 10.5934H27.9154V9.97733C27.9154 7.75955 26.6679 5.9884 24.3269 5.9884C21.9859 5.9884 20.4766 7.82115 20.4766 10.1929C20.4766 12.6879 22.0937 14.3975 24.4039 14.3975ZM24.3115 7.54393C25.482 7.54393 26.0364 8.31399 26.0518 9.20727H22.3401C22.6173 8.11378 23.3566 7.54393 24.3115 7.54393Z" fill="black" fill-opacity="0.92"/>
+<path d="M29.3008 14.2281H31.1489V9.48449C31.1489 8.32939 31.996 7.71334 32.8277 7.71334C33.8442 7.71334 34.2446 8.4372 34.2446 9.43828V14.2281H36.0927V8.89924C36.0927 7.1589 35.0763 5.9884 33.3821 5.9884C32.3348 5.9884 31.611 6.46584 31.1489 7.00489V6.14242H29.3008V14.2281Z" fill="black" fill-opacity="0.92"/>
+<path d="M41.5095 3.172L37.3203 14.2301H39.2763L40.2157 11.7043H44.9901L45.945 14.2301H47.9318L43.7426 3.172H41.5095ZM42.5875 5.35898L44.3433 9.97935H40.8626L42.5875 5.35898Z" fill="black" fill-opacity="0.92"/>
+<path d="M51.1042 3.20325H49.1328V14.2613H51.1042V3.20325Z" fill="black" fill-opacity="0.92"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/openai-transparent.svg b/app/components/base/icons/assets/public/llm/openai-transparent.svg
new file mode 100644
index 0000000..fe041ba
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/openai-transparent.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M21.276 10.0045C21.7751 8.50639 21.6033 6.86529 20.8051 5.50264C19.6048 3.41259 17.1917 2.33732 14.835 2.84333C13.7866 1.66218 12.2803 0.990477 10.7011 1.0001C8.29218 0.994602 6.15478 2.54563 5.41367 4.83781C3.86614 5.15475 2.53036 6.12346 1.74869 7.49643C0.539398 9.58097 0.81508 12.2087 2.43067 13.9962C1.93156 15.4943 2.10343 17.1354 2.9016 18.498C4.10195 20.5881 6.51502 21.6634 8.87173 21.1573C9.91945 22.3385 11.4264 23.0102 13.0056 22.9999C15.4159 23.0061 17.554 21.4537 18.2951 19.1594C19.8426 18.8425 21.1784 17.8738 21.9601 16.5008C23.168 14.4163 22.8916 11.7906 21.2767 10.0031L21.276 10.0045ZM13.007 21.5623C12.0424 21.5637 11.1081 21.2261 10.3677 20.608C10.4014 20.5901 10.4598 20.5578 10.4976 20.5345L14.8783 18.0044C15.1024 17.8772 15.2399 17.6386 15.2385 17.3808V11.2049L17.0899 12.274C17.1099 12.2836 17.1229 12.3028 17.1257 12.3248V17.4393C17.1229 19.7136 15.2812 21.5575 13.007 21.5623ZM4.14939 17.7789C3.66608 16.9443 3.49215 15.9659 3.65783 15.0165C3.69015 15.0357 3.74721 15.0708 3.78777 15.0942L8.16843 17.6242C8.39049 17.7541 8.66548 17.7541 8.88823 17.6242L14.2362 14.5359V16.6741C14.2376 16.6961 14.2272 16.7174 14.2101 16.7311L9.78196 19.288C7.80956 20.4238 5.29061 19.7486 4.15007 17.7789H4.14939ZM2.99647 8.21626C3.47771 7.38024 4.23738 6.74085 5.14212 6.40878C5.14212 6.44659 5.14005 6.51328 5.14005 6.56003V11.6208C5.13868 11.878 5.27618 12.1165 5.49961 12.2437L10.8476 15.3313L8.99616 16.4004C8.9776 16.4128 8.95422 16.4149 8.9336 16.4059L4.50482 13.847C2.53654 12.7071 1.86143 10.1887 2.99578 8.21694L2.99647 8.21626ZM18.2078 11.7563L12.8598 8.66795L14.7112 7.59956C14.7298 7.58718 14.7532 7.58512 14.7738 7.59406L19.2026 10.1509C21.1743 11.2901 21.8501 13.8126 20.7109 15.7844C20.229 16.6191 19.47 17.2584 18.566 17.5912V12.3792C18.568 12.122 18.4312 11.8841 18.2085 11.7563H18.2078ZM20.0502 8.98284C20.0179 8.9629 19.9609 8.92852 19.9203 8.90515L15.5397 6.37509C15.3176 6.24515 15.0426 6.24515 14.8199 6.37509L9.4719 9.46341V7.32524C9.47053 7.30324 9.48084 7.28192 9.49803 7.26817L13.9261 4.71337C15.8985 3.57553 18.4202 4.25273 19.5573 6.2259C20.0379 7.05917 20.2118 8.03475 20.0489 8.98284H20.0502ZM8.46542 12.7937L6.61334 11.7246C6.5934 11.715 6.58034 11.6958 6.57759 11.6738V6.55935C6.57896 4.2823 8.42624 2.43701 10.7032 2.43838C11.6664 2.43838 12.5986 2.77664 13.339 3.39265C13.3053 3.41053 13.2476 3.44284 13.2091 3.46622L8.82841 5.99627C8.60429 6.12346 8.4668 6.36134 8.46817 6.61916L8.46542 12.7924V12.7937ZM9.47121 10.6253L11.8534 9.24959L14.2355 10.6246V13.3754L11.8534 14.7504L9.47121 13.3754V10.6253Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/openai-violet.svg b/app/components/base/icons/assets/public/llm/openai-violet.svg
new file mode 100644
index 0000000..342fb41
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/openai-violet.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="#AB68FF"/>
+<path d="M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z" fill="white"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/openllm-text.svg b/app/components/base/icons/assets/public/llm/openllm-text.svg
new file mode 100644
index 0000000..59bb579
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/openllm-text.svg
@@ -0,0 +1,19 @@
+<svg width="92" height="25" viewBox="0 0 92 25" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_9850_26886)">
+<path d="M24.9181 1.27026C24.8737 1.12859 24.813 0.994621 24.7379 0.871257C24.6473 0.721871 24.5355 0.586942 24.4073 0.470325C24.3861 0.451049 24.3639 0.431773 24.3417 0.413462C24.1856 0.284315 24.0073 0.181191 23.8136 0.109871C23.6199 0.0385512 23.4107 0 23.1929 0H6.99952C6.96289 0 6.92627 0.00192756 6.88965 0.00385512C6.87905 0.00385512 6.86748 0.00578268 6.85688 0.00674646C6.83086 0.00867402 6.80387 0.0115654 6.77785 0.0144567C6.76628 0.0154205 6.75568 0.017348 6.74508 0.0183118C6.71424 0.0231307 6.6834 0.0279496 6.65256 0.0337323C6.64774 0.0337323 6.64388 0.0356599 6.63906 0.0356599C6.60437 0.0424063 6.56967 0.0510803 6.53594 0.0597543C6.5263 0.0626457 6.51666 0.065537 6.50703 0.0674646C6.48197 0.074211 6.45691 0.0819213 6.43185 0.0905953C6.42125 0.0944504 6.41065 0.0973418 6.40101 0.101197C6.37403 0.110835 6.34704 0.120472 6.32102 0.132038C6.31524 0.134929 6.30849 0.136857 6.30271 0.139748C6.2709 0.153241 6.2391 0.167698 6.20729 0.183118C6.19958 0.186973 6.19187 0.190828 6.18416 0.194684C6.16007 0.207213 6.13694 0.219742 6.11381 0.232271C6.10417 0.23709 6.09549 0.242873 6.08586 0.247691C6.06273 0.261184 6.0396 0.275641 6.01646 0.291062C6.00972 0.294917 6.00297 0.299736 5.99719 0.303591C5.96828 0.322866 5.94033 0.343106 5.91238 0.363345C5.90659 0.3672 5.90177 0.372019 5.89696 0.375874C5.87479 0.393222 5.85262 0.41057 5.83142 0.428882C5.82371 0.435628 5.816 0.442375 5.80829 0.449121C5.78805 0.466469 5.76877 0.484781 5.7495 0.503093C5.74372 0.508876 5.73697 0.514658 5.73119 0.520441C5.72058 0.531043 5.70998 0.541644 5.70035 0.552246C5.70035 0.552246 5.70035 0.551282 5.70131 0.550318L1.45008 4.37942C1.16191 4.66759 1 5.05792 1 5.4656V22.5592C1 23.4073 1.68717 24.0955 2.53626 24.0955H19.6298C20.0375 24.0955 20.4278 23.9335 20.716 23.6454L24.5383 19.2072C24.6077 19.1291 24.6714 19.0453 24.7263 18.9566C24.7282 18.9537 24.7301 18.9498 24.7321 18.9469C24.7427 18.9296 24.7523 18.9123 24.7629 18.8949C24.7668 18.8882 24.7706 18.8814 24.7745 18.8747C24.7831 18.8583 24.7918 18.8429 24.8005 18.8265C24.8053 18.8178 24.8101 18.8091 24.814 18.7995C24.8217 18.7841 24.8284 18.7686 24.8362 18.7532C24.841 18.7426 24.8458 18.733 24.8497 18.7224C24.8564 18.7079 24.8622 18.6925 24.8689 18.6771C24.8737 18.6655 24.8786 18.654 24.8824 18.6424C24.8882 18.6279 24.893 18.6135 24.8988 18.5981C24.9036 18.5855 24.9075 18.573 24.9113 18.5605C24.9162 18.546 24.921 18.5316 24.9248 18.5171C24.9287 18.5036 24.9325 18.4901 24.9364 18.4766C24.9402 18.4631 24.9441 18.4487 24.947 18.4342C24.9508 18.4198 24.9537 18.4053 24.9566 18.3908C24.9595 18.3774 24.9624 18.3639 24.9653 18.3504C24.9682 18.3349 24.9711 18.3195 24.974 18.3041C24.9759 18.2906 24.9788 18.2781 24.9807 18.2646C24.9836 18.2482 24.9855 18.2309 24.9875 18.2145C24.9894 18.2019 24.9904 18.1904 24.9923 18.1779C24.9942 18.1586 24.9952 18.1393 24.9971 18.12C24.9971 18.1094 24.999 18.0998 24.999 18.0892C25.001 18.0593 25.001 18.0294 25.001 17.9996V1.80709C25.001 1.62011 24.972 1.43989 24.92 1.27026H24.9181ZM23.1929 0.541644C23.4107 0.541644 23.616 0.597543 23.7953 0.694885C23.8849 0.744038 23.9678 0.802829 24.043 0.871257C24.0584 0.88475 24.0728 0.899207 24.0873 0.9127C24.1162 0.941613 24.1432 0.97149 24.1692 1.00233C24.1952 1.03317 24.2193 1.06594 24.2425 1.09967C24.3793 1.30207 24.4584 1.54494 24.4584 1.80612V17.9996C24.4584 18.0362 24.4564 18.0718 24.4535 18.1075C24.4535 18.1114 24.4535 18.1162 24.4535 18.12C24.4506 18.1538 24.4458 18.1875 24.44 18.2203C24.44 18.2251 24.4381 18.2299 24.4372 18.2357C24.4304 18.2684 24.4237 18.3012 24.415 18.333C24.414 18.3369 24.4131 18.3407 24.4121 18.3446C24.4025 18.3783 24.3919 18.4111 24.3803 18.4429C24.3803 18.4439 24.3803 18.4448 24.3793 18.4458C24.3408 18.5489 24.2887 18.6443 24.2251 18.733V18.7349C24.203 18.7638 24.1808 18.7927 24.1577 18.8197C24.1432 18.8361 24.1287 18.8525 24.1133 18.8689C24.1133 18.8689 24.1133 18.8689 24.1124 18.8698C24.0979 18.8853 24.0825 18.9007 24.0671 18.9151C24.0671 18.9151 24.0661 18.9161 24.0651 18.9171C24.0497 18.9315 24.0333 18.946 24.0169 18.9604C24.0169 18.9604 24.0169 18.9604 24.016 18.9614C23.9312 19.0337 23.8377 19.0944 23.7355 19.1426C23.7336 19.1436 23.7317 19.1445 23.7288 19.1455C23.7114 19.1532 23.6941 19.1609 23.6758 19.1686C23.6709 19.1705 23.6661 19.1725 23.6613 19.1744C23.6459 19.1802 23.6305 19.186 23.615 19.1917C23.6083 19.1937 23.6025 19.1956 23.5958 19.1985C23.5813 19.2033 23.5669 19.2081 23.5524 19.212C23.5447 19.2139 23.5379 19.2158 23.5302 19.2178C23.5167 19.2216 23.5023 19.2255 23.4888 19.2284C23.4811 19.2303 23.4734 19.2322 23.4657 19.2342C23.4522 19.237 23.4377 19.2399 23.4242 19.2428C23.4165 19.2448 23.4078 19.2457 23.4001 19.2476C23.3857 19.2496 23.3712 19.2515 23.3568 19.2534C23.349 19.2544 23.3413 19.2554 23.3327 19.2563C23.3172 19.2582 23.3009 19.2592 23.2845 19.2602C23.2777 19.2602 23.271 19.2611 23.2642 19.2621C23.2411 19.2631 23.2189 19.264 23.1958 19.264H6.99952C6.65063 19.264 6.33451 19.1224 6.10513 18.893C6.04827 18.8361 5.99622 18.7735 5.95093 18.706C5.8372 18.5373 5.76299 18.3407 5.74082 18.1287C5.73697 18.0863 5.73408 18.0429 5.73408 17.9996V1.80709C5.73408 1.78299 5.73408 1.75986 5.736 1.73673C5.736 1.72902 5.73697 1.72227 5.73793 1.71456C5.7389 1.69818 5.74082 1.68276 5.74179 1.66638C5.74179 1.6577 5.74372 1.64999 5.74468 1.64132C5.74661 1.62686 5.74853 1.61144 5.75143 1.59698C5.75239 1.58831 5.75432 1.5806 5.75624 1.57192C5.75914 1.55747 5.76203 1.54205 5.76588 1.52759C5.76781 1.51988 5.76974 1.51217 5.7707 1.50446C5.77456 1.48808 5.77938 1.47169 5.78419 1.45531C5.78612 1.44952 5.78709 1.44374 5.78901 1.43892C5.80251 1.39459 5.81889 1.35122 5.83624 1.30881C5.83624 1.30881 5.83624 1.30689 5.8372 1.30689C5.84588 1.28665 5.85551 1.26641 5.86515 1.24713C5.86708 1.24424 5.86804 1.24038 5.86997 1.23749C5.87864 1.22015 5.88828 1.2028 5.89792 1.18641C5.89985 1.18256 5.90177 1.17967 5.9037 1.17678C5.91334 1.15943 5.92394 1.14304 5.93454 1.12666C5.93647 1.12377 5.93743 1.12184 5.93936 1.11895C5.95189 1.10064 5.96442 1.08232 5.97695 1.06401C6.04634 0.969563 6.12826 0.883786 6.22079 0.811503C6.30078 0.748857 6.38752 0.695849 6.48101 0.654406C6.48293 0.654406 6.48486 0.652479 6.48679 0.651515C6.51666 0.638022 6.54751 0.626457 6.57835 0.614892C6.58027 0.614892 6.58317 0.612964 6.58509 0.612964C6.64678 0.591761 6.71038 0.575377 6.77496 0.562847C6.77978 0.562847 6.7846 0.56092 6.79038 0.559956C6.82122 0.555137 6.85206 0.551282 6.88386 0.548391C6.88965 0.548391 6.89543 0.548391 6.90025 0.547427C6.93302 0.544536 6.96579 0.543572 6.99855 0.543572H23.192L23.1929 0.541644Z" fill="black"/>
+<path d="M17.2794 11.0016C17.8867 11.0016 18.379 10.5093 18.379 9.90192C18.379 9.29459 17.8867 8.80225 17.2794 8.80225C16.672 8.80225 16.1797 9.29459 16.1797 9.90192C16.1797 10.5093 16.672 11.0016 17.2794 11.0016Z" fill="black"/>
+<path d="M12.9219 11.0016C13.5293 11.0016 14.0216 10.5093 14.0216 9.90192C14.0216 9.29459 13.5293 8.80225 12.9219 8.80225C12.3146 8.80225 11.8223 9.29459 11.8223 9.90192C11.8223 10.5093 12.3146 11.0016 12.9219 11.0016Z" fill="black"/>
+</g>
+<path d="M36.4876 17.098C35.5822 17.098 34.7469 16.888 33.9816 16.468C33.2256 16.0387 32.6236 15.446 32.1756 14.69C31.7369 13.9247 31.5176 13.066 31.5176 12.114C31.5176 11.162 31.7369 10.308 32.1756 9.55204C32.6236 8.79604 33.2256 8.20804 33.9816 7.78804C34.7469 7.35871 35.5822 7.14404 36.4876 7.14404C37.4022 7.14404 38.2376 7.35871 38.9936 7.78804C39.7589 8.20804 40.3609 8.79604 40.7996 9.55204C41.2382 10.308 41.4576 11.162 41.4576 12.114C41.4576 13.066 41.2382 13.9247 40.7996 14.69C40.3609 15.446 39.7589 16.0387 38.9936 16.468C38.2376 16.888 37.4022 17.098 36.4876 17.098ZM36.4876 15.712C37.1316 15.712 37.7056 15.5674 38.2096 15.278C38.7136 14.9794 39.1056 14.5594 39.3856 14.018C39.6749 13.4674 39.8196 12.8327 39.8196 12.114C39.8196 11.3954 39.6749 10.7654 39.3856 10.224C39.1056 9.68271 38.7136 9.26738 38.2096 8.97804C37.7056 8.68871 37.1316 8.54404 36.4876 8.54404C35.8436 8.54404 35.2696 8.68871 34.7656 8.97804C34.2616 9.26738 33.8649 9.68271 33.5756 10.224C33.2956 10.7654 33.1556 11.3954 33.1556 12.114C33.1556 12.8327 33.2956 13.4674 33.5756 14.018C33.8649 14.5594 34.2616 14.9794 34.7656 15.278C35.2696 15.5674 35.8436 15.712 36.4876 15.712Z" fill="#1D2939"/>
+<path d="M44.3441 10.42C44.6148 10.0654 44.9834 9.76671 45.4501 9.52404C45.9168 9.28138 46.4441 9.16004 47.0321 9.16004C47.7041 9.16004 48.3154 9.32804 48.8661 9.66404C49.4261 9.99071 49.8648 10.4527 50.1821 11.05C50.4994 11.6474 50.6581 12.3334 50.6581 13.108C50.6581 13.8827 50.4994 14.578 50.1821 15.194C49.8648 15.8007 49.4261 16.2767 48.8661 16.622C48.3154 16.958 47.7041 17.126 47.0321 17.126C46.4441 17.126 45.9214 17.0094 45.4641 16.776C45.0068 16.5334 44.6334 16.2347 44.3441 15.88V20.668H42.7481V9.28604H44.3441V10.42ZM49.0341 13.108C49.0341 12.576 48.9221 12.1187 48.6981 11.736C48.4834 11.344 48.1941 11.05 47.8301 10.854C47.4754 10.6487 47.0928 10.546 46.6821 10.546C46.2808 10.546 45.8981 10.6487 45.5341 10.854C45.1794 11.0594 44.8901 11.358 44.6661 11.75C44.4514 12.142 44.3441 12.604 44.3441 13.136C44.3441 13.668 44.4514 14.1347 44.6661 14.536C44.8901 14.928 45.1794 15.2267 45.5341 15.432C45.8981 15.6374 46.2808 15.74 46.6821 15.74C47.0928 15.74 47.4754 15.6374 47.8301 15.432C48.1941 15.2174 48.4834 14.9094 48.6981 14.508C48.9221 14.1067 49.0341 13.64 49.0341 13.108Z" fill="#1D2939"/>
+<path d="M59.0264 12.954C59.0264 13.2434 59.0077 13.5047 58.9704 13.738H53.0764C53.123 14.354 53.3517 14.8487 53.7624 15.222C54.173 15.5954 54.677 15.782 55.2744 15.782C56.133 15.782 56.7397 15.4227 57.0944 14.704H58.8164C58.583 15.4134 58.1584 15.9967 57.5424 16.454C56.9357 16.902 56.1797 17.126 55.2744 17.126C54.537 17.126 53.8744 16.9627 53.2864 16.636C52.7077 16.3 52.2504 15.8334 51.9144 15.236C51.5877 14.6294 51.4244 13.9294 51.4244 13.136C51.4244 12.3427 51.583 11.6474 51.9004 11.05C52.227 10.4434 52.6797 9.97671 53.2584 9.65004C53.8464 9.32338 54.5184 9.16004 55.2744 9.16004C56.0024 9.16004 56.651 9.31871 57.2204 9.63604C57.7897 9.95338 58.233 10.4014 58.5504 10.98C58.8677 11.5494 59.0264 12.2074 59.0264 12.954ZM57.3604 12.45C57.351 11.862 57.141 11.3907 56.7304 11.036C56.3197 10.6814 55.811 10.504 55.2044 10.504C54.6537 10.504 54.1824 10.6814 53.7904 11.036C53.3984 11.3814 53.165 11.8527 53.0904 12.45H57.3604Z" fill="#1D2939"/>
+<path d="M64.209 9.16004C64.8157 9.16004 65.357 9.28604 65.833 9.53804C66.3183 9.79004 66.6963 10.1634 66.967 10.658C67.2377 11.1527 67.373 11.75 67.373 12.45V17H65.791V12.688C65.791 11.9974 65.6183 11.47 65.273 11.106C64.9277 10.7327 64.4563 10.546 63.859 10.546C63.2617 10.546 62.7857 10.7327 62.431 11.106C62.0857 11.47 61.913 11.9974 61.913 12.688V17H60.317V9.28604H61.913V10.168C62.1743 9.85071 62.5057 9.60338 62.907 9.42604C63.3177 9.24871 63.7517 9.16004 64.209 9.16004Z" fill="#1D2939"/>
+<path d="M70.7248 15.712H74.0148V17H69.1288V7.27004H70.7248V15.712Z" fill="#1D2939"/>
+<path d="M76.6655 15.712H79.9555V17H75.0695V7.27004H76.6655V15.712Z" fill="#1D2939"/>
+<path d="M91.2582 7.27004V17H89.6622V10.336L86.6942 17H85.5882L82.6062 10.336V17H81.0102V7.27004H82.7322L86.1482 14.9L89.5502 7.27004H91.2582Z" fill="#1D2939"/>
+<defs>
+<clipPath id="clip0_9850_26886">
+<rect width="24" height="24.0945" fill="white" transform="translate(1)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/openllm.svg b/app/components/base/icons/assets/public/llm/openllm.svg
new file mode 100644
index 0000000..d25d627
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/openllm.svg
@@ -0,0 +1,12 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Camada_2" clip-path="url(#clip0_9866_5923)">
+<path id="Vector" d="M23.9181 1.27026C23.8737 1.12859 23.813 0.994621 23.7379 0.871257C23.6473 0.721871 23.5355 0.586942 23.4073 0.470325C23.3861 0.451049 23.3639 0.431773 23.3417 0.413462C23.1856 0.284315 23.0073 0.181191 22.8136 0.109871C22.6199 0.0385512 22.4107 0 22.1929 0H5.99952C5.96289 0 5.92627 0.00192756 5.88965 0.00385512C5.87905 0.00385512 5.86748 0.00578268 5.85688 0.00674646C5.83086 0.00867402 5.80387 0.0115654 5.77785 0.0144567C5.76628 0.0154205 5.75568 0.017348 5.74508 0.0183118C5.71424 0.0231307 5.6834 0.0279496 5.65256 0.0337323C5.64774 0.0337323 5.64388 0.0356599 5.63906 0.0356599C5.60437 0.0424063 5.56967 0.0510803 5.53594 0.0597543C5.5263 0.0626457 5.51666 0.065537 5.50703 0.0674646C5.48197 0.074211 5.45691 0.0819213 5.43185 0.0905953C5.42125 0.0944504 5.41065 0.0973418 5.40101 0.101197C5.37403 0.110835 5.34704 0.120472 5.32102 0.132038C5.31524 0.134929 5.30849 0.136857 5.30271 0.139748C5.2709 0.153241 5.2391 0.167698 5.20729 0.183118C5.19958 0.186973 5.19187 0.190828 5.18416 0.194684C5.16007 0.207213 5.13694 0.219742 5.11381 0.232271C5.10417 0.23709 5.09549 0.242873 5.08586 0.247691C5.06273 0.261184 5.0396 0.275641 5.01646 0.291062C5.00972 0.294917 5.00297 0.299736 4.99719 0.303591C4.96828 0.322866 4.94033 0.343106 4.91238 0.363345C4.90659 0.3672 4.90177 0.372019 4.89696 0.375874C4.87479 0.393222 4.85262 0.41057 4.83142 0.428882C4.82371 0.435628 4.816 0.442375 4.80829 0.449121C4.78805 0.466469 4.76877 0.484781 4.7495 0.503093C4.74372 0.508876 4.73697 0.514658 4.73119 0.520441C4.72058 0.531043 4.70998 0.541644 4.70035 0.552246C4.70035 0.552246 4.70035 0.551282 4.70131 0.550318L0.450084 4.37942C0.161915 4.66759 0 5.05792 0 5.4656V22.5592C0 23.4073 0.687174 24.0955 1.53626 24.0955H18.6298C19.0375 24.0955 19.4278 23.9335 19.716 23.6454L23.5383 19.2072C23.6077 19.1291 23.6714 19.0453 23.7263 18.9566C23.7282 18.9537 23.7301 18.9498 23.7321 18.9469C23.7427 18.9296 23.7523 18.9123 23.7629 18.8949C23.7668 18.8882 23.7706 18.8814 23.7745 18.8747C23.7831 18.8583 23.7918 18.8429 23.8005 18.8265C23.8053 18.8178 23.8101 18.8091 23.814 18.7995C23.8217 18.7841 23.8284 18.7686 23.8362 18.7532C23.841 18.7426 23.8458 18.733 23.8497 18.7224C23.8564 18.7079 23.8622 18.6925 23.8689 18.6771C23.8737 18.6655 23.8786 18.654 23.8824 18.6424C23.8882 18.6279 23.893 18.6135 23.8988 18.5981C23.9036 18.5855 23.9075 18.573 23.9113 18.5605C23.9162 18.546 23.921 18.5316 23.9248 18.5171C23.9287 18.5036 23.9325 18.4901 23.9364 18.4766C23.9402 18.4631 23.9441 18.4487 23.947 18.4342C23.9508 18.4198 23.9537 18.4053 23.9566 18.3908C23.9595 18.3774 23.9624 18.3639 23.9653 18.3504C23.9682 18.3349 23.9711 18.3195 23.974 18.3041C23.9759 18.2906 23.9788 18.2781 23.9807 18.2646C23.9836 18.2482 23.9855 18.2309 23.9875 18.2145C23.9894 18.2019 23.9904 18.1904 23.9923 18.1779C23.9942 18.1586 23.9952 18.1393 23.9971 18.12C23.9971 18.1094 23.999 18.0998 23.999 18.0892C24.001 18.0593 24.001 18.0294 24.001 17.9996V1.80709C24.001 1.62011 23.972 1.43989 23.92 1.27026H23.9181ZM22.1929 0.541644C22.4107 0.541644 22.616 0.597543 22.7953 0.694885C22.8849 0.744038 22.9678 0.802829 23.043 0.871257C23.0584 0.88475 23.0728 0.899207 23.0873 0.9127C23.1162 0.941613 23.1432 0.97149 23.1692 1.00233C23.1952 1.03317 23.2193 1.06594 23.2425 1.09967C23.3793 1.30207 23.4584 1.54494 23.4584 1.80612V17.9996C23.4584 18.0362 23.4564 18.0718 23.4535 18.1075C23.4535 18.1114 23.4535 18.1162 23.4535 18.12C23.4506 18.1538 23.4458 18.1875 23.44 18.2203C23.44 18.2251 23.4381 18.2299 23.4372 18.2357C23.4304 18.2684 23.4237 18.3012 23.415 18.333C23.414 18.3369 23.4131 18.3407 23.4121 18.3446C23.4025 18.3783 23.3919 18.4111 23.3803 18.4429C23.3803 18.4439 23.3803 18.4448 23.3793 18.4458C23.3408 18.5489 23.2887 18.6443 23.2251 18.733V18.7349C23.203 18.7638 23.1808 18.7927 23.1577 18.8197C23.1432 18.8361 23.1287 18.8525 23.1133 18.8689C23.1133 18.8689 23.1133 18.8689 23.1124 18.8698C23.0979 18.8853 23.0825 18.9007 23.0671 18.9151C23.0671 18.9151 23.0661 18.9161 23.0651 18.9171C23.0497 18.9315 23.0333 18.946 23.0169 18.9604C23.0169 18.9604 23.0169 18.9604 23.016 18.9614C22.9312 19.0337 22.8377 19.0944 22.7355 19.1426C22.7336 19.1436 22.7317 19.1445 22.7288 19.1455C22.7114 19.1532 22.6941 19.1609 22.6758 19.1686C22.6709 19.1705 22.6661 19.1725 22.6613 19.1744C22.6459 19.1802 22.6305 19.186 22.615 19.1917C22.6083 19.1937 22.6025 19.1956 22.5958 19.1985C22.5813 19.2033 22.5669 19.2081 22.5524 19.212C22.5447 19.2139 22.5379 19.2158 22.5302 19.2178C22.5167 19.2216 22.5023 19.2255 22.4888 19.2284C22.4811 19.2303 22.4734 19.2322 22.4657 19.2342C22.4522 19.237 22.4377 19.2399 22.4242 19.2428C22.4165 19.2448 22.4078 19.2457 22.4001 19.2476C22.3857 19.2496 22.3712 19.2515 22.3568 19.2534C22.349 19.2544 22.3413 19.2554 22.3327 19.2563C22.3172 19.2582 22.3009 19.2592 22.2845 19.2602C22.2777 19.2602 22.271 19.2611 22.2642 19.2621C22.2411 19.2631 22.2189 19.264 22.1958 19.264H5.99952C5.65063 19.264 5.33451 19.1224 5.10513 18.893C5.04827 18.8361 4.99622 18.7735 4.95093 18.706C4.8372 18.5373 4.76299 18.3407 4.74082 18.1287C4.73697 18.0863 4.73408 18.0429 4.73408 17.9996V1.80709C4.73408 1.78299 4.73408 1.75986 4.736 1.73673C4.736 1.72902 4.73697 1.72227 4.73793 1.71456C4.7389 1.69818 4.74082 1.68276 4.74179 1.66638C4.74179 1.6577 4.74372 1.64999 4.74468 1.64132C4.74661 1.62686 4.74853 1.61144 4.75143 1.59698C4.75239 1.58831 4.75432 1.5806 4.75624 1.57192C4.75914 1.55747 4.76203 1.54205 4.76588 1.52759C4.76781 1.51988 4.76974 1.51217 4.7707 1.50446C4.77456 1.48808 4.77938 1.47169 4.78419 1.45531C4.78612 1.44952 4.78709 1.44374 4.78901 1.43892C4.80251 1.39459 4.81889 1.35122 4.83624 1.30881C4.83624 1.30881 4.83624 1.30689 4.8372 1.30689C4.84588 1.28665 4.85551 1.26641 4.86515 1.24713C4.86708 1.24424 4.86804 1.24038 4.86997 1.23749C4.87864 1.22015 4.88828 1.2028 4.89792 1.18641C4.89985 1.18256 4.90177 1.17967 4.9037 1.17678C4.91334 1.15943 4.92394 1.14304 4.93454 1.12666C4.93647 1.12377 4.93743 1.12184 4.93936 1.11895C4.95189 1.10064 4.96442 1.08232 4.97695 1.06401C5.04634 0.969563 5.12826 0.883786 5.22079 0.811503C5.30078 0.748857 5.38752 0.695849 5.48101 0.654406C5.48293 0.654406 5.48486 0.652479 5.48679 0.651515C5.51666 0.638022 5.54751 0.626457 5.57835 0.614892C5.58027 0.614892 5.58317 0.612964 5.58509 0.612964C5.64678 0.591761 5.71038 0.575377 5.77496 0.562847C5.77978 0.562847 5.7846 0.56092 5.79038 0.559956C5.82122 0.555137 5.85206 0.551282 5.88386 0.548391C5.88965 0.548391 5.89543 0.548391 5.90025 0.547427C5.93302 0.544536 5.96579 0.543572 5.99855 0.543572H22.192L22.1929 0.541644Z" fill="black"/>
+<path id="Vector_2" d="M16.2794 11.0016C16.8867 11.0016 17.379 10.5093 17.379 9.90192C17.379 9.29459 16.8867 8.80225 16.2794 8.80225C15.672 8.80225 15.1797 9.29459 15.1797 9.90192C15.1797 10.5093 15.672 11.0016 16.2794 11.0016Z" fill="black"/>
+<path id="Vector_3" d="M11.9219 11.0016C12.5293 11.0016 13.0216 10.5093 13.0216 9.90192C13.0216 9.29459 12.5293 8.80225 11.9219 8.80225C11.3146 8.80225 10.8223 9.29459 10.8223 9.90192C10.8223 10.5093 11.3146 11.0016 11.9219 11.0016Z" fill="black"/>
+</g>
+<defs>
+<clipPath id="clip0_9866_5923">
+<rect width="24" height="24.0945" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/replicate-text.svg b/app/components/base/icons/assets/public/llm/replicate-text.svg
new file mode 100644
index 0000000..63c0947
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/replicate-text.svg
@@ -0,0 +1,13 @@
+<svg width="92" height="24" viewBox="0 0 92 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M18.4933 2V3.79H6.005V17.9017H4V2H18.4933Z" fill="black"/>
+<path d="M18.4974 5.39453V7.18453H9.79573V17.9012H7.78906V5.39453H18.4974Z" fill="black"/>
+<path d="M18.4936 8.77734V10.5773H13.577V17.9007H11.5703V8.77734H18.4936Z" fill="black"/>
+<path d="M24.2014 8.60156C26.588 8.60156 28.593 10.1849 28.593 13.1282C28.593 13.3232 28.593 13.4882 28.573 13.7866H21.403C21.4964 15.2782 22.6997 16.2649 24.2114 16.2649C25.4864 16.2649 26.3414 15.6782 26.813 14.8766L28.3464 15.9666C27.523 17.2632 26.1047 18.0849 24.1914 18.0849C21.4247 18.0849 19.4297 16.1199 19.4297 13.3432C19.4397 10.6582 21.4347 8.60156 24.203 8.60156M21.508 12.3149H26.5797C26.363 10.9982 25.3047 10.2882 24.1314 10.2882C22.958 10.2882 21.7764 10.9666 21.508 12.3149Z" fill="black"/>
+<path d="M30.6328 8.77656H32.6378V9.9999C33.1528 9.2699 34.2628 8.60156 35.5695 8.60156C38.0695 8.60156 39.9611 10.7316 39.9611 13.3432C39.9611 15.9549 38.0678 18.0849 35.5695 18.0849C34.2528 18.0849 33.1411 17.4066 32.6378 16.6749V21.7049H30.6328V8.77656ZM35.2095 10.4216C33.5845 10.4216 32.4728 11.6966 32.4728 13.3432C32.4728 14.9899 33.5845 16.2649 35.2095 16.2649C36.8345 16.2649 37.9245 14.9899 37.9245 13.3432C37.9245 11.6966 36.8128 10.4216 35.2095 10.4216Z" fill="black"/>
+<path d="M44.0128 4.2207H42.0078V17.8907H44.0128V4.2207Z" fill="black"/>
+<path d="M47.7139 6.79443C46.9839 6.79443 46.3672 6.19776 46.3672 5.44776C46.3672 4.69776 46.9839 4.12109 47.7139 4.12109C48.4439 4.12109 49.0405 4.72776 49.0405 5.44776C49.0405 6.19943 48.4639 6.79443 47.7139 6.79443ZM46.7155 8.77943H48.7205V17.8928H46.7155V8.77943Z" fill="black"/>
+<path d="M55.5711 18.0771C52.8345 18.0771 50.7578 16.0304 50.7578 13.3354C50.7578 10.6404 52.8361 8.59375 55.5711 8.59375C57.4528 8.59375 59.0378 9.60208 59.8195 11.1137L58.0711 12.0604C57.6295 11.1354 56.7445 10.4554 55.5711 10.4554C53.9461 10.4554 52.8045 11.7104 52.8045 13.3354C52.8045 14.9604 53.9561 16.2154 55.5711 16.2154C56.7328 16.2154 57.6278 15.5371 58.0711 14.6104L59.8195 15.5571C59.0378 17.0787 57.4428 18.0771 55.5711 18.0771Z" fill="black"/>
+<path d="M65.3995 8.60156C66.7161 8.60156 67.8061 9.2799 68.3211 9.9999V8.77656H70.3261V17.8899H68.3211V16.6666C67.8061 17.3966 66.7161 18.0766 65.3995 18.0766C62.8995 18.0766 61.0078 15.9466 61.0078 13.3349C61.0078 10.7232 62.9011 8.60323 65.3995 8.60323M65.7695 10.4232C64.1445 10.4232 63.0545 11.6982 63.0545 13.3449C63.0545 14.9916 64.1445 16.2666 65.7695 16.2666C67.3945 16.2666 68.4845 14.9916 68.4845 13.3449C68.4845 11.6982 67.3845 10.4232 65.7695 10.4232Z" fill="black"/>
+<path d="M73.7627 17.9033V10.57H71.8594V8.78H73.7627V6.25H75.7694V8.78H79.2244V10.57H75.7694V16.1033H79.2244V17.9033H73.7627Z" fill="black"/>
+<path d="M84.9435 8.60156C87.3302 8.60156 89.3352 10.1849 89.3352 13.1282C89.3352 13.3232 89.3352 13.4882 89.3152 13.7866H82.1452C82.2385 15.2782 83.4419 16.2649 84.9535 16.2649C86.2285 16.2649 87.0835 15.6782 87.5552 14.8766L89.0885 15.9666C88.2652 17.2632 86.8469 18.0849 84.9335 18.0849C82.1669 18.0849 80.1719 16.1199 80.1719 13.3432C80.1919 10.6582 82.1769 8.60156 84.9452 8.60156M82.2502 12.3149H87.3219C87.1052 10.9982 86.0469 10.2882 84.8735 10.2882C83.7002 10.2882 82.5285 10.9666 82.2502 12.3149Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/replicate.svg b/app/components/base/icons/assets/public/llm/replicate.svg
new file mode 100644
index 0000000..527316e
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/replicate.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19.9961 4V5.79H7.93621V19.9017H6V4H19.9961ZM20 7.39453V9.18453H11.5969V19.9012H9.65906V7.39453H20ZM19.9964 12.5773V10.7773H13.3106V19.9007H15.2484V12.5773H19.9964Z" fill="white"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/xorbits-inference-text.svg b/app/components/base/icons/assets/public/llm/xorbits-inference-text.svg
new file mode 100644
index 0000000..8109176
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/xorbits-inference-text.svg
@@ -0,0 +1,42 @@
+<svg width="152" height="24" viewBox="0 0 152 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="xorbits 1" clip-path="url(#clip0_9866_6170)">
+<path id="Vector" d="M8.00391 12.3124C8.69334 13.0754 9.47526 13.7494 10.3316 14.3188C11.0667 14.8105 11.8509 15.2245 12.6716 15.5541C14.1617 14.1465 15.3959 12.4907 16.3192 10.6606L21.7051 0L12.3133 7.38353C10.5832 8.74456 9.12178 10.416 8.00391 12.3124Z" fill="url(#paint0_linear_9866_6170)"/>
+<path id="Vector_2" d="M7.23504 18.9512C6.56092 18.5012 5.92386 18.0265 5.3221 17.5394L2.06445 24L7.91975 19.3959C7.69034 19.2494 7.46092 19.103 7.23504 18.9512Z" fill="url(#paint1_linear_9866_6170)"/>
+<path id="Vector_3" d="M19.3161 8.57474C21.0808 10.9147 21.5961 13.5159 20.3996 15.3053C18.6526 17.9189 13.9161 17.8183 9.82024 15.0812C5.72435 12.3441 3.82024 8.0065 5.56729 5.39297C6.76377 3.60356 9.36318 3.0865 12.2008 3.81886C7.29318 1.73474 2.62376 1.94121 0.813177 4.64474C-1.45976 8.04709 1.64435 14.1177 7.74494 18.1889C13.8455 22.26 20.6361 22.8124 22.9091 19.4118C24.7179 16.703 23.1173 12.3106 19.3161 8.57474Z" fill="url(#paint2_linear_9866_6170)"/>
+<g id="Xorbits Inference">
+<path d="M35.5162 12.142L38.5402 17H36.7482L34.5502 13.472L32.4922 17H30.7142L33.7382 12.142L30.7002 7.27002H32.4922L34.7042 10.826L36.7762 7.27002H38.5542L35.5162 12.142Z" fill="#1D2939"/>
+<path d="M43.3584 17.126C42.6304 17.126 41.9724 16.9627 41.3844 16.636C40.7964 16.3 40.3344 15.8334 39.9984 15.236C39.6624 14.6294 39.4944 13.9293 39.4944 13.136C39.4944 12.352 39.6671 11.6567 40.0124 11.05C40.3577 10.4434 40.8291 9.97668 41.4264 9.65002C42.0237 9.32335 42.6911 9.16002 43.4284 9.16002C44.1657 9.16002 44.8331 9.32335 45.4304 9.65002C46.0277 9.97668 46.4991 10.4434 46.8444 11.05C47.1897 11.6567 47.3624 12.352 47.3624 13.136C47.3624 13.92 47.185 14.6154 46.8304 15.222C46.4757 15.8287 45.9904 16.3 45.3744 16.636C44.7677 16.9627 44.0957 17.126 43.3584 17.126ZM43.3584 15.74C43.769 15.74 44.1517 15.642 44.5064 15.446C44.8704 15.25 45.1644 14.956 45.3884 14.564C45.6124 14.172 45.7244 13.696 45.7244 13.136C45.7244 12.576 45.6171 12.1047 45.4024 11.722C45.1877 11.33 44.9031 11.036 44.5484 10.84C44.1937 10.644 43.8111 10.546 43.4004 10.546C42.9897 10.546 42.607 10.644 42.2524 10.84C41.9071 11.036 41.6317 11.33 41.4264 11.722C41.221 12.1047 41.1184 12.576 41.1184 13.136C41.1184 13.9667 41.3284 14.6107 41.7484 15.068C42.1777 15.516 42.7144 15.74 43.3584 15.74Z" fill="#1D2939"/>
+<path d="M50.2561 10.406C50.4895 10.014 50.7974 9.71068 51.1801 9.49602C51.5721 9.27202 52.0341 9.16002 52.5661 9.16002V10.812H52.1601C51.5348 10.812 51.0588 10.9707 50.7321 11.288C50.4148 11.6054 50.2561 12.156 50.2561 12.94V17H48.6601V9.28602H50.2561V10.406Z" fill="#1D2939"/>
+<path d="M55.3492 10.434C55.6198 10.0607 55.9885 9.75735 56.4552 9.52402C56.9312 9.28135 57.4585 9.16002 58.0372 9.16002C58.7185 9.16002 59.3345 9.32335 59.8852 9.65002C60.4358 9.97668 60.8698 10.4434 61.1872 11.05C61.5045 11.6473 61.6632 12.3333 61.6632 13.108C61.6632 13.8827 61.5045 14.578 61.1872 15.194C60.8698 15.8007 60.4312 16.2767 59.8712 16.622C59.3205 16.958 58.7092 17.126 58.0372 17.126C57.4398 17.126 56.9078 17.0093 56.4412 16.776C55.9838 16.5427 55.6198 16.244 55.3492 15.88V17H53.7532V6.64002H55.3492V10.434ZM60.0392 13.108C60.0392 12.576 59.9272 12.1187 59.7032 11.736C59.4885 11.344 59.1992 11.05 58.8352 10.854C58.4805 10.6487 58.0978 10.546 57.6872 10.546C57.2858 10.546 56.9032 10.6487 56.5392 10.854C56.1845 11.0594 55.8952 11.358 55.6712 11.75C55.4565 12.142 55.3492 12.604 55.3492 13.136C55.3492 13.668 55.4565 14.1347 55.6712 14.536C55.8952 14.928 56.1845 15.2267 56.5392 15.432C56.9032 15.6374 57.2858 15.74 57.6872 15.74C58.0978 15.74 58.4805 15.6374 58.8352 15.432C59.1992 15.2174 59.4885 14.9093 59.7032 14.508C59.9272 14.1067 60.0392 13.64 60.0392 13.108Z" fill="#1D2939"/>
+<path d="M63.7734 8.26402C63.4841 8.26402 63.2414 8.16602 63.0454 7.97002C62.8494 7.77402 62.7514 7.53135 62.7514 7.24202C62.7514 6.95268 62.8494 6.71002 63.0454 6.51402C63.2414 6.31802 63.4841 6.22002 63.7734 6.22002C64.0534 6.22002 64.2914 6.31802 64.4874 6.51402C64.6834 6.71002 64.7814 6.95268 64.7814 7.24202C64.7814 7.53135 64.6834 7.77402 64.4874 7.97002C64.2914 8.16602 64.0534 8.26402 63.7734 8.26402ZM64.5574 9.28602V17H62.9614V9.28602H64.5574Z" fill="#1D2939"/>
+<path d="M68.2348 10.588V14.858C68.2348 15.1474 68.3002 15.3573 68.4309 15.488C68.5709 15.6093 68.8042 15.67 69.1308 15.67H70.1109V17H68.8508C68.1322 17 67.5815 16.832 67.1988 16.496C66.8162 16.16 66.6248 15.614 66.6248 14.858V10.588H65.7148V9.28602H66.6248V7.36802H68.2348V9.28602H70.1109V10.588H68.2348Z" fill="#1D2939"/>
+<path d="M74.1018 17.126C73.4952 17.126 72.9492 17.0187 72.4638 16.804C71.9878 16.58 71.6098 16.2813 71.3298 15.908C71.0498 15.5253 70.9005 15.1007 70.8818 14.634H72.5338C72.5618 14.9607 72.7158 15.236 72.9958 15.46C73.2852 15.6747 73.6445 15.782 74.0738 15.782C74.5218 15.782 74.8672 15.698 75.1098 15.53C75.3618 15.3527 75.4878 15.1287 75.4878 14.858C75.4878 14.5687 75.3478 14.354 75.0678 14.214C74.7972 14.074 74.3632 13.92 73.7658 13.752C73.1872 13.5933 72.7158 13.4394 72.3518 13.29C71.9878 13.1407 71.6705 12.912 71.3998 12.604C71.1385 12.296 71.0078 11.89 71.0078 11.386C71.0078 10.9753 71.1292 10.602 71.3718 10.266C71.6145 9.92068 71.9598 9.65002 72.4078 9.45402C72.8652 9.25802 73.3878 9.16002 73.9758 9.16002C74.8532 9.16002 75.5578 9.38402 76.0898 9.83202C76.6312 10.2707 76.9205 10.8727 76.9578 11.638H75.3618C75.3338 11.2927 75.1938 11.0173 74.9418 10.812C74.6898 10.6067 74.3492 10.504 73.9198 10.504C73.4998 10.504 73.1778 10.5833 72.9538 10.742C72.7298 10.9007 72.6178 11.1107 72.6178 11.372C72.6178 11.5773 72.6925 11.75 72.8418 11.89C72.9912 12.03 73.1732 12.142 73.3878 12.226C73.6025 12.3007 73.9198 12.3987 74.3398 12.52C74.8998 12.6693 75.3572 12.8233 75.7118 12.982C76.0758 13.1314 76.3885 13.3554 76.6498 13.654C76.9112 13.9527 77.0465 14.3493 77.0558 14.844C77.0558 15.2827 76.9345 15.6747 76.6918 16.02C76.4492 16.3654 76.1038 16.636 75.6558 16.832C75.2172 17.028 74.6992 17.126 74.1018 17.126Z" fill="#1D2939"/>
+<path d="M83.4531 7.27002V17H81.8571V7.27002H83.4531Z" fill="#1D2939"/>
+<path d="M89.1605 9.16002C89.7671 9.16002 90.3085 9.28602 90.7845 9.53802C91.2698 9.79002 91.6478 10.1633 91.9185 10.658C92.1891 11.1527 92.3245 11.75 92.3245 12.45V17H90.7425V12.688C90.7425 11.9973 90.5698 11.47 90.2245 11.106C89.8791 10.7327 89.4078 10.546 88.8105 10.546C88.2131 10.546 87.7371 10.7327 87.3825 11.106C87.0371 11.47 86.8645 11.9973 86.8645 12.688V17H85.2685V9.28602H86.8645V10.168C87.1258 9.85068 87.4571 9.60335 87.8585 9.42602C88.2691 9.24868 88.7031 9.16002 89.1605 9.16002Z" fill="#1D2939"/>
+<path d="M97.3143 10.588H95.8863V17H94.2763V10.588H93.3663V9.28602H94.2763V8.74002C94.2763 7.85335 94.5096 7.20935 94.9763 6.80802C95.4523 6.39735 96.1943 6.19202 97.2023 6.19202V7.52202C96.7169 7.52202 96.3763 7.61535 96.1803 7.80202C95.9843 7.97935 95.8863 8.29202 95.8863 8.74002V9.28602H97.3143V10.588Z" fill="#1D2939"/>
+<path d="M105.519 12.954C105.519 13.2433 105.5 13.5047 105.463 13.738H99.5687C99.6154 14.354 99.844 14.8487 100.255 15.222C100.665 15.5954 101.169 15.782 101.767 15.782C102.625 15.782 103.232 15.4227 103.587 14.704H105.309C105.075 15.4133 104.651 15.9967 104.035 16.454C103.428 16.902 102.672 17.126 101.767 17.126C101.029 17.126 100.367 16.9627 99.7787 16.636C99.2 16.3 98.7427 15.8334 98.4067 15.236C98.08 14.6294 97.9167 13.9293 97.9167 13.136C97.9167 12.3427 98.0754 11.6473 98.3927 11.05C98.7194 10.4434 99.172 9.97668 99.7507 9.65002C100.339 9.32335 101.011 9.16002 101.767 9.16002C102.495 9.16002 103.143 9.31868 103.713 9.63602C104.282 9.95335 104.725 10.4014 105.043 10.98C105.36 11.5493 105.519 12.2073 105.519 12.954ZM103.853 12.45C103.843 11.862 103.633 11.3907 103.223 11.036C102.812 10.6813 102.303 10.504 101.697 10.504C101.146 10.504 100.675 10.6813 100.283 11.036C99.8907 11.3813 99.6574 11.8527 99.5827 12.45H103.853Z" fill="#1D2939"/>
+<path d="M108.405 10.406C108.639 10.014 108.947 9.71068 109.329 9.49602C109.721 9.27202 110.183 9.16002 110.715 9.16002V10.812H110.309C109.684 10.812 109.208 10.9707 108.881 11.288C108.564 11.6054 108.405 12.156 108.405 12.94V17H106.809V9.28602H108.405V10.406Z" fill="#1D2939"/>
+<path d="M118.972 12.954C118.972 13.2433 118.954 13.5047 118.916 13.738H113.022C113.069 14.354 113.298 14.8487 113.708 15.222C114.119 15.5954 114.623 15.782 115.22 15.782C116.079 15.782 116.686 15.4227 117.04 14.704H118.762C118.529 15.4133 118.104 15.9967 117.488 16.454C116.882 16.902 116.126 17.126 115.22 17.126C114.483 17.126 113.82 16.9627 113.232 16.636C112.654 16.3 112.196 15.8334 111.86 15.236C111.534 14.6294 111.37 13.9293 111.37 13.136C111.37 12.3427 111.529 11.6473 111.846 11.05C112.173 10.4434 112.626 9.97668 113.204 9.65002C113.792 9.32335 114.464 9.16002 115.22 9.16002C115.948 9.16002 116.597 9.31868 117.166 9.63602C117.736 9.95335 118.179 10.4014 118.496 10.98C118.814 11.5493 118.972 12.2073 118.972 12.954ZM117.306 12.45C117.297 11.862 117.087 11.3907 116.676 11.036C116.266 10.6813 115.757 10.504 115.15 10.504C114.6 10.504 114.128 10.6813 113.736 11.036C113.344 11.3813 113.111 11.8527 113.036 12.45H117.306Z" fill="#1D2939"/>
+<path d="M124.155 9.16002C124.762 9.16002 125.303 9.28602 125.779 9.53802C126.264 9.79002 126.642 10.1633 126.913 10.658C127.184 11.1527 127.319 11.75 127.319 12.45V17H125.737V12.688C125.737 11.9973 125.564 11.47 125.219 11.106C124.874 10.7327 124.402 10.546 123.805 10.546C123.208 10.546 122.732 10.7327 122.377 11.106C122.032 11.47 121.859 11.9973 121.859 12.688V17H120.263V9.28602H121.859V10.168C122.12 9.85068 122.452 9.60335 122.853 9.42602C123.264 9.24868 123.698 9.16002 124.155 9.16002Z" fill="#1D2939"/>
+<path d="M128.543 13.136C128.543 12.3427 128.701 11.6473 129.019 11.05C129.345 10.4434 129.793 9.97668 130.363 9.65002C130.932 9.32335 131.585 9.16002 132.323 9.16002C133.256 9.16002 134.026 9.38402 134.633 9.83202C135.249 10.2707 135.664 10.9007 135.879 11.722H134.157C134.017 11.3394 133.793 11.0407 133.485 10.826C133.177 10.6113 132.789 10.504 132.323 10.504C131.669 10.504 131.147 10.7373 130.755 11.204C130.372 11.6613 130.181 12.3053 130.181 13.136C130.181 13.9667 130.372 14.6153 130.755 15.082C131.147 15.5487 131.669 15.782 132.323 15.782C133.247 15.782 133.858 15.376 134.157 14.564H135.879C135.655 15.348 135.235 15.9733 134.619 16.44C134.003 16.8973 133.237 17.126 132.323 17.126C131.585 17.126 130.932 16.9627 130.363 16.636C129.793 16.3 129.345 15.8334 129.019 15.236C128.701 14.6294 128.543 13.9293 128.543 13.136Z" fill="#1D2939"/>
+<path d="M144.259 12.954C144.259 13.2433 144.241 13.5047 144.203 13.738H138.309C138.356 14.354 138.585 14.8487 138.995 15.222C139.406 15.5954 139.91 15.782 140.507 15.782C141.366 15.782 141.973 15.4227 142.327 14.704H144.049C143.816 15.4133 143.391 15.9967 142.775 16.454C142.169 16.902 141.413 17.126 140.507 17.126C139.77 17.126 139.107 16.9627 138.519 16.636C137.941 16.3 137.483 15.8334 137.147 15.236C136.821 14.6294 136.657 13.9293 136.657 13.136C136.657 12.3427 136.816 11.6473 137.133 11.05C137.46 10.4434 137.913 9.97668 138.491 9.65002C139.079 9.32335 139.751 9.16002 140.507 9.16002C141.235 9.16002 141.884 9.31868 142.453 9.63602C143.023 9.95335 143.466 10.4014 143.783 10.98C144.101 11.5493 144.259 12.2073 144.259 12.954ZM142.593 12.45C142.584 11.862 142.374 11.3907 141.963 11.036C141.553 10.6813 141.044 10.504 140.437 10.504C139.887 10.504 139.415 10.6813 139.023 11.036C138.631 11.3813 138.398 11.8527 138.323 12.45H142.593Z" fill="#1D2939"/>
+</g>
+</g>
+<defs>
+<linearGradient id="paint0_linear_9866_6170" x1="2.15214" y1="24.3018" x2="21.2921" y2="0.0988218" gradientUnits="userSpaceOnUse">
+<stop stop-color="#E9A85E"/>
+<stop offset="1" stop-color="#F52B76"/>
+</linearGradient>
+<linearGradient id="paint1_linear_9866_6170" x1="2.06269" y1="24.2294" x2="21.2027" y2="0.028252" gradientUnits="userSpaceOnUse">
+<stop stop-color="#E9A85E"/>
+<stop offset="1" stop-color="#F52B76"/>
+</linearGradient>
+<linearGradient id="paint2_linear_9866_6170" x1="-0.613606" y1="3.843" x2="21.4449" y2="18.7258" gradientUnits="userSpaceOnUse">
+<stop stop-color="#6A0CF5"/>
+<stop offset="1" stop-color="#AB66F3"/>
+</linearGradient>
+<clipPath id="clip0_9866_6170">
+<rect width="152" height="24" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/xorbits-inference.svg b/app/components/base/icons/assets/public/llm/xorbits-inference.svg
new file mode 100644
index 0000000..f5c5f75
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/xorbits-inference.svg
@@ -0,0 +1,24 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Xorbits Square" clip-path="url(#clip0_9850_26870)">
+<path id="Vector" d="M8.00391 12.3124C8.69334 13.0754 9.47526 13.7494 10.3316 14.3188C11.0667 14.8105 11.8509 15.2245 12.6716 15.5541C14.1617 14.1465 15.3959 12.4907 16.3192 10.6606L21.7051 0L12.3133 7.38353C10.5832 8.74456 9.12178 10.416 8.00391 12.3124Z" fill="url(#paint0_linear_9850_26870)"/>
+<path id="Vector_2" d="M7.23504 18.9512C6.56092 18.5012 5.92386 18.0265 5.3221 17.5394L2.06445 24L7.91975 19.3959C7.69034 19.2494 7.46092 19.103 7.23504 18.9512Z" fill="url(#paint1_linear_9850_26870)"/>
+<path id="Vector_3" d="M19.3161 8.57474C21.0808 10.9147 21.5961 13.5159 20.3996 15.3053C18.6526 17.9189 13.9161 17.8183 9.82024 15.0812C5.72435 12.3441 3.82024 8.0065 5.56729 5.39297C6.76377 3.60356 9.36318 3.0865 12.2008 3.81886C7.29318 1.73474 2.62376 1.94121 0.813177 4.64474C-1.45976 8.04709 1.64435 14.1177 7.74494 18.1889C13.8455 22.26 20.6361 22.8124 22.9091 19.4118C24.7179 16.703 23.1173 12.3106 19.3161 8.57474Z" fill="url(#paint2_linear_9850_26870)"/>
+</g>
+<defs>
+<linearGradient id="paint0_linear_9850_26870" x1="2.15214" y1="24.3018" x2="21.2921" y2="0.0988218" gradientUnits="userSpaceOnUse">
+<stop stop-color="#E9A85E"/>
+<stop offset="1" stop-color="#F52B76"/>
+</linearGradient>
+<linearGradient id="paint1_linear_9850_26870" x1="2.06269" y1="24.2294" x2="21.2027" y2="0.028252" gradientUnits="userSpaceOnUse">
+<stop stop-color="#E9A85E"/>
+<stop offset="1" stop-color="#F52B76"/>
+</linearGradient>
+<linearGradient id="paint2_linear_9850_26870" x1="-0.613606" y1="3.843" x2="21.4449" y2="18.7258" gradientUnits="userSpaceOnUse">
+<stop stop-color="#6A0CF5"/>
+<stop offset="1" stop-color="#AB66F3"/>
+</linearGradient>
+<clipPath id="clip0_9850_26870">
+<rect width="24" height="24" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/zhipuai-text-cn.svg b/app/components/base/icons/assets/public/llm/zhipuai-text-cn.svg
new file mode 100644
index 0000000..067ea2c
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/zhipuai-text-cn.svg
@@ -0,0 +1,8 @@
+<svg width="86" height="32" viewBox="0 0 86 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="shape">
+<path d="M85.3919 8.94111H83.2742V22.4705H85.3919V8.94111ZM76.9919 8.94111L74.8272 22.4705H76.7801L77.0154 20.9411L77.133 20.2117C77.1566 20.0705 77.3448 19.9529 77.5566 19.9529H79.3919C79.6036 19.9529 79.7919 20.0705 79.8154 20.2117L79.933 20.9411L80.1683 22.4705H82.3095L80.1213 8.94111H76.9919ZM79.2742 18.3529H77.6507C77.533 18.3529 77.4389 18.2352 77.4389 18.1176L78.1683 12.2117C78.1919 12.047 78.3095 11.9293 78.4507 11.9293C78.5919 11.9293 78.7095 12.047 78.733 12.2117L79.4625 18.1176C79.486 18.2588 79.3919 18.3529 79.2742 18.3529ZM15.2742 31.3176C15.086 31.3176 14.9448 31.4588 14.9448 31.647C14.9448 31.8352 15.086 31.9764 15.2742 31.9764C15.4624 31.9764 15.6036 31.8352 15.6036 31.647C15.6036 31.4588 15.4624 31.3176 15.2742 31.3176ZM19.133 11.6705C19.7321 11.6705 20.3067 11.4325 20.7303 11.0089C21.1539 10.5853 21.3919 10.0108 21.3919 9.4117C21.3919 8.81262 21.1539 8.23808 20.7303 7.81447C20.3067 7.39086 19.7321 7.15288 19.133 7.15288C18.534 7.15288 17.9594 7.39086 17.5358 7.81447C17.1122 8.23808 16.8742 8.81262 16.8742 9.4117C16.8742 10.0108 17.1122 10.5853 17.5358 11.0089C17.9594 11.4325 18.534 11.6705 19.133 11.6705ZM24.5601 17.6752C24.7699 17.4655 24.9363 17.2165 25.0498 16.9424C25.1633 16.6683 25.2218 16.3746 25.2218 16.0779C25.2218 15.7813 25.1633 15.4875 25.0498 15.2135C24.9363 14.9394 24.7699 14.6904 24.5601 14.4806C24.1365 14.057 23.5619 13.8191 22.9628 13.8191C22.3638 13.8191 21.7892 14.0571 21.3656 14.4808C20.942 14.9044 20.7041 15.4789 20.7041 16.078C20.7041 16.6771 20.9421 17.2516 21.3657 17.6752C21.5755 17.885 21.8245 18.0514 22.0985 18.165C22.3726 18.2785 22.6663 18.337 22.9629 18.337C23.2596 18.337 23.5533 18.2785 23.8273 18.165C24.1014 18.0514 24.3504 17.885 24.5601 17.6752ZM9.69233 16.9369C9.9216 16.3834 9.9216 15.7614 9.69232 15.2079C9.46304 14.6544 9.02327 14.2146 8.46974 13.9853C7.91622 13.7561 7.29429 13.7561 6.74077 13.9854C6.18725 14.2146 5.74749 14.6544 5.51821 15.2079C5.28894 15.7615 5.28895 16.3834 5.51823 16.9369C5.74751 17.4904 6.18728 17.9302 6.7408 18.1595C7.01488 18.273 7.30863 18.3314 7.60529 18.3314C7.90195 18.3314 8.1957 18.273 8.46977 18.1595C9.02329 17.9302 9.46306 17.4904 9.69233 16.9369ZM24.9683 11.8823C25.1506 11.8823 25.3312 11.8464 25.4996 11.7766C25.668 11.7069 25.8211 11.6046 25.95 11.4757C26.0789 11.3468 26.1811 11.1937 26.2509 11.0253C26.3207 10.8569 26.3566 10.6764 26.3566 10.4941C26.3566 10.3117 26.3207 10.1312 26.2509 9.9628C26.1811 9.79437 26.0789 9.64133 25.95 9.51242C25.8211 9.38351 25.668 9.28126 25.4996 9.21149C25.3312 9.14173 25.1506 9.10582 24.9683 9.10582C24.6001 9.10582 24.247 9.25208 23.9867 9.51242C23.7264 9.77277 23.5801 10.1259 23.5801 10.4941C23.5801 10.8622 23.7264 11.2153 23.9867 11.4757C24.247 11.736 24.6001 11.8823 24.9683 11.8823ZM15.5904 6.24605C15.77 6.20622 15.9398 6.13112 16.0901 6.02511C16.2403 5.9191 16.368 5.78429 16.4658 5.62851C16.5635 5.47273 16.6293 5.29909 16.6593 5.11766C16.6894 4.93624 16.6831 4.75065 16.6408 4.57168C16.5986 4.39271 16.5212 4.22392 16.4131 4.07512C16.3051 3.92631 16.1685 3.80046 16.0114 3.70486C15.8543 3.60926 15.6798 3.54583 15.498 3.51824C15.3162 3.49066 15.1307 3.49947 14.9523 3.54417C14.5984 3.63287 14.2936 3.85737 14.1039 4.1691C13.9142 4.48083 13.8548 4.85472 13.9387 5.20986C14.0226 5.565 14.2429 5.87284 14.552 6.06676C14.8612 6.26068 15.2342 6.32509 15.5904 6.24605ZM5.60362 11.8823C5.78593 11.8823 5.96645 11.8464 6.13488 11.7766C6.30331 11.7069 6.45635 11.6046 6.58526 11.4757C6.71417 11.3468 6.81642 11.1937 6.88619 11.0253C6.95595 10.8569 6.99186 10.6764 6.99186 10.4941C6.99186 10.3117 6.95595 10.1312 6.88619 9.9628C6.81642 9.79437 6.71417 9.64133 6.58526 9.51242C6.45635 9.38351 6.30331 9.28126 6.13488 9.21149C5.96645 9.14173 5.78593 9.10582 5.60362 9.10582C5.23544 9.10582 4.88234 9.25208 4.62199 9.51242C4.36165 9.77277 4.21539 10.1259 4.21539 10.4941C4.21539 10.8622 4.36165 11.2153 4.62199 11.4757C4.88234 11.736 5.23544 11.8823 5.60362 11.8823ZM6.58904 22.6493C6.71795 22.5204 6.82021 22.3674 6.88997 22.199C6.95974 22.0305 6.99565 21.85 6.99565 21.6677C6.99565 21.4854 6.95974 21.3049 6.88997 21.1364C6.82021 20.968 6.71795 20.815 6.58904 20.6861C6.46012 20.5571 6.30708 20.4549 6.13865 20.3851C5.97022 20.3154 5.7897 20.2794 5.60739 20.2794C5.42508 20.2794 5.24456 20.3154 5.07613 20.3851C4.90769 20.4549 4.75465 20.5571 4.62574 20.6861C4.36539 20.9464 4.21913 21.2995 4.21913 21.6677C4.21913 22.0359 4.36539 22.389 4.62574 22.6493C4.88609 22.9097 5.2392 23.056 5.60739 23.056C5.97558 23.056 6.32869 22.9097 6.58904 22.6493ZM15.5919 28.5983C15.7693 28.5564 15.9367 28.48 16.0846 28.3734C16.2324 28.2668 16.3579 28.1321 16.4537 27.977C16.5495 27.8219 16.6138 27.6495 16.643 27.4696C16.6722 27.2896 16.6656 27.1057 16.6237 26.9283C16.5818 26.7509 16.5054 26.5835 16.3988 26.4356C16.2922 26.2877 16.1575 26.1623 16.0025 26.0665C15.8474 25.9707 15.675 25.9063 15.495 25.8771C15.3151 25.848 15.1312 25.8545 14.9537 25.8964C14.7742 25.9362 14.6044 26.0113 14.4541 26.1174C14.3039 26.2234 14.1762 26.3582 14.0784 26.514C13.9807 26.6697 13.9149 26.8434 13.8849 27.0248C13.8548 27.2062 13.8611 27.3918 13.9034 27.5708C13.9456 27.7497 14.023 27.9185 14.1311 28.0673C14.2391 28.2162 14.3757 28.342 14.5328 28.4376C14.6898 28.5332 14.8644 28.5966 15.0462 28.6242C15.228 28.6518 15.4135 28.643 15.5919 28.5983ZM25.2848 22.9973C25.4634 22.9566 25.6322 22.881 25.7815 22.7747C25.9307 22.6684 26.0574 22.5337 26.1543 22.3782C26.2512 22.2227 26.3164 22.0496 26.3461 21.8688C26.3758 21.6881 26.3694 21.5032 26.3273 21.3249C26.2853 21.1466 26.2083 20.9784 26.1009 20.83C25.9935 20.6815 25.8578 20.5559 25.7015 20.4601C25.5453 20.3644 25.3717 20.3006 25.1907 20.2723C25.0097 20.244 24.8249 20.2518 24.6469 20.2952C24.291 20.3821 23.9839 20.6062 23.7925 20.9185C23.6011 21.2309 23.541 21.6063 23.6251 21.9628C23.7093 22.3193 23.931 22.6281 24.2419 22.8219C24.5528 23.0157 24.9276 23.0788 25.2848 22.9973ZM22.286 4.82347C22.7566 4.82347 23.133 4.447 23.133 3.97641C23.133 3.50582 22.7566 3.12935 22.286 3.12935C21.8154 3.12935 21.4389 3.50582 21.4389 3.97641C21.4389 4.447 21.8154 4.82347 22.286 4.82347ZM8.28598 4.82347C8.75657 4.82347 9.13304 4.447 9.13304 3.97641C9.13304 3.50582 8.75657 3.12935 8.28598 3.12935C7.81539 3.12935 7.43892 3.50582 7.43892 3.97641C7.43892 4.447 7.81539 4.82347 8.28598 4.82347ZM1.29774 15.2235C0.827154 15.2235 0.450684 15.5999 0.450684 16.0705C0.450684 16.5411 0.827154 16.9176 1.29774 16.9176C1.76833 16.9176 2.1448 16.5411 2.1448 16.0705C2.16833 15.5999 1.76833 15.2235 1.29774 15.2235ZM8.28598 27.3176C7.81539 27.3176 7.43892 27.6941 7.43892 28.1646C7.43892 28.6352 7.81539 29.0117 8.28598 29.0117C8.75657 29.0117 9.13304 28.6352 9.13304 28.1646C9.13304 27.6941 8.75657 27.3176 8.28598 27.3176ZM22.286 27.3411C21.8154 27.3411 21.4389 27.7176 21.4389 28.1882C21.4389 28.6588 21.8154 29.0352 22.286 29.0352C22.7566 29.0352 23.133 28.6588 23.133 28.1882C23.133 27.7176 22.7566 27.3411 22.286 27.3411ZM29.2742 15.2235C28.8036 15.2235 28.4272 15.5999 28.4272 16.0705C28.4272 16.5411 28.8036 16.9176 29.2742 16.9176C29.7448 16.9176 30.1213 16.5411 30.1213 16.0705C30.1213 15.5999 29.7448 15.2235 29.2742 15.2235ZM28.7566 8.6117C28.9448 8.6117 29.086 8.47053 29.086 8.28229C29.086 8.09405 28.9448 7.95288 28.7566 7.95288C28.5683 7.95288 28.4272 8.09405 28.4272 8.28229C28.4272 8.47053 28.5919 8.6117 28.7566 8.6117ZM15.2742 0.846995C15.4624 0.846995 15.6036 0.705819 15.6036 0.517583C15.6036 0.329348 15.4624 0.188171 15.2742 0.188171C15.086 0.188171 14.9448 0.329348 14.9448 0.517583C14.9448 0.705819 15.1095 0.846995 15.2742 0.846995ZM1.81539 8.6117C2.00362 8.6117 2.1448 8.47053 2.1448 8.28229C2.1448 8.09405 2.00362 7.95288 1.81539 7.95288C1.62715 7.95288 1.48598 8.09405 1.48598 8.28229C1.48598 8.47053 1.62715 8.6117 1.81539 8.6117ZM1.81539 23.5293C1.62715 23.5293 1.48598 23.6705 1.48598 23.8588C1.48598 24.047 1.62715 24.1882 1.81539 24.1882C2.00362 24.1882 2.1448 24.047 2.1448 23.8588C2.1448 23.6705 1.9801 23.5293 1.81539 23.5293ZM28.7801 23.5058C28.5919 23.5058 28.4507 23.647 28.4507 23.8352C28.4507 24.0235 28.5919 24.1646 28.7801 24.1646C28.9683 24.1646 29.1095 24.0235 29.1095 23.8352C29.1095 23.6705 28.9683 23.5058 28.7801 23.5058Z" fill="#3859FF"/>
+<path d="M19.8154 20.5882C18.8036 20.2588 17.7683 20.6823 17.2272 21.5293L17.2036 21.5764C16.686 22.447 15.6507 22.9176 14.6389 22.6117C14.0742 22.4235 13.6272 22.047 13.3448 21.5529C13.2977 21.4117 13.2742 21.2705 13.2742 21.1058C13.2272 20.1411 13.9801 19.3176 14.9448 19.2941H15.1801C16.9683 19.3646 18.4507 17.9764 18.5213 16.2117C18.5919 14.4235 17.2036 12.9411 15.4389 12.8705H14.9448C13.9801 12.8235 13.2977 12.0705 13.3448 11.1293C13.3448 10.8941 13.3919 10.6823 13.486 10.4705L13.5095 10.3999C13.5566 10.2823 13.5801 10.2352 13.6272 10.1176C14.0036 8.91758 13.3448 7.67052 12.1448 7.29405C10.9683 6.94111 9.69774 7.57641 9.32127 8.75288C8.9448 9.90582 9.5801 11.1529 10.733 11.5529C10.9213 11.6235 11.0389 11.647 11.2036 11.6705L11.2977 11.6941C12.2154 11.7882 12.9213 12.5176 12.8977 13.4588C12.8742 13.7882 12.7801 14.1176 12.5919 14.3764C12.286 14.847 12.1213 15.3882 12.0977 15.9764C12.0742 16.6588 12.2624 17.3176 12.5919 17.8352C12.7801 18.0941 12.8742 18.3999 12.8977 18.7529C12.9448 19.6941 12.3095 20.4235 11.3919 20.5176H11.3683C11.2272 20.5176 11.086 20.5411 10.9683 20.5646C9.72127 20.847 8.99186 22.0705 9.27421 23.2705C9.55657 24.4941 10.7801 25.2235 11.9566 24.9646C12.5919 24.8235 13.086 24.447 13.3919 23.9529C13.9095 23.0588 14.9919 22.6352 16.0272 22.9646C16.5919 23.1293 16.9683 23.4823 17.2507 23.9293L17.2742 23.9764C17.5095 24.3529 17.9566 24.7529 18.4977 24.9176C19.7213 25.2705 20.9213 24.6117 21.2977 23.4588C21.6742 22.2117 20.9683 20.9646 19.8154 20.5882ZM70.2625 16.2588C70.537 16.2588 70.8004 16.1497 70.9945 15.9555C71.1887 15.7614 71.2977 15.498 71.2977 15.2235C71.2977 14.9489 71.1887 14.6856 70.9945 14.4914C70.8004 14.2972 70.537 14.1882 70.2625 14.1882C69.9879 14.1882 69.7245 14.2972 69.5304 14.4914C69.3362 14.6856 69.2272 14.9489 69.2272 15.2235C69.2272 15.498 69.3362 15.7614 69.5304 15.9555C69.7245 16.1497 69.9879 16.2588 70.2625 16.2588ZM43.8624 15.5293C43.7213 15.4588 43.5095 15.2941 43.2036 15.1058C42.3801 14.5411 41.7448 14.1176 41.3448 13.8117H43.9095V12.5882H41.5095C41.5566 12.4705 41.5566 11.2941 41.5566 10.9646C41.5801 10.6823 41.6036 10.447 41.6036 10.2823H43.5095V9.05876H39.5801C39.7683 8.72935 39.9095 8.37641 40.0272 7.95288L38.7095 7.83523C38.3801 8.89405 37.8154 9.8117 37.0154 10.5882C37.3448 10.9176 37.533 11.1293 37.6036 11.2705C37.7213 11.3882 37.7919 11.5058 37.886 11.5764C38.333 11.1293 38.6624 10.7058 38.9213 10.2823H40.2389C40.2389 10.7764 40.1919 12.1646 40.1213 12.5646H37.133V13.7882H39.8625C39.5095 14.6352 38.5448 15.3882 37.0389 15.9999C37.3213 16.3999 37.6036 16.8235 37.8625 17.2941C38.1448 17.0823 38.4507 16.9176 38.733 16.7999V23.5293H40.1448V22.847H47.0625V23.5293H48.5213V16.7529H43.086L43.8624 15.5293ZM38.8036 16.7293C39.7919 16.1176 40.4272 15.4823 40.7566 14.847C40.8977 14.9176 41.086 15.0823 41.2977 15.2705C42.0507 15.8823 42.6625 16.3764 43.086 16.7293H38.8036ZM47.0625 21.7646H40.1448V20.4235H47.0625V21.7646ZM47.0625 19.3176H40.1448V18.0235H47.0625V19.3176Z" fill="#3859FF"/>
+<path d="M44.4507 15.6941H49.5095V8.94111H44.4507V15.6941ZM45.7683 10.3058H48.2154V14.4235H45.7683V10.3058ZM54.4742 11.3882L55.7213 10.5411C55.0389 9.55288 54.4507 8.79994 53.9801 8.2117L52.8977 8.94111C53.0389 9.17641 53.2507 9.52935 53.5566 9.97641C54.0036 10.6352 54.3095 11.1058 54.4742 11.3882ZM64.0272 13.9764C64.1448 13.8588 64.286 13.647 64.4742 13.3646C64.8742 12.847 65.1566 12.447 65.2977 12.2117L64.3095 11.5293C64.0977 11.9058 63.6742 12.4705 63.0625 13.247L64.0272 13.9764ZM58.4507 13.247C58.3095 13.0352 58.0977 12.7529 57.7919 12.3999C57.5095 11.9999 57.2742 11.7176 57.133 11.5529L56.2154 12.2352C56.7566 12.9646 57.1801 13.5529 57.4624 13.9999L58.4507 13.247ZM55.2977 20.2823C55.1801 20.3999 55.1095 20.4941 55.086 20.5176V13.9293H52.5213V15.4588H53.6742V20.8941C53.6742 21.4352 53.5566 21.8117 53.2977 22.047L54.1683 23.3882C54.686 22.7058 55.4624 21.8823 56.4977 20.9411C56.3801 20.2117 56.3095 19.647 56.2154 19.2235C56.0507 19.4823 55.7448 19.8352 55.2977 20.2823ZM54.1683 23.4117V23.3882L54.1448 23.4117H54.1683ZM57.0389 23.5764H58.4036V22.9646H63.0389V23.5764H64.4507V17.0352H57.0389V23.5764ZM58.4036 18.2588H63.0389V19.5529H58.4036V18.2588ZM58.4036 20.5882H63.0389V21.8117H58.4036V20.5882Z" fill="#3859FF"/>
+<path d="M65.3213 10.7999V9.647H62.9213C63.2742 9.08229 63.5095 8.72935 63.5801 8.6117C63.6977 8.39994 63.7683 8.25876 63.8625 8.18817L62.4977 7.88229C62.1683 8.49405 61.8154 9.08229 61.4154 9.647H60.0977C59.9566 9.4117 59.7213 9.03523 59.3919 8.54111C59.2036 8.25876 59.0625 8.02347 58.9448 7.85876L57.6272 8.16464C57.8154 8.39994 58.1213 8.89405 58.5448 9.62347H56.2625V10.7764H58.8272V14.7764H55.7683V15.9293H65.6742V14.7764H62.5213V10.7999H65.3213ZM61.3448 14.7764H60.0977V10.7764H61.3448V14.7764Z" fill="#3859FF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/zhipuai-text.svg b/app/components/base/icons/assets/public/llm/zhipuai-text.svg
new file mode 100644
index 0000000..d324999
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/zhipuai-text.svg
@@ -0,0 +1,6 @@
+<svg width="89" height="32" viewBox="0 0 89 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="shape">
+<path d="M88.8045 8.82998H86.7123V22.4497H88.8045V8.82998ZM80.5485 8.82998L78.4158 22.4497H80.3339L80.5589 20.9156L80.6709 20.1853C80.6916 20.0394 80.8751 19.9142 81.0793 19.9142H82.8855C83.0897 19.9142 83.2732 20.029 83.2939 20.1853L83.4059 20.9156L83.6299 22.4497H85.7429L83.6102 8.82998H80.5485ZM82.7838 18.2963H81.181C81.1522 18.2968 81.1237 18.2909 81.0975 18.279C81.0713 18.2671 81.0481 18.2495 81.0295 18.2275C81.0109 18.2056 80.9975 18.1797 80.9902 18.1519C80.9828 18.1241 80.9818 18.095 80.9871 18.0667L81.7024 12.1175C81.7212 11.95 81.8436 11.8352 81.9772 11.8352C82.109 11.8352 82.2426 11.95 82.253 12.1175L82.9673 18.0657C82.9767 18.1919 82.8855 18.2963 82.7735 18.2963H82.7838ZM14.8563 31.3316C14.7706 31.3519 14.6961 31.4046 14.6485 31.4787C14.6009 31.5528 14.584 31.6425 14.6012 31.7288C14.6417 31.9057 14.8158 32.0309 14.989 31.9895C15.0746 31.9695 15.1491 31.9169 15.1967 31.843C15.2443 31.769 15.2613 31.6795 15.244 31.5933C15.2036 31.4154 15.0295 31.2902 14.8563 31.3316ZM19.6337 11.3693C20.7471 10.8544 21.2412 9.51233 20.7368 8.37257C20.2323 7.23374 18.9203 6.72739 17.8059 7.24316C16.6925 7.75986 16.1975 9.10198 16.7019 10.2408C17.2064 11.3806 18.5184 11.885 19.6337 11.3693ZM23.1245 18.1712C24.2963 17.8107 24.9598 16.5476 24.6078 15.3504C24.2549 14.1523 23.02 13.4737 21.8483 13.8342C20.6775 14.1947 20.013 15.4577 20.3659 16.6559C20.7189 17.853 21.9537 18.5316 23.1245 18.1712ZM5.89628 14.2982C5.45885 14.7037 5.19533 15.2628 5.16094 15.8583C5.12655 16.4537 5.32396 17.0394 5.71181 17.4926C5.90262 17.7129 6.13553 17.8928 6.39686 18.0219C6.6582 18.1509 6.94268 18.2264 7.23361 18.2439C7.52453 18.2615 7.81602 18.2207 8.09096 18.124C8.36591 18.0273 8.61875 17.8766 8.83463 17.6808C9.27207 17.2753 9.53559 16.7162 9.56998 16.1208C9.60437 15.5253 9.40695 14.9396 9.0191 14.4864C8.8283 14.2661 8.59539 14.0862 8.33405 13.9571C8.07272 13.8281 7.78823 13.7526 7.49731 13.7351C7.20639 13.7175 6.91489 13.7583 6.63995 13.855C6.36501 13.9517 6.11217 14.1024 5.89628 14.2982ZM25.3579 11.4182C25.9189 10.9062 25.9697 10.0196 25.4699 9.44551C25.3521 9.30917 25.2082 9.19782 25.0467 9.11802C24.8852 9.03822 24.7093 8.99159 24.5295 8.98088C24.3496 8.97018 24.1694 8.99562 23.9996 9.0557C23.8297 9.11578 23.6736 9.20928 23.5405 9.33068C23.27 9.581 23.1072 9.92649 23.0863 10.2944C23.0654 10.6624 23.1881 11.0241 23.4285 11.3034C23.9292 11.8775 24.796 11.9293 25.3579 11.4182ZM14.9278 6.15798C15.6826 6.15798 16.2953 5.53116 16.2953 4.75939C16.2953 3.98763 15.6836 3.3608 14.9278 3.3608C14.172 3.3608 13.5603 3.98669 13.5603 4.75939C13.5603 5.53116 14.172 6.15798 14.9278 6.15798ZM5.40687 11.773C6.16169 11.773 6.77346 11.1472 6.77346 10.3744C6.77346 9.60268 6.16169 8.97586 5.40593 8.97586C4.65111 8.97586 4.0384 9.60174 4.0384 10.3744C4.0384 11.1462 4.65111 11.773 5.40687 11.773ZM4.48734 20.5815C4.21673 20.8317 4.05374 21.1771 4.03268 21.5451C4.01161 21.913 4.13411 22.2748 4.3744 22.5542C4.87511 23.1283 5.74287 23.181 6.30381 22.669C6.86569 22.158 6.91558 21.2704 6.41675 20.6963C6.29897 20.56 6.15507 20.4486 5.99354 20.3688C5.83201 20.289 5.65613 20.2424 5.47628 20.2317C5.29643 20.221 5.11626 20.2464 4.94641 20.3065C4.77656 20.3666 4.62046 20.4601 4.48734 20.5815ZM14.9278 28.6493C15.6826 28.6493 16.2953 28.0234 16.2953 27.2507C16.2953 26.4789 15.6836 25.8521 14.9278 25.8521C14.172 25.8521 13.5603 26.4789 13.5603 27.2507C13.5603 28.0234 14.172 28.6493 14.9278 28.6493ZM24.4591 23.0135C25.2149 23.0135 25.8266 22.3876 25.8266 21.6149C25.8266 20.8432 25.2149 20.2163 24.4591 20.2163C23.7043 20.2163 23.0916 20.8422 23.0916 21.6149C23.0916 22.3867 23.7033 23.0135 24.4591 23.0135ZM21.7645 4.68692C21.8768 4.69378 21.9894 4.67794 22.0955 4.64035C22.2015 4.60275 22.2989 4.54416 22.3819 4.46809C22.4648 4.39202 22.5315 4.30001 22.5781 4.19757C22.6247 4.09514 22.6502 3.98436 22.653 3.87186C22.6618 3.75964 22.6481 3.64679 22.6126 3.53995C22.5771 3.43312 22.5206 3.33448 22.4464 3.24983C22.3722 3.16518 22.2818 3.09625 22.1805 3.0471C22.0793 2.99794 21.9692 2.96956 21.8568 2.96363C21.7446 2.9569 21.6322 2.9728 21.5263 3.0104C21.4204 3.048 21.3232 3.10652 21.2404 3.18248C21.1575 3.25845 21.0909 3.35029 21.0443 3.45256C20.9977 3.55482 20.9722 3.66541 20.9692 3.77774C20.9604 3.88997 20.9741 4.00282 21.0096 4.10965C21.0451 4.21648 21.1016 4.31513 21.1758 4.39978C21.25 4.48442 21.3404 4.55335 21.4417 4.60251C21.543 4.65166 21.6521 4.68099 21.7645 4.68692ZM7.5904 4.5401C7.68271 4.60167 7.78644 4.6441 7.89544 4.66485C8.00445 4.68561 8.11651 4.68427 8.22499 4.66093C8.33347 4.63758 8.43616 4.5927 8.52697 4.52894C8.61779 4.46518 8.69489 4.38384 8.75369 4.28974C8.8757 4.09858 8.91838 3.8674 8.87269 3.64527C8.827 3.42315 8.69653 3.22758 8.50899 3.1001C8.41664 3.03837 8.31284 2.99582 8.20374 2.97499C8.09464 2.95415 7.98246 2.95544 7.87387 2.9788C7.76528 3.00215 7.66248 3.04708 7.57159 3.11092C7.4807 3.17477 7.40356 3.25622 7.34475 3.35045C7.22275 3.54161 7.18006 3.7728 7.22575 3.99492C7.27144 4.21704 7.40285 4.41261 7.5904 4.5401ZM0.803576 15.2281C0.384753 15.4361 0.221929 15.9584 0.426164 16.3857C0.474224 16.4863 0.541877 16.5762 0.625154 16.6502C0.708432 16.7242 0.805655 16.7809 0.911121 16.8168C1.01659 16.8528 1.12817 16.8673 1.23932 16.8595C1.35047 16.8518 1.45895 16.8219 1.5584 16.7716C1.97722 16.5636 2.14005 16.0413 1.93581 15.614C1.88775 15.5136 1.82013 15.4238 1.73693 15.3498C1.65372 15.2759 1.55659 15.2193 1.45124 15.1833C1.34588 15.1474 1.23442 15.1329 1.12337 15.1405C1.01232 15.1482 0.902978 15.178 0.803576 15.2281ZM8.10052 27.3241C7.98827 27.3172 7.87579 27.333 7.76979 27.3706C7.66378 27.4081 7.56642 27.4666 7.48351 27.5426C7.40059 27.6186 7.33383 27.7105 7.28719 27.8128C7.24055 27.9151 7.215 28.0258 7.21205 28.1382C7.20322 28.2504 7.21695 28.3633 7.25243 28.4701C7.28791 28.577 7.34442 28.6756 7.41863 28.7602C7.49284 28.8449 7.58324 28.9138 7.68451 28.963C7.78578 29.0121 7.89587 29.0405 8.00828 29.0464C8.12045 29.0532 8.23283 29.0373 8.33873 28.9997C8.44462 28.9621 8.54187 28.9035 8.62468 28.8276C8.70749 28.7516 8.77417 28.6598 8.82075 28.5575C8.86733 28.4553 8.89286 28.3447 8.89581 28.2323C8.90464 28.1202 8.89094 28.0074 8.85551 27.9006C8.82009 27.7939 8.76367 27.6953 8.68956 27.6106C8.61545 27.526 8.52515 27.457 8.42399 27.4078C8.32283 27.3586 8.21285 27.3301 8.10052 27.3241ZM22.2756 27.47C22.1832 27.4085 22.0795 27.3662 21.9705 27.3455C21.8615 27.3248 21.7495 27.3262 21.6411 27.3495C21.5326 27.3729 21.43 27.4177 21.3391 27.4814C21.2483 27.5451 21.1712 27.6263 21.1123 27.7203C20.99 27.9116 20.9471 28.143 20.9928 28.3653C21.0385 28.5877 21.1692 28.7834 21.357 28.9109C21.4494 28.9725 21.5531 29.0148 21.6622 29.0355C21.7712 29.0562 21.8833 29.0548 21.9918 29.0313C22.1003 29.0079 22.2029 28.9629 22.2937 28.8991C22.3845 28.8352 22.4615 28.7538 22.5203 28.6596C22.6423 28.4685 22.685 28.2373 22.6393 28.0152C22.5936 27.793 22.4631 27.5975 22.2756 27.47ZM29.1433 15.2799C29.051 15.2184 28.9473 15.1761 28.8383 15.1554C28.7293 15.1347 28.6173 15.1361 28.5088 15.1594C28.4004 15.1828 28.2977 15.2276 28.2069 15.2913C28.1161 15.355 28.0389 15.4362 27.98 15.5302C27.858 15.7214 27.8154 15.9526 27.861 16.1747C27.9067 16.3968 28.0372 16.5924 28.2248 16.7199C28.3171 16.7816 28.4209 16.8241 28.53 16.845C28.6391 16.8658 28.7513 16.8645 28.8599 16.8412C28.9685 16.8178 29.0713 16.7729 29.1621 16.709C29.253 16.6452 29.3302 16.5637 29.389 16.4695C29.511 16.2783 29.5537 16.0472 29.508 15.825C29.4623 15.6029 29.3309 15.4073 29.1433 15.2799ZM28.4092 8.4121C28.4723 8.35188 28.5104 8.27016 28.516 8.18315C28.5215 8.09614 28.4942 8.01022 28.4393 7.94245C28.382 7.87833 28.3018 7.83918 28.216 7.83338C28.1302 7.82757 28.0455 7.85557 27.98 7.91139C27.917 7.9716 27.8789 8.05333 27.8733 8.14034C27.8677 8.22734 27.8951 8.31326 27.9499 8.38104C28.0073 8.44516 28.0874 8.48431 28.1732 8.49011C28.2591 8.49591 28.3438 8.46791 28.4092 8.4121ZM14.988 0.668097C15.0739 0.648054 15.1486 0.595414 15.1964 0.521299C15.2442 0.447185 15.2613 0.357402 15.244 0.270921C15.2036 0.0939798 15.0295 -0.0311966 14.8563 0.0102151C14.7708 0.0304659 14.6965 0.0830504 14.6489 0.156931C14.6013 0.230811 14.5843 0.320241 14.6012 0.40645C14.6417 0.584333 14.8149 0.709509 14.988 0.668097ZM1.56875 8.48551C1.74193 8.54763 1.9264 8.44315 1.98758 8.27657C2.0149 8.19261 2.00894 8.10137 1.97093 8.02168C1.93293 7.94199 1.86578 7.87994 1.78334 7.84833C1.60922 7.78621 1.42569 7.89068 1.36452 8.05727C1.3372 8.14123 1.34315 8.23247 1.38116 8.31216C1.41916 8.39185 1.48632 8.4539 1.56875 8.48551ZM1.4464 23.5763C1.38294 23.6365 1.3445 23.7183 1.33874 23.8055C1.33299 23.8928 1.36034 23.979 1.41534 24.0469C1.47268 24.111 1.55284 24.1502 1.63866 24.156C1.72449 24.1618 1.80918 24.1338 1.87463 24.078C1.93783 24.0179 1.9761 23.9362 1.98186 23.8492C1.98761 23.7622 1.96042 23.6762 1.90569 23.6083C1.84835 23.5442 1.7682 23.5051 1.68237 23.4993C1.59655 23.4935 1.51185 23.5205 1.4464 23.5763ZM28.2963 23.5039C28.1231 23.4417 27.9396 23.5462 27.8784 23.7128C27.8511 23.7968 27.857 23.888 27.895 23.9677C27.933 24.0474 28.0002 24.1094 28.0826 24.141C28.2558 24.2032 28.4403 24.0987 28.5005 23.9321C28.5279 23.8483 28.5221 23.7571 28.4842 23.6774C28.4464 23.5978 28.3785 23.5356 28.2963 23.5039Z" fill="#3859FF"/>
+<path d="M19.3866 20.5504C18.918 20.3949 18.4104 20.4031 17.947 20.5738C17.4836 20.7444 17.0919 21.0674 16.836 21.4897L16.8153 21.5311C16.3052 22.4186 15.2944 22.8883 14.2949 22.5645C13.7534 22.3884 13.3002 22.011 13.029 21.5104C12.986 21.364 12.9585 21.2135 12.9471 21.0614C12.9066 20.092 13.6313 19.277 14.58 19.2252H14.805C16.5499 19.2977 18.0295 17.9094 18.101 16.1146C18.1725 14.3198 16.8153 12.8167 15.06 12.7433H14.58C13.6313 12.7019 12.9678 11.9499 13.0083 10.9795C13.0083 10.7499 13.0497 10.5203 13.141 10.3217L13.1617 10.2595C13.205 10.1646 13.2427 10.0672 13.2746 9.96778C13.6417 8.76684 12.9885 7.49343 11.8252 7.1179C10.6713 6.75272 9.42616 7.38896 9.04875 8.60025C8.68169 9.76919 9.29345 11.021 10.4266 11.4285C10.6102 11.4906 10.7222 11.5123 10.8963 11.5433H10.9876C11.8864 11.6468 12.5904 12.3885 12.5593 13.3278C12.5499 13.6723 12.437 13.9857 12.2638 14.2464C11.9614 14.7295 11.7925 15.2842 11.7744 15.8539C11.7439 16.5152 11.9146 17.1701 12.2638 17.7325C12.437 17.9932 12.549 18.3066 12.5593 18.6511C12.6007 19.5904 11.988 20.3311 11.0902 20.4252H11.0695C10.9377 20.4252 10.7843 20.4563 10.661 20.477C9.43745 20.7593 8.71275 21.98 8.98757 23.2017C9.26333 24.4327 10.4671 25.1527 11.6106 24.892C11.9023 24.8289 12.1778 24.7064 12.42 24.5321C12.6622 24.3579 12.866 24.1357 13.0186 23.8793C13.2694 23.4422 13.6626 23.1044 14.1324 22.9221C14.6022 22.7399 15.1203 22.7243 15.6003 22.8779C16.1415 23.0548 16.5292 23.389 16.805 23.8586L16.8351 23.9113C17.0704 24.2972 17.5193 24.6944 18.0492 24.8506C19.2539 25.2158 20.4379 24.5475 20.8163 23.3786C21.2031 22.1579 20.5095 20.8939 19.3866 20.5297V20.5504ZM75.0064 14.1005C74.4454 14.1005 73.9862 14.5701 73.9862 15.1443C73.9862 15.7184 74.4454 16.188 75.0064 16.188C75.5673 16.188 76.0266 15.7174 76.0266 15.1433C76.0286 14.87 75.9225 14.607 75.7314 14.4117C75.5403 14.2163 75.2797 14.1045 75.0064 14.1005ZM38.1029 10.7395H41.4506C41.5214 10.7415 41.5886 10.7709 41.6381 10.8214C41.6876 10.872 41.7156 10.9398 41.716 11.0106C41.716 11.0426 41.716 11.084 41.6963 11.1047L37.9203 20.3941V22.2831H43.972V20.3631H40.4407C40.3698 20.3611 40.3025 20.3316 40.2529 20.2809C40.2034 20.2301 40.1756 20.162 40.1753 20.0911C40.1753 20.06 40.1753 20.028 40.196 19.997L43.972 10.7075V8.82049H38.1029V10.7395ZM49.6153 14.3198C49.6149 14.3906 49.5869 14.4584 49.5374 14.509C49.4879 14.5595 49.4207 14.5889 49.3499 14.5908H47.524C47.4887 14.5908 47.4536 14.5838 47.421 14.5701C47.3884 14.5564 47.3588 14.5364 47.334 14.5112C47.3092 14.4859 47.2897 14.456 47.2766 14.4232C47.2635 14.3903 47.2571 14.3552 47.2577 14.3198V8.81861H45.1862V22.2821H47.2577V16.7819C47.2578 16.7127 47.2842 16.6461 47.3315 16.5956C47.3789 16.5451 47.4437 16.5144 47.5127 16.5099H49.3396C49.4826 16.5099 49.5946 16.636 49.5946 16.7819V22.2821H51.6972V8.81861H49.5946V14.3188L49.6153 14.3198ZM55.2887 8.81861H53.2182V22.2831H55.2887V8.81861ZM59.8412 8.81861H56.7899V22.2831H58.8605V17.2214H59.8412C61.9127 17.2214 62.9226 16.0525 62.9226 13.8915V12.1381C62.9226 9.98849 61.9127 8.80825 59.8412 8.80825V8.81861ZM60.8511 14.0271C60.8511 14.9871 60.4934 15.3005 59.8412 15.3005H59.1259C59.0907 15.3002 59.0559 15.293 59.0235 15.2792C58.9911 15.2654 58.9617 15.2454 58.9371 15.2202C58.9125 15.1949 58.8932 15.1651 58.8802 15.1324C58.8672 15.0996 58.8608 15.0646 58.8615 15.0294V11.0106C58.8619 10.9398 58.8899 10.872 58.9394 10.8214C58.9889 10.7709 59.0561 10.7415 59.1269 10.7395H59.8412C60.4944 10.7395 60.8511 11.0426 60.8511 12.013V14.0271ZM67.9946 19.2035C67.9946 20.1635 67.5767 20.509 66.9236 20.509C66.2704 20.509 65.8525 20.1645 65.8525 19.2035V8.81955H63.78V19.069C63.78 21.2186 64.8313 22.4497 66.8624 22.4497C68.8934 22.4497 69.9447 21.2186 69.9447 19.068V8.81861H67.9852V19.2035H67.9946Z" fill="#3859FF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/llm/zhipuai.svg b/app/components/base/icons/assets/public/llm/zhipuai.svg
new file mode 100644
index 0000000..016f97d
--- /dev/null
+++ b/app/components/base/icons/assets/public/llm/zhipuai.svg
@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="ZHIPU Square">
+<g id="shape">
+<path d="M11.8923 23.4987C11.8281 23.5139 11.7722 23.5535 11.7365 23.609C11.7008 23.6646 11.6881 23.7319 11.701 23.7966C11.7314 23.9293 11.862 24.0232 11.9919 23.9921C12.0561 23.9771 12.1119 23.9377 12.1476 23.8823C12.1833 23.8268 12.1961 23.7596 12.1832 23.695C12.1528 23.5616 12.0222 23.4677 11.8923 23.4987ZM15.4754 8.52697C16.3105 8.14085 16.681 7.13426 16.3027 6.27944C15.9243 5.42532 14.9403 5.04556 14.1046 5.43238C13.2695 5.81991 12.8982 6.8265 13.2766 7.68062C13.6549 8.53544 14.6389 8.91379 15.4754 8.52697ZM18.0935 13.6284C18.9723 13.358 19.47 12.4107 19.206 11.5129C18.9413 10.6143 18.0152 10.1053 17.1363 10.3757C16.2582 10.646 15.7599 11.5933 16.0246 12.4919C16.2893 13.3898 17.2154 13.8987 18.0935 13.6284ZM5.17233 10.7237C4.84426 11.0278 4.64662 11.4471 4.62083 11.8937C4.59503 12.3403 4.74309 12.7796 5.03398 13.1194C5.17709 13.2847 5.35177 13.4196 5.54777 13.5164C5.74377 13.6132 5.95713 13.6698 6.17533 13.683C6.39352 13.6961 6.61214 13.6655 6.81835 13.593C7.02455 13.5205 7.21418 13.4075 7.3761 13.2606C7.70417 12.9565 7.90182 12.5372 7.92761 12.0906C7.9534 11.644 7.80534 11.2047 7.51445 10.8649C7.37135 10.6996 7.19666 10.5647 7.00066 10.4679C6.80466 10.3711 6.5913 10.3145 6.37311 10.3013C6.15491 10.2882 5.93629 10.3188 5.73009 10.3913C5.52388 10.4638 5.33425 10.5768 5.17233 10.7237ZM19.7686 8.56368C20.1893 8.17968 20.2274 7.51473 19.8526 7.08415C19.7642 6.98189 19.6563 6.89838 19.5352 6.83853C19.414 6.77868 19.2821 6.74371 19.1472 6.73568C19.0123 6.72765 18.8772 6.74673 18.7498 6.79179C18.6224 6.83685 18.5054 6.90698 18.4055 6.99803C18.2027 7.18577 18.0805 7.44488 18.0649 7.72084C18.0492 7.99679 18.1412 8.26806 18.3215 8.47756C18.697 8.90815 19.3472 8.94697 19.7686 8.56368ZM11.946 4.6185C12.5121 4.6185 12.9716 4.14838 12.9716 3.56956C12.9716 2.99074 12.5128 2.52062 11.946 2.52062C11.3792 2.52062 10.9203 2.99003 10.9203 3.56956C10.9203 4.14838 11.3792 4.6185 11.946 4.6185ZM4.80527 8.82979C5.37139 8.82979 5.83022 8.36038 5.83022 7.78085C5.83022 7.20203 5.37139 6.73191 4.80457 6.73191C4.23845 6.73191 3.77892 7.20132 3.77892 7.78085C3.77892 8.35968 4.23845 8.82979 4.80527 8.82979ZM4.11563 15.4361C3.91267 15.6238 3.79043 15.8829 3.77463 16.1588C3.75883 16.4348 3.85071 16.7061 4.03092 16.9157C4.40645 17.3463 5.05727 17.3858 5.47798 17.0018C5.89939 16.6185 5.9368 15.9529 5.56269 15.5223C5.47435 15.42 5.36642 15.3365 5.24528 15.2766C5.12413 15.2168 4.99222 15.1818 4.85733 15.1738C4.72245 15.1658 4.58732 15.1848 4.45993 15.2299C4.33254 15.275 4.21547 15.3451 4.11563 15.4361ZM11.946 21.487C12.5121 21.487 12.9716 21.0176 12.9716 20.438C12.9716 19.8592 12.5128 19.3891 11.946 19.3891C11.3792 19.3891 10.9203 19.8592 10.9203 20.438C10.9203 21.0176 11.3792 21.487 11.946 21.487ZM19.0945 17.2601C19.6613 17.2601 20.1201 16.7907 20.1201 16.2112C20.1201 15.6324 19.6613 15.1623 19.0945 15.1623C18.5283 15.1623 18.0688 15.6317 18.0688 16.2112C18.0688 16.79 18.5276 17.2601 19.0945 17.2601ZM17.0735 3.51521C17.1578 3.52035 17.2422 3.50847 17.3217 3.48028C17.4013 3.45208 17.4743 3.40814 17.5365 3.35108C17.5987 3.29403 17.6488 3.22503 17.6837 3.1482C17.7186 3.07137 17.7377 2.98829 17.7399 2.90391C17.7465 2.81974 17.7362 2.7351 17.7096 2.65498C17.683 2.57486 17.6406 2.50087 17.5849 2.43739C17.5293 2.3739 17.4615 2.3222 17.3855 2.28534C17.3096 2.24847 17.227 2.22719 17.1427 2.22274C17.0586 2.21769 16.9743 2.22962 16.8949 2.25782C16.8154 2.28602 16.7425 2.32991 16.6804 2.38688C16.6183 2.44385 16.5683 2.51273 16.5333 2.58943C16.4984 2.66613 16.4793 2.74907 16.477 2.83332C16.4704 2.91749 16.4807 3.00213 16.5073 3.08225C16.5339 3.16238 16.5763 3.23636 16.632 3.29985C16.6876 3.36333 16.7554 3.41503 16.8314 3.4519C16.9073 3.48876 16.9892 3.51075 17.0735 3.51521ZM6.44292 3.40509C6.51215 3.45127 6.58995 3.48309 6.6717 3.49865C6.75346 3.51422 6.8375 3.51322 6.91886 3.49571C7.00022 3.4782 7.07724 3.44454 7.14535 3.39672C7.21347 3.3489 7.27129 3.2879 7.31539 3.21732C7.40689 3.07395 7.43891 2.90056 7.40464 2.73397C7.37038 2.56738 7.27252 2.4207 7.13186 2.32509C7.06261 2.27879 6.98475 2.24688 6.90293 2.23126C6.8211 2.21563 6.73697 2.2166 6.65552 2.23411C6.57408 2.25163 6.49698 2.28532 6.42882 2.33321C6.36065 2.38109 6.30279 2.44218 6.25869 2.51285C6.16718 2.65622 6.13517 2.82961 6.16944 2.9962C6.2037 3.1628 6.30226 3.30947 6.44292 3.40509ZM1.3528 11.4211C1.03869 11.5771 0.916569 11.9689 1.06975 12.2893C1.10579 12.3647 1.15653 12.4322 1.21899 12.4877C1.28145 12.5432 1.35436 12.5857 1.43346 12.6126C1.51256 12.6396 1.59625 12.6505 1.67961 12.6447C1.76298 12.6388 1.84434 12.6164 1.91892 12.5787C2.23304 12.4227 2.35516 12.031 2.20198 11.7105C2.16593 11.6352 2.11522 11.5678 2.05282 11.5124C1.99041 11.4569 1.91757 11.4145 1.83855 11.3875C1.75954 11.3606 1.67594 11.3497 1.59265 11.3554C1.50936 11.3612 1.42736 11.3835 1.3528 11.4211ZM6.82551 20.4931C6.74132 20.4879 6.65697 20.4998 6.57746 20.528C6.49796 20.5561 6.42494 20.6 6.36275 20.657C6.30057 20.7139 6.25049 20.7829 6.21551 20.8596C6.18054 20.9364 6.16137 21.0194 6.15916 21.1037C6.15254 21.1878 6.16284 21.2725 6.18945 21.3526C6.21606 21.4327 6.25844 21.5067 6.3141 21.5702C6.36975 21.6337 6.43755 21.6854 6.51351 21.7222C6.58946 21.7591 6.67202 21.7804 6.75633 21.7849C6.84046 21.7899 6.92475 21.778 7.00417 21.7498C7.08359 21.7216 7.15652 21.6777 7.21863 21.6207C7.28074 21.5637 7.33075 21.4949 7.36568 21.4182C7.40062 21.3415 7.41976 21.2585 7.42198 21.1743C7.4286 21.0902 7.41832 21.0056 7.39176 20.9255C7.36519 20.8454 7.32287 20.7715 7.26729 20.708C7.21171 20.6445 7.14399 20.5928 7.06812 20.5559C6.99225 20.519 6.90976 20.4976 6.82551 20.4931ZM17.4568 20.6025C17.3875 20.5564 17.3097 20.5247 17.228 20.5092C17.1463 20.4937 17.0623 20.4947 16.9809 20.5122C16.8996 20.5297 16.8226 20.5633 16.7545 20.6111C16.6864 20.6588 16.6285 20.7198 16.5843 20.7903C16.4926 20.9337 16.4605 21.1072 16.4947 21.274C16.529 21.4408 16.627 21.5876 16.7679 21.6832C16.8371 21.7294 16.915 21.7611 16.9968 21.7766C17.0785 21.7922 17.1626 21.7911 17.244 21.7735C17.3253 21.7559 17.4023 21.7222 17.4704 21.6743C17.5385 21.6264 17.5963 21.5654 17.6403 21.4947C17.7318 21.3514 17.7639 21.178 17.7296 21.0114C17.6953 20.8448 17.5975 20.6981 17.4568 20.6025ZM22.6076 11.4599C22.5384 11.4138 22.4606 11.3821 22.3788 11.3666C22.2971 11.3511 22.2131 11.3521 22.1318 11.3696C22.0504 11.3871 21.9734 11.4207 21.9053 11.4685C21.8372 11.5162 21.7793 11.5772 21.7352 11.6477C21.6437 11.791 21.6116 11.9644 21.6459 12.131C21.6802 12.2976 21.778 12.4443 21.9187 12.5399C21.9879 12.5862 22.0658 12.6181 22.1476 12.6337C22.2295 12.6494 22.3136 12.6484 22.395 12.6309C22.4765 12.6134 22.5536 12.5797 22.6217 12.5318C22.6899 12.4839 22.7478 12.4228 22.7919 12.3521C22.8834 12.2088 22.9154 12.0354 22.8811 11.8688C22.8468 11.7022 22.7483 11.5555 22.6076 11.4599ZM22.057 6.30909C22.1043 6.26393 22.1329 6.20263 22.1371 6.13738C22.1413 6.07212 22.1208 6.00768 22.0796 5.95685C22.0366 5.90876 21.9765 5.8794 21.9121 5.87505C21.8478 5.8707 21.7842 5.8917 21.7352 5.93356C21.6879 5.97872 21.6593 6.04001 21.6551 6.10527C21.6509 6.17052 21.6714 6.23496 21.7126 6.28579C21.7556 6.33388 21.8157 6.36325 21.8801 6.3676C21.9444 6.37195 22.0079 6.35095 22.057 6.30909ZM11.9912 0.501088C12.0556 0.486056 12.1116 0.446576 12.1474 0.39099C12.1832 0.335404 12.1961 0.268066 12.1832 0.203206C12.1528 0.0705002 12.0222 -0.0233822 11.8923 0.00767661C11.8282 0.0228647 11.7725 0.0623031 11.7368 0.117713C11.7011 0.173123 11.6883 0.240196 11.701 0.304853C11.7314 0.438265 11.8613 0.532147 11.9912 0.501088ZM1.92669 6.36415C2.05657 6.41073 2.19492 6.33238 2.2408 6.20744C2.2613 6.14447 2.25683 6.07605 2.22832 6.01628C2.19982 5.95651 2.14945 5.90997 2.08763 5.88626C1.95704 5.83968 1.81939 5.91803 1.77351 6.04297C1.75302 6.10594 1.75749 6.17437 1.78599 6.23413C1.8145 6.2939 1.86486 6.34044 1.92669 6.36415ZM1.83492 17.6823C1.78733 17.7274 1.7585 17.7887 1.75418 17.8542C1.74986 17.9196 1.77038 17.9842 1.81163 18.0352C1.85464 18.0833 1.91475 18.1127 1.97912 18.117C2.04349 18.1214 2.10701 18.1004 2.1561 18.0585C2.20349 18.0134 2.2322 17.9522 2.23651 17.8869C2.24083 17.8217 2.22044 17.7572 2.17939 17.7063C2.13638 17.6582 2.07627 17.6288 2.0119 17.6245C1.94753 17.6201 1.88401 17.6404 1.83492 17.6823ZM21.9723 17.6279C21.8425 17.5813 21.7048 17.6597 21.6589 17.7846C21.6384 17.8476 21.6429 17.916 21.6714 17.9758C21.6999 18.0355 21.7503 18.0821 21.8121 18.1058C21.942 18.1524 22.0803 18.074 22.1255 17.9491C22.146 17.8862 22.1417 17.8179 22.1133 17.7581C22.0849 17.6983 22.034 17.6518 21.9723 17.6279Z" fill="#3859FF"/>
+<path d="M15.2901 15.4128C14.9386 15.2962 14.5579 15.3024 14.2104 15.4304C13.8628 15.5583 13.5691 15.8005 13.3772 16.1173L13.3616 16.1483C12.979 16.814 12.2209 17.1662 11.4713 16.9234C11.0652 16.7913 10.7253 16.5083 10.5219 16.1328C10.4896 16.023 10.469 15.9102 10.4604 15.7961C10.4301 15.069 10.9736 14.4577 11.6852 14.4189H11.8539C13.1626 14.4733 14.2722 13.4321 14.3259 12.086C14.3795 10.7399 13.3616 9.61256 12.0452 9.5575H11.6852C10.9736 9.52644 10.476 8.96244 10.5063 8.23468C10.5063 8.06244 10.5374 7.89021 10.6059 7.74126L10.6214 7.69468C10.6539 7.62345 10.6821 7.55038 10.7061 7.47585C10.9814 6.57515 10.4915 5.62009 9.61904 5.33844C8.75362 5.06456 7.81974 5.54174 7.53668 6.45021C7.26139 7.32691 7.72021 8.26574 8.57009 8.57138C8.70774 8.61797 8.79174 8.63421 8.92233 8.6575H8.9908C9.66492 8.73515 10.1929 9.29138 10.1696 9.99585C10.1626 10.2542 10.0779 10.4893 9.94798 10.6848C9.72118 11.0472 9.59453 11.4632 9.58092 11.8904C9.55808 12.3864 9.68605 12.8776 9.94798 13.2994C10.0779 13.4949 10.1619 13.73 10.1696 13.9883C10.2007 14.6928 9.74115 15.2483 9.06774 15.3189H9.05221C8.95339 15.3189 8.83833 15.3422 8.74586 15.3577C7.82821 15.5695 7.28468 16.485 7.4908 17.4013C7.69762 18.3246 8.60045 18.8646 9.45809 18.669C9.67681 18.6217 9.88344 18.5298 10.0651 18.3991C10.2468 18.2685 10.3996 18.1018 10.5141 17.9095C10.7022 17.5817 10.997 17.3283 11.3494 17.1916C11.7018 17.0549 12.0904 17.0432 12.4503 17.1584C12.8562 17.2911 13.147 17.5417 13.3539 17.894L13.3764 17.9335C13.5529 18.2229 13.8896 18.5208 14.287 18.638C15.1906 18.9119 16.0786 18.4107 16.3623 17.534C16.6524 16.6184 16.1322 15.6704 15.2901 15.3973V15.4128Z" fill="#3859FF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/model/checked.svg b/app/components/base/icons/assets/public/model/checked.svg
new file mode 100644
index 0000000..a355703
--- /dev/null
+++ b/app/components/base/icons/assets/public/model/checked.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M13.3332 4L5.99984 11.3333L2.6665 8" stroke="#155EEF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/other/Icon-3-dots.svg b/app/components/base/icons/assets/public/other/Icon-3-dots.svg
new file mode 100644
index 0000000..fee9b18
--- /dev/null
+++ b/app/components/base/icons/assets/public/other/Icon-3-dots.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103" stroke="#667085" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/other/default-tool-icon.svg b/app/components/base/icons/assets/public/other/default-tool-icon.svg
new file mode 100644
index 0000000..2c501c1
--- /dev/null
+++ b/app/components/base/icons/assets/public/other/default-tool-icon.svg
@@ -0,0 +1,9 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.5">
+<rect width="24" height="24" rx="6" fill="#E5E7EB"/>
+<rect x="0.25" y="0.25" width="23.5" height="23.5" rx="5.75" stroke="black" stroke-opacity="0.05" stroke-width="0.5"/>
+<path d="M11.8876 5.30588C11.9601 5.26959 12.019 5.21074 12.0553 5.13817L12.414 4.4208C12.5522 4.1444 12.9466 4.1444 13.0848 4.4208L13.4435 5.13817C13.4797 5.21074 13.5386 5.26959 13.6112 5.30588L14.3285 5.66457C14.6049 5.80276 14.6049 6.19719 14.3285 6.33539L13.6112 6.69407C13.5386 6.73036 13.4797 6.78921 13.4435 6.86178L13.0848 7.57916C12.9466 7.85555 12.5522 7.85555 12.414 7.57916L12.0553 6.86178C12.019 6.78921 11.9601 6.73036 11.8876 6.69407L11.1702 6.33539C10.8938 6.19719 10.8938 5.80276 11.1702 5.66457L11.8876 5.30588Z" fill="#667085"/>
+<path d="M7.88756 6.55588C7.96013 6.51959 8.01898 6.46074 8.05527 6.38817L8.28895 5.9208C8.42715 5.6444 8.82158 5.6444 8.95978 5.9208L9.19346 6.38817C9.22975 6.46074 9.2886 6.51959 9.36117 6.55588L9.82854 6.78956C10.1049 6.92776 10.1049 7.32219 9.82854 7.46039L9.36117 7.69407C9.2886 7.73036 9.22975 7.78921 9.19346 7.86178L8.95978 8.32915C8.82158 8.60555 8.42715 8.60555 8.28895 8.32915L8.05527 7.86178C8.01898 7.78921 7.96013 7.73036 7.88756 7.69407L7.42019 7.46039C7.14379 7.32219 7.14379 6.92776 7.42019 6.78957L7.88756 6.55588Z" fill="#667085"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M17.9417 5.91012C18.1985 6.08504 18.2648 6.43496 18.0899 6.6917L16.0062 9.74998H17.4375C17.7482 9.74998 18 10.0018 18 10.3125V18.1875C18 18.9124 17.4124 19.5 16.6875 19.5H7.3125C6.58763 19.5 6 18.9123 6 18.1875V10.3125C6 10.0018 6.25184 9.74998 6.5625 9.74998H14.6449L17.1601 6.05826C17.3351 5.80152 17.685 5.7352 17.9417 5.91012ZM10.3125 12.75C10.0018 12.75 9.75 13.0018 9.75 13.3125C9.75 13.6231 10.0018 13.875 10.3125 13.875H13.6875C13.9982 13.875 14.25 13.6231 14.25 13.3125C14.25 13.0018 13.9982 12.75 13.6875 12.75H10.3125Z" fill="#667085"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/other/message-3-fill.svg b/app/components/base/icons/assets/public/other/message-3-fill.svg
new file mode 100644
index 0000000..95c41f9
--- /dev/null
+++ b/app/components/base/icons/assets/public/other/message-3-fill.svg
@@ -0,0 +1,23 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="message-3-fill">
+<g id="Vector" filter="url(#filter0_d_1071_49501)">
+<path d="M2 8.99374C2 5.68349 4.67654 3 8.00066 3H15.9993C19.3134 3 22 5.69478 22 8.99374V21H8.00066C4.68659 21 2 18.3052 2 15.0063V8.99374ZM14 11V13H16V11H14ZM8 11V13H10V11H8Z" fill="url(#paint0_linear_1071_49501)"/>
+</g>
+</g>
+<defs>
+<filter id="filter0_d_1071_49501" x="1.5" y="2.75" width="21" height="19" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="0.25"/>
+<feGaussianBlur stdDeviation="0.25"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1071_49501"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1071_49501" result="shape"/>
+</filter>
+<linearGradient id="paint0_linear_1071_49501" x1="12" y1="3" x2="12" y2="21" gradientUnits="userSpaceOnUse">
+<stop stop-color="#296DFF"/>
+<stop offset="1" stop-color="#0BA5EC"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/other/row-struct.svg b/app/components/base/icons/assets/public/other/row-struct.svg
new file mode 100644
index 0000000..ba275ff
--- /dev/null
+++ b/app/components/base/icons/assets/public/other/row-struct.svg
@@ -0,0 +1,5 @@
+<svg width="624" height="48" viewBox="0 0 624 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="8" y="7" width="16" height="16" rx="5" fill="#F2F4F7"/>
+<rect x="32" y="10" width="233" height="10" rx="3" fill="#EAECF0"/>
+<rect x="32" y="31" width="345" height="6" rx="3" fill="#F2F4F7"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/plugins/google.svg b/app/components/base/icons/assets/public/plugins/google.svg
new file mode 100644
index 0000000..ac232b4
--- /dev/null
+++ b/app/components/base/icons/assets/public/plugins/google.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M22.501 12.2331C22.501 11.3698 22.4296 10.7398 22.2748 10.0864H12.2153V13.983H18.12C18.001 14.9514 17.3582 16.4097 15.9296 17.3897L15.9096 17.5202L19.0902 19.9349L19.3106 19.9564C21.3343 18.1247 22.501 15.4297 22.501 12.2331Z" fill="#4285F4"/>
+<path d="M12.2147 22.5001C15.1075 22.5001 17.5361 21.5667 19.3099 19.9567L15.929 17.39C15.0242 18.0083 13.8099 18.44 12.2147 18.44C9.38142 18.44 6.97669 16.6083 6.11947 14.0767L5.99382 14.0871L2.68656 16.5955L2.64331 16.7133C4.40519 20.1433 8.02423 22.5001 12.2147 22.5001Z" fill="#34A853"/>
+<path d="M6.11997 14.0765C5.89379 13.4232 5.76289 12.7231 5.76289 11.9998C5.76289 11.2764 5.89379 10.5765 6.10807 9.92313L6.10208 9.78398L2.75337 7.23535L2.64381 7.28642C1.91765 8.70977 1.50098 10.3081 1.50098 11.9998C1.50098 13.6915 1.91765 15.2897 2.64381 16.7131L6.11997 14.0765Z" fill="#FBBC05"/>
+<path d="M12.2148 5.55997C14.2267 5.55997 15.5838 6.41163 16.3576 7.12335L19.3814 4.23C17.5243 2.53834 15.1076 1.5 12.2148 1.5C8.02426 1.5 4.4052 3.85665 2.64331 7.28662L6.10759 9.92332C6.97672 7.39166 9.38146 5.55997 12.2148 5.55997Z" fill="#EB4335"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/plugins/partner-dark.svg b/app/components/base/icons/assets/public/plugins/partner-dark.svg
new file mode 100644
index 0000000..edb71d6
--- /dev/null
+++ b/app/components/base/icons/assets/public/plugins/partner-dark.svg
@@ -0,0 +1,58 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Partner">
+<mask id="mask0_6296_109592" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="1" y="0" width="18" height="20">
+<g id="Mask">
+<path d="M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z" fill="#932F19"/>
+<path d="M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z" fill="url(#paint0_linear_6296_109592)" fill-opacity="0.9"/>
+<path d="M7.47222 1.78016C8.45993 1.20991 8.90155 0.958665 9.36471 0.860217C9.78356 0.771189 10.2164 0.771189 10.6353 0.860217C11.0984 0.958665 11.5401 1.20991 12.5278 1.78016L15.8547 3.70096C16.8424 4.27121 17.2808 4.52805 17.5976 4.87994C17.8842 5.19815 18.1006 5.57304 18.2329 5.98028C18.3792 6.43061 18.3825 6.9387 18.3825 8.0792V11.9208C18.3825 13.0613 18.3792 13.5694 18.2329 14.0197C18.1006 14.427 17.8842 14.8018 17.5976 15.1201C17.2808 15.4719 16.8424 15.7288 15.8547 16.299L12.5278 18.2198C11.5401 18.7901 11.0984 19.0413 10.6353 19.1398C10.2164 19.2288 9.78356 19.2288 9.36471 19.1398C8.90155 19.0413 8.45993 18.7901 7.47222 18.2198L4.1453 16.299C3.1576 15.7288 2.7192 15.4719 2.40236 15.1201C2.11584 14.8018 1.89939 14.427 1.76707 14.0197C1.62075 13.5694 1.61752 13.0613 1.61752 11.9208V8.0792C1.61752 6.9387 1.62075 6.43061 1.76707 5.98028C1.89939 5.57304 2.11584 5.19815 2.40236 4.87994C2.7192 4.52805 3.1576 4.27121 4.1453 3.70096L7.47222 1.78016Z" stroke="url(#paint1_linear_6296_109592)" stroke-opacity="0.8" stroke-width="0.555556"/>
+</g>
+</mask>
+<g mask="url(#mask0_6296_109592)">
+<g id="badge-bg">
+<path d="M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z" fill="#932F19"/>
+<path d="M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z" fill="url(#paint2_linear_6296_109592)" fill-opacity="0.9"/>
+<path d="M7.58333 1.97261C8.58402 1.39487 8.99036 1.16698 9.41092 1.07758C9.7993 0.99503 10.2007 0.99503 10.5891 1.07758C11.0096 1.16698 11.416 1.39487 12.4167 1.97261L15.7436 3.89341C16.7443 4.47116 17.1448 4.70911 17.4325 5.02863C17.6982 5.3237 17.8989 5.67133 18.0216 6.04895C18.1544 6.45786 18.1603 6.92371 18.1603 8.0792V11.9208C18.1603 13.0763 18.1544 13.5421 18.0216 13.951C17.8989 14.3287 17.6982 14.6763 17.4325 14.9714C17.1448 15.2909 16.7443 15.5288 15.7436 16.1066L12.4167 18.0274C11.416 18.6051 11.0096 18.833 10.5891 18.9224C10.2007 19.005 9.7993 19.005 9.41092 18.9224C8.99036 18.833 8.58402 18.6051 7.58333 18.0274L4.25641 16.1066C3.25572 15.5288 2.8552 15.2909 2.5675 14.9714C2.30182 14.6763 2.10112 14.3287 1.97842 13.951C1.84556 13.5421 1.83975 13.0763 1.83975 11.9208V8.0792C1.83975 6.92371 1.84556 6.45786 1.97842 6.04895C2.10112 5.67133 2.30182 5.3237 2.5675 5.02863C2.8552 4.70911 3.25572 4.47116 4.25641 3.89341L7.58333 1.97261Z" stroke="url(#paint3_linear_6296_109592)" stroke-opacity="0.8"/>
+</g>
+<g id="handshake" filter="url(#filter0_d_6296_109592)">
+<path d="M11.0969 9.64841C10.895 9.44642 10.5675 9.44642 10.3656 9.64841L9.99991 10.0141C9.59596 10.418 8.94109 10.418 8.53717 10.0141C8.13325 9.61015 8.13325 8.95527 8.53717 8.55135L11.4491 5.63868C12.5371 5.39255 13.7238 5.69302 14.5709 6.54011C15.8221 7.79128 15.8807 9.78339 14.7469 11.104L13.6567 12.2081L11.0969 9.64841ZM5.42889 6.54011C6.55286 5.41614 8.27475 5.25452 9.57067 6.05524L7.80581 7.81999C6.99797 8.62783 6.99797 9.9376 7.80581 10.7454C8.58917 11.5288 9.8445 11.5525 10.6564 10.8167L10.7313 10.7454L12.9253 12.9395L10.7313 15.1336C10.3273 15.5375 9.67245 15.5375 9.26855 15.1336L5.42889 11.2939C4.11615 9.9812 4.11615 7.85284 5.42889 6.54011Z" fill="url(#paint4_linear_6296_109592)" shape-rendering="crispEdges"/>
+</g>
+<path id="highlight" opacity="0.5" d="M0 0H15.5556L5.26663 20H0V0Z" fill="url(#paint5_linear_6296_109592)"/>
+</g>
+</g>
+<defs>
+<filter id="filter0_d_6296_109592" x="3.94434" y="5.30556" width="12.1111" height="10.881" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="0.25"/>
+<feGaussianBlur stdDeviation="0.25"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6296_109592"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6296_109592" result="shape"/>
+</filter>
+<linearGradient id="paint0_linear_6296_109592" x1="0" y1="0" x2="22.6412" y2="1.78551" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FF692E"/>
+<stop offset="1" stop-color="#E04F16"/>
+</linearGradient>
+<linearGradient id="paint1_linear_6296_109592" x1="8.55422" y1="-1.28187e-07" x2="19.7802" y2="12.7346" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.2"/>
+<stop offset="1" stop-color="#FF4405"/>
+</linearGradient>
+<linearGradient id="paint2_linear_6296_109592" x1="0" y1="0" x2="22.6412" y2="1.78551" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FF692E"/>
+<stop offset="1" stop-color="#E04F16"/>
+</linearGradient>
+<linearGradient id="paint3_linear_6296_109592" x1="8.55422" y1="-1.28187e-07" x2="19.7802" y2="12.7346" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.2"/>
+<stop offset="1" stop-color="#FF4405"/>
+</linearGradient>
+<linearGradient id="paint4_linear_6296_109592" x1="9.99989" y1="5.55556" x2="9.99989" y2="15.4365" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.95"/>
+<stop offset="1" stop-color="white" stop-opacity="0.8"/>
+</linearGradient>
+<linearGradient id="paint5_linear_6296_109592" x1="-4.78632" y1="4.375" x2="16.2164" y2="10.4" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.12"/>
+<stop offset="1" stop-color="white" stop-opacity="0.2"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/plugins/partner-light.svg b/app/components/base/icons/assets/public/plugins/partner-light.svg
new file mode 100644
index 0000000..a4ae934
--- /dev/null
+++ b/app/components/base/icons/assets/public/plugins/partner-light.svg
@@ -0,0 +1,58 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Partner">
+<mask id="mask0_6291_109635" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="1" y="0" width="18" height="20">
+<g id="Mask">
+<path d="M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z" fill="#F9DBAF"/>
+<path d="M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z" fill="url(#paint0_linear_6291_109635)" fill-opacity="0.9"/>
+<path d="M7.47222 1.78016C8.45993 1.20991 8.90155 0.958665 9.36471 0.860217C9.78356 0.771189 10.2164 0.771189 10.6353 0.860217C11.0984 0.958665 11.5401 1.20991 12.5278 1.78016L15.8547 3.70096C16.8424 4.27121 17.2808 4.52805 17.5976 4.87994C17.8842 5.19815 18.1006 5.57304 18.2329 5.98028C18.3792 6.43061 18.3825 6.9387 18.3825 8.0792V11.9208C18.3825 13.0613 18.3792 13.5694 18.2329 14.0197C18.1006 14.427 17.8842 14.8018 17.5976 15.1201C17.2808 15.4719 16.8424 15.7288 15.8547 16.299L12.5278 18.2198C11.5401 18.7901 11.0984 19.0413 10.6353 19.1398C10.2164 19.2288 9.78356 19.2288 9.36471 19.1398C8.90155 19.0413 8.45993 18.7901 7.47222 18.2198L4.1453 16.299C3.1576 15.7288 2.7192 15.4719 2.40236 15.1201C2.11584 14.8018 1.89939 14.427 1.76707 14.0197C1.62075 13.5694 1.61752 13.0613 1.61752 11.9208V8.0792C1.61752 6.9387 1.62075 6.43061 1.76707 5.98028C1.89939 5.57304 2.11584 5.19815 2.40236 4.87994C2.7192 4.52805 3.1576 4.27121 4.1453 3.70096L7.47222 1.78016Z" stroke="url(#paint1_linear_6291_109635)" stroke-opacity="0.8" stroke-width="0.555556"/>
+</g>
+</mask>
+<g mask="url(#mask0_6291_109635)">
+<g id="badge-bg">
+<path d="M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z" fill="#F9DBAF"/>
+<path d="M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z" fill="url(#paint2_linear_6291_109635)" fill-opacity="0.9"/>
+<path d="M7.58333 1.97261C8.58402 1.39487 8.99036 1.16698 9.41092 1.07758C9.7993 0.99503 10.2007 0.99503 10.5891 1.07758C11.0096 1.16698 11.416 1.39487 12.4167 1.97261L15.7436 3.89341C16.7443 4.47116 17.1448 4.70911 17.4325 5.02863C17.6982 5.3237 17.8989 5.67133 18.0216 6.04895C18.1544 6.45786 18.1603 6.92371 18.1603 8.0792V11.9208C18.1603 13.0763 18.1544 13.5421 18.0216 13.951C17.8989 14.3287 17.6982 14.6763 17.4325 14.9714C17.1448 15.2909 16.7443 15.5288 15.7436 16.1066L12.4167 18.0274C11.416 18.6051 11.0096 18.833 10.5891 18.9224C10.2007 19.005 9.7993 19.005 9.41092 18.9224C8.99036 18.833 8.58402 18.6051 7.58333 18.0274L4.25641 16.1066C3.25572 15.5288 2.8552 15.2909 2.5675 14.9714C2.30182 14.6763 2.10112 14.3287 1.97842 13.951C1.84556 13.5421 1.83975 13.0763 1.83975 11.9208V8.0792C1.83975 6.92371 1.84556 6.45786 1.97842 6.04895C2.10112 5.67133 2.30182 5.3237 2.5675 5.02863C2.8552 4.70911 3.25572 4.47116 4.25641 3.89341L7.58333 1.97261Z" stroke="url(#paint3_linear_6291_109635)" stroke-opacity="0.8"/>
+</g>
+<g id="handshake" filter="url(#filter0_d_6291_109635)">
+<path d="M11.0969 9.64852C10.895 9.44652 10.5675 9.44652 10.3656 9.64852L9.99991 10.0142C9.59596 10.4181 8.94109 10.4181 8.53717 10.0142C8.13325 9.61025 8.13325 8.95537 8.53717 8.55146L11.4491 5.63879C12.5371 5.39265 13.7238 5.69313 14.5709 6.54022C15.8221 7.79139 15.8807 9.7835 14.7469 11.1041L13.6567 12.2083L11.0969 9.64852ZM5.42889 6.54022C6.55286 5.41625 8.27475 5.25463 9.57067 6.05534L7.80581 7.8201C6.99797 8.62794 6.99797 9.93771 7.80581 10.7456C8.58917 11.5289 9.8445 11.5526 10.6564 10.8168L10.7313 10.7456L12.9253 12.9396L10.7313 15.1337C10.3273 15.5376 9.67245 15.5376 9.26855 15.1337L5.42889 11.294C4.11615 9.98131 4.11615 7.85295 5.42889 6.54022Z" fill="url(#paint4_linear_6291_109635)" shape-rendering="crispEdges"/>
+</g>
+<path id="highlight" opacity="0.5" d="M0 0H15.5556L5.26663 20H0V0Z" fill="url(#paint5_linear_6291_109635)"/>
+</g>
+</g>
+<defs>
+<filter id="filter0_d_6291_109635" x="3.94434" y="5.30566" width="12.1111" height="10.8809" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="0.25"/>
+<feGaussianBlur stdDeviation="0.25"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6291_109635"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6291_109635" result="shape"/>
+</filter>
+<linearGradient id="paint0_linear_6291_109635" x1="0" y1="0" x2="22.6412" y2="1.78551" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FF692E"/>
+<stop offset="1" stop-color="#E04F16"/>
+</linearGradient>
+<linearGradient id="paint1_linear_6291_109635" x1="8.55422" y1="-1.28187e-07" x2="19.7802" y2="12.7346" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.95"/>
+<stop offset="1" stop-color="#E62E05"/>
+</linearGradient>
+<linearGradient id="paint2_linear_6291_109635" x1="0" y1="0" x2="22.6412" y2="1.78551" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FF692E"/>
+<stop offset="1" stop-color="#E04F16"/>
+</linearGradient>
+<linearGradient id="paint3_linear_6291_109635" x1="8.55422" y1="-1.28187e-07" x2="19.7802" y2="12.7346" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.95"/>
+<stop offset="1" stop-color="#E62E05"/>
+</linearGradient>
+<linearGradient id="paint4_linear_6291_109635" x1="9.99989" y1="5.55566" x2="9.99989" y2="15.4366" gradientUnits="userSpaceOnUse">
+<stop stop-color="white"/>
+<stop offset="1" stop-color="white" stop-opacity="0.9"/>
+</linearGradient>
+<linearGradient id="paint5_linear_6291_109635" x1="-4.78632" y1="4.375" x2="16.2164" y2="10.4" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.12"/>
+<stop offset="1" stop-color="white" stop-opacity="0.3"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/plugins/verified-dark.svg b/app/components/base/icons/assets/public/plugins/verified-dark.svg
new file mode 100644
index 0000000..aae1193
--- /dev/null
+++ b/app/components/base/icons/assets/public/plugins/verified-dark.svg
@@ -0,0 +1,58 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Verified">
+<mask id="mask0_6296_109593" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="20" height="20">
+<g id="Mask">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.08817 1.62521C9.14394 0.569383 10.8558 0.569374 11.9116 1.62521L12.8128 2.52641C12.9819 2.69542 13.2111 2.79037 13.4501 2.79037H14.5059C15.9991 2.79037 17.2095 4.00082 17.2095 5.49398V6.54981C17.2095 6.78882 17.3045 7.01805 17.4735 7.18706L18.3747 8.08826C19.4305 9.1441 19.4305 10.8559 18.3747 11.9118L17.4735 12.813C17.3045 12.982 17.2095 13.2112 17.2095 13.4502V14.506C17.2095 15.9992 15.9991 17.2096 14.5059 17.2096H13.4501C13.2111 17.2096 12.9819 17.3046 12.8128 17.4736L11.9116 18.3748C10.8558 19.4306 9.14403 19.4306 8.08817 18.3748L7.18696 17.4736C7.01795 17.3046 6.78873 17.2096 6.54972 17.2096H5.49389C4.00072 17.2096 2.79028 15.9992 2.79028 14.506V13.4502C2.79028 13.2112 2.69533 12.982 2.52632 12.813L1.62513 11.9118C0.569295 10.8559 0.569295 9.1441 1.62512 8.08826L2.52632 7.18706C2.69533 7.01806 2.79028 6.78882 2.79028 6.54981V5.49398C2.79028 4.00082 4.00072 2.79037 5.49389 2.79037H6.54972C6.78873 2.79037 7.01795 2.69542 7.18696 2.52641L8.08817 1.62521Z" fill="#003DC1"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.08817 1.62521C9.14394 0.569383 10.8558 0.569374 11.9116 1.62521L12.8128 2.52641C12.9819 2.69542 13.2111 2.79037 13.4501 2.79037H14.5059C15.9991 2.79037 17.2095 4.00082 17.2095 5.49398V6.54981C17.2095 6.78882 17.3045 7.01805 17.4735 7.18706L18.3747 8.08826C19.4305 9.1441 19.4305 10.8559 18.3747 11.9118L17.4735 12.813C17.3045 12.982 17.2095 13.2112 17.2095 13.4502V14.506C17.2095 15.9992 15.9991 17.2096 14.5059 17.2096H13.4501C13.2111 17.2096 12.9819 17.3046 12.8128 17.4736L11.9116 18.3748C10.8558 19.4306 9.14403 19.4306 8.08817 18.3748L7.18696 17.4736C7.01795 17.3046 6.78873 17.2096 6.54972 17.2096H5.49389C4.00072 17.2096 2.79028 15.9992 2.79028 14.506V13.4502C2.79028 13.2112 2.69533 12.982 2.52632 12.813L1.62513 11.9118C0.569295 10.8559 0.569295 9.1441 1.62512 8.08826L2.52632 7.18706C2.69533 7.01806 2.79028 6.78882 2.79028 6.54981V5.49398C2.79028 4.00082 4.00072 2.79037 5.49389 2.79037H6.54972C6.78873 2.79037 7.01795 2.69542 7.18696 2.52641L8.08817 1.62521Z" fill="url(#paint0_linear_6296_109593)" fill-opacity="0.9"/>
+<path d="M8.27881 1.81585L8.27881 1.81585C9.2293 0.865317 10.7704 0.865301 11.721 1.81585L12.6222 2.71705L12.6222 2.71709C12.8418 2.9366 13.1395 3.05997 13.4501 3.05997H14.5059C15.8502 3.05997 16.9399 4.14972 16.9399 5.49398V6.54981C16.9399 6.86036 17.0633 7.15813 17.2828 7.37768L17.2829 7.3777L18.1841 8.2789L18.3747 8.08826L18.1841 8.27891C19.1346 9.22945 19.1346 10.7706 18.1841 11.7211L17.2829 12.6224C17.0633 12.8419 16.9399 13.1397 16.9399 13.4502V14.506C16.9399 15.8503 15.8502 16.94 14.5059 16.94H13.4501C13.1395 16.94 12.8418 17.0634 12.6222 17.2829L12.6222 17.2829L11.721 18.1841C10.7704 19.1347 9.22939 19.1347 8.27881 18.1841L7.37761 17.2829L7.37759 17.2829C7.15804 17.0634 6.86027 16.94 6.54972 16.94H5.49389C4.14962 16.94 3.05989 15.8503 3.05989 14.506V13.4502C3.05989 13.1398 2.93655 12.8419 2.71696 12.6224C2.71696 12.6223 2.71695 12.6223 2.71694 12.6223L1.81577 11.7211C0.865224 10.7706 0.865226 9.22945 1.81576 8.2789L2.71696 7.3777C2.71696 7.3777 2.71696 7.3777 2.71696 7.3777C2.93654 7.15813 3.05989 6.86033 3.05989 6.54981V5.49398C3.05989 4.14972 4.14963 3.05997 5.49389 3.05997H6.54972C6.86024 3.05997 7.15803 2.93662 7.3776 2.71706L7.37761 2.71705L8.27881 1.81585Z" stroke="url(#paint1_linear_6296_109593)" stroke-opacity="0.8" stroke-width="0.539216"/>
+</g>
+</mask>
+<g mask="url(#mask0_6296_109593)">
+<g id="badge-bg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.08817 1.62521C9.14394 0.569383 10.8558 0.569374 11.9116 1.62521L12.8128 2.52641C12.9819 2.69542 13.2111 2.79037 13.4501 2.79037H14.5059C15.9991 2.79037 17.2095 4.00082 17.2095 5.49398V6.54981C17.2095 6.78882 17.3045 7.01805 17.4735 7.18706L18.3747 8.08826C19.4305 9.1441 19.4305 10.8559 18.3747 11.9118L17.4735 12.813C17.3045 12.982 17.2095 13.2112 17.2095 13.4502V14.506C17.2095 15.9992 15.9991 17.2096 14.5059 17.2096H13.4501C13.2111 17.2096 12.9819 17.3046 12.8128 17.4736L11.9116 18.3748C10.8558 19.4306 9.14403 19.4306 8.08817 18.3748L7.18696 17.4736C7.01795 17.3046 6.78873 17.2096 6.54972 17.2096H5.49389C4.00072 17.2096 2.79028 15.9992 2.79028 14.506V13.4502C2.79028 13.2112 2.69533 12.982 2.52632 12.813L1.62513 11.9118C0.569295 10.8559 0.569295 9.1441 1.62512 8.08826L2.52632 7.18706C2.69533 7.01806 2.79028 6.78882 2.79028 6.54981V5.49398C2.79028 4.00082 4.00072 2.79037 5.49389 2.79037H6.54972C6.78873 2.79037 7.01795 2.69542 7.18696 2.52641L8.08817 1.62521Z" fill="#003DC1"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.08817 1.62521C9.14394 0.569383 10.8558 0.569374 11.9116 1.62521L12.8128 2.52641C12.9819 2.69542 13.2111 2.79037 13.4501 2.79037H14.5059C15.9991 2.79037 17.2095 4.00082 17.2095 5.49398V6.54981C17.2095 6.78882 17.3045 7.01805 17.4735 7.18706L18.3747 8.08826C19.4305 9.1441 19.4305 10.8559 18.3747 11.9118L17.4735 12.813C17.3045 12.982 17.2095 13.2112 17.2095 13.4502V14.506C17.2095 15.9992 15.9991 17.2096 14.5059 17.2096H13.4501C13.2111 17.2096 12.9819 17.3046 12.8128 17.4736L11.9116 18.3748C10.8558 19.4306 9.14403 19.4306 8.08817 18.3748L7.18696 17.4736C7.01795 17.3046 6.78873 17.2096 6.54972 17.2096H5.49389C4.00072 17.2096 2.79028 15.9992 2.79028 14.506V13.4502C2.79028 13.2112 2.69533 12.982 2.52632 12.813L1.62513 11.9118C0.569295 10.8559 0.569295 9.1441 1.62512 8.08826L2.52632 7.18706C2.69533 7.01806 2.79028 6.78882 2.79028 6.54981V5.49398C2.79028 4.00082 4.00072 2.79037 5.49389 2.79037H6.54972C6.78873 2.79037 7.01795 2.69542 7.18696 2.52641L8.08817 1.62521Z" fill="url(#paint2_linear_6296_109593)" fill-opacity="0.9"/>
+<path d="M8.44172 1.97876L8.44173 1.97875C9.30224 1.11821 10.6975 1.11818 11.5581 1.97876L12.4593 2.87997L12.4593 2.88003C12.7221 3.1427 13.0784 3.29037 13.4501 3.29037H14.5059C15.723 3.29037 16.7095 4.27696 16.7095 5.49398V6.54981C16.7095 6.92148 16.8572 7.27785 17.1199 7.54057L17.1199 7.54061L18.0211 8.44182L18.3747 8.08826L18.0211 8.44182C18.8817 9.30239 18.8817 10.6976 18.0211 11.5582L17.1199 12.4594C16.8572 12.7222 16.7095 13.0786 16.7095 13.4502V14.506C16.7095 15.7231 15.723 16.7096 14.5059 16.7096H13.4501C13.0784 16.7096 12.7221 16.8573 12.4594 17.1199L12.4593 17.12L11.5581 18.0212C10.6975 18.8818 9.30233 18.8818 8.44172 18.0212L7.54052 17.12L7.54048 17.12C7.27775 16.8573 6.92139 16.7096 6.54972 16.7096H5.49389C4.27686 16.7096 3.29028 15.7231 3.29028 14.506V13.4502C3.29028 13.0787 3.14267 12.7222 2.87984 12.4594L1.97868 11.5582C1.11811 10.6976 1.11811 9.30238 1.97867 8.44181L2.87986 7.54062C2.87987 7.54062 2.87987 7.54061 2.87987 7.54061C3.14266 7.27784 3.29028 6.92143 3.29028 6.54981V5.49398C3.29028 4.27696 4.27687 3.29037 5.49389 3.29037H6.54972C6.92135 3.29037 7.27774 3.14273 7.54051 2.87998L7.54052 2.87997L8.44172 1.97876Z" stroke="url(#paint3_linear_6296_109593)" stroke-opacity="0.8"/>
+</g>
+<g id="check" filter="url(#filter0_d_6296_109593)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4219 6.98132C13.8732 7.28924 13.9829 7.89545 13.667 8.33533L10.04 13.3858C9.87754 13.612 9.62408 13.7602 9.34287 13.7934C9.06166 13.8266 8.77923 13.7417 8.56605 13.5599L6.49346 11.7923C6.0789 11.4387 6.03689 10.8245 6.39963 10.4204C6.76238 10.0163 7.39252 9.97533 7.80709 10.3289L9.04316 11.3831L12.0328 7.22026C12.3487 6.78038 12.9706 6.6734 13.4219 6.98132Z" fill="url(#paint4_linear_6296_109593)" shape-rendering="crispEdges"/>
+</g>
+<path id="highlight" opacity="0.5" d="M0 0H15.5556L5.26663 20H0V0Z" fill="url(#paint5_linear_6296_109593)"/>
+</g>
+</g>
+<defs>
+<filter id="filter0_d_6296_109593" x="5.65283" y="6.55549" width="8.69458" height="7.995" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="0.25"/>
+<feGaussianBlur stdDeviation="0.25"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6296_109593"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6296_109593" result="shape"/>
+</filter>
+<linearGradient id="paint0_linear_6296_109593" x1="16.302" y1="19.1667" x2="-0.37184" y2="14.8201" gradientUnits="userSpaceOnUse">
+<stop stop-color="#296DFF"/>
+<stop offset="1" stop-color="#5289FF"/>
+</linearGradient>
+<linearGradient id="paint1_linear_6296_109593" x1="8.67462" y1="0.833336" x2="18.9651" y2="12.5067" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.2"/>
+<stop offset="1" stop-color="#296DFF"/>
+</linearGradient>
+<linearGradient id="paint2_linear_6296_109593" x1="16.302" y1="19.1667" x2="-0.37184" y2="14.8201" gradientUnits="userSpaceOnUse">
+<stop stop-color="#296DFF"/>
+<stop offset="1" stop-color="#5289FF"/>
+</linearGradient>
+<linearGradient id="paint3_linear_6296_109593" x1="8.67462" y1="0.833336" x2="18.9651" y2="12.5067" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.2"/>
+<stop offset="1" stop-color="#296DFF"/>
+</linearGradient>
+<linearGradient id="paint4_linear_6296_109593" x1="10.0001" y1="6.80549" x2="10.0001" y2="13.8005" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.95"/>
+<stop offset="1" stop-color="white" stop-opacity="0.8"/>
+</linearGradient>
+<linearGradient id="paint5_linear_6296_109593" x1="-4.78632" y1="4.375" x2="16.2164" y2="10.4" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.12"/>
+<stop offset="1" stop-color="white" stop-opacity="0.2"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/plugins/verified-light.svg b/app/components/base/icons/assets/public/plugins/verified-light.svg
new file mode 100644
index 0000000..c55f67f
--- /dev/null
+++ b/app/components/base/icons/assets/public/plugins/verified-light.svg
@@ -0,0 +1,58 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Verified">
+<mask id="mask0_6295_120949" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="20" height="20">
+<g id="Mask">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.08817 1.62512C9.14394 0.569299 10.8558 0.56929 11.9116 1.62512L12.8128 2.52633C12.9819 2.69533 13.2111 2.79028 13.4501 2.79028H14.5059C15.9991 2.79028 17.2095 4.00074 17.2095 5.4939V6.54972C17.2095 6.78874 17.3045 7.01796 17.4735 7.18697L18.3747 8.08818C19.4305 9.14401 19.4305 10.8559 18.3747 11.9117L17.4735 12.8129C17.3045 12.9819 17.2095 13.2112 17.2095 13.4502V14.5059C17.2095 15.9991 15.9991 17.2095 14.5059 17.2095H13.4501C13.2111 17.2095 12.9819 17.3045 12.8128 17.4735L11.9116 18.3747C10.8558 19.4305 9.14403 19.4305 8.08817 18.3747L7.18696 17.4735C7.01795 17.3045 6.78873 17.2095 6.54972 17.2095H5.49389C4.00072 17.2095 2.79028 15.9991 2.79028 14.5059V13.4502C2.79028 13.2112 2.69533 12.9819 2.52632 12.8129L1.62513 11.9117C0.569295 10.8559 0.569295 9.14401 1.62512 8.08818L2.52632 7.18697C2.69533 7.01797 2.79028 6.78874 2.79028 6.54972V5.4939C2.79028 4.00074 4.00072 2.79028 5.49389 2.79028H6.54972C6.78873 2.79028 7.01795 2.69533 7.18696 2.52633L8.08817 1.62512Z" fill="#B2CAFF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.08817 1.62512C9.14394 0.569299 10.8558 0.56929 11.9116 1.62512L12.8128 2.52633C12.9819 2.69533 13.2111 2.79028 13.4501 2.79028H14.5059C15.9991 2.79028 17.2095 4.00074 17.2095 5.4939V6.54972C17.2095 6.78874 17.3045 7.01796 17.4735 7.18697L18.3747 8.08818C19.4305 9.14401 19.4305 10.8559 18.3747 11.9117L17.4735 12.8129C17.3045 12.9819 17.2095 13.2112 17.2095 13.4502V14.5059C17.2095 15.9991 15.9991 17.2095 14.5059 17.2095H13.4501C13.2111 17.2095 12.9819 17.3045 12.8128 17.4735L11.9116 18.3747C10.8558 19.4305 9.14403 19.4305 8.08817 18.3747L7.18696 17.4735C7.01795 17.3045 6.78873 17.2095 6.54972 17.2095H5.49389C4.00072 17.2095 2.79028 15.9991 2.79028 14.5059V13.4502C2.79028 13.2112 2.69533 12.9819 2.52632 12.8129L1.62513 11.9117C0.569295 10.8559 0.569295 9.14401 1.62512 8.08818L2.52632 7.18697C2.69533 7.01797 2.79028 6.78874 2.79028 6.54972V5.4939C2.79028 4.00074 4.00072 2.79028 5.49389 2.79028H6.54972C6.78873 2.79028 7.01795 2.69533 7.18696 2.52633L8.08817 1.62512Z" fill="url(#paint0_linear_6295_120949)" fill-opacity="0.9"/>
+<path d="M8.27881 1.81577L8.27881 1.81576C9.2293 0.865233 10.7704 0.865217 11.721 1.81577L12.6222 2.71697L12.6222 2.71701C12.8418 2.93652 13.1395 3.05989 13.4501 3.05989H14.5059C15.8502 3.05989 16.9399 4.14963 16.9399 5.4939V6.54972C16.9399 6.86027 17.0633 7.15805 17.2828 7.3776L17.2829 7.37762L18.1841 8.27882L18.3747 8.08818L18.1841 8.27882C19.1346 9.22937 19.1346 10.7705 18.1841 11.7211L17.2829 12.6223C17.0633 12.8418 16.9399 13.1396 16.9399 13.4502V14.5059C16.9399 15.8502 15.8502 16.9399 14.5059 16.9399H13.4501C13.1395 16.9399 12.8418 17.0633 12.6222 17.2828L12.6222 17.2829L11.721 18.1841C10.7704 19.1346 9.22939 19.1346 8.27881 18.1841L7.37761 17.2829L7.37759 17.2828C7.15804 17.0633 6.86027 16.9399 6.54972 16.9399H5.49389C4.14962 16.9399 3.05989 15.8502 3.05989 14.5059V13.4502C3.05989 13.1397 2.93655 12.8418 2.71696 12.6223C2.71696 12.6223 2.71695 12.6223 2.71694 12.6222L1.81577 11.7211C0.865224 10.7705 0.865226 9.22936 1.81576 8.27882L2.71696 7.37762C2.71696 7.37762 2.71696 7.37762 2.71696 7.37762C2.93654 7.15805 3.05989 6.86024 3.05989 6.54972V5.4939C3.05989 4.14964 4.14963 3.05989 5.49389 3.05989H6.54972C6.86024 3.05989 7.15803 2.93653 7.3776 2.71698L7.37761 2.71697L8.27881 1.81577Z" stroke="url(#paint1_linear_6295_120949)" stroke-opacity="0.8" stroke-width="0.539216"/>
+</g>
+</mask>
+<g mask="url(#mask0_6295_120949)">
+<g id="badge-bg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.08817 1.62512C9.14394 0.569299 10.8558 0.56929 11.9116 1.62512L12.8128 2.52633C12.9819 2.69533 13.2111 2.79028 13.4501 2.79028H14.5059C15.9991 2.79028 17.2095 4.00074 17.2095 5.4939V6.54972C17.2095 6.78874 17.3045 7.01796 17.4735 7.18697L18.3747 8.08818C19.4305 9.14401 19.4305 10.8559 18.3747 11.9117L17.4735 12.8129C17.3045 12.9819 17.2095 13.2112 17.2095 13.4502V14.5059C17.2095 15.9991 15.9991 17.2095 14.5059 17.2095H13.4501C13.2111 17.2095 12.9819 17.3045 12.8128 17.4735L11.9116 18.3747C10.8558 19.4305 9.14403 19.4305 8.08817 18.3747L7.18696 17.4735C7.01795 17.3045 6.78873 17.2095 6.54972 17.2095H5.49389C4.00072 17.2095 2.79028 15.9991 2.79028 14.5059V13.4502C2.79028 13.2112 2.69533 12.9819 2.52632 12.8129L1.62513 11.9117C0.569295 10.8559 0.569295 9.14401 1.62512 8.08818L2.52632 7.18697C2.69533 7.01797 2.79028 6.78874 2.79028 6.54972V5.4939C2.79028 4.00074 4.00072 2.79028 5.49389 2.79028H6.54972C6.78873 2.79028 7.01795 2.69533 7.18696 2.52633L8.08817 1.62512Z" fill="#B2CAFF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.08817 1.62512C9.14394 0.569299 10.8558 0.56929 11.9116 1.62512L12.8128 2.52633C12.9819 2.69533 13.2111 2.79028 13.4501 2.79028H14.5059C15.9991 2.79028 17.2095 4.00074 17.2095 5.4939V6.54972C17.2095 6.78874 17.3045 7.01796 17.4735 7.18697L18.3747 8.08818C19.4305 9.14401 19.4305 10.8559 18.3747 11.9117L17.4735 12.8129C17.3045 12.9819 17.2095 13.2112 17.2095 13.4502V14.5059C17.2095 15.9991 15.9991 17.2095 14.5059 17.2095H13.4501C13.2111 17.2095 12.9819 17.3045 12.8128 17.4735L11.9116 18.3747C10.8558 19.4305 9.14403 19.4305 8.08817 18.3747L7.18696 17.4735C7.01795 17.3045 6.78873 17.2095 6.54972 17.2095H5.49389C4.00072 17.2095 2.79028 15.9991 2.79028 14.5059V13.4502C2.79028 13.2112 2.69533 12.9819 2.52632 12.8129L1.62513 11.9117C0.569295 10.8559 0.569295 9.14401 1.62512 8.08818L2.52632 7.18697C2.69533 7.01797 2.79028 6.78874 2.79028 6.54972V5.4939C2.79028 4.00074 4.00072 2.79028 5.49389 2.79028H6.54972C6.78873 2.79028 7.01795 2.69533 7.18696 2.52633L8.08817 1.62512Z" fill="url(#paint2_linear_6295_120949)" fill-opacity="0.9"/>
+<path d="M8.44172 1.97868L8.44173 1.97867C9.30224 1.11812 10.6975 1.1181 11.5581 1.97868L12.4593 2.87988L12.4593 2.87995C12.7221 3.14262 13.0784 3.29028 13.4501 3.29028H14.5059C15.723 3.29028 16.7095 4.27687 16.7095 5.4939V6.54972C16.7095 6.9214 16.8572 7.27776 17.1199 7.54049L17.1199 7.54053L18.0211 8.44173L18.3747 8.08818L18.0211 8.44174C18.8817 9.3023 18.8817 10.6976 18.0211 11.5582L17.1199 12.4594C16.8572 12.7221 16.7095 13.0785 16.7095 13.4502V14.5059C16.7095 15.723 15.723 16.7095 14.5059 16.7095H13.4501C13.0784 16.7095 12.7221 16.8573 12.4594 17.1198L12.4593 17.1199L11.5581 18.0211C10.6975 18.8817 9.30233 18.8817 8.44172 18.0211L7.54052 17.1199L7.54048 17.1199C7.27775 16.8572 6.92139 16.7095 6.54972 16.7095H5.49389C4.27686 16.7095 3.29028 15.723 3.29028 14.5059V13.4502C3.29028 13.0786 3.14267 12.7221 2.87984 12.4593L1.97868 11.5582C1.11811 10.6976 1.11811 9.3023 1.97867 8.44173L2.87986 7.54054C2.87987 7.54053 2.87987 7.54053 2.87987 7.54053C3.14266 7.27775 3.29028 6.92134 3.29028 6.54972V5.4939C3.29028 4.27688 4.27687 3.29028 5.49389 3.29028H6.54972C6.92135 3.29028 7.27774 3.14265 7.54051 2.87989L7.54052 2.87988L8.44172 1.97868Z" stroke="url(#paint3_linear_6295_120949)" stroke-opacity="0.8"/>
+</g>
+<g id="check" filter="url(#filter0_d_6295_120949)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4219 6.98125C13.8732 7.28917 13.9829 7.89538 13.667 8.33526L10.04 13.3857C9.87754 13.6119 9.62408 13.7601 9.34287 13.7933C9.06166 13.8266 8.77923 13.7417 8.56605 13.5599L6.49346 11.7922C6.0789 11.4386 6.03689 10.8244 6.39963 10.4203C6.76238 10.0162 7.39252 9.97526 7.80709 10.3288L9.04316 11.3831L12.0328 7.22019C12.3487 6.78031 12.9706 6.67333 13.4219 6.98125Z" fill="url(#paint4_linear_6295_120949)" shape-rendering="crispEdges"/>
+</g>
+<path id="highlight" opacity="0.5" d="M0 0H15.5556L5.26663 20H0V0Z" fill="url(#paint5_linear_6295_120949)"/>
+</g>
+</g>
+<defs>
+<filter id="filter0_d_6295_120949" x="5.65283" y="6.55542" width="8.69458" height="7.99512" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="0.25"/>
+<feGaussianBlur stdDeviation="0.25"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6295_120949"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6295_120949" result="shape"/>
+</filter>
+<linearGradient id="paint0_linear_6295_120949" x1="16.302" y1="19.1666" x2="-0.37184" y2="14.82" gradientUnits="userSpaceOnUse">
+<stop stop-color="#155AEF"/>
+<stop offset="1" stop-color="#5289FF"/>
+</linearGradient>
+<linearGradient id="paint1_linear_6295_120949" x1="8.67462" y1="0.833252" x2="18.9651" y2="12.5066" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.95"/>
+<stop offset="1" stop-color="#155AEF"/>
+</linearGradient>
+<linearGradient id="paint2_linear_6295_120949" x1="16.302" y1="19.1666" x2="-0.37184" y2="14.82" gradientUnits="userSpaceOnUse">
+<stop stop-color="#155AEF"/>
+<stop offset="1" stop-color="#5289FF"/>
+</linearGradient>
+<linearGradient id="paint3_linear_6295_120949" x1="8.67462" y1="0.833252" x2="18.9651" y2="12.5066" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.95"/>
+<stop offset="1" stop-color="#155AEF"/>
+</linearGradient>
+<linearGradient id="paint4_linear_6295_120949" x1="10.0001" y1="6.80542" x2="10.0001" y2="13.8004" gradientUnits="userSpaceOnUse">
+<stop stop-color="white"/>
+<stop offset="1" stop-color="white" stop-opacity="0.9"/>
+</linearGradient>
+<linearGradient id="paint5_linear_6295_120949" x1="-4.78632" y1="4.375" x2="16.2164" y2="10.4" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.12"/>
+<stop offset="1" stop-color="white" stop-opacity="0.3"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/plugins/web-reader.svg b/app/components/base/icons/assets/public/plugins/web-reader.svg
new file mode 100644
index 0000000..61fbf69
--- /dev/null
+++ b/app/components/base/icons/assets/public/plugins/web-reader.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.59235 3.32566C10.3587 3.11341 11.1661 3 12 3C13.962 3 15.7773 3.62779 17.2561 4.69345C16.4693 5.21349 15.8824 5.77819 15.4756 6.38193C14.854 7.30445 14.6947 8.25844 14.8234 9.12887C14.9484 9.97416 15.3366 10.696 15.7446 11.2301C16.1402 11.7479 16.6256 12.181 17.0531 12.3946C18.1294 12.9327 19.3714 13.2022 20.2999 13.341C21.1399 13.4667 22.9206 13.8871 22.9865 12.5492C22.9955 12.3672 23 12.1841 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C12.1841 23 12.3672 22.9955 12.5492 22.9865C13.1008 22.9593 13.526 22.4902 13.4988 21.9385C13.4716 21.3869 13.0024 20.9618 12.4508 20.9889C12.3015 20.9963 12.1512 21 12 21C8.49063 21 5.45038 18.9914 3.96619 16.0611L4.93474 15.502L8.50745 16.1706C9.43309 16.3439 10.2876 15.6313 10.2834 14.6896L10.2694 11.5365L12.0952 8.41051C12.3911 7.90404 12.3646 7.27161 12.0274 6.79167L9.59235 3.32566Z" fill="#444CE7"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M13.9456 12.6561C13.5777 12.5165 13.1621 12.6057 12.8839 12.884C12.6056 13.1623 12.5164 13.5778 12.656 13.9458L15.8228 22.2945C15.969 22.68 16.3367 22.9362 16.7489 22.9399C17.1611 22.9435 17.5333 22.6938 17.6863 22.3111L19.007 19.0071L22.311 17.6865C22.6937 17.5334 22.9434 17.1612 22.9397 16.749C22.9361 16.3368 22.6799 15.9691 22.2944 15.8229L13.9456 12.6561Z" fill="#444CE7"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/plugins/wikipedia.svg b/app/components/base/icons/assets/public/plugins/wikipedia.svg
new file mode 100644
index 0000000..a2f10d9
--- /dev/null
+++ b/app/components/base/icons/assets/public/plugins/wikipedia.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M23.8431 5.0001H19.2179H19.0609V5.15706V5.66001V5.81696H19.2179H19.5393C19.9131 5.81696 20.2502 6.00882 20.4411 6.33021C20.632 6.65161 20.6392 7.0394 20.4603 7.36765L15.3174 16.8077L12.9751 11.2238L15.1813 7.17527C15.6379 6.33743 16.5143 5.81696 17.4684 5.81696H17.5726H17.7296V5.66001V5.15706V5.0001H17.5726H12.9474H12.7905V5.15706V5.66001V5.81696H12.9474H13.2688C13.6426 5.81696 13.9797 6.00882 14.1706 6.33021C14.3615 6.65161 14.3687 7.0394 14.1899 7.36765L12.5896 10.305L11.1634 6.9051C11.0601 6.65867 11.0856 6.38965 11.2336 6.16714C11.3816 5.94462 11.6197 5.81696 11.887 5.81696H12.2526H12.4095V5.66001V5.15706V5.0001H12.2526H6.72092H6.56396V5.15706V5.66001V5.81696H6.72092H6.79699C7.88821 5.81696 8.866 6.46719 9.28817 7.47344L11.3954 12.497L9.04698 16.8077L4.89304 6.9051C4.78966 6.65867 4.81525 6.38965 4.9632 6.16714C5.11116 5.94462 5.34932 5.81696 5.61657 5.81696H6.17832H6.33527V5.66001V5.15706V5.0001H6.17832H0.156957H0V5.15706V5.66001V5.81696H0.156957H0.52654C1.61776 5.81696 2.59561 6.46719 3.01772 7.47344L7.80628 18.889C7.89004 19.0887 8.08425 19.2177 8.30111 19.2177C8.50014 19.2177 8.67588 19.1131 8.77125 18.9381L9.39589 17.7918L11.7807 13.4155L14.0767 18.889C14.1604 19.0886 14.3547 19.2176 14.5715 19.2176C14.7705 19.2176 14.9463 19.1131 15.0417 18.938L15.6663 17.7917L21.4517 7.17517C21.9083 6.33733 22.7847 5.81686 23.7388 5.81686H23.843H24V5.6599V5.15696V5H23.8431V5.0001Z" fill="#222A30"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/thought/data-set.svg b/app/components/base/icons/assets/public/thought/data-set.svg
new file mode 100644
index 0000000..bdee170
--- /dev/null
+++ b/app/components/base/icons/assets/public/thought/data-set.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_7847_32895)">
+<path d="M10.5 2.5C10.5 3.32843 8.48528 4 6 4C3.51472 4 1.5 3.32843 1.5 2.5M10.5 2.5C10.5 1.67157 8.48528 1 6 1C3.51472 1 1.5 1.67157 1.5 2.5M10.5 2.5V9.5C10.5 10.33 8.5 11 6 11C3.5 11 1.5 10.33 1.5 9.5V2.5M10.5 6C10.5 6.83 8.5 7.5 6 7.5C3.5 7.5 1.5 6.83 1.5 6" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_7847_32895">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/thought/loading.svg b/app/components/base/icons/assets/public/thought/loading.svg
new file mode 100644
index 0000000..c666e17
--- /dev/null
+++ b/app/components/base/icons/assets/public/thought/loading.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_7998_4025)">
+<path d="M6 1.125V2.375M6 9V11M2.875 6H1.125M10.625 6H9.875M9.22855 9.22855L8.875 8.875M9.33211 2.70789L8.625 3.415M2.46079 9.53921L3.875 8.125M2.56434 2.60434L3.625 3.665" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_7998_4025">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/thought/search.svg b/app/components/base/icons/assets/public/thought/search.svg
new file mode 100644
index 0000000..314b04d
--- /dev/null
+++ b/app/components/base/icons/assets/public/thought/search.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_7847_32899)">
+<path d="M10.5 10.5L8.75005 8.75M10 5.75C10 8.09721 8.09721 10 5.75 10C3.40279 10 1.5 8.09721 1.5 5.75C1.5 3.40279 3.40279 1.5 5.75 1.5C8.09721 1.5 10 3.40279 10 5.75Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_7847_32899">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/thought/thought-list.svg b/app/components/base/icons/assets/public/thought/thought-list.svg
new file mode 100644
index 0000000..b8e17f0
--- /dev/null
+++ b/app/components/base/icons/assets/public/thought/thought-list.svg
@@ -0,0 +1,8 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4 6C4 5.72386 4.22386 5.5 4.5 5.5L10.5 5.5C10.7761 5.5 11 5.72386 11 6C11 6.27614 10.7761 6.5 10.5 6.5L4.5 6.5C4.22386 6.5 4 6.27614 4 6Z" fill="#667085"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4 3C4 2.72386 4.22386 2.5 4.5 2.5L10.5 2.5C10.7761 2.5 11 2.72386 11 3C11 3.27614 10.7761 3.5 10.5 3.5L4.5 3.5C4.22386 3.5 4 3.27614 4 3Z" fill="#667085"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4 9C4 8.72386 4.22386 8.5 4.5 8.5L10.5 8.5C10.7761 8.5 11 8.72386 11 9C11 9.27614 10.7761 9.5 10.5 9.5L4.5 9.5C4.22386 9.5 4 9.27614 4 9Z" fill="#667085"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1 6C1 5.44772 1.44772 5 2 5C2.55228 5 3 5.44772 3 6C3 6.55228 2.55228 7 2 7C1.44772 7 1 6.55228 1 6Z" fill="#667085"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1 3C1 2.44772 1.44772 2 2 2C2.55228 2 3 2.44772 3 3C3 3.55228 2.55228 4 2 4C1.44772 4 1 3.55228 1 3Z" fill="#667085"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1 9C1 8.44772 1.44772 8 2 8C2.55228 8 3 8.44772 3 9C3 9.55228 2.55228 10 2 10C1.44772 10 1 9.55228 1 9Z" fill="#667085"/>
+</svg>
diff --git a/app/components/base/icons/assets/public/thought/web-reader.svg b/app/components/base/icons/assets/public/thought/web-reader.svg
new file mode 100644
index 0000000..1c2291e
--- /dev/null
+++ b/app/components/base/icons/assets/public/thought/web-reader.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_7847_32887)">
+<path d="M4.5 1.75V1M2.53033 2.53033L2 2M2.53033 6.5L2 7.03033M6.5 2.53033L7.03033 2M1.75 4.5H1M7.93224 8.09479L6.68637 10.4085C6.54404 10.6728 6.47287 10.805 6.38725 10.8384C6.31295 10.8674 6.22926 10.8592 6.16199 10.8164C6.08447 10.767 6.04028 10.6235 5.95191 10.3366L4.22259 4.72263C4.1504 4.48825 4.1143 4.37107 4.14335 4.29192C4.16865 4.22298 4.22298 4.16865 4.29192 4.14335C4.37107 4.1143 4.48825 4.1504 4.72262 4.2226L10.3366 5.95192C10.6235 6.0403 10.767 6.08449 10.8164 6.16201C10.8592 6.22928 10.8674 6.31297 10.8384 6.38727C10.805 6.47289 10.6728 6.54406 10.4085 6.68639L8.09479 7.93224C8.05551 7.95339 8.03587 7.96396 8.01868 7.97755C8.00341 7.98961 7.98961 8.00341 7.97755 8.01868C7.96396 8.03587 7.95339 8.05551 7.93224 8.09479Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_7847_32887">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/tracing/langfuse-icon-big.svg b/app/components/base/icons/assets/public/tracing/langfuse-icon-big.svg
new file mode 100644
index 0000000..6ce0c27
--- /dev/null
+++ b/app/components/base/icons/assets/public/tracing/langfuse-icon-big.svg
@@ -0,0 +1,32 @@
+<svg width="111" height="24" viewBox="0 0 111 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Clip path group">
+<mask id="mask0_20135_18315" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="144" height="24">
+<g id="clip0_823_291">
+<path id="Vector" d="M143.36 0H0V24H143.36V0Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask0_20135_18315)">
+<g id="Group">
+<path id="Vector_2" d="M31.9258 17.3144V5.5896H33.5612V15.7456H39.5908V17.3144H31.9258ZM41.5502 11.1713C41.8806 9.47033 43.3343 8.36391 45.1845 8.36391C47.3155 8.36391 48.7197 9.60244 48.7197 12.03V15.3492C48.7197 15.729 48.8849 15.8942 49.2483 15.8942H49.6283V17.3144H49.1657C48.1085 17.3144 47.4807 16.7529 47.3155 15.9768C46.9852 16.7859 45.9609 17.5125 44.5898 17.5125C42.8222 17.5125 41.4016 16.5878 41.4016 15.019C41.4016 13.2024 42.7396 12.6905 44.755 12.3107L47.1173 11.8483C47.1008 10.5107 46.3409 9.85015 45.168 9.85015C44.1768 9.85015 43.45 10.4446 43.2517 11.2868L41.5502 11.1713ZM43.0865 14.9859C43.1031 15.5969 43.6317 16.1089 44.7881 16.1089C46.1096 16.1089 47.1503 15.1841 47.1503 13.6153V13.2355L45.2671 13.5657C44.0447 13.7804 43.0865 13.8795 43.0865 14.9859ZM51.8189 8.56208H53.2892L53.3387 10.0318C53.8013 8.90887 54.7759 8.36391 55.9488 8.36391C57.8981 8.36391 58.8563 9.80061 58.8563 11.6832V17.3144H57.2539V12.096C57.2539 10.5437 56.7418 9.73455 55.5358 9.73455C54.2638 9.73455 53.4213 10.5437 53.4213 12.096V17.3144H51.8189V8.56208ZM64.8465 16.852C62.6824 16.852 61.1461 15.118 61.1461 12.6575C61.1461 10.1144 62.6824 8.36391 64.8465 8.36391C66.0193 8.36391 67.0436 8.99143 67.44 9.89969L67.4565 8.56208H68.9929V16.3566C68.9763 18.7511 67.4565 19.9896 65.1108 19.9896C63.1945 19.9896 61.8069 18.9823 61.3939 17.463L63.0789 17.3474C63.4258 18.107 64.1031 18.5529 65.1108 18.5529C66.5315 18.5529 67.3739 17.9089 67.3905 16.7034V15.3988C66.9444 16.241 65.8872 16.852 64.8465 16.852ZM62.8311 12.641C62.8311 14.2924 63.7066 15.4483 65.1438 15.4483C66.548 15.4483 67.407 14.2924 67.4235 12.641C67.4565 11.0061 66.581 9.85015 65.1438 9.85015C63.7066 9.85015 62.8311 11.0061 62.8311 12.641ZM73.4961 8.18226C73.4961 6.56391 74.3055 5.5896 76.0897 5.5896H78.5015V7.00978H76.0566C75.495 7.00978 75.0985 7.43914 75.0985 8.14923V9.12354H78.3859V10.5437H75.0985V17.3144H73.4961V10.5437H71.1999V9.12354H73.4961V8.18226ZM88.3571 17.3144H86.8373L86.8207 15.8942C86.3582 16.9841 85.4001 17.5125 84.2767 17.5125C82.3605 17.5125 81.4189 16.0758 81.4189 14.1933V8.56208H83.0212V13.7804C83.0212 15.3327 83.5334 16.1419 84.6897 16.1419C85.9287 16.1419 86.7547 15.3327 86.7547 13.7804V8.56208H88.3571V17.3144ZM96.7925 11.3034C96.6108 10.3786 95.7518 9.85015 94.7275 9.85015C93.885 9.85015 93.1086 10.263 93.1251 11.0722C93.1251 11.9474 94.1824 12.1456 95.1571 12.3933C96.8255 12.8061 98.494 13.4171 98.494 15.052C98.494 16.7694 96.842 17.5125 95.0249 17.5125C92.9765 17.5125 91.308 16.3566 91.1758 14.5401L92.8608 14.441C93.026 15.4153 93.9016 16.0263 95.0249 16.0263C95.9004 16.0263 96.809 15.7951 96.809 14.9694C96.809 14.1107 95.7022 13.9621 94.7275 13.7309C93.0756 13.3346 91.4402 12.7235 91.4402 11.1382C91.4402 9.37125 93.026 8.36391 94.8762 8.36391C96.7264 8.36391 98.1636 9.47033 98.4444 11.2043L96.7925 11.3034ZM100.817 12.9382C100.817 10.1474 102.419 8.36391 104.88 8.36391C106.846 8.36391 108.63 9.63547 108.763 12.7896V13.4006H102.518C102.65 15.052 103.493 16.0263 104.88 16.0263C105.756 16.0263 106.549 15.5144 106.929 14.6391L108.63 14.7878C108.135 16.4557 106.632 17.5125 104.88 17.5125C102.419 17.5125 100.817 15.729 100.817 12.9382ZM102.568 12.1125H107.011C106.78 10.4446 105.872 9.85015 104.88 9.85015C103.608 9.85015 102.799 10.6924 102.568 12.1125Z" fill="black"/>
+<g id="Clip path group_2">
+<mask id="mask1_20135_18315" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="25" height="26">
+<g id="clip1_823_291">
+<path id="Vector_3" d="M24.5471 -0.0771484H0.308594V24.1529H24.5471V-0.0771484Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask1_20135_18315)">
+<g id="Group_2">
+<path id="Vector_4" d="M21.9423 16.8532C20.8746 18.2972 19.2396 19.2605 17.3946 19.4012C17.3372 19.4051 17.2797 19.4092 17.2215 19.4124C15.0582 19.5201 13.424 18.5334 12.3404 17.6174C10.4229 16.6027 8.92256 16.3471 8.04475 16.1261C7.4064 15.9654 6.84782 15.644 6.60842 15.4833C6.39617 15.3572 5.96925 15.0647 5.65086 14.5191C5.29416 13.9077 5.27342 13.3235 5.279 13.0752C5.46493 13.0504 5.70512 13.023 5.98601 13.0054C6.21582 12.9909 6.43845 12.9853 6.68823 12.9844C8.62571 12.982 10.1283 13.0768 11.2215 13.5622C11.8128 13.8241 12.361 14.1728 12.8493 14.5979C13.4774 15.1459 14.7613 16.012 16.3437 15.7164C16.5448 15.6786 16.7379 15.6287 16.9239 15.5677C17.4935 15.4857 18.4679 15.4198 19.6154 15.7243C20.7046 16.0136 21.4882 16.5134 21.9423 16.8532Z" fill="#0A60B5" stroke="black" stroke-width="2.56" stroke-miterlimit="10"/>
+<path id="Vector_5" d="M21.8003 6.90944C21.319 6.28602 20.7339 5.69669 20.043 5.29456C19.3066 4.86626 18.367 4.49744 17.2306 4.3975C14.4541 4.15321 12.5557 5.69273 12.2099 5.98382C11.7796 6.38753 10.0582 7.81602 7.98609 8.60917C7.62509 8.73768 6.93016 9.0414 6.31253 9.71961C5.82401 10.2557 5.58492 10.8046 5.46777 11.1457C5.71483 11.1798 5.96985 11.2044 6.23284 11.2194C8.2419 11.3313 9.96813 11.3424 11.0974 10.7896C11.8433 10.4247 12.4976 9.90517 13.0618 9.29681C14.0787 8.19987 15.5618 7.71051 16.9118 8.04605C17.5318 8.13247 18.6117 8.19833 19.8605 7.81602C20.7228 7.55189 21.3652 7.21957 21.8003 6.90944Z" fill="#0A60B5" stroke="black" stroke-width="2.56" stroke-miterlimit="10"/>
+<path id="Vector_6" d="M2.95884 7.37229C2.1886 6.97653 1.58732 6.52001 1.17721 6.16263C0.947963 5.96275 0.591797 6.12665 0.591797 6.43206V8.92893C0.591797 9.03766 0.640978 9.14079 0.725063 9.20796L1.74835 10.1922C1.80229 9.79638 1.9181 9.25834 2.17829 8.66347C2.4234 8.10227 2.71769 7.67288 2.95884 7.37229Z" fill="#0A60B5" stroke="black" stroke-width="2.56" stroke-miterlimit="10"/>
+<path id="Vector_7" d="M19.4326 12.9446C19.5497 12.584 19.6146 12.2056 19.6243 11.8201C19.6323 11.5156 19.597 11.4018 19.5441 11.1069C20.0886 11.0155 20.7686 10.8664 21.3886 10.7061C22.0438 10.537 22.5282 10.3406 23.0727 10.145C23.1521 10.5257 23.2355 10.7109 23.2644 10.993C23.2916 11.2591 23.3085 11.5348 23.3132 11.8201C23.3277 12.7066 23.2194 13.5105 23.0526 14.215C22.5394 13.9488 21.9299 13.6732 21.2282 13.4311C20.5754 13.2051 19.9683 13.0512 19.4326 12.9446Z" fill="#0A60B5" stroke="black" stroke-width="2.56" stroke-miterlimit="10"/>
+<path id="Vector_8" d="M1.15342 18.2166C0.918616 18.3871 0.591797 18.2191 0.591797 17.927V14.8605C0.591797 14.7676 0.627493 14.6796 0.689366 14.614C0.720303 14.5812 0.748859 14.5628 0.761552 14.5556L1.77532 14.1204C1.84988 14.5268 1.97284 15.0133 2.17829 15.5429C2.41864 16.1621 2.7042 16.6637 2.95884 17.0454C2.35676 17.4358 1.75469 17.8263 1.15342 18.2166Z" fill="#0A60B5" stroke="black" stroke-width="2.56" stroke-miterlimit="10"/>
+<path id="Vector_9" fill-rule="evenodd" clip-rule="evenodd" d="M7.68233 4.81872C9.70993 4.71818 11.2261 5.56713 12.0077 6.13451C11.4161 6.65689 9.81509 7.91742 7.92157 8.64547C7.79386 8.69117 7.62441 8.7588 7.43136 8.85733C6.06118 9.53194 5.24643 10.8764 5.21006 12.3127C5.20395 12.5545 5.21629 12.7953 5.24827 13.032C5.24481 13.0325 5.24136 13.033 5.23794 13.0334C5.23236 13.2797 5.2531 13.8593 5.60958 14.4661C5.9278 15.0073 6.35446 15.2975 6.5666 15.4227C6.67187 15.4928 6.83891 15.5939 7.04732 15.6986C7.29214 15.829 7.56361 15.9383 7.86305 16.0229C7.90892 16.0362 7.95532 16.0488 8.00211 16.0605C8.11111 16.0877 8.22985 16.1159 8.35794 16.1463C9.26137 16.3607 10.6303 16.6854 12.3087 17.5673C12.4783 17.7095 12.6609 17.8529 12.8568 17.993C12.7973 18.0463 12.7472 18.0927 12.7067 18.1309C12.3606 18.4235 10.4609 19.9709 7.68233 19.7254C6.5451 19.625 5.60404 19.2542 4.86793 18.8238C3.62779 18.0991 2.69071 16.9526 2.17951 15.6109C1.85014 14.7459 1.56303 13.6274 1.5423 12.3111C1.52395 11.187 1.70419 10.1969 1.94983 9.37575C2.70188 6.86682 4.89504 5.0268 7.5093 4.82989L7.50941 4.82988C7.5668 4.82589 7.62418 4.82191 7.68233 4.81872ZM21.8835 16.7762C21.4284 16.4391 20.6476 15.947 19.5661 15.6619C18.4192 15.3597 17.4455 15.4251 16.8761 15.5064C16.6902 15.567 16.4972 15.6164 16.2963 15.6539C14.7148 15.9473 13.4316 15.0879 12.8039 14.5442C12.6819 14.4387 12.5561 14.338 12.4269 14.2422C12.8493 13.871 13.3137 13.5508 13.82 13.3021C14.9501 12.7473 16.6775 12.7584 18.6881 12.87C21.4586 13.0247 23.3726 14.3441 24.1367 14.95C24.222 15.0177 24.2707 15.1198 24.2707 15.2282V17.718C24.2707 18.0233 23.9125 18.1867 23.682 17.9867C23.2692 17.6292 22.6618 17.1721 21.8835 16.7762ZM13.0009 9.33672C12.8193 9.5334 12.6283 9.72087 12.4279 9.89693C12.8159 10.1847 13.2353 10.4283 13.6788 10.6234C14.7715 11.1049 16.2732 11.199 18.2095 11.1966C21.0495 11.1926 23.1406 10.1235 24.1 9.54153C24.206 9.47696 24.2707 9.36218 24.2707 9.23781V6.182C24.2707 5.89101 23.9421 5.72359 23.706 5.8934C23.1472 6.29546 22.3162 6.80863 21.2445 7.21229C20.8586 7.43971 20.3776 7.6719 19.8046 7.84826C18.5548 8.23249 17.4742 8.16632 16.8538 8.07944C15.5028 7.74222 14.0186 8.2341 13.0009 9.33672Z" fill="#E11312"/>
+<path id="Vector_10" d="M12.0069 6.13459L12.21 6.36447L12.4968 6.11122L12.1871 5.88642L12.0069 6.13459ZM7.68154 4.8188L7.66636 4.51247L7.66557 4.51251L7.66477 4.51255L7.68154 4.8188ZM7.92078 8.64555L8.0241 8.9344L8.02755 8.93317L8.03092 8.93187L7.92078 8.64555ZM7.43056 8.85741L7.56612 9.13253L7.56811 9.13161L7.57008 9.13062L7.43056 8.85741ZM5.24747 13.0321L5.28765 13.3361L5.59271 13.2959L5.55152 12.991L5.24747 13.0321ZM5.23715 13.0335L5.1967 12.7295L4.93636 12.764L4.93041 13.0265L5.23715 13.0335ZM6.56581 15.4228L6.736 15.1676L6.729 15.1629L6.72175 15.1587L6.56581 15.4228ZM7.04653 15.6987L7.19079 15.428L7.18759 15.4263L7.18433 15.4247L7.04653 15.6987ZM7.86225 16.023L7.94762 15.7285L7.9467 15.7282L7.94571 15.7279L7.86225 16.023ZM12.3079 17.5673L12.5052 17.3324L12.4799 17.3112L12.4506 17.2958L12.3079 17.5673ZM12.856 17.9931L13.0606 18.2216L13.3458 17.9664L13.0346 17.7437L12.856 17.9931ZM12.7059 18.131L12.904 18.3652L12.9105 18.3598L12.9165 18.3541L12.7059 18.131ZM4.86713 18.8239L5.02207 18.5591L5.02197 18.559L4.86713 18.8239ZM1.5415 12.3112L1.84828 12.3064L1.84827 12.3062L1.5415 12.3112ZM1.94903 9.37583L1.65512 9.28773L1.65507 9.28796L1.94903 9.37583ZM7.5085 4.82997L7.48794 4.52395L7.48669 4.52403L7.48544 4.52413L7.5085 4.82997ZM7.50862 4.82996L7.52918 5.13598L7.52987 5.13593L7.50862 4.82996ZM19.5653 15.662L19.6435 15.3654H19.6435L19.5653 15.662ZM21.8827 16.7763L21.7001 17.0227L21.7207 17.038L21.7436 17.0496L21.8827 16.7763ZM16.8753 15.5065L16.8319 15.2028L16.8055 15.2066L16.7801 15.2149L16.8753 15.5065ZM16.2955 15.654L16.3515 15.9555H16.3517L16.2955 15.654ZM12.8031 14.5443L13.0041 14.3125L13.0038 14.3122L12.8031 14.5443ZM12.4261 14.2422L12.2236 14.0119L11.9383 14.2625L12.2434 14.4886L12.4261 14.2422ZM18.6873 12.8701L18.7044 12.5638H18.7042L18.6873 12.8701ZM24.1359 14.95L24.3267 14.7099L24.3266 14.7098L24.1359 14.95ZM23.6813 17.9868L23.8824 17.7552L23.8821 17.7549L23.6813 17.9868ZM12.4271 9.89701L12.2246 9.66667L11.9394 9.91717L12.2444 10.1434L12.4271 9.89701ZM13.678 10.6234L13.8018 10.3428L13.8016 10.3427L13.678 10.6234ZM18.2087 11.1967L18.2091 11.5034H18.2092L18.2087 11.1967ZM24.0992 9.54161L24.2584 9.80384L24.2588 9.80361L24.0992 9.54161ZM21.2437 7.21237L21.1355 6.92536L21.1107 6.9347L21.088 6.94815L21.2437 7.21237ZM16.853 8.07952L16.7786 8.37711L16.7943 8.38102L16.8104 8.38324L16.853 8.07952ZM12.1871 5.88642C11.3742 5.29623 9.7896 4.40718 7.66636 4.51247L7.69672 5.12514C9.62867 5.02934 11.0765 5.83819 11.8266 6.38275L12.1871 5.88642ZM8.03092 8.93187C9.97246 8.18534 11.605 6.89867 12.21 6.36447L11.8038 5.90471C11.2255 6.41528 9.65613 7.64973 7.81063 8.35932L8.03092 8.93187ZM7.57008 9.13062C7.74904 9.03922 7.90597 8.97657 8.0241 8.9344L7.81746 8.35679C7.68016 8.40586 7.49818 8.47855 7.29104 8.58429L7.57008 9.13062ZM5.51598 12.3205C5.54953 10.9957 6.30059 9.75569 7.56612 9.13253L7.29499 8.5823C5.82017 9.30843 4.94173 10.7573 4.90255 12.3051L5.51598 12.3205ZM5.55152 12.991C5.52184 12.7713 5.51027 12.5468 5.51598 12.3205L4.90255 12.3051C4.89604 12.5623 4.90915 12.8196 4.94341 13.0731L5.55152 12.991ZM5.27759 13.3375C5.28094 13.3371 5.28429 13.3366 5.28765 13.3361L5.20729 12.728C5.20373 12.7285 5.2002 12.729 5.1967 12.7295L5.27759 13.3375ZM5.87334 14.3108C5.55756 13.7734 5.53893 13.2588 5.54388 13.0404L4.93041 13.0265C4.92419 13.3008 4.94703 13.9455 5.34423 14.6215L5.87334 14.3108ZM6.72175 15.1587C6.53331 15.0475 6.15501 14.7899 5.87331 14.3107L5.34423 14.6215C5.69895 15.2249 6.17402 15.5477 6.40985 15.6869L6.72175 15.1587ZM7.18433 15.4247C6.98719 15.3256 6.83096 15.2309 6.736 15.1676L6.39562 15.678C6.51119 15.755 6.68904 15.8623 6.90873 15.9728L7.18433 15.4247ZM7.94571 15.7279C7.66622 15.6489 7.41526 15.5476 7.19079 15.428L6.90227 15.9694C7.16743 16.1106 7.4594 16.2279 7.7788 16.3182L7.94571 15.7279ZM8.07572 15.763C8.03277 15.7523 7.99004 15.7407 7.94762 15.7285L7.7768 16.3176C7.8262 16.3319 7.87621 16.3455 7.92691 16.3581L8.07572 15.763ZM8.42802 15.8479C8.29947 15.8174 8.18257 15.7897 8.07572 15.763L7.92691 16.3581C8.03798 16.3859 8.15864 16.4145 8.28627 16.4448L8.42802 15.8479ZM12.4506 17.2958C10.7369 16.3954 9.3372 16.0636 8.42802 15.8479L8.28627 16.4448C9.18402 16.6578 10.522 16.9755 12.1651 17.8389L12.4506 17.2958ZM13.0346 17.7437C12.8458 17.6086 12.6693 17.4702 12.5052 17.3324L12.1107 17.8023C12.2855 17.949 12.4745 18.0973 12.6774 18.2425L13.0346 17.7437ZM12.9165 18.3541C12.9555 18.3173 13.0035 18.2727 13.0606 18.2216L12.6514 17.7646C12.5895 17.8199 12.5373 17.8684 12.4953 17.908L12.9165 18.3541ZM7.65454 20.031C10.5596 20.2878 12.5414 18.6718 12.904 18.3652L12.5078 17.8968C12.1782 18.1755 10.3606 19.6543 7.70861 19.42L7.65454 20.031ZM4.7122 19.0885C5.48062 19.538 6.46494 19.9259 7.65455 20.0311L7.70861 19.42C6.62375 19.3242 5.72585 18.9707 5.02207 18.5591L4.7122 19.0885ZM1.89197 15.7201C2.42664 17.1235 3.4083 18.3266 4.71229 19.0886L5.02197 18.559C3.84569 17.8717 2.95318 16.7819 2.46543 15.5018L1.89197 15.7201ZM1.23472 12.316C1.25612 13.6744 1.55244 14.8284 1.89197 15.7201L2.46546 15.5019C2.14624 14.6635 1.86835 13.5804 1.84828 12.3064L1.23472 12.316ZM1.65507 9.28796C1.40184 10.1345 1.21579 11.1561 1.23472 12.3163L1.84827 12.3062C1.83052 11.2181 2.00495 10.2594 2.24298 9.4637L1.65507 9.28796ZM7.48544 4.52413C4.73874 4.73102 2.44195 6.66285 1.65512 9.28773L2.24293 9.46385C2.96021 7.07095 5.04976 5.32275 7.53155 5.13581L7.48544 4.52413ZM7.48805 4.52394L7.48794 4.52395L7.52906 5.13599L7.52918 5.13598L7.48805 4.52394ZM7.66477 4.51255C7.60399 4.51588 7.54439 4.52003 7.48736 4.52399L7.52987 5.13593C7.58761 5.13192 7.64276 5.1281 7.69834 5.12505L7.66477 4.51255ZM19.4871 15.9585C20.5195 16.2307 21.2651 16.7006 21.7001 17.0227L22.0654 16.5298C21.5901 16.1778 20.7741 15.6634 19.6435 15.3654L19.4871 15.9585ZM16.9186 15.8101C17.4624 15.7325 18.3923 15.6701 19.4871 15.9585L19.6435 15.3654C18.4447 15.0495 17.427 15.1179 16.8319 15.2028L16.9186 15.8101ZM16.3517 15.9555C16.5658 15.9156 16.7717 15.8629 16.9704 15.7981L16.7801 15.2149C16.6071 15.2713 16.4271 15.3174 16.2392 15.3524L16.3517 15.9555ZM12.6023 14.776C13.2517 15.3386 14.6295 16.275 16.3515 15.9555L16.2395 15.3524C14.7985 15.6197 13.6099 14.8372 13.0041 14.3125L12.6023 14.776ZM12.2434 14.4886C12.3665 14.5799 12.4863 14.6758 12.6025 14.7763L13.0038 14.3122C12.876 14.2017 12.7442 14.0962 12.6089 13.9959L12.2434 14.4886ZM13.6839 13.0269C13.1508 13.2889 12.6639 13.625 12.2236 14.0119L12.6286 14.4726C13.033 14.1173 13.4752 13.8129 13.9546 13.5774L13.6839 13.0269ZM18.7042 12.5638C17.6973 12.5079 16.7474 12.4763 15.9035 12.5301C15.0621 12.5838 14.3014 12.7237 13.6839 13.0269L13.9546 13.5774C14.4672 13.3258 15.1352 13.1938 15.9426 13.1423C16.7477 13.0909 17.6667 13.1206 18.6702 13.1763L18.7042 12.5638ZM24.3266 14.7098C23.5387 14.085 21.5647 12.7236 18.7044 12.5638L18.6702 13.1763C21.3509 13.3259 23.2049 14.6033 23.9452 15.1903L24.3266 14.7098ZM24.5767 15.2283C24.5767 15.0273 24.4861 14.8365 24.3267 14.7099L23.945 15.1902C23.9563 15.1992 23.9631 15.2124 23.9631 15.2283H24.5767ZM24.5767 17.7181V15.2283H23.9631V17.7181H24.5767ZM23.4801 18.2183C23.9096 18.5912 24.5767 18.2859 24.5767 17.7181H23.9631C23.9631 17.7326 23.9593 17.7405 23.9559 17.7456C23.9516 17.7519 23.9445 17.7584 23.9345 17.7629C23.9246 17.7675 23.915 17.7685 23.9076 17.7677C23.9016 17.7669 23.8933 17.7646 23.8824 17.7552L23.4801 18.2183ZM21.7436 17.0496C22.4948 17.4318 23.0817 17.8734 23.4804 18.2186L23.8821 17.7549C23.4551 17.3852 22.8272 16.9126 22.0218 16.5029L21.7436 17.0496ZM12.6296 10.1274C12.8386 9.94385 13.0372 9.74886 13.2256 9.54483L12.7747 9.1287C12.5998 9.31809 12.4165 9.49805 12.2246 9.66667L12.6296 10.1274ZM13.8016 10.3427C13.379 10.1569 12.9795 9.92476 12.6099 9.65072L12.2444 10.1434C12.6507 10.4448 13.0899 10.6999 13.5545 10.9042L13.8016 10.3427ZM18.2083 10.89C16.2651 10.8924 14.8268 10.7946 13.8018 10.3428L13.5543 10.9041C14.7145 11.4154 16.2797 11.5058 18.2091 11.5034L18.2083 10.89ZM23.94 9.27945C23.0063 9.84586 20.971 10.8861 18.2083 10.89L18.2092 11.5034C21.1263 11.4993 23.2733 10.4014 24.2584 9.80384L23.94 9.27945ZM23.9631 9.23789C23.9631 9.25522 23.9542 9.27078 23.9396 9.27968L24.2588 9.80361C24.4563 9.68338 24.5767 9.4693 24.5767 9.23789H23.9631ZM23.9631 6.18208V9.23789H24.5767V6.18208H23.9631ZM23.8844 6.14243C23.9185 6.11792 23.9631 6.14225 23.9631 6.18208H24.5767C24.5767 5.63993 23.9641 5.32941 23.526 5.64453L23.8844 6.14243ZM21.3519 7.49938C22.4546 7.08404 23.3093 6.55621 23.8844 6.14243L23.526 5.64453C22.9834 6.03488 22.1762 6.53338 21.1355 6.92536L21.3519 7.49938ZM19.894 8.14148C20.4934 7.95707 20.9962 7.71423 21.3995 7.4766L21.088 6.94815C20.7192 7.16536 20.2602 7.38697 19.7135 7.55519L19.894 8.14148ZM16.8104 8.38324C17.4579 8.47395 18.5872 8.54334 19.894 8.14148L19.7136 7.55517C18.5209 7.92187 17.4889 7.85892 16.8955 7.7758L16.8104 8.38324ZM13.2256 9.54483C14.1759 8.5152 15.5483 8.07001 16.7786 8.37711L16.9273 7.78194C15.4556 7.41459 13.8597 7.95323 12.7746 9.12877L13.2256 9.54483Z" fill="black"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/tracing/langfuse-icon.svg b/app/components/base/icons/assets/public/tracing/langfuse-icon.svg
new file mode 100644
index 0000000..fe10082
--- /dev/null
+++ b/app/components/base/icons/assets/public/tracing/langfuse-icon.svg
@@ -0,0 +1,32 @@
+<svg width="74" height="16" viewBox="0 0 74 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Clip path group">
+<mask id="mask0_20135_12984" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="96" height="16">
+<g id="clip0_823_291">
+<path id="Vector" d="M95.5733 0H0V16H95.5733V0Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask0_20135_12984)">
+<g id="Group">
+<path id="Vector_2" d="M21.2832 11.5431V3.72656H22.3735V10.4972H26.3932V11.5431H21.2832ZM27.6995 7.44766C27.9198 6.31372 28.8889 5.5761 30.1224 5.5761C31.543 5.5761 32.4791 6.40179 32.4791 8.02014V10.233C32.4791 10.4862 32.5893 10.5963 32.8316 10.5963H33.0849V11.5431H32.7765C32.0717 11.5431 31.6532 11.1688 31.543 10.6513C31.3228 11.1908 30.64 11.6752 29.7259 11.6752C28.5475 11.6752 27.6004 11.0587 27.6004 10.0128C27.6004 8.80179 28.4924 8.46051 29.836 8.2073L31.4109 7.89904C31.3999 7.0073 30.8933 6.56693 30.1114 6.56693C29.4506 6.56693 28.966 6.96326 28.8338 7.52473L27.6995 7.44766ZM28.7237 9.99078C28.7347 10.3981 29.0871 10.7394 29.8581 10.7394C30.7391 10.7394 31.4329 10.1229 31.4329 9.07702V8.82381L30.1774 9.04399C29.3625 9.18711 28.7237 9.25317 28.7237 9.99078ZM34.5453 5.70821H35.5255L35.5585 6.68803C35.8669 5.93941 36.5166 5.5761 37.2986 5.5761C38.5981 5.5761 39.2369 6.5339 39.2369 7.78895V11.5431H38.1686V8.06418C38.1686 7.02931 37.8272 6.48987 37.0232 6.48987C36.1752 6.48987 35.6136 7.02931 35.6136 8.06418V11.5431H34.5453V5.70821ZM43.2303 11.2348C41.7876 11.2348 40.7634 10.0789 40.7634 8.43849C40.7634 6.74308 41.7876 5.5761 43.2303 5.5761C44.0122 5.5761 44.6951 5.99445 44.9594 6.59996L44.9704 5.70821H45.9946V10.9045C45.9836 12.5009 44.9704 13.3266 43.4065 13.3266C42.129 13.3266 41.2039 12.655 40.9286 11.6422L42.0519 11.5651C42.2832 12.0715 42.7347 12.3688 43.4065 12.3688C44.3536 12.3688 44.9153 11.9394 44.9263 11.1357V10.266C44.629 10.8275 43.9241 11.2348 43.2303 11.2348ZM41.8867 8.42748C41.8867 9.5284 42.4704 10.299 43.4286 10.299C44.3647 10.299 44.9373 9.5284 44.9483 8.42748C44.9704 7.33757 44.3867 6.56693 43.4286 6.56693C42.4704 6.56693 41.8867 7.33757 41.8867 8.42748ZM48.9967 5.455C48.9967 4.3761 49.5364 3.72656 50.7258 3.72656H52.3337V4.67335H50.7038C50.3293 4.67335 50.065 4.95959 50.065 5.43298V6.08253H52.2566V7.02931H50.065V11.5431H48.9967V7.02931H47.4659V6.08253H48.9967V5.455ZM58.9041 11.5431H57.8909L57.8798 10.5963C57.5715 11.3229 56.9327 11.6752 56.1838 11.6752C54.9063 11.6752 54.2786 10.7174 54.2786 9.46234V5.70821H55.3468V9.18711C55.3468 10.222 55.6883 10.7614 56.4592 10.7614C57.2851 10.7614 57.8358 10.222 57.8358 9.18711V5.70821H58.9041V11.5431ZM64.5277 7.53574C64.4065 6.91922 63.8338 6.56693 63.151 6.56693C62.5894 6.56693 62.0718 6.84216 62.0828 7.38161C62.0828 7.9651 62.7876 8.09721 63.4374 8.26234C64.5497 8.53757 65.662 8.94491 65.662 10.0348C65.662 11.1798 64.5607 11.6752 63.3493 11.6752C61.9837 11.6752 60.8713 10.9045 60.7832 9.69354L61.9066 9.62748C62.0167 10.277 62.6004 10.6844 63.3493 10.6844C63.933 10.6844 64.5387 10.5302 64.5387 9.97977C64.5387 9.4073 63.8008 9.30821 63.151 9.15409C62.0497 8.88987 60.9594 8.48253 60.9594 7.42565C60.9594 6.24766 62.0167 5.5761 63.2502 5.5761C64.4836 5.5761 65.4417 6.31372 65.629 7.46968L64.5277 7.53574ZM67.2104 8.62565C67.2104 6.76509 68.2787 5.5761 69.9196 5.5761C71.2302 5.5761 72.4196 6.42381 72.5077 8.52656V8.9339H68.3448C68.4329 10.0348 68.9945 10.6844 69.9196 10.6844C70.5033 10.6844 71.032 10.3431 71.2853 9.75959L72.4196 9.85867C72.0892 10.9706 71.087 11.6752 69.9196 11.6752C68.2787 11.6752 67.2104 10.4862 67.2104 8.62565ZM68.3778 8.07519H71.3403C71.1861 6.96326 70.5804 6.56693 69.9196 6.56693C69.0716 6.56693 68.532 7.1284 68.3778 8.07519Z" fill="black"/>
+<g id="Clip path group_2">
+<mask id="mask1_20135_12984" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="-1" width="17" height="18">
+<g id="clip1_823_291">
+<path id="Vector_3" d="M16.3621 -0.0512695H0.203125V16.1021H16.3621V-0.0512695Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask1_20135_12984)">
+<g id="Group_2">
+<path id="Vector_4" d="M14.6259 11.2357C13.9141 12.1984 12.8241 12.8406 11.5941 12.9344C11.5558 12.937 11.5175 12.9397 11.4787 12.9419C10.0365 13.0136 8.94706 12.3558 8.22466 11.7452C6.94631 11.0687 5.94609 10.8983 5.36089 10.751C4.93532 10.6438 4.56293 10.4296 4.40334 10.3225C4.26183 10.2384 3.97722 10.0434 3.76496 9.67965C3.52716 9.27204 3.51333 8.88257 3.51706 8.71705C3.641 8.70048 3.80113 8.68224 3.98839 8.67048C4.1416 8.66082 4.29002 8.65709 4.45654 8.65652C5.74819 8.65494 6.7499 8.71812 7.47874 9.0417C7.87295 9.21632 8.23842 9.4488 8.56395 9.73215C8.98265 10.0975 9.83862 10.6749 10.8935 10.4778C11.0276 10.4526 11.1563 10.4194 11.2803 10.3787C11.6601 10.3241 12.3097 10.2801 13.0747 10.4831C13.8008 10.676 14.3232 11.0092 14.6259 11.2357Z" fill="#0A60B5" stroke="black" stroke-width="1.70667" stroke-miterlimit="10"/>
+<path id="Vector_5" d="M14.53 4.60662C14.2091 4.19101 13.819 3.79812 13.3584 3.53003C12.8675 3.2445 12.2411 2.99862 11.4835 2.93199C9.63248 2.76913 8.36691 3.79548 8.13634 3.98954C7.84947 4.25868 6.70187 5.21101 5.32048 5.73977C5.07981 5.82545 4.61653 6.02793 4.20477 6.48007C3.87909 6.83749 3.7197 7.20339 3.6416 7.43076C3.80631 7.45351 3.97632 7.46992 4.15164 7.47994C5.49102 7.55452 6.64184 7.56193 7.39466 7.19337C7.89196 6.95015 8.32815 6.60377 8.70431 6.1982C9.38222 5.4669 10.3709 5.14067 11.271 5.36436C11.6843 5.42197 12.4042 5.46588 13.2368 5.21101C13.8116 5.03492 14.2399 4.81337 14.53 4.60662Z" fill="#0A60B5" stroke="black" stroke-width="1.70667" stroke-miterlimit="10"/>
+<path id="Vector_6" d="M1.96963 4.91518C1.45614 4.65135 1.05528 4.347 0.781876 4.10874C0.629046 3.97549 0.391602 4.08476 0.391602 4.28837V5.95295C0.391602 6.02543 0.424389 6.09419 0.480445 6.13896L1.16264 6.79512C1.19859 6.53125 1.2758 6.17255 1.44926 5.77597C1.61267 5.40184 1.80886 5.11558 1.96963 4.91518Z" fill="#0A60B5" stroke="black" stroke-width="1.70667" stroke-miterlimit="10"/>
+<path id="Vector_7" d="M12.9521 8.63005C13.0302 8.38964 13.0735 8.13742 13.0799 7.8804C13.0853 7.67736 13.0617 7.6015 13.0264 7.4049C13.3895 7.34397 13.8428 7.24459 14.2561 7.1377C14.6929 7.02499 15.0158 6.89407 15.3789 6.76367C15.4318 7.01747 15.4874 7.14092 15.5067 7.32899C15.5248 7.50642 15.5361 7.69019 15.5392 7.8804C15.5489 8.47138 15.4767 9.0073 15.3655 9.47698C15.0233 9.29954 14.617 9.11577 14.1492 8.95439C13.714 8.8037 13.3093 8.70115 12.9521 8.63005Z" fill="#0A60B5" stroke="black" stroke-width="1.70667" stroke-miterlimit="10"/>
+<path id="Vector_8" d="M0.766014 12.1447C0.609481 12.2583 0.391602 12.1463 0.391602 11.9516V9.90721C0.391602 9.84531 0.415399 9.78667 0.456648 9.74292C0.477272 9.72104 0.49631 9.70877 0.504771 9.70397L1.18061 9.41382C1.23032 9.6848 1.3123 10.0091 1.44926 10.3622C1.6095 10.775 1.79987 11.1094 1.96963 11.3638C1.56825 11.6241 1.16686 11.8844 0.766014 12.1447Z" fill="#0A60B5" stroke="black" stroke-width="1.70667" stroke-miterlimit="10"/>
+<path id="Vector_9" fill-rule="evenodd" clip-rule="evenodd" d="M5.11863 3.21273C6.47036 3.1457 7.48116 3.71166 8.00219 4.08992C7.60778 4.43817 6.54047 5.27853 5.27812 5.76389C5.19298 5.79436 5.08001 5.83945 4.95131 5.90513C4.03786 6.35487 3.49469 7.25118 3.47044 8.20872C3.46637 8.3699 3.4746 8.53046 3.49592 8.68826C3.49361 8.68857 3.49131 8.68888 3.48903 8.68918C3.48531 8.85338 3.49914 9.23978 3.73679 9.64428C3.94894 10.0051 4.23338 10.1986 4.37481 10.282C4.44499 10.3288 4.55634 10.3962 4.69529 10.466C4.8585 10.5529 5.03948 10.6258 5.2391 10.6822C5.26968 10.6911 5.30062 10.6995 5.33181 10.7072C5.40448 10.7254 5.48364 10.7442 5.56903 10.7644C6.17131 10.9074 7.08394 11.1238 8.20285 11.7118C8.31591 11.8066 8.43766 11.9022 8.56827 11.9956C8.52858 12.0311 8.49519 12.0621 8.46819 12.0875C8.23747 12.2826 6.97098 13.3142 5.11863 13.1505C4.36047 13.0836 3.73309 12.8364 3.24236 12.5494C2.4156 12.0663 1.79088 11.302 1.45008 10.4075C1.2305 9.83086 1.03909 9.08515 1.02527 8.20765C1.01304 7.45826 1.1332 6.79817 1.29696 6.25074C1.79833 4.57812 3.26043 3.35145 5.00327 3.22017L5.00335 3.22016C5.0416 3.21751 5.07986 3.21485 5.11863 3.21273ZM14.5861 11.1844C14.2827 10.9597 13.7622 10.6316 13.0411 10.4415C12.2766 10.2401 11.6274 10.2837 11.2478 10.3378C11.1239 10.3782 10.9952 10.4112 10.8613 10.4362C9.80694 10.6318 8.95148 10.0588 8.53303 9.69637C8.45168 9.62603 8.36781 9.55891 8.28165 9.49501C8.56326 9.2476 8.87288 9.03413 9.21043 8.8683C9.96382 8.49841 11.1154 8.50582 12.4558 8.58025C14.3028 8.68336 15.5788 9.56295 16.0882 9.96688C16.145 10.0121 16.1775 10.0801 16.1775 10.1524V11.8123C16.1775 12.0158 15.9388 12.1247 15.7851 11.9914C15.5098 11.7531 15.1049 11.4483 14.5861 11.1844ZM8.66435 6.22472C8.54326 6.35584 8.41593 6.48083 8.28237 6.59819C8.54101 6.79004 8.82057 6.95244 9.11629 7.08249C9.84473 7.40351 10.8459 7.46623 12.1367 7.46465C14.0301 7.46199 15.4241 6.74925 16.0637 6.36126C16.1344 6.31822 16.1775 6.2417 16.1775 6.15878V4.12158C16.1775 3.92758 15.9585 3.81597 15.8011 3.92917C15.4285 4.19722 14.8745 4.53933 14.1601 4.80844C13.9028 4.96005 13.5822 5.11485 13.2001 5.23242C12.367 5.48857 11.6466 5.44446 11.2329 5.38654C10.3323 5.16172 9.34277 5.48964 8.66435 6.22472Z" fill="#E11312"/>
+<path id="Vector_10" d="M8.00166 4.09005L8.13707 4.2433L8.32826 4.07447L8.12183 3.92461L8.00166 4.09005ZM5.11809 3.21286L5.10798 3.00864L5.10745 3.00866L5.10692 3.0087L5.11809 3.21286ZM5.27759 5.76403L5.34647 5.95659L5.34877 5.95577L5.35102 5.9549L5.27759 5.76403ZM4.95078 5.90527L5.04115 6.08868L5.04247 6.08807L5.04379 6.0874L4.95078 5.90527ZM3.49538 8.6884L3.52217 8.89108L3.72555 8.86425L3.69809 8.661L3.49538 8.6884ZM3.4885 8.68932L3.46154 8.48664L3.28798 8.50969L3.28401 8.68467L3.4885 8.68932ZM4.37427 10.2822L4.48774 10.112L4.48307 10.1089L4.47824 10.1061L4.37427 10.2822ZM4.69475 10.4661L4.79093 10.2857L4.78879 10.2845L4.78663 10.2834L4.69475 10.4661ZM5.23857 10.6823L5.29549 10.486L5.29487 10.4858L5.29421 10.4856L5.23857 10.6823ZM8.20232 11.7119L8.33384 11.5553L8.31701 11.5412L8.29748 11.5309L8.20232 11.7119ZM8.56773 11.9957L8.70411 12.1481L8.89429 11.978L8.68678 11.8295L8.56773 11.9957ZM8.46766 12.0877L8.59975 12.2438L8.60404 12.2402L8.60808 12.2364L8.46766 12.0877ZM3.24183 12.5496L3.34511 12.3731L3.34505 12.373L3.24183 12.5496ZM1.02474 8.20779L1.22926 8.20456L1.22925 8.20446L1.02474 8.20779ZM1.29642 6.25088L1.10049 6.19214L1.10045 6.1923L1.29642 6.25088ZM5.00274 3.2203L4.98903 3.01629L4.9882 3.01635L4.98737 3.01641L5.00274 3.2203ZM5.00281 3.2203L5.01652 3.42431L5.01698 3.42428L5.00281 3.2203ZM13.0406 10.4417L13.0928 10.2439H13.0927L13.0406 10.4417ZM14.5855 11.1845L14.4638 11.3488L14.4775 11.359L14.4928 11.3667L14.5855 11.1845ZM11.2473 10.338L11.2183 10.1356L11.2007 10.1381L11.1838 10.1436L11.2473 10.338ZM10.8607 10.4363L10.8981 10.6373H10.8982L10.8607 10.4363ZM8.5325 9.6965L8.66648 9.54197L8.66627 9.54177L8.5325 9.6965ZM8.28112 9.49515L8.14612 9.34159L7.95594 9.50864L8.15931 9.65939L8.28112 9.49515ZM12.4553 8.58039L12.4667 8.37622H12.4666L12.4553 8.58039ZM16.0877 9.96702L16.2149 9.80692L16.2148 9.80687L16.0877 9.96702ZM15.7846 11.9915L15.9187 11.8371L15.9185 11.8369L15.7846 11.9915ZM8.28183 6.59833L8.14678 6.44477L7.95666 6.61177L8.15998 6.76257L8.28183 6.59833ZM9.11576 7.08262L9.19829 6.89553L9.19814 6.89548L9.11576 7.08262ZM12.1362 7.46478L12.1365 7.66925H12.1365L12.1362 7.46478ZM16.0632 6.3614L16.1693 6.53622L16.1696 6.53607L16.0632 6.3614ZM14.1596 4.80857L14.0874 4.61723L14.0709 4.62346L14.0557 4.63242L14.1596 4.80857ZM11.2324 5.38667L11.1828 5.58506L11.1933 5.58767L11.204 5.58915L11.2324 5.38667ZM8.12183 3.92461C7.57989 3.53114 6.52347 2.93845 5.10798 3.00864L5.12822 3.41708C6.41618 3.35322 7.38138 3.89245 7.88144 4.25549L8.12183 3.92461ZM5.35102 5.9549C6.64538 5.45722 7.73371 4.59944 8.13707 4.2433L7.86625 3.9368C7.48074 4.27718 6.43449 5.10015 5.20416 5.5732L5.35102 5.9549ZM5.04379 6.0874C5.16309 6.02647 5.26772 5.98471 5.34647 5.95659L5.20871 5.57152C5.11717 5.60423 4.99585 5.65269 4.85776 5.72318L5.04379 6.0874ZM3.67439 8.21402C3.69676 7.3308 4.19746 6.50412 5.04115 6.08868L4.8604 5.72186C3.87719 6.20595 3.29156 7.17188 3.26543 8.2037L3.67439 8.21402ZM3.69809 8.661C3.6783 8.51455 3.67058 8.36487 3.67439 8.21402L3.26543 8.2037C3.2611 8.3752 3.26984 8.5467 3.29268 8.71575L3.69809 8.661ZM3.51546 8.892C3.5177 8.8917 3.51993 8.89139 3.52217 8.89108L3.4686 8.48566C3.46623 8.48597 3.46387 8.48633 3.46154 8.48664L3.51546 8.892ZM3.91263 9.54085C3.70211 9.18256 3.68969 8.83956 3.69299 8.69392L3.28401 8.68467C3.27987 8.86752 3.29509 9.29732 3.55989 9.74798L3.91263 9.54085ZM4.47824 10.1061C4.35261 10.032 4.10041 9.86028 3.91261 9.54079L3.55989 9.74798C3.79637 10.1503 4.11309 10.3655 4.2703 10.4583L4.47824 10.1061ZM4.78663 10.2834C4.6552 10.2174 4.55104 10.1543 4.48774 10.112L4.26081 10.4523C4.33787 10.5037 4.45643 10.5752 4.60289 10.6488L4.78663 10.2834ZM5.29421 10.4856C5.10788 10.4329 4.94058 10.3654 4.79093 10.2857L4.59858 10.6466C4.77536 10.7407 4.97 10.819 5.18294 10.8791L5.29421 10.4856ZM5.38088 10.509C5.35225 10.5019 5.32376 10.4941 5.29549 10.486L5.18161 10.8787C5.21454 10.8883 5.24788 10.8973 5.28168 10.9058L5.38088 10.509ZM5.61575 10.5656C5.53005 10.5453 5.45212 10.5268 5.38088 10.509L5.28168 10.9058C5.35572 10.9243 5.43616 10.9433 5.52125 10.9635L5.61575 10.5656ZM8.29748 11.5309C7.155 10.9306 6.22187 10.7094 5.61575 10.5656L5.52125 10.9635C6.11975 11.1055 7.01177 11.3174 8.10715 11.8929L8.29748 11.5309ZM8.68678 11.8295C8.56093 11.7394 8.44327 11.6471 8.33384 11.5553L8.07085 11.8685C8.18744 11.9664 8.31338 12.0652 8.44864 12.162L8.68678 11.8295ZM8.60808 12.2364C8.63406 12.2119 8.66607 12.1821 8.70411 12.1481L8.4313 11.8434C8.39004 11.8803 8.35526 11.9126 8.32724 11.939L8.60808 12.2364ZM5.10009 13.3543C7.03682 13.5255 8.35798 12.4482 8.59975 12.2438L8.33558 11.9315C8.11585 12.1173 6.90412 13.1032 5.13615 12.947L5.10009 13.3543ZM3.13854 12.726C3.65082 13.0256 4.30703 13.2843 5.10011 13.3544L5.13615 12.947C4.4129 12.8831 3.8143 12.6475 3.34511 12.3731L3.13854 12.726ZM1.25838 10.4804C1.61483 11.416 2.26927 12.2181 3.1386 12.7261L3.34505 12.373C2.56087 11.9148 1.96586 11.1883 1.64069 10.3349L1.25838 10.4804ZM0.820219 8.21101C0.834481 9.11662 1.03203 9.88594 1.25838 10.4804L1.64071 10.3349C1.4279 9.77599 1.24263 9.05395 1.22926 8.20456L0.820219 8.21101ZM1.10045 6.1923C0.93163 6.75664 0.807599 7.43774 0.820219 8.21116L1.22925 8.20446C1.21742 7.47904 1.3337 6.83991 1.49239 6.30946L1.10045 6.1923ZM4.98737 3.01641C3.15623 3.15434 1.62504 4.44222 1.10049 6.19214L1.49236 6.30956C1.97055 4.7143 3.36357 3.54883 5.0181 3.4242L4.98737 3.01641ZM4.9891 3.01629L4.98903 3.01629L5.01644 3.42432L5.01652 3.42431L4.9891 3.01629ZM5.10692 3.0087C5.0664 3.01091 5.02666 3.01368 4.98864 3.01632L5.01698 3.42428C5.05547 3.42161 5.09225 3.41906 5.12929 3.41703L5.10692 3.0087ZM12.9885 10.6393C13.6767 10.8208 14.1738 11.134 14.4638 11.3488L14.7073 11.0202C14.3904 10.7855 13.8465 10.4426 13.0928 10.2439L12.9885 10.6393ZM11.2762 10.5404C11.6387 10.4886 12.2586 10.4471 12.9885 10.6393L13.0927 10.2439C12.2935 10.0333 11.6151 10.0789 11.2183 10.1356L11.2762 10.5404ZM10.8982 10.6373C11.0409 10.6107 11.1782 10.5756 11.3107 10.5324L11.1838 10.1436C11.0685 10.1812 10.9485 10.2119 10.8232 10.2353L10.8982 10.6373ZM8.39858 9.85098C8.83155 10.2261 9.75005 10.8503 10.8981 10.6373L10.8234 10.2353C9.86276 10.4135 9.07035 9.89182 8.66648 9.54197L8.39858 9.85098ZM8.15931 9.65939C8.24138 9.72027 8.32126 9.78422 8.39873 9.85118L8.66627 9.54177C8.58108 9.46816 8.49323 9.39782 8.40297 9.3309L8.15931 9.65939ZM9.1197 8.68492C8.76425 8.85959 8.43969 9.08364 8.14612 9.34159L8.41617 9.64876C8.68576 9.41187 8.98056 9.20894 9.30011 9.05195L9.1197 8.68492ZM12.4666 8.37622C11.7952 8.33895 11.162 8.31784 10.5994 8.35373C10.0385 8.38951 9.53134 8.4828 9.1197 8.68492L9.30011 9.05195C9.64185 8.88418 10.0872 8.79621 10.6255 8.76186C11.1622 8.72761 11.7749 8.74739 12.4439 8.78455L12.4666 8.37622ZM16.2148 9.80687C15.6896 9.39035 14.3735 8.4827 12.4667 8.37622L12.4438 8.78455C14.231 8.88428 15.467 9.73586 15.9605 10.1272L16.2148 9.80687ZM16.3815 10.1525C16.3815 10.0185 16.3211 9.89131 16.2149 9.80692L15.9604 10.1271C15.9679 10.1331 15.9724 10.1419 15.9724 10.1525H16.3815ZM16.3815 11.8124V10.1525H15.9724V11.8124H16.3815ZM15.6504 12.1459C15.9368 12.3945 16.3815 12.1909 16.3815 11.8124H15.9724C15.9724 11.822 15.9699 11.8273 15.9676 11.8307C15.9648 11.8349 15.9601 11.8393 15.9534 11.8423C15.9468 11.8453 15.9404 11.846 15.9355 11.8455C15.9315 11.8449 15.926 11.8434 15.9187 11.8371L15.6504 12.1459ZM14.4928 11.3667C14.9936 11.6215 15.3848 11.916 15.6507 12.1461L15.9185 11.8369C15.6338 11.5905 15.2152 11.2754 14.6783 11.0023L14.4928 11.3667ZM8.41683 6.75194C8.55613 6.62956 8.68852 6.49957 8.81416 6.36354L8.51353 6.08612C8.39694 6.21239 8.27472 6.33236 8.14678 6.44477L8.41683 6.75194ZM9.19814 6.89548C8.91638 6.77157 8.65006 6.61683 8.40369 6.43414L8.15998 6.76257C8.43089 6.96352 8.7237 7.13359 9.03343 7.26982L9.19814 6.89548ZM12.136 7.26031C10.8405 7.26189 9.88163 7.19672 9.19829 6.89553L9.03328 7.26972C9.80676 7.61062 10.8502 7.67084 12.1365 7.66925L12.136 7.26031ZM15.9571 6.18662C15.3346 6.56423 13.9777 7.2577 12.136 7.26031L12.1365 7.66925C14.0813 7.66655 15.5126 6.93458 16.1693 6.53622L15.9571 6.18662ZM15.9724 6.15892C15.9724 6.17047 15.9666 6.18085 15.9568 6.18678L16.1696 6.53607C16.3012 6.45591 16.3815 6.31319 16.3815 6.15892H15.9724ZM15.9724 4.12171V6.15892H16.3815V4.12171H15.9724ZM15.92 4.09528C15.9427 4.07894 15.9724 4.09516 15.9724 4.12171H16.3815C16.3815 3.76028 15.9731 3.55327 15.6811 3.76334L15.92 4.09528ZM14.2317 4.99991C14.9668 4.72302 15.5366 4.37113 15.92 4.09528L15.6811 3.76334C15.3193 4.02358 14.7812 4.35591 14.0874 4.61723L14.2317 4.99991ZM13.2597 5.42798C13.6594 5.30504 13.9946 5.14315 14.2634 4.98473L14.0557 4.63242C13.8099 4.77723 13.5039 4.92497 13.1394 5.03712L13.2597 5.42798ZM11.204 5.58915C11.6356 5.64963 12.3885 5.69589 13.2597 5.42798L13.1395 5.03711C12.3443 5.28157 11.6564 5.23961 11.2608 5.18419L11.204 5.58915ZM8.81416 6.36354C9.44768 5.67713 10.3626 5.38033 11.1828 5.58506L11.2819 5.18828C10.3008 4.94339 9.23685 5.30248 8.51348 6.08617L8.81416 6.36354Z" fill="black"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/tracing/langsmith-icon-big.svg b/app/components/base/icons/assets/public/tracing/langsmith-icon-big.svg
new file mode 100644
index 0000000..95e1ff4
--- /dev/null
+++ b/app/components/base/icons/assets/public/tracing/langsmith-icon-big.svg
@@ -0,0 +1,24 @@
+<svg width="124" height="20" viewBox="0 0 124 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Clip path group">
+<mask id="mask0_20135_18175" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="124" height="20">
+<g id="a">
+<path id="Vector" d="M123.825 0.399902H0.200195V19.5999H123.825V0.399902Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask0_20135_18175)">
+<g id="Group">
+<path id="Vector_2" d="M45.54 4.18408V15.827H53.561V14.069H47.361V4.18408H45.54Z" fill="#1C3C3C"/>
+<path id="Vector_3" d="M57.8358 6.94629C56.0878 6.94629 54.7807 7.76575 54.25 9.19423C54.2162 9.28562 54.1141 9.56133 54.1141 9.56133L55.6124 10.5305L55.8159 9.99986C56.1631 9.09515 56.8051 8.67352 57.8358 8.67352C58.8664 8.67352 59.4563 9.17349 59.4455 10.1581C59.4455 10.198 59.4424 10.3186 59.4424 10.3186C59.4424 10.3186 58.0785 10.5398 57.5163 10.6588C55.1178 11.1657 54.1133 12.0811 54.1133 13.5787C54.1133 14.3767 54.5564 15.2407 55.3651 15.7253C55.8505 16.0156 56.4841 16.1254 57.1837 16.1254C57.6438 16.1254 58.0908 16.0571 58.5047 15.9311C59.4455 15.6185 59.7082 15.0041 59.7082 15.0041V15.8075H61.2664V10.0644C61.2664 8.11211 59.9839 6.94629 57.8358 6.94629ZM59.4517 13.0749C59.4517 13.6786 58.7942 14.5288 57.2629 14.5288C56.8305 14.5288 56.524 14.4143 56.3197 14.2438C56.0463 14.0157 55.9565 13.6878 55.9941 13.3983C56.0102 13.2723 56.0863 13.0012 56.3681 12.7662C56.6561 12.5258 57.1653 12.3538 57.9517 12.1825C58.5984 12.042 59.4524 11.8868 59.4524 11.8868V13.0757L59.4517 13.0749Z" fill="#1C3C3C"/>
+<path id="Vector_4" d="M67.0275 6.94657C66.8109 6.94657 66.5997 6.96193 66.3946 6.99034C64.9992 7.20001 64.5906 7.90887 64.5906 7.90887L64.5921 7.20001H62.8457V15.8093H64.6666V11.0339C64.6666 9.41108 65.8501 8.67226 66.9499 8.67226C68.1388 8.67226 68.7163 9.31124 68.7163 10.6268V15.8093H70.5372V10.3765C70.5372 8.25985 69.1925 6.9458 67.0282 6.9458L67.0275 6.94657Z" fill="#1C3C3C"/>
+<path id="Vector_5" d="M78.1373 7.19359V8.08063C78.1373 8.08063 77.6911 6.94629 75.6611 6.94629C73.139 6.94629 71.5723 8.68658 71.5723 11.489C71.5723 13.0703 72.0776 14.3152 72.9693 15.1017C73.6628 15.713 74.589 16.0264 75.6918 16.0479C76.4591 16.0624 76.9559 15.8536 77.2664 15.6562C77.8623 15.2768 78.0835 14.9166 78.0835 14.9166C78.0835 14.9166 78.0582 15.1984 78.0121 15.5801C77.9791 15.8566 77.9169 16.0509 77.9169 16.0509C77.6396 17.0378 76.8285 17.6084 75.6457 17.6084C74.463 17.6084 73.7465 17.2191 73.6044 16.4518L71.8342 16.9802C72.1398 18.4548 73.5238 19.3349 75.5359 19.3349C76.9037 19.3349 77.976 18.9632 78.7233 18.229C79.4767 17.4886 79.8591 16.4219 79.8591 15.0579V7.19282H78.1373V7.19359ZM78.0229 11.5666C78.0229 13.29 77.1811 14.3191 75.7709 14.3191C74.2603 14.3191 73.394 13.2869 73.394 11.4882C73.394 9.68959 74.2603 8.67275 75.7709 8.67275C77.1473 8.67275 78.0098 9.69726 78.0229 11.3469V11.5666Z" fill="#1C3C3C"/>
+<path id="Vector_6" d="M90.532 14.0495C90.7777 13.6033 90.9022 13.0772 90.9022 12.4851C90.9022 11.893 90.7969 11.4383 90.5888 11.0704C90.3807 10.701 90.1119 10.3992 89.7909 10.1727C89.4675 9.94455 89.1258 9.76484 88.7771 9.63735C88.4269 9.50987 88.1051 9.40695 87.8217 9.33246L85.7427 8.75262C85.4801 8.68273 85.2174 8.59441 84.9609 8.48919C84.7021 8.38321 84.4817 8.23652 84.3073 8.05298C84.1292 7.86635 84.0385 7.62367 84.0385 7.32952C84.0385 7.02079 84.1437 6.74661 84.3503 6.51467C84.5554 6.28504 84.8288 6.10687 85.1637 5.98475C85.4962 5.86264 85.8625 5.80351 86.2527 5.80888C86.6536 5.81963 87.0368 5.90181 87.3909 6.05387C87.7464 6.20594 88.0521 6.43019 88.2994 6.7205C88.5398 7.00312 88.7064 7.34719 88.7955 7.74424L90.8054 7.3948C90.6341 6.70667 90.3423 6.10994 89.9368 5.62149C89.5236 5.12383 89.0029 4.73829 88.3885 4.4764C87.7733 4.21375 87.0629 4.07781 86.2765 4.07243C85.5023 4.06706 84.7858 4.19071 84.1522 4.44031C83.5201 4.68914 83.011 5.06853 82.6385 5.56773C82.2668 6.06616 82.0778 6.69131 82.0778 7.42552C82.0778 7.92779 82.1615 8.35403 82.3274 8.69349C82.4933 9.03371 82.7099 9.31634 82.9702 9.53522C83.2321 9.75487 83.5132 9.92843 83.8066 10.0529C84.1023 10.178 84.3811 10.2794 84.636 10.3531L87.6328 11.2394C87.8493 11.3047 88.0429 11.383 88.208 11.4721C88.3747 11.562 88.5129 11.6633 88.6197 11.7732C88.7272 11.8838 88.8101 12.0113 88.8654 12.1526C88.9207 12.2939 88.9484 12.449 88.9484 12.6134C88.9484 12.9812 88.8301 13.2969 88.5958 13.5496C88.3647 13.7999 88.0598 13.9935 87.6904 14.1232C87.3225 14.253 86.9254 14.3191 86.5092 14.3191C85.8065 14.3191 85.1767 14.1271 84.6383 13.7485C84.1077 13.3752 83.749 12.8422 83.5724 12.1648L81.6309 12.4598C81.7507 13.1909 82.0264 13.8322 82.4503 14.3652C82.8819 14.9081 83.441 15.3313 84.1107 15.6224C84.782 15.9142 85.5484 16.0624 86.3871 16.0624C86.9769 16.0624 87.5491 15.9872 88.089 15.8382C88.6273 15.69 89.1127 15.4642 89.5313 15.167C89.9491 14.8713 90.2855 14.4942 90.5304 14.048L90.532 14.0495Z" fill="#1C3C3C"/>
+<path id="Vector_7" d="M100.071 8.84108C100.322 8.69747 100.611 8.62451 100.928 8.62451C101.441 8.62451 101.855 8.79654 102.156 9.13676C102.457 9.47545 102.61 9.94931 102.61 10.5476V15.7462H104.474V10.0607C104.474 9.14368 104.218 8.39334 103.715 7.83116C103.212 7.27052 102.477 6.9856 101.532 6.9856C100.961 6.9856 100.436 7.11308 99.9714 7.36422C99.536 7.6 99.1789 7.9287 98.9116 8.34035L98.8763 8.39488L98.8455 8.33804C98.6343 7.9479 98.3348 7.62918 97.9547 7.3911C97.5253 7.1223 96.9831 6.9856 96.3442 6.9856C95.7628 6.9856 95.2306 7.11462 94.7636 7.36806C94.405 7.56236 94.0985 7.81657 93.8528 8.12224L93.7844 8.20748V7.2014H92.1455V15.7462H94.0263V10.4762C94.0263 9.93164 94.1799 9.48236 94.4833 9.14137C94.7874 8.79884 95.1968 8.62528 95.7006 8.62528C96.2044 8.62528 96.636 8.79884 96.9378 9.14137C97.2381 9.48236 97.3902 9.9639 97.3902 10.5714V15.7462H99.2464V10.4762C99.2464 10.0937 99.3209 9.75884 99.4684 9.48006C99.6166 9.20051 99.8194 8.98624 100.071 8.84185L100.071 8.84108Z" fill="#1C3C3C"/>
+<path id="Vector_8" d="M110.408 13.5589C110.418 13.9429 110.522 14.3254 110.717 14.694C110.938 15.0972 111.265 15.3967 111.689 15.5834C112.118 15.7707 112.61 15.8729 113.153 15.8859C113.689 15.899 114.243 15.8537 114.801 15.7515V14.201C114.276 14.2762 113.8 14.2962 113.387 14.2593C112.951 14.2209 112.63 14.0328 112.431 13.701C112.325 13.5305 112.269 13.307 112.26 13.0382C112.252 12.7748 112.248 12.466 112.248 12.1189V8.56844H114.801V7.12307H112.248V4.19775H110.392V7.12307H108.812V8.56844H110.392V12.2318C110.392 12.7249 110.397 13.1718 110.408 13.5597V13.5589Z" fill="#1C3C3C"/>
+<path id="Vector_9" d="M120.316 6.93339C120.116 6.93339 119.922 6.94645 119.733 6.97103C118.359 7.1853 117.955 7.88495 117.955 7.88495V7.67989H117.955V4.1709H116.134V15.7977H117.955V11.0222C117.955 9.38869 119.138 8.64527 120.238 8.64527C121.427 8.64527 122.004 9.28424 122.004 10.5998V15.7977H123.825V10.3495C123.825 8.27509 122.448 6.93416 120.316 6.93416L120.316 6.93339Z" fill="#1C3C3C"/>
+<path id="Vector_10" d="M107.589 7.19922H105.777V15.8162H107.589V7.19922Z" fill="#1C3C3C"/>
+<path id="Vector_11" d="M106.682 6.55761C107.334 6.55761 107.863 6.02913 107.863 5.37719C107.863 4.72527 107.334 4.19678 106.682 4.19678C106.03 4.19678 105.502 4.72527 105.502 5.37719C105.502 6.02913 106.03 6.55761 106.682 6.55761Z" fill="#1C3C3C"/>
+<path id="Vector_12" d="M22.3912 15.1309C22.286 15.306 21.9696 15.3175 21.7 15.1555C21.5618 15.0725 21.455 14.9581 21.3997 14.8337C21.349 14.7208 21.3483 14.614 21.3966 14.5334C21.4519 14.4412 21.5664 14.3944 21.7015 14.3944C21.8229 14.3944 21.9611 14.432 22.0886 14.5088C22.3582 14.6709 22.4972 14.9558 22.392 15.1309H22.3912ZM37.9908 9.9999C37.9908 15.293 33.6839 19.5999 28.3908 19.5999H9.81289C4.51983 19.5999 0.212891 15.2937 0.212891 9.9999C0.212891 4.70608 4.51983 0.399902 9.81289 0.399902H28.3908C33.6846 0.399902 37.9908 4.70685 37.9908 9.9999ZM18.714 14.8145C18.8653 14.6309 18.1664 14.1141 18.0236 13.9244C17.7333 13.6095 17.7317 13.1564 17.5359 12.7885C17.0567 11.678 16.506 10.5759 15.7357 9.63587C14.9216 8.60752 13.9171 7.75657 13.0347 6.7912C12.3795 6.11766 12.2044 5.15843 11.6261 4.43421C10.829 3.25686 8.30838 2.93584 7.93897 4.59856C7.94051 4.65078 7.92438 4.68381 7.87906 4.71683C7.67477 4.86505 7.49276 5.03478 7.33992 5.23984C6.96591 5.76054 6.90831 6.64374 7.37525 7.11145C7.39061 6.86493 7.39906 6.63222 7.59413 6.45558C7.9551 6.76585 8.50037 6.87491 8.91893 6.64374C9.8436 7.96393 9.6132 9.79024 10.3474 11.2126C10.5502 11.549 10.7545 11.8923 11.0148 12.1872C11.226 12.5159 11.9556 12.9037 11.9986 13.2078C12.0063 13.7301 11.9449 14.3007 12.2874 14.7377C12.4487 15.0649 12.0524 15.3936 11.7329 15.3529C11.3182 15.4097 10.8121 15.0741 10.4488 15.2807C10.3205 15.4197 10.0694 15.2661 9.9588 15.4588C9.9204 15.5587 9.71304 15.6992 9.83669 15.7952C9.97416 15.6908 10.1017 15.5817 10.2867 15.6439C10.2591 15.7945 10.3781 15.816 10.4726 15.8597C10.4695 15.9619 10.4096 16.0663 10.488 16.1531C10.5793 16.061 10.6339 15.9304 10.779 15.892C11.2613 16.5348 11.7521 15.2415 12.7958 15.8236C12.5838 15.8137 12.3957 15.8398 12.2528 16.0141C12.2175 16.0533 12.1875 16.0994 12.2497 16.15C12.8127 15.7868 12.8096 16.2745 13.1752 16.1247C13.4563 15.978 13.7358 15.7945 14.0699 15.8467C13.745 15.9404 13.732 16.2015 13.5415 16.4219C13.5093 16.4557 13.4939 16.4941 13.5315 16.5502C14.2058 16.4933 14.2611 16.2691 14.8057 15.9941C15.2119 15.7461 15.6167 16.3474 15.9684 16.0049C16.046 15.9304 16.152 15.9557 16.248 15.9458C16.1251 15.2907 14.7742 16.0656 14.7957 15.187C15.2304 14.8913 15.1305 14.3253 15.1597 13.8683C15.6597 14.1456 16.2157 14.3068 16.7057 14.5718C16.953 14.9712 17.3408 15.4988 17.8577 15.4642C17.8715 15.4243 17.8838 15.389 17.8984 15.3483C18.0551 15.3751 18.2563 15.4788 18.3423 15.2807C18.5765 15.5257 18.9206 15.5134 19.227 15.4504C19.4536 15.2661 18.8008 15.0034 18.7132 14.8137L18.714 14.8145ZM25.722 11.7187L24.6944 10.3317C23.7974 11.3577 23.1984 11.8577 23.1876 11.8669C23.1822 11.8723 22.6101 12.4291 22.0886 12.9068C21.5771 13.3753 21.1731 13.7462 20.9673 14.1517C20.9105 14.2638 20.7868 14.677 20.9604 15.0902C21.094 15.4097 21.3667 15.637 21.7714 15.766C21.8928 15.8044 22.0087 15.8213 22.1193 15.8213C22.8482 15.8213 23.3266 15.0902 23.3297 15.0841C23.3358 15.0756 23.9556 14.1901 24.7106 13.0719C24.9617 12.7002 25.2489 12.307 25.722 11.7179V11.7187ZM30.5535 14.9128C30.5535 14.7085 30.479 14.5111 30.3438 14.3583L30.2163 14.2139C29.446 13.3407 27.4684 11.0989 26.6989 10.228C25.7328 9.13437 24.6522 7.74045 24.5623 7.62371L24.4325 7.35491V6.88182C24.4325 6.70825 24.398 6.53853 24.3312 6.37878L24.0562 5.72598C24.0524 5.71677 24.0508 5.70601 24.0524 5.69603L24.0631 5.60541C24.0647 5.59081 24.0716 5.57776 24.0831 5.56777C24.2974 5.37885 25.0946 4.76598 26.3287 4.81744C26.49 4.82435 26.5184 4.73603 26.523 4.6984C26.5453 4.51715 26.1314 4.30365 25.7458 4.22454C25.2159 4.11625 23.8074 3.82902 22.6807 4.56861L22.6723 4.57475C21.9442 5.18301 21.359 5.64765 21.3529 5.65225L21.3398 5.66531C21.3314 5.67529 21.1255 5.92182 21.1755 6.23593C21.2077 6.44022 21.1017 6.51318 21.0956 6.51702C21.0894 6.52086 20.9451 6.61149 20.7961 6.50934C20.6156 6.37417 20.3022 6.60611 20.2385 6.6568L19.7654 7.06384L19.7562 7.07305C19.7477 7.08304 19.545 7.32035 19.8161 7.70128C20.0503 8.03075 20.1333 8.14057 20.3368 8.39401C20.5434 8.65053 20.9159 8.97539 20.9358 8.99229C20.9451 8.99997 21.1724 9.172 21.4857 8.93238C21.743 8.73501 21.9496 8.55683 21.9496 8.55683C21.9665 8.54301 22.1155 8.42013 22.1224 8.23888C22.1247 8.18665 22.1224 8.14134 22.1224 8.09987C22.1186 7.97238 22.1178 7.93475 22.2138 7.87331C22.2599 7.87331 22.4012 7.92477 22.5225 7.98621C22.5356 7.99389 22.8389 8.16438 23.1147 8.15209C23.2882 8.17513 23.4802 8.37251 23.5463 8.45315C23.5524 8.45929 24.1392 9.07523 24.9655 10.1558C25.123 10.3609 25.7013 11.1312 25.8595 11.3462C26.1237 11.7056 26.5238 12.2494 26.9539 12.8354C27.6988 13.8499 28.5344 14.9873 28.9138 15.4988C29.0398 15.6685 29.2233 15.7837 29.4307 15.8236L29.5712 15.8505C29.625 15.8605 29.6787 15.8659 29.7325 15.8659C29.9813 15.8659 30.2171 15.7568 30.373 15.5633L30.3815 15.5525C30.4936 15.4105 30.555 15.2284 30.555 15.0411V14.9128H30.5535ZM31.2147 5.80355L31.0512 5.63997C31.0035 5.59235 30.9367 5.56393 30.8691 5.56931C30.8016 5.57238 30.7378 5.6031 30.694 5.65533L29.6649 6.87261C29.6357 6.90717 29.5943 6.92867 29.5497 6.93328L29.1834 6.97014C29.1365 6.97475 29.0897 6.96016 29.0536 6.93021L28.4684 6.43485C28.4307 6.40259 28.4085 6.35651 28.4069 6.30736L28.3985 6.01398C28.397 5.97174 28.4115 5.93027 28.4384 5.89801L29.4391 4.69225C29.5144 4.60163 29.5136 4.4703 29.4376 4.37968L29.337 4.26064C29.2709 4.18307 29.1619 4.15465 29.0667 4.19075C28.8301 4.28061 28.2341 4.51331 27.8033 4.74678C27.1943 5.07549 26.7711 5.59696 26.6981 6.10768C26.6444 6.48169 26.6666 7.0984 26.6851 7.43248C26.692 7.56381 26.6628 7.69513 26.5991 7.81264C26.5207 7.95856 26.3825 8.19203 26.1721 8.47312C26.0645 8.62134 25.997 8.67587 25.904 8.78569L27.0361 10.1166C27.3087 9.79869 27.5475 9.55753 27.7557 9.32483C28.1358 8.90166 28.2541 8.89782 28.5705 8.88707C28.7656 8.88016 29.0329 8.87171 29.456 8.76573C30.6111 8.47696 30.9767 7.22665 30.992 7.17136L31.2793 6.03549C31.3 5.95331 31.2754 5.86422 31.2155 5.80432L31.2147 5.80355ZM13.4524 13.7324C13.328 14.2178 13.2873 15.0449 12.656 15.0687C12.6038 15.349 12.8503 15.4542 13.0738 15.3644C13.2958 15.2622 13.401 15.445 13.4755 15.627C13.818 15.677 14.3249 15.5126 14.3441 15.1071C13.8326 14.8122 13.6744 14.2516 13.4517 13.7324H13.4524Z" fill="#1C3C3C"/>
+</g>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/tracing/langsmith-icon.svg b/app/components/base/icons/assets/public/tracing/langsmith-icon.svg
new file mode 100644
index 0000000..8efa791
--- /dev/null
+++ b/app/components/base/icons/assets/public/tracing/langsmith-icon.svg
@@ -0,0 +1,24 @@
+<svg width="84" height="14" viewBox="0 0 84 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Clip path group">
+<mask id="mask0_20135_16592" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="84" height="14">
+<g id="a">
+<path id="Vector" d="M83.2164 0.600098H0.799805V13.4001H83.2164V0.600098Z" fill="white"/>
+</g>
+</mask>
+<g mask="url(#mask0_20135_16592)">
+<g id="Group">
+<path id="Vector_2" d="M31.0264 3.12256V10.8845H36.3737V9.71251H32.2403V3.12256H31.0264Z" fill="#1C3C3C"/>
+<path id="Vector_3" d="M39.2238 4.96436C38.0585 4.96436 37.1871 5.51066 36.8333 6.46298C36.8108 6.52391 36.7427 6.70772 36.7427 6.70772L37.7416 7.35386L37.8773 7.00007C38.1087 6.39693 38.5367 6.11584 39.2238 6.11584C39.911 6.11584 40.3042 6.44916 40.297 7.10554C40.297 7.13216 40.295 7.21255 40.295 7.21255C40.295 7.21255 39.3856 7.36 39.0109 7.43936C37.4119 7.77728 36.7422 8.38759 36.7422 9.38599C36.7422 9.91796 37.0376 10.494 37.5767 10.817C37.9003 11.0106 38.3227 11.0838 38.7892 11.0838C39.0959 11.0838 39.3938 11.0382 39.6698 10.9542C40.297 10.7459 40.4721 10.3363 40.4721 10.3363V10.8718H41.511V7.04308C41.511 5.74157 40.6559 4.96436 39.2238 4.96436ZM40.3011 9.05012C40.3011 9.45255 39.8628 10.0193 38.8419 10.0193C38.5536 10.0193 38.3494 9.94304 38.2132 9.82938C38.0309 9.67732 37.971 9.45869 37.9961 9.26567C38.0068 9.1817 38.0575 9.00096 38.2454 8.84429C38.4374 8.68404 38.7769 8.56935 39.3012 8.45517C39.7323 8.36148 40.3016 8.25805 40.3016 8.25805V9.05063L40.3011 9.05012Z" fill="#1C3C3C"/>
+<path id="Vector_4" d="M45.3523 4.96438C45.2079 4.96438 45.0671 4.97462 44.9304 4.99356C44.0001 5.13334 43.7277 5.60591 43.7277 5.60591L43.7287 5.13334H42.5645V10.8729H43.7784V7.68924C43.7784 6.60739 44.5674 6.11484 45.3006 6.11484C46.0932 6.11484 46.4782 6.54083 46.4782 7.41788V10.8729H47.6921V7.25097C47.6921 5.8399 46.7956 4.96387 45.3528 4.96387L45.3523 4.96438Z" fill="#1C3C3C"/>
+<path id="Vector_5" d="M52.7575 5.12922V5.72058C52.7575 5.72058 52.4601 4.96436 51.1067 4.96436C49.4253 4.96436 48.3809 6.12455 48.3809 7.99284C48.3809 9.04704 48.7178 9.877 49.3122 10.4013C49.7745 10.8088 50.392 11.0177 51.1272 11.0321C51.6387 11.0418 51.97 10.9025 52.1769 10.7709C52.5742 10.518 52.7217 10.2779 52.7217 10.2779C52.7217 10.2779 52.7048 10.4658 52.6741 10.7203C52.6521 10.9046 52.6106 11.0341 52.6106 11.0341C52.4258 11.692 51.885 12.0725 51.0965 12.0725C50.308 12.0725 49.8303 11.8129 49.7356 11.3014L48.5555 11.6536C48.7592 12.6367 49.6819 13.2234 51.0233 13.2234C51.9352 13.2234 52.65 12.9756 53.1482 12.4861C53.6505 11.9926 53.9054 11.2814 53.9054 10.3721V5.12871H52.7575V5.12922ZM52.6813 8.04455C52.6813 9.19348 52.1201 9.87956 51.18 9.87956C50.1729 9.87956 49.5953 9.19143 49.5953 7.99232C49.5953 6.79322 50.1729 6.11533 51.18 6.11533C52.0976 6.11533 52.6725 6.79834 52.6813 7.89812V8.04455Z" fill="#1C3C3C"/>
+<path id="Vector_6" d="M61.022 9.69984C61.1858 9.40237 61.2688 9.05165 61.2688 8.65689C61.2688 8.26214 61.1986 7.95904 61.0599 7.71379C60.9211 7.46752 60.7419 7.2663 60.5279 7.11526C60.3123 6.9632 60.0845 6.84339 59.852 6.7584C59.6186 6.67341 59.404 6.6048 59.2151 6.55513L57.8291 6.16857C57.654 6.12198 57.4789 6.0631 57.3079 5.99296C57.1354 5.9223 56.9884 5.82451 56.8722 5.70215C56.7534 5.57773 56.693 5.41594 56.693 5.21984C56.693 5.01402 56.7632 4.83124 56.9009 4.67661C57.0376 4.52352 57.2199 4.40474 57.4431 4.32333C57.6648 4.24192 57.909 4.2025 58.1691 4.20608C58.4364 4.21325 58.6919 4.26804 58.9279 4.36941C59.1649 4.47079 59.3687 4.62029 59.5336 4.81383C59.6938 5.00224 59.8049 5.23162 59.8643 5.49632L61.2042 5.26336C61.0901 4.80461 60.8955 4.40679 60.6252 4.08116C60.3497 3.74938 60.0026 3.49236 59.593 3.31776C59.1829 3.14266 58.7093 3.05204 58.185 3.04845C57.6689 3.04487 57.1912 3.1273 56.7688 3.2937C56.3474 3.45959 56.008 3.71252 55.7596 4.04532C55.5118 4.3776 55.3859 4.79437 55.3859 5.28384C55.3859 5.61869 55.4417 5.90285 55.5523 6.12916C55.6629 6.35597 55.8072 6.54439 55.9808 6.69031C56.1554 6.83674 56.3428 6.95245 56.5384 7.0354C56.7355 7.11885 56.9214 7.18644 57.0913 7.23559L59.0892 7.82644C59.2335 7.86996 59.3626 7.92218 59.4727 7.98157C59.5838 8.04148 59.6759 8.10906 59.7471 8.18228C59.8188 8.256 59.8741 8.341 59.9109 8.4352C59.9478 8.52941 59.9662 8.63284 59.9662 8.7424C59.9662 8.98765 59.8874 9.19808 59.7312 9.36653C59.5771 9.53344 59.3738 9.66247 59.1276 9.749C58.8823 9.83552 58.6176 9.87956 58.3401 9.87956C57.8716 9.87956 57.4518 9.75156 57.0929 9.49914C56.7391 9.25031 56.5 8.89498 56.3822 8.4434L55.0879 8.64C55.1678 9.12743 55.3516 9.55495 55.6342 9.91028C55.9219 10.2723 56.2947 10.5544 56.7411 10.7484C57.1886 10.943 57.6996 11.0418 58.2587 11.0418C58.6519 11.0418 59.0334 10.9916 59.3933 10.8923C59.7522 10.7935 60.0758 10.6429 60.3548 10.4448C60.6334 10.2477 60.8576 9.99629 61.0209 9.69882L61.022 9.69984Z" fill="#1C3C3C"/>
+<path id="Vector_7" d="M67.38 6.22747C67.5479 6.13173 67.7405 6.08309 67.9514 6.08309C68.2939 6.08309 68.5699 6.19777 68.7706 6.42459C68.9708 6.65038 69.0727 6.96629 69.0727 7.36513V10.8309H70.3158V7.04053C70.3158 6.4292 70.1453 5.92897 69.8094 5.55419C69.4741 5.18043 68.9846 4.99048 68.3543 4.99048C67.9734 4.99048 67.6237 5.07547 67.314 5.24289C67.0237 5.40008 66.7856 5.61921 66.6074 5.89365L66.5838 5.93L66.5634 5.89211C66.4226 5.63201 66.2229 5.41953 65.9694 5.26081C65.6832 5.08161 65.3218 4.99048 64.8958 4.99048C64.5082 4.99048 64.1534 5.07649 63.8421 5.24545C63.603 5.37499 63.3987 5.54446 63.2349 5.74824L63.1893 5.80507V5.13435H62.0967V10.8309H63.3506V7.31752C63.3506 6.95451 63.453 6.65499 63.6552 6.42766C63.858 6.19931 64.1309 6.0836 64.4667 6.0836C64.8026 6.0836 65.0903 6.19931 65.2916 6.42766C65.4918 6.65499 65.5931 6.97601 65.5931 7.38101V10.8309H66.8306V7.31752C66.8306 7.06254 66.8803 6.83931 66.9786 6.65345C67.0774 6.46709 67.2126 6.32424 67.3805 6.22798L67.38 6.22747Z" fill="#1C3C3C"/>
+<path id="Vector_8" d="M74.2724 9.3726C74.2796 9.6286 74.3487 9.88358 74.4787 10.1293C74.6257 10.3981 74.8438 10.5978 75.1269 10.7222C75.4126 10.8472 75.7408 10.9153 76.1028 10.924C76.4597 10.9327 76.8293 10.9025 77.2016 10.8344V9.80064C76.8514 9.85081 76.5339 9.86412 76.2585 9.83955C75.9682 9.81395 75.7541 9.68851 75.621 9.46732C75.5509 9.35366 75.513 9.20467 75.5074 9.02547C75.5022 8.84985 75.4992 8.64403 75.4992 8.4126V6.04563H77.2016V5.08204H75.4992V3.13184H74.2617V5.08204H73.209V6.04563H74.2617V8.48787C74.2617 8.81657 74.2652 9.11456 74.2724 9.37312V9.3726Z" fill="#1C3C3C"/>
+<path id="Vector_9" d="M80.8767 4.95543C80.7436 4.95543 80.6141 4.96414 80.4881 4.98052C79.5726 5.12337 79.3033 5.5898 79.3033 5.5898V5.4531H79.3028V3.11377H78.0889V10.8649H79.3028V7.68132C79.3028 6.5923 80.0918 6.09668 80.825 6.09668C81.6176 6.09668 82.0026 6.52267 82.0026 7.39972V10.8649H83.2165V7.23281C83.2165 5.8499 82.298 4.95595 80.8772 4.95595L80.8767 4.95543Z" fill="#1C3C3C"/>
+<path id="Vector_10" d="M72.3934 5.13281H71.1855V10.8775H72.3934V5.13281Z" fill="#1C3C3C"/>
+<path id="Vector_11" d="M71.7889 4.70524C72.2236 4.70524 72.5758 4.35291 72.5758 3.91829C72.5758 3.48368 72.2236 3.13135 71.7889 3.13135C71.3542 3.13135 71.002 3.48368 71.002 3.91829C71.002 4.35291 71.3542 4.70524 71.7889 4.70524Z" fill="#1C3C3C"/>
+<path id="Vector_12" d="M15.5941 10.4208C15.524 10.5375 15.313 10.5452 15.1333 10.4372C15.0412 10.3819 14.97 10.3056 14.9331 10.2226C14.8993 10.1474 14.8988 10.0762 14.9311 10.0224C14.968 9.96099 15.0442 9.92976 15.1344 9.92976C15.2152 9.92976 15.3074 9.95485 15.3924 10.0061C15.5721 10.1141 15.6648 10.304 15.5946 10.4208H15.5941ZM25.9939 7.0001C25.9939 10.5288 23.1226 13.4001 19.5939 13.4001H7.20859C3.67989 13.4001 0.808594 10.5293 0.808594 7.0001C0.808594 3.47088 3.67989 0.600098 7.20859 0.600098H19.5939C23.1231 0.600098 25.9939 3.47139 25.9939 7.0001ZM13.1427 10.2098C13.2435 10.0875 12.7776 9.74288 12.6824 9.61642C12.4888 9.4065 12.4878 9.10442 12.3573 8.85917C12.0378 8.11882 11.6707 7.3841 11.1571 6.75741C10.6144 6.07184 9.94472 5.50455 9.35643 4.86096C8.9197 4.41194 8.80296 3.77245 8.41743 3.28963C7.88597 2.50474 6.20559 2.29072 5.95931 3.3992C5.96034 3.43402 5.94959 3.45603 5.91937 3.47805C5.78318 3.57687 5.66184 3.69002 5.55995 3.82672C5.3106 4.17386 5.2722 4.76266 5.5835 5.07447C5.59374 4.91011 5.59937 4.75498 5.72942 4.63722C5.97007 4.84407 6.33358 4.91677 6.61262 4.76266C7.22907 5.64279 7.07547 6.86032 7.56494 7.80855C7.70011 8.0328 7.8363 8.26167 8.00987 8.45827C8.15067 8.67741 8.63707 8.93597 8.66574 9.13872C8.67086 9.48688 8.6299 9.8673 8.85825 10.1586C8.96577 10.3767 8.70158 10.5959 8.48859 10.5687C8.21211 10.6066 7.8747 10.3829 7.63252 10.5206C7.54702 10.6133 7.3796 10.5109 7.30587 10.6394C7.28027 10.706 7.14203 10.7997 7.22446 10.8637C7.31611 10.794 7.4011 10.7213 7.52449 10.7628C7.50606 10.8631 7.58542 10.8775 7.6484 10.9067C7.64635 10.9748 7.60641 11.0444 7.65864 11.1022C7.71956 11.0408 7.75592 10.9538 7.85268 10.9282C8.17422 11.3567 8.50139 10.4945 9.1972 10.8826C9.05588 10.8759 8.93044 10.8933 8.83521 11.0096C8.81166 11.0357 8.79169 11.0664 8.83316 11.1002C9.20846 10.858 9.20641 11.1831 9.45012 11.0833C9.63752 10.9855 9.82388 10.8631 10.0466 10.898C9.83003 10.9604 9.82132 11.1345 9.69435 11.2814C9.67284 11.304 9.6626 11.3296 9.68769 11.3669C10.1372 11.3291 10.1741 11.1796 10.5371 10.9963C10.8079 10.8309 11.0778 11.2318 11.3123 11.0034C11.364 10.9538 11.4346 10.9707 11.4986 10.964C11.4167 10.5273 10.5161 11.0439 10.5304 10.4581C10.8202 10.261 10.7537 9.88368 10.7731 9.57904C11.1064 9.76387 11.4771 9.87139 11.8038 10.048C11.9687 10.3143 12.2272 10.666 12.5718 10.643C12.581 10.6164 12.5892 10.5928 12.5989 10.5657C12.7034 10.5836 12.8375 10.6527 12.8949 10.5206C13.051 10.6839 13.2804 10.6757 13.4847 10.6338C13.6357 10.5109 13.2005 10.3358 13.1422 10.2093L13.1427 10.2098ZM17.8147 8.14595L17.1296 7.22128C16.5316 7.90531 16.1322 8.23863 16.1251 8.24477C16.1215 8.24835 15.74 8.61955 15.3924 8.93802C15.0514 9.25034 14.7821 9.49763 14.6449 9.76797C14.607 9.84272 14.5246 10.1182 14.6403 10.3936C14.7294 10.6066 14.9111 10.7582 15.1809 10.8442C15.2618 10.8698 15.3392 10.8811 15.4129 10.8811C15.8988 10.8811 16.2177 10.3936 16.2198 10.3895C16.2239 10.3839 16.6371 9.79357 17.1404 9.0481C17.3078 8.80029 17.4993 8.53815 17.8147 8.14544V8.14595ZM21.0357 10.2754C21.0357 10.1392 20.986 10.0076 20.8959 9.9057L20.8109 9.80944C20.2974 9.2273 18.979 7.73277 18.4659 7.15216C17.8218 6.42307 17.1015 5.49379 17.0416 5.41597L16.955 5.23677V4.92138C16.955 4.80567 16.932 4.69251 16.8874 4.58602L16.7041 4.15082C16.7016 4.14467 16.7006 4.13751 16.7016 4.13085L16.7088 4.07043C16.7098 4.06071 16.7144 4.052 16.7221 4.04535C16.8649 3.91939 17.3964 3.51082 18.2192 3.54512C18.3267 3.54973 18.3456 3.49085 18.3487 3.46576C18.3635 3.34493 18.0876 3.20259 17.8305 3.14986C17.4773 3.07767 16.5383 2.88618 15.7872 3.37923L15.7815 3.38333C15.2961 3.78883 14.906 4.09859 14.9019 4.10167L14.8932 4.11037C14.8876 4.11703 14.7504 4.28138 14.7836 4.49079C14.8051 4.62698 14.7345 4.67562 14.7304 4.67818C14.7263 4.68074 14.63 4.74115 14.5307 4.67306C14.4104 4.58295 14.2015 4.73757 14.159 4.77136L13.8436 5.04272L13.8375 5.04887C13.8318 5.05552 13.6967 5.21373 13.8774 5.46768C14.0336 5.68733 14.0888 5.76055 14.2245 5.92951C14.3623 6.10051 14.6106 6.31709 14.6239 6.32835C14.63 6.33347 14.7816 6.44816 14.9905 6.28842C15.162 6.15683 15.2997 6.03805 15.2997 6.03805C15.311 6.02883 15.4103 5.94691 15.4149 5.82608C15.4165 5.79127 15.4149 5.76106 15.4149 5.73341C15.4124 5.64842 15.4119 5.62333 15.4759 5.58237C15.5066 5.58237 15.6008 5.61667 15.6817 5.65763C15.6904 5.66275 15.8926 5.77642 16.0764 5.76823C16.1921 5.78359 16.3201 5.91517 16.3642 5.96893C16.3683 5.97303 16.7594 6.38365 17.3104 7.10403C17.4153 7.24074 17.8008 7.75427 17.9063 7.89763C18.0824 8.13725 18.3492 8.49975 18.6359 8.8904C19.1326 9.56675 19.6896 10.325 19.9425 10.666C20.0265 10.7792 20.1489 10.856 20.2871 10.8826L20.3808 10.9005C20.4167 10.9072 20.4525 10.9108 20.4883 10.9108C20.6542 10.9108 20.8114 10.8381 20.9153 10.709L20.921 10.7019C20.9957 10.6071 21.0367 10.4858 21.0367 10.3609V10.2754H21.0357ZM21.4765 4.20253L21.3674 4.09347C21.3357 4.06173 21.2912 4.04279 21.2461 4.04637C21.201 4.04842 21.1585 4.0689 21.1294 4.10371L20.4433 4.91523C20.4238 4.93827 20.3962 4.95261 20.3665 4.95568L20.1223 4.98026C20.091 4.98333 20.0598 4.9736 20.0357 4.95363L19.6456 4.62339C19.6205 4.60189 19.6056 4.57117 19.6046 4.5384L19.599 4.34282C19.598 4.31466 19.6077 4.28701 19.6256 4.26551L20.2928 3.46167C20.3429 3.40125 20.3424 3.3137 20.2917 3.25328L20.2247 3.17392C20.1806 3.12221 20.1079 3.10327 20.0444 3.12733C19.8867 3.18723 19.4894 3.34237 19.2022 3.49802C18.7962 3.71715 18.5141 4.0648 18.4654 4.40528C18.4296 4.65463 18.4444 5.06576 18.4567 5.28848C18.4613 5.37603 18.4419 5.46359 18.3994 5.54192C18.3472 5.6392 18.255 5.79485 18.1147 5.98224C18.043 6.08106 17.998 6.11741 17.936 6.19063L18.6907 7.07792C18.8725 6.86595 19.0317 6.70519 19.1704 6.55005C19.4239 6.26794 19.5027 6.26538 19.7137 6.25821C19.8437 6.2536 20.0219 6.24797 20.304 6.17731C21.0741 5.9848 21.3178 5.15127 21.328 5.1144L21.5195 4.35715C21.5333 4.30237 21.5169 4.24298 21.477 4.20304L21.4765 4.20253ZM9.63496 9.48842C9.55202 9.812 9.52488 10.3634 9.10402 10.3793C9.0692 10.5662 9.23355 10.6363 9.38255 10.5764C9.53051 10.5083 9.60066 10.6302 9.65032 10.7515C9.87867 10.7848 10.2166 10.6752 10.2294 10.4049C9.8884 10.2083 9.78293 9.83453 9.63445 9.48842H9.63496Z" fill="#1C3C3C"/>
+</g>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/tracing/opik-icon-big.svg b/app/components/base/icons/assets/public/tracing/opik-icon-big.svg
new file mode 100644
index 0000000..99aa2da
--- /dev/null
+++ b/app/components/base/icons/assets/public/tracing/opik-icon-big.svg
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="70.700851"
+ height="24"
+ viewBox="0 0 70.700851 24"
+ fill="none"
+ version="1.1"
+ id="svg6"
+ sodipodi:docname="opik-icon-big.svg"
+ inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview6"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="18.615088"
+ inkscape:cx="36.314629"
+ inkscape:cy="18.989972"
+ inkscape:window-width="2560"
+ inkscape:window-height="1371"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg6" />
+ <rect
+ width="70.700851"
+ height="24"
+ fill="#ffffff"
+ id="rect1"
+ x="0"
+ y="0"
+ style="stroke-width:0.0683761;fill:none" />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M 14.463316,5.8949744 C 11.191179,4.456547 7.3065299,5.9932444 5.8118769,9.3932308 4.3172308,12.793231 5.8113846,16.694496 9.0834872,18.132923 c 1.3197948,0.580171 2.7316238,0.676855 4.0492308,0.364923 0.567179,-0.13429 1.135863,0.216684 1.270085,0.783863 0.134291,0.56718 -0.216615,1.135864 -0.783863,1.270154 C 11.873983,20.964923 9.9916581,20.83788 8.2340513,20.065231 3.8540444,18.139761 1.9338872,12.969778 3.8795692,8.5437949 5.8252581,4.1177778 10.932786,2.0372103 15.312752,3.9626667 c 2.672342,1.1747624 4.432069,3.564376 4.952137,6.2470423 0.110974,0.57224 -0.262974,1.126017 -0.835214,1.236992 -0.572171,0.110906 -1.126017,-0.263043 -1.236923,-0.835282 C 17.796308,8.5668376 16.46359,6.7742906 14.463316,5.8949744 Z M 18.01388,17.557812 c 0.20424,0.856752 -0.324786,1.716786 -1.181538,1.921026 -0.856752,0.204171 -1.716855,-0.324787 -1.921026,-1.181539 -0.204239,-0.856752 0.324787,-1.716855 1.181539,-1.921025 0.856752,-0.20424 1.716854,0.324786 1.921025,1.181538 z m 1.329368,-1.216547 c 1.144615,-0.272821 1.85135,-1.42188 1.57853,-2.566427 -0.272821,-1.144616 -1.421881,-1.851351 -2.566428,-1.57853 -1.144615,0.27282 -1.85135,1.421812 -1.578529,2.566427 0.27282,1.144615 1.42188,1.85135 2.566427,1.57853 z"
+ fill="url(#paint0_linear_3874_31725)"
+ id="path1"
+ style="fill:url(#paint0_linear_3874_31725);stroke-width:0.0683761" />
+ <path
+ d="m 31.039658,17.805538 c -1.082803,0 -2.046769,-0.231042 -2.891897,-0.693196 -0.84506,-0.475419 -1.511932,-1.122462 -2.000479,-1.941128 -0.488615,-0.818667 -0.732855,-1.749607 -0.732855,-2.792821 0,-1.056342 0.24424,-1.987282 0.732855,-2.7928204 0.488547,-0.8186666 1.155419,-1.4590769 2.000479,-1.9212991 0.845128,-0.4621538 1.809094,-0.6931966 2.891897,-0.6931966 1.096,0 2.06653,0.2310428 2.911658,0.6931966 0.858257,0.4622222 1.525128,1.096 2.000479,1.9015385 0.488615,0.80547 0.732855,1.742974 0.732855,2.812581 0,1.043214 -0.24424,1.974154 -0.732855,2.792821 -0.475351,0.818666 -1.142222,1.465709 -2.000479,1.941128 -0.845128,0.462154 -1.815658,0.693196 -2.911658,0.693196 z m 0,-2.119316 c 0.607385,0 1.148786,-0.132102 1.624137,-0.396171 0.475419,-0.264068 0.845128,-0.647042 1.109196,-1.148786 0.277334,-0.501812 0.416,-1.089436 0.416,-1.762872 0,-0.686632 -0.138666,-1.274256 -0.416,-1.762803 -0.264068,-0.501812 -0.633777,-0.8847182 -1.109196,-1.148855 -0.475351,-0.2640683 -1.01012,-0.3961025 -1.604376,-0.3961025 -0.607385,0 -1.148787,0.1320342 -1.624137,0.3961025 -0.462222,0.2641368 -0.831932,0.647043 -1.109265,1.148855 -0.277265,0.488547 -0.415932,1.076171 -0.415932,1.762803 0,0.673436 0.138667,1.26106 0.415932,1.762872 0.277333,0.501744 0.647043,0.884718 1.109265,1.148786 0.47535,0.264069 1.01012,0.396171 1.604376,0.396171 z"
+ fill="#3a3a3a"
+ id="path2"
+ style="stroke-width:0.0683761" />
+ <path
+ d="m 44.915145,17.805538 c -0.858256,0 -1.643966,-0.198017 -2.35706,-0.594188 -0.699829,-0.396171 -1.261059,-0.990359 -1.683555,-1.782632 -0.409368,-0.805539 -0.614017,-1.822291 -0.614017,-3.050325 0,-1.241231 0.198017,-2.257983 0.594188,-3.0503246 0.409367,-0.7922735 0.963966,-1.3798975 1.663795,-1.7628034 0.699829,-0.396171 1.498735,-0.5941881 2.396649,-0.5941881 1.043214,0 1.960958,0.2244787 2.753231,0.6734359 0.80547,0.4489573 1.439316,1.076171 1.90147,1.881641 0.475351,0.8055382 0.713026,1.7562392 0.713026,2.8522392 0,1.096 -0.237675,2.053333 -0.713026,2.872069 -0.462154,0.80547 -1.096,1.432683 -1.90147,1.881641 -0.792273,0.448957 -1.710017,0.673435 -2.753231,0.673435 z m -4.714598,3.703932 c -0.634188,0 -1.148308,-0.514051 -1.148308,-1.148239 V 8.2381538 c 0,-0.634188 0.51412,-1.1482393 1.148308,-1.1482393 h 0.06044 c 0.634188,0 1.148308,0.5140513 1.148308,1.1482393 v 1.3474188 l -0.07925,2.8126494 0.198086,2.812581 v 5.150428 c 0,0.634188 -0.51412,1.148239 -1.148308,1.148239 z m 4.437333,-5.823248 c 0.594188,0 1.122394,-0.132102 1.584547,-0.396171 0.475351,-0.264068 0.851693,-0.647042 1.129026,-1.148786 0.277265,-0.501812 0.415932,-1.089436 0.415932,-1.762872 0,-0.686632 -0.138667,-1.274256 -0.415932,-1.762803 C 47.07412,10.113778 46.697778,9.7308718 46.222427,9.466735 45.760274,9.2026667 45.232068,9.0706325 44.63788,9.0706325 c -0.594256,0 -1.129025,0.1320342 -1.604376,0.3961025 -0.475419,0.2641368 -0.85176,0.647043 -1.129025,1.148855 -0.277334,0.488547 -0.415932,1.076171 -0.415932,1.762803 0,0.673436 0.138598,1.26106 0.415932,1.762872 0.277265,0.501744 0.653606,0.884718 1.129025,1.148786 0.475351,0.264069 1.01012,0.396171 1.604376,0.396171 z"
+ fill="#3a3a3a"
+ id="path3"
+ style="stroke-width:0.0683761" />
+ <path
+ d="m 53.779282,17.66694 c -0.634188,0 -1.148308,-0.514119 -1.148308,-1.148308 V 8.2381538 c 0,-0.634188 0.51412,-1.1482393 1.148308,-1.1482393 h 0.179282 c 0.634188,0 1.148308,0.5140513 1.148308,1.1482393 v 8.2804782 c 0,0.634189 -0.51412,1.148308 -1.148308,1.148308 z m 0.09956,-12.3200819 c -0.462154,0 -0.845129,-0.1452513 -1.148855,-0.4357607 -0.290462,-0.2905025 -0.435692,-0.6404307 -0.435692,-1.0497777 0,-0.4225505 0.14523,-0.7724787 0.435692,-1.0497778 0.303726,-0.2905026 0.686701,-0.4357607 1.148855,-0.4357607 0.462153,0 0.838495,0.138653 1.129025,0.4159521 0.303658,0.2640958 0.455522,0.6008205 0.455522,1.0101676 0,0.4357538 -0.145231,0.8054906 -0.435761,1.1091965 -0.290462,0.2905094 -0.673436,0.4357607 -1.148786,0.4357607 z"
+ fill="#3a3a3a"
+ id="path4"
+ style="stroke-width:0.0683761" />
+ <path
+ d="m 60.376821,15.30988 0.05942,-3.109743 5.22106,-4.8280344 c 0.196169,-0.1814701 0.453537,-0.2821881 0.72075,-0.2821881 v 0 c 0.944752,0 1.41894,1.141265 0.752274,1.8107351 l -2.891077,2.9033164 -1.307282,1.089436 z m -0.872069,2.35706 c -0.634188,0 -1.148239,-0.514119 -1.148239,-1.148308 V 4.1182838 c 0,-0.6341812 0.514051,-1.1482872 1.148239,-1.1482872 h 0.179351 c 0.634188,0 1.148307,0.514106 1.148307,1.1482872 V 16.518632 c 0,0.634189 -0.514119,1.148308 -1.148307,1.148308 z m 7.382017,0 c -0.346598,0 -0.674666,-0.156581 -0.892718,-0.426051 l -3.517675,-4.347487 1.564786,-1.980718 3.848206,4.89641 c 0.592,0.753368 0.05538,1.857846 -0.902838,1.857846 z"
+ fill="#3a3a3a"
+ id="path5"
+ style="stroke-width:0.0683761" />
+ <defs
+ id="defs6">
+ <linearGradient
+ id="paint0_linear_3874_31725"
+ x1="258.13101"
+ y1="269.78299"
+ x2="88.645203"
+ y2="75.4571"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="scale(0.06837607)">
+ <stop
+ stop-color="#FB9341"
+ id="stop5" />
+ <stop
+ offset="1"
+ stop-color="#E30D3E"
+ id="stop6" />
+ </linearGradient>
+ </defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/tracing/opik-icon.svg b/app/components/base/icons/assets/public/tracing/opik-icon.svg
new file mode 100644
index 0000000..fb49254
--- /dev/null
+++ b/app/components/base/icons/assets/public/tracing/opik-icon.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="47.133904"
+ height="16"
+ viewBox="0 0 47.133904 16"
+ fill="none"
+ version="1.1"
+ id="svg6"
+ sodipodi:docname="opik-icon.svg"
+ inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview6"
+ pagecolor="#b95d5d"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="18.615087"
+ inkscape:cx="34.541874"
+ inkscape:cy="18.882533"
+ inkscape:window-width="2560"
+ inkscape:window-height="1371"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg6" />
+ <rect
+ width="47.119099"
+ height="15.98219"
+ fill="#ffffff"
+ id="rect1"
+ x="0"
+ y="0"
+ style="stroke-width:0.0455515;fill:none"
+ inkscape:label="rect1" />
+ <path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M 9.6391824,3.9256084 C 7.4584431,2.9677242 4.8694901,3.9910489 3.8733677,6.2551834 2.8772499,8.519327 3.8730396,11.117275 6.0537561,12.075159 c 0.8795869,0.38635 1.8205107,0.450735 2.6986394,0.243012 0.3780009,-0.08943 0.7570043,0.144295 0.8464576,0.521993 0.089499,0.377699 -0.1443649,0.7564 -0.5224113,0.845827 C 7.9135024,13.961058 6.6590133,13.876457 5.4876434,13.361931 2.568556,12.079712 1.2888532,8.636894 2.5855671,5.6895232 3.8822857,2.7421295 7.286235,1.3566284 10.205295,2.6388372 11.986296,3.4211403 13.15908,5.0124429 13.505682,6.7988966 13.579642,7.1799648 13.330421,7.548739 12.949049,7.6226396 12.567721,7.6964947 12.198606,7.447473 12.124692,7.0664048 11.860478,5.7048679 10.972279,4.5111667 9.6391824,3.9256084 Z m 2.3662996,7.7665706 c 0.136116,0.570532 -0.216457,1.14325 -0.787445,1.279258 -0.570989,0.135962 -1.14421,-0.216283 -1.2802814,-0.786816 -0.1361171,-0.570532 0.2164564,-1.143295 0.7874454,-1.279258 0.570987,-0.136008 1.14421,0.216283 1.280281,0.786816 z m 0.885967,-0.810128 c 0.762836,-0.181679 1.233846,-0.9468664 1.052022,-1.7090479 -0.181824,-0.7622275 -0.947622,-1.2328598 -1.710414,-1.0511819 -0.762838,0.1816779 -1.233846,0.9468196 -1.052023,1.7090471 0.181823,0.7622277 0.947623,1.2328597 1.710415,1.0511827 z"
+ fill="url(#paint0_linear_3874_31725)"
+ id="path1"
+ style="fill:url(#paint0_linear_3874_31725);stroke-width:0.0455515" />
+ <path
+ d="m 20.686606,11.857146 c -0.721642,0 -1.364084,-0.153857 -1.927326,-0.461616 -0.563197,-0.316594 -1.007638,-0.747475 -1.333234,-1.292646 -0.325641,-0.54517 -0.488416,-1.165106 -0.488416,-1.8598076 0,-0.703444 0.162775,-1.32338 0.488416,-1.8598079 0.325596,-0.5451702 0.770037,-0.9716351 1.333234,-1.2794403 0.563242,-0.3077596 1.205684,-0.4616167 1.927326,-0.4616167 0.730437,0 1.377254,0.1538571 1.940495,0.4616167 0.571992,0.3078052 1.016434,0.7298533 1.333234,1.2662813 0.325641,0.5363823 0.488417,1.1606894 0.488417,1.8729669 0,0.6947016 -0.162776,1.3146376 -0.488417,1.8598076 -0.3168,0.545171 -0.761242,0.976052 -1.333234,1.292646 -0.563241,0.307759 -1.210058,0.461616 -1.940495,0.461616 z m 0,-1.411304 c 0.404796,0 0.765617,-0.08797 1.082418,-0.263821 0.316846,-0.17585 0.563242,-0.4308815 0.739232,-0.7650049 0.184831,-0.3341689 0.277246,-0.7254822 0.277246,-1.1739397 0,-0.4572454 -0.09241,-0.8485586 -0.277246,-1.1738941 C 22.332266,6.7350133 22.08587,6.4800268 21.769024,6.3041317 21.452223,6.1282821 21.095822,6.0403572 20.699776,6.0403572 c -0.404796,0 -0.765617,0.087925 -1.082418,0.2637745 -0.308051,0.1758951 -0.554446,0.4308816 -0.739277,0.7650506 -0.184786,0.3253355 -0.277201,0.7166487 -0.277201,1.1738941 0,0.4484575 0.09241,0.8397708 0.277201,1.1739397 0.184831,0.3341234 0.431226,0.5891549 0.739277,0.7650049 0.316801,0.17585 0.673201,0.263821 1.069248,0.263821 z"
+ fill="#3a3a3a"
+ id="path2"
+ style="stroke-width:0.0455515" />
+ <path
+ d="m 29.934026,11.857146 c -0.571992,0 -1.095634,-0.131865 -1.57088,-0.395684 -0.466407,-0.26382 -0.840442,-0.659504 -1.122018,-1.1871 -0.272826,-0.5364272 -0.409217,-1.2135074 -0.409217,-2.0312856 0,-0.826566 0.131971,-1.5036463 0.396002,-2.0312862 0.272826,-0.5275944 0.642442,-0.9189077 1.108848,-1.1738942 0.466406,-0.26382 0.998843,-0.3956845 1.597265,-0.3956845 0.695257,0 1.306893,0.1494859 1.83491,0.4484576 0.536811,0.2989717 0.959243,0.7166486 1.267248,1.253031 0.316801,0.5364279 0.475202,1.169523 0.475202,1.8993763 0,0.7298534 -0.158401,1.3673652 -0.475202,1.9125806 -0.308005,0.536383 -0.730437,0.95406 -1.267248,1.253031 -0.528017,0.298972 -1.139653,0.448458 -1.83491,0.448458 z m -3.142079,2.466539 c -0.422659,0 -0.765298,-0.342319 -0.765298,-0.764641 V 5.4859892 c 0,-0.4223213 0.342639,-0.7646408 0.765298,-0.7646408 h 0.04028 c 0.42266,0 0.765299,0.3423195 0.765299,0.7646408 v 0.8972793 l -0.05281,1.8730126 0.132016,1.8729669 v 3.429796 c 0,0.422322 -0.342639,0.764641 -0.765298,0.764641 z m 2.957293,-3.877843 c 0.396001,0 0.748027,-0.08797 1.056033,-0.263821 0.316801,-0.17585 0.567616,-0.4308815 0.752447,-0.7650049 0.184786,-0.3341689 0.277201,-0.7254822 0.277201,-1.1739397 0,-0.4572454 -0.09241,-0.8485586 -0.277201,-1.1738941 C 31.372889,6.7350133 31.122074,6.4800268 30.805273,6.3041317 30.497267,6.1282821 30.145241,6.0403572 29.74924,6.0403572 c -0.396046,0 -0.752447,0.087925 -1.069248,0.2637745 -0.316846,0.1758951 -0.567662,0.4308816 -0.752447,0.7650506 -0.184831,0.3253355 -0.277201,0.7166487 -0.277201,1.1738941 0,0.4484575 0.09237,0.8397708 0.277201,1.1739397 0.184785,0.3341234 0.435601,0.5891549 0.752447,0.7650049 0.316801,0.17585 0.673202,0.263821 1.069248,0.263821 z"
+ fill="#3a3a3a"
+ id="path3"
+ style="stroke-width:0.0455515" />
+ <path
+ d="m 35.841594,11.76485 c -0.422659,0 -0.765298,-0.342365 -0.765298,-0.764686 V 5.4859892 c 0,-0.4223213 0.342639,-0.7646408 0.765298,-0.7646408 h 0.119484 c 0.422659,0 0.765298,0.3423195 0.765298,0.7646408 v 5.5141748 c 0,0.422321 -0.342639,0.764686 -0.765298,0.764686 z m 0.06635,-8.2042457 c -0.308006,0 -0.563241,-0.096726 -0.765662,-0.2901837 -0.19358,-0.1934528 -0.290371,-0.4264787 -0.290371,-0.6990729 0,-0.2813867 0.0968,-0.5144125 0.290371,-0.6990728 0.202421,-0.1934528 0.457656,-0.2901838 0.765662,-0.2901838 0.308006,0 0.558822,0.092332 0.752448,0.2769928 0.202375,0.1758678 0.303585,0.4001011 0.303585,0.6726954 0,0.2901792 -0.0968,0.536396 -0.290415,0.7386413 -0.19358,0.1934573 -0.448817,0.2901837 -0.765618,0.2901837 z"
+ fill="#3a3a3a"
+ id="path4"
+ style="stroke-width:0.0455515" />
+ <path
+ d="m 40.238571,10.195226 0.0396,-2.0708549 3.479613,-3.2151067 c 0.130739,-0.1208454 0.302264,-0.187916 0.480351,-0.187916 v 0 c 0.629636,0 0.945662,0.7599964 0.501357,1.2058131 l -1.926779,1.9333896 -0.871247,0.7254822 z m -0.581195,1.569624 c -0.42266,0 -0.765253,-0.342365 -0.765253,-0.764686 V 2.7424664 c 0,-0.4223168 0.342593,-0.7646726 0.765253,-0.7646726 h 0.119528 c 0.42266,0 0.765298,0.3423558 0.765298,0.7646726 v 8.2576976 c 0,0.422321 -0.342638,0.764686 -0.765298,0.764686 z m 4.919799,0 c -0.230994,0 -0.449637,-0.104271 -0.594959,-0.283718 l -2.34438,-2.8950987 1.042863,-1.3190088 2.564664,3.2606405 c 0.394542,0.501685 0.03692,1.237185 -0.601702,1.237185 z"
+ fill="#3a3a3a"
+ id="path5"
+ style="stroke-width:0.0455515" />
+ <defs
+ id="defs6">
+ <linearGradient
+ id="paint0_linear_3874_31725"
+ x1="258.13101"
+ y1="269.78299"
+ x2="88.645203"
+ y2="75.4571"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="scale(0.04556973,0.04553331)">
+ <stop
+ stop-color="#FB9341"
+ id="stop5" />
+ <stop
+ offset="1"
+ stop-color="#E30D3E"
+ id="stop6" />
+ </linearGradient>
+ </defs>
+</svg>
diff --git a/app/components/base/icons/assets/public/tracing/tracing-icon.svg b/app/components/base/icons/assets/public/tracing/tracing-icon.svg
new file mode 100644
index 0000000..b58357f
--- /dev/null
+++ b/app/components/base/icons/assets/public/tracing/tracing-icon.svg
@@ -0,0 +1,6 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="analytics-fill">
+<path id="Vector" opacity="0.6" d="M5 2.5C3.61929 2.5 2.5 3.61929 2.5 5V9.16667H6.15164C6.78293 9.16667 7.36003 9.52333 7.64235 10.088L8.33333 11.4699L10.9213 6.29399C11.0625 6.01167 11.351 5.83333 11.6667 5.83333C11.9823 5.83333 12.2708 6.01167 12.412 6.29399L13.8483 9.16667H17.5V5C17.5 3.61929 16.3807 2.5 15 2.5H5Z" fill="white"/>
+<path id="Vector_2" d="M2.5 14.9999C2.5 16.3807 3.61929 17.4999 5 17.4999H15C16.3807 17.4999 17.5 16.3807 17.5 14.9999V10.8333H13.8483C13.2171 10.8333 12.64 10.4766 12.3577 9.91195L11.6667 8.53003L9.07867 13.7059C8.9375 13.9883 8.649 14.1666 8.33333 14.1666C8.01769 14.1666 7.72913 13.9883 7.58798 13.7059L6.15164 10.8333H2.5V14.9999Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/tracing/weave-icon-big.svg b/app/components/base/icons/assets/public/tracing/weave-icon-big.svg
new file mode 100644
index 0000000..9b1f9a8
--- /dev/null
+++ b/app/components/base/icons/assets/public/tracing/weave-icon-big.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="124px" height="16px" viewBox="0 0 120 16" version="1.1">
+<g id="surface1">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 20.847656 3.292969 C 20.875 3.292969 20.902344 3.292969 20.933594 3.292969 C 20.949219 3.292969 20.964844 3.292969 20.980469 3.292969 C 21.035156 3.292969 21.089844 3.292969 21.140625 3.292969 C 21.179688 3.292969 21.21875 3.292969 21.253906 3.292969 C 21.359375 3.292969 21.464844 3.292969 21.566406 3.292969 C 21.675781 3.292969 21.78125 3.292969 21.890625 3.292969 C 22.097656 3.292969 22.300781 3.292969 22.507812 3.292969 C 22.738281 3.292969 22.972656 3.292969 23.207031 3.296875 C 23.6875 3.296875 24.167969 3.296875 24.648438 3.296875 C 24.648438 3.519531 24.648438 3.742188 24.648438 3.96875 C 24.113281 4.042969 24.113281 4.042969 23.566406 4.113281 C 23.667969 4.496094 23.769531 4.882812 23.867188 5.265625 C 23.878906 5.308594 23.878906 5.308594 23.890625 5.351562 C 24.128906 6.269531 24.371094 7.183594 24.609375 8.097656 C 24.675781 8.339844 24.738281 8.582031 24.800781 8.824219 C 24.816406 8.878906 24.832031 8.933594 24.84375 8.992188 C 24.867188 9.078125 24.890625 9.167969 24.914062 9.257812 C 24.921875 9.289062 24.933594 9.320312 24.941406 9.355469 C 24.953125 9.398438 24.964844 9.441406 24.976562 9.484375 C 24.984375 9.523438 24.984375 9.523438 24.996094 9.558594 C 25.007812 9.625 25.007812 9.625 25.007812 9.71875 C 25.023438 9.71875 25.039062 9.71875 25.054688 9.71875 C 25.058594 9.707031 25.058594 9.695312 25.0625 9.679688 C 25.097656 9.492188 25.152344 9.3125 25.210938 9.128906 C 25.222656 9.097656 25.234375 9.0625 25.246094 9.027344 C 25.269531 8.953125 25.292969 8.882812 25.316406 8.808594 C 25.355469 8.691406 25.390625 8.574219 25.429688 8.457031 C 25.464844 8.339844 25.503906 8.21875 25.542969 8.097656 C 25.660156 7.738281 25.773438 7.375 25.890625 7.011719 C 25.902344 6.96875 25.917969 6.921875 25.933594 6.875 C 26.226562 5.945312 26.519531 5.019531 26.808594 4.089844 C 26.785156 4.089844 26.765625 4.089844 26.742188 4.085938 C 26.507812 4.074219 26.273438 4.046875 26.042969 4.015625 C 26.007812 4.011719 25.972656 4.007812 25.933594 4.003906 C 25.851562 3.992188 25.765625 3.980469 25.679688 3.96875 C 25.679688 3.746094 25.679688 3.523438 25.679688 3.296875 C 26.175781 3.296875 26.667969 3.296875 27.160156 3.296875 C 27.390625 3.292969 27.621094 3.292969 27.851562 3.292969 C 28.050781 3.292969 28.25 3.292969 28.449219 3.292969 C 28.554688 3.292969 28.660156 3.292969 28.765625 3.292969 C 28.867188 3.292969 28.964844 3.292969 29.066406 3.292969 C 29.101562 3.292969 29.140625 3.292969 29.175781 3.292969 C 29.226562 3.292969 29.273438 3.292969 29.324219 3.292969 C 29.367188 3.292969 29.367188 3.292969 29.410156 3.292969 C 29.472656 3.296875 29.472656 3.296875 29.496094 3.320312 C 29.5 3.367188 29.5 3.417969 29.5 3.464844 C 29.5 3.492188 29.5 3.515625 29.5 3.542969 C 29.496094 3.59375 29.496094 3.59375 29.496094 3.648438 C 29.496094 3.753906 29.496094 3.859375 29.496094 3.96875 C 29.09375 4.015625 28.6875 4.066406 28.273438 4.113281 C 28.679688 5.460938 28.679688 5.460938 29.089844 6.808594 C 29.105469 6.859375 29.121094 6.910156 29.136719 6.960938 C 29.234375 7.292969 29.335938 7.625 29.4375 7.960938 C 29.484375 8.113281 29.53125 8.265625 29.578125 8.417969 C 29.605469 8.507812 29.632812 8.597656 29.660156 8.691406 C 29.878906 9.40625 29.878906 9.40625 29.976562 9.746094 C 30.027344 9.664062 30.046875 9.601562 30.070312 9.507812 C 30.078125 9.484375 30.078125 9.484375 30.085938 9.457031 C 30.101562 9.402344 30.117188 9.34375 30.132812 9.289062 C 30.144531 9.25 30.152344 9.207031 30.164062 9.167969 C 30.1875 9.082031 30.214844 8.992188 30.238281 8.90625 C 30.292969 8.691406 30.351562 8.480469 30.410156 8.269531 C 30.433594 8.191406 30.453125 8.117188 30.472656 8.042969 C 30.621094 7.5 30.769531 6.960938 30.921875 6.421875 C 30.949219 6.324219 30.976562 6.226562 31 6.128906 C 31.066406 5.902344 31.128906 5.675781 31.191406 5.449219 C 31.230469 5.308594 31.269531 5.164062 31.308594 5.023438 C 31.335938 4.925781 31.363281 4.828125 31.390625 4.734375 C 31.402344 4.6875 31.414062 4.640625 31.429688 4.59375 C 31.445312 4.53125 31.464844 4.46875 31.480469 4.40625 C 31.488281 4.386719 31.492188 4.367188 31.496094 4.347656 C 31.515625 4.277344 31.535156 4.207031 31.558594 4.136719 C 31.210938 4.074219 30.855469 4.023438 30.503906 3.96875 C 30.503906 3.746094 30.503906 3.523438 30.503906 3.296875 C 30.878906 3.296875 31.253906 3.296875 31.628906 3.296875 C 31.804688 3.292969 31.976562 3.292969 32.152344 3.292969 C 32.304688 3.292969 32.457031 3.292969 32.605469 3.292969 C 32.6875 3.292969 32.769531 3.292969 32.847656 3.292969 C 32.9375 3.292969 33.027344 3.292969 33.117188 3.292969 C 33.144531 3.292969 33.171875 3.292969 33.199219 3.292969 C 33.222656 3.292969 33.246094 3.292969 33.273438 3.292969 C 33.304688 3.292969 33.304688 3.292969 33.335938 3.292969 C 33.382812 3.296875 33.382812 3.296875 33.40625 3.320312 C 33.410156 3.367188 33.410156 3.414062 33.410156 3.460938 C 33.410156 3.488281 33.410156 3.515625 33.410156 3.542969 C 33.410156 3.574219 33.410156 3.605469 33.410156 3.632812 C 33.410156 3.664062 33.410156 3.695312 33.410156 3.726562 C 33.410156 3.796875 33.410156 3.871094 33.40625 3.945312 C 33.292969 3.964844 33.175781 3.984375 33.0625 4.007812 C 33.023438 4.011719 32.984375 4.019531 32.945312 4.027344 C 32.738281 4.0625 32.535156 4.097656 32.328125 4.113281 C 32.320312 4.144531 32.320312 4.144531 32.3125 4.179688 C 32.238281 4.480469 32.15625 4.78125 32.070312 5.082031 C 32.058594 5.128906 32.042969 5.171875 32.03125 5.21875 C 31.875 5.78125 31.714844 6.347656 31.550781 6.910156 C 31.375 7.535156 31.195312 8.160156 31.019531 8.785156 C 30.992188 8.871094 30.96875 8.957031 30.945312 9.042969 C 30.835938 9.433594 30.722656 9.820312 30.613281 10.210938 C 30.566406 10.378906 30.519531 10.542969 30.472656 10.707031 C 30.445312 10.804688 30.417969 10.902344 30.390625 11 C 30.277344 11.390625 30.167969 11.785156 30.046875 12.175781 C 29.730469 12.175781 29.414062 12.175781 29.089844 12.175781 C 29.03125 12.003906 29.03125 12.003906 28.976562 11.832031 C 28.925781 11.675781 28.878906 11.523438 28.828125 11.367188 C 28.820312 11.347656 28.8125 11.328125 28.808594 11.304688 C 28.632812 10.769531 28.460938 10.230469 28.285156 9.695312 C 28.144531 9.273438 28.007812 8.847656 27.875 8.425781 C 27.695312 7.867188 27.515625 7.308594 27.332031 6.753906 C 27.304688 6.679688 27.28125 6.605469 27.257812 6.53125 C 27.238281 6.476562 27.222656 6.425781 27.207031 6.375 C 27.046875 5.894531 27.046875 5.894531 27.046875 5.796875 C 27.03125 5.796875 27.015625 5.796875 27 5.796875 C 26.996094 5.8125 26.996094 5.828125 26.992188 5.84375 C 26.964844 5.988281 26.925781 6.132812 26.882812 6.273438 C 26.875 6.296875 26.867188 6.316406 26.859375 6.339844 C 26.84375 6.390625 26.828125 6.4375 26.8125 6.488281 C 26.769531 6.625 26.726562 6.761719 26.683594 6.898438 C 26.675781 6.929688 26.664062 6.957031 26.65625 6.988281 C 26.546875 7.328125 26.445312 7.667969 26.339844 8.007812 C 26.316406 8.078125 26.296875 8.144531 26.273438 8.214844 C 26.230469 8.355469 26.1875 8.496094 26.144531 8.636719 C 26.074219 8.863281 26.007812 9.089844 25.9375 9.3125 C 25.933594 9.328125 25.925781 9.347656 25.921875 9.363281 C 25.894531 9.449219 25.871094 9.535156 25.84375 9.617188 C 25.796875 9.769531 25.75 9.921875 25.703125 10.074219 C 25.675781 10.15625 25.652344 10.242188 25.625 10.328125 C 25.613281 10.363281 25.605469 10.394531 25.59375 10.429688 C 25.414062 11.011719 25.234375 11.59375 25.054688 12.175781 C 24.738281 12.175781 24.421875 12.175781 24.097656 12.175781 C 23.816406 11.230469 23.535156 10.285156 23.261719 9.339844 C 23.253906 9.320312 23.25 9.304688 23.246094 9.285156 C 23.195312 9.117188 23.144531 8.949219 23.097656 8.78125 C 22.960938 8.3125 22.824219 7.84375 22.6875 7.375 C 22.664062 7.304688 22.644531 7.234375 22.625 7.164062 C 22.414062 6.449219 22.207031 5.738281 22 5.027344 C 21.976562 4.953125 21.953125 4.878906 21.933594 4.804688 C 21.898438 4.683594 21.859375 4.5625 21.824219 4.441406 C 21.820312 4.421875 21.8125 4.402344 21.808594 4.382812 C 21.796875 4.347656 21.785156 4.3125 21.777344 4.28125 C 21.753906 4.203125 21.742188 4.148438 21.742188 4.066406 C 21.726562 4.066406 21.710938 4.0625 21.691406 4.0625 C 21.382812 4.042969 21.070312 4.003906 20.761719 3.96875 C 20.757812 3.863281 20.757812 3.753906 20.757812 3.648438 C 20.757812 3.617188 20.757812 3.585938 20.757812 3.554688 C 20.757812 3.523438 20.757812 3.496094 20.757812 3.464844 C 20.757812 3.4375 20.757812 3.410156 20.757812 3.382812 C 20.761719 3.296875 20.761719 3.296875 20.847656 3.292969 Z M 20.847656 3.292969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 82.488281 3.25 C 83.046875 3.246094 83.605469 3.246094 84.167969 3.246094 C 84.425781 3.246094 84.6875 3.246094 84.945312 3.246094 C 85.171875 3.242188 85.398438 3.242188 85.625 3.242188 C 85.746094 3.242188 85.867188 3.242188 85.984375 3.242188 C 88.15625 3.238281 88.15625 3.238281 88.894531 3.898438 C 88.914062 3.914062 88.9375 3.929688 88.957031 3.945312 C 89.191406 4.144531 89.363281 4.402344 89.472656 4.691406 C 89.480469 4.714844 89.492188 4.742188 89.5 4.765625 C 89.65625 5.25 89.601562 5.785156 89.382812 6.234375 C 89.117188 6.753906 88.695312 7.078125 88.152344 7.265625 C 87.984375 7.320312 87.816406 7.367188 87.648438 7.410156 C 87.664062 7.414062 87.679688 7.417969 87.699219 7.421875 C 88.523438 7.605469 89.300781 7.851562 89.78125 8.597656 C 90.0625 9.0625 90.125 9.636719 90.003906 10.164062 C 89.808594 10.804688 89.363281 11.304688 88.78125 11.621094 C 88.324219 11.863281 87.820312 11.988281 87.3125 12.054688 C 87.28125 12.058594 87.253906 12.0625 87.222656 12.066406 C 86.777344 12.121094 86.332031 12.109375 85.882812 12.105469 C 85.765625 12.105469 85.644531 12.105469 85.523438 12.105469 C 85.300781 12.105469 85.074219 12.105469 84.847656 12.105469 C 84.589844 12.105469 84.332031 12.105469 84.074219 12.105469 C 83.546875 12.105469 83.015625 12.101562 82.488281 12.101562 C 82.488281 11.878906 82.488281 11.65625 82.488281 11.429688 C 82.859375 11.390625 83.234375 11.347656 83.617188 11.308594 C 83.617188 8.910156 83.617188 6.511719 83.617188 4.042969 C 83.488281 4.035156 83.363281 4.027344 83.230469 4.019531 C 83.117188 4.007812 83.003906 3.996094 82.890625 3.980469 C 82.863281 3.980469 82.832031 3.976562 82.804688 3.972656 C 82.695312 3.960938 82.59375 3.949219 82.488281 3.921875 C 82.488281 3.699219 82.488281 3.476562 82.488281 3.25 Z M 85.390625 3.96875 C 85.390625 4.242188 85.386719 4.515625 85.382812 4.785156 C 85.382812 4.914062 85.378906 5.039062 85.378906 5.164062 C 85.371094 5.824219 85.367188 6.484375 85.367188 7.144531 C 86.488281 7.183594 86.488281 7.183594 87.457031 6.691406 C 87.796875 6.320312 87.859375 5.832031 87.847656 5.351562 C 87.832031 4.992188 87.71875 4.644531 87.460938 4.378906 C 87 3.96875 86.363281 3.964844 85.78125 3.96875 C 85.742188 3.96875 85.703125 3.96875 85.667969 3.96875 C 85.574219 3.96875 85.484375 3.96875 85.390625 3.96875 Z M 85.390625 7.84375 C 85.390625 9.003906 85.390625 10.160156 85.390625 11.355469 C 86.28125 11.386719 86.28125 11.386719 87.152344 11.21875 C 87.171875 11.214844 87.1875 11.207031 87.207031 11.199219 C 87.578125 11.066406 87.886719 10.824219 88.066406 10.46875 C 88.28125 9.988281 88.289062 9.417969 88.125 8.921875 C 87.960938 8.492188 87.664062 8.234375 87.257812 8.046875 C 86.664062 7.804688 86.023438 7.84375 85.390625 7.84375 Z M 85.390625 7.84375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 76.167969 3.476562 C 76.367188 3.671875 76.507812 3.917969 76.585938 4.1875 C 76.589844 4.203125 76.59375 4.222656 76.601562 4.242188 C 76.707031 4.675781 76.621094 5.144531 76.414062 5.53125 C 76.34375 5.644531 76.265625 5.746094 76.175781 5.847656 C 76.15625 5.867188 76.136719 5.886719 76.117188 5.910156 C 75.71875 6.332031 75.199219 6.617188 74.6875 6.882812 C 74.707031 6.902344 74.726562 6.921875 74.746094 6.941406 C 74.972656 7.191406 74.972656 7.191406 75.066406 7.296875 C 75.140625 7.382812 75.21875 7.464844 75.300781 7.542969 C 75.351562 7.59375 75.394531 7.640625 75.4375 7.695312 C 75.527344 7.796875 75.621094 7.894531 75.714844 7.992188 C 76.089844 8.394531 76.089844 8.394531 76.253906 8.585938 C 76.351562 8.695312 76.449219 8.800781 76.546875 8.90625 C 76.621094 8.980469 76.691406 9.058594 76.761719 9.136719 C 76.773438 9.152344 76.789062 9.164062 76.800781 9.179688 C 76.824219 9.207031 76.851562 9.234375 76.875 9.261719 C 76.933594 9.324219 76.992188 9.382812 77.0625 9.429688 C 77.070312 9.410156 77.070312 9.410156 77.082031 9.386719 C 77.113281 9.304688 77.152344 9.230469 77.195312 9.15625 C 77.5625 8.476562 77.800781 7.753906 77.976562 7 C 77.953125 7 77.933594 6.996094 77.910156 6.996094 C 77.707031 6.96875 77.5 6.9375 77.296875 6.902344 C 77.273438 6.898438 77.25 6.894531 77.222656 6.890625 C 77.050781 6.859375 77.050781 6.859375 76.96875 6.832031 C 76.960938 6.328125 76.960938 6.328125 77.015625 6.160156 C 77.949219 6.160156 78.886719 6.160156 79.847656 6.160156 C 79.847656 6.367188 79.847656 6.574219 79.847656 6.785156 C 79.53125 6.839844 79.214844 6.894531 78.886719 6.953125 C 78.859375 7.046875 78.832031 7.140625 78.804688 7.234375 C 78.539062 8.09375 78.164062 9.035156 77.601562 9.746094 C 77.5625 9.792969 77.5625 9.792969 77.566406 9.851562 C 77.601562 9.933594 77.648438 9.980469 77.714844 10.039062 C 77.792969 10.113281 77.867188 10.1875 77.9375 10.269531 C 78.027344 10.375 78.125 10.46875 78.222656 10.566406 C 78.308594 10.65625 78.390625 10.742188 78.472656 10.839844 C 78.539062 10.914062 78.601562 10.933594 78.695312 10.949219 C 78.71875 10.953125 78.746094 10.957031 78.769531 10.960938 C 78.796875 10.964844 78.824219 10.96875 78.851562 10.972656 C 78.875 10.980469 78.902344 10.984375 78.933594 10.988281 C 79.019531 11.003906 79.105469 11.019531 79.191406 11.03125 C 79.277344 11.046875 79.363281 11.0625 79.449219 11.078125 C 79.503906 11.085938 79.558594 11.097656 79.613281 11.105469 C 79.648438 11.113281 79.648438 11.113281 79.6875 11.117188 C 79.707031 11.121094 79.730469 11.125 79.75 11.128906 C 79.800781 11.140625 79.800781 11.140625 79.824219 11.164062 C 79.820312 11.421875 79.785156 11.679688 79.753906 11.933594 C 79.691406 11.949219 79.632812 11.964844 79.570312 11.980469 C 79.546875 11.984375 79.546875 11.984375 79.519531 11.992188 C 79.214844 12.066406 78.910156 12.085938 78.597656 12.085938 C 78.539062 12.085938 78.484375 12.085938 78.425781 12.085938 C 77.847656 12.089844 77.332031 11.917969 76.894531 11.523438 C 76.855469 11.484375 76.816406 11.445312 76.777344 11.40625 C 76.71875 11.347656 76.660156 11.296875 76.601562 11.242188 C 76.578125 11.21875 76.578125 11.21875 76.554688 11.195312 C 76.515625 11.160156 76.476562 11.125 76.441406 11.089844 C 76.429688 11.101562 76.417969 11.109375 76.410156 11.117188 C 76.140625 11.351562 75.859375 11.554688 75.542969 11.71875 C 75.511719 11.738281 75.476562 11.757812 75.445312 11.777344 C 75.3125 11.847656 75.179688 11.894531 75.039062 11.9375 C 75.011719 11.945312 75.011719 11.945312 74.984375 11.953125 C 74.632812 12.058594 74.269531 12.089844 73.90625 12.085938 C 73.84375 12.085938 73.785156 12.085938 73.722656 12.089844 C 72.941406 12.089844 72.222656 11.824219 71.652344 11.28125 C 71.203125 10.820312 71.023438 10.246094 71.03125 9.609375 C 71.042969 9.058594 71.230469 8.546875 71.59375 8.132812 C 71.609375 8.113281 71.625 8.09375 71.644531 8.070312 C 71.980469 7.683594 72.398438 7.421875 72.839844 7.171875 C 72.871094 7.152344 72.902344 7.132812 72.9375 7.113281 C 72.960938 7.101562 72.984375 7.085938 73.007812 7.074219 C 72.996094 7.0625 72.988281 7.050781 72.976562 7.042969 C 72.398438 6.425781 72.09375 5.613281 72.113281 4.773438 C 72.128906 4.371094 72.257812 3.988281 72.527344 3.679688 C 72.542969 3.660156 72.558594 3.644531 72.570312 3.625 C 72.917969 3.210938 73.496094 2.996094 74.015625 2.933594 C 74.050781 2.929688 74.050781 2.929688 74.082031 2.925781 C 74.804688 2.847656 75.621094 2.964844 76.167969 3.476562 Z M 73.671875 3.796875 C 73.433594 4.113281 73.414062 4.4375 73.457031 4.820312 C 73.550781 5.460938 73.921875 5.9375 74.328125 6.425781 C 74.398438 6.390625 74.449219 6.355469 74.503906 6.300781 C 74.527344 6.28125 74.527344 6.28125 74.550781 6.257812 C 74.566406 6.242188 74.582031 6.226562 74.597656 6.210938 C 74.613281 6.191406 74.628906 6.175781 74.644531 6.160156 C 74.773438 6.03125 74.890625 5.894531 75 5.75 C 75.019531 5.726562 75.035156 5.699219 75.054688 5.675781 C 75.335938 5.292969 75.5 4.859375 75.457031 4.378906 C 75.40625 4.078125 75.289062 3.820312 75.035156 3.636719 C 74.59375 3.363281 74.03125 3.410156 73.671875 3.796875 Z M 73.046875 7.828125 C 72.664062 8.226562 72.519531 8.789062 72.519531 9.332031 C 72.53125 9.800781 72.71875 10.257812 73.039062 10.601562 C 73.46875 10.996094 73.980469 11.140625 74.550781 11.125 C 74.960938 11.105469 75.339844 11.003906 75.703125 10.8125 C 75.71875 10.804688 75.738281 10.796875 75.753906 10.785156 C 75.84375 10.738281 75.90625 10.699219 75.960938 10.609375 C 75.949219 10.601562 75.941406 10.589844 75.933594 10.582031 C 75.460938 10.074219 75.460938 10.074219 75.25 9.8125 C 75.1875 9.738281 75.125 9.664062 75.0625 9.59375 C 74.972656 9.484375 74.882812 9.375 74.796875 9.265625 C 74.695312 9.132812 74.589844 9.003906 74.480469 8.878906 C 74.390625 8.773438 74.304688 8.667969 74.214844 8.5625 C 74.152344 8.484375 74.085938 8.40625 74.019531 8.328125 C 73.921875 8.214844 73.828125 8.101562 73.734375 7.984375 C 73.726562 7.96875 73.714844 7.957031 73.703125 7.941406 C 73.683594 7.914062 73.660156 7.886719 73.640625 7.859375 C 73.589844 7.792969 73.539062 7.730469 73.488281 7.667969 C 73.460938 7.632812 73.460938 7.632812 73.433594 7.601562 C 73.414062 7.578125 73.414062 7.578125 73.390625 7.554688 C 73.265625 7.554688 73.132812 7.742188 73.046875 7.828125 Z M 73.046875 7.828125 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 49.992188 5.535156 C 50.101562 5.609375 50.101562 5.609375 50.136719 5.679688 C 50.136719 5.746094 50.140625 5.8125 50.140625 5.882812 C 50.140625 5.914062 50.140625 5.914062 50.140625 5.941406 C 50.140625 5.984375 50.140625 6.027344 50.140625 6.070312 C 50.140625 6.136719 50.140625 6.203125 50.140625 6.269531 C 50.140625 6.308594 50.140625 6.351562 50.140625 6.390625 C 50.140625 6.410156 50.140625 6.429688 50.140625 6.453125 C 50.140625 6.589844 50.140625 6.589844 50.113281 6.617188 C 50.074219 6.617188 50.035156 6.621094 49.996094 6.621094 C 49.972656 6.621094 49.949219 6.621094 49.921875 6.621094 C 49.894531 6.621094 49.871094 6.617188 49.84375 6.617188 C 49.816406 6.617188 49.789062 6.617188 49.757812 6.617188 C 49.671875 6.617188 49.585938 6.617188 49.5 6.617188 C 49.441406 6.617188 49.378906 6.617188 49.320312 6.617188 C 49.175781 6.617188 49.03125 6.617188 48.886719 6.617188 C 48.898438 6.640625 48.90625 6.660156 48.917969 6.683594 C 48.929688 6.714844 48.945312 6.746094 48.957031 6.773438 C 48.964844 6.789062 48.96875 6.804688 48.976562 6.820312 C 49.203125 7.339844 49.195312 8 48.988281 8.523438 C 48.75 9.0625 48.355469 9.457031 47.804688 9.671875 C 47.066406 9.941406 46.210938 9.941406 45.457031 9.746094 C 45.277344 10.003906 45.214844 10.273438 45.238281 10.585938 C 45.269531 10.699219 45.316406 10.761719 45.402344 10.835938 C 45.617188 10.945312 45.851562 10.949219 46.089844 10.949219 C 46.113281 10.953125 46.132812 10.953125 46.15625 10.953125 C 46.203125 10.953125 46.25 10.953125 46.292969 10.953125 C 46.367188 10.953125 46.441406 10.953125 46.515625 10.953125 C 46.726562 10.953125 46.9375 10.957031 47.144531 10.957031 C 47.273438 10.957031 47.402344 10.957031 47.53125 10.960938 C 47.582031 10.960938 47.628906 10.960938 47.675781 10.960938 C 48.324219 10.960938 49.039062 11.019531 49.53125 11.492188 C 49.546875 11.511719 49.566406 11.53125 49.585938 11.550781 C 49.601562 11.566406 49.617188 11.582031 49.636719 11.597656 C 49.957031 11.929688 50.0625 12.394531 50.066406 12.84375 C 50.054688 13.351562 49.847656 13.800781 49.511719 14.171875 C 49.496094 14.191406 49.480469 14.207031 49.460938 14.226562 C 48.8125 14.921875 47.769531 15.179688 46.855469 15.210938 C 45.890625 15.234375 44.761719 15.230469 44.015625 14.523438 C 43.738281 14.222656 43.660156 13.886719 43.671875 13.488281 C 43.679688 13.363281 43.699219 13.253906 43.753906 13.136719 C 43.761719 13.117188 43.769531 13.09375 43.78125 13.074219 C 43.996094 12.644531 44.386719 12.410156 44.785156 12.175781 C 44.765625 12.167969 44.746094 12.160156 44.730469 12.152344 C 44.398438 11.996094 44.222656 11.808594 44.089844 11.476562 C 43.988281 11.136719 44.070312 10.757812 44.222656 10.453125 C 44.421875 10.109375 44.695312 9.824219 44.976562 9.550781 C 44.960938 9.542969 44.945312 9.53125 44.925781 9.523438 C 44.757812 9.417969 44.613281 9.304688 44.472656 9.167969 C 44.457031 9.152344 44.441406 9.136719 44.425781 9.121094 C 44.214844 8.902344 44.085938 8.597656 44.015625 8.300781 C 44.011719 8.28125 44.003906 8.257812 44 8.238281 C 43.882812 7.675781 43.964844 7.042969 44.277344 6.558594 C 44.621094 6.070312 45.09375 5.773438 45.671875 5.628906 C 45.6875 5.625 45.703125 5.621094 45.71875 5.617188 C 46.25 5.492188 46.917969 5.496094 47.449219 5.628906 C 47.464844 5.632812 47.480469 5.636719 47.496094 5.640625 C 47.6875 5.691406 47.867188 5.761719 48.046875 5.84375 C 48.0625 5.851562 48.078125 5.859375 48.09375 5.867188 C 48.164062 5.902344 48.226562 5.933594 48.289062 5.980469 C 48.390625 6.066406 48.390625 6.066406 48.515625 6.082031 C 48.582031 6.0625 48.644531 6.035156 48.707031 6.003906 C 48.730469 5.996094 48.753906 5.984375 48.78125 5.976562 C 48.855469 5.941406 48.929688 5.910156 49.003906 5.875 C 49.054688 5.851562 49.101562 5.832031 49.152344 5.808594 C 49.320312 5.738281 49.488281 5.664062 49.652344 5.585938 C 49.679688 5.574219 49.703125 5.566406 49.730469 5.554688 C 49.75 5.542969 49.769531 5.535156 49.789062 5.523438 C 49.867188 5.503906 49.917969 5.515625 49.992188 5.535156 Z M 45.835938 6.507812 C 45.472656 6.984375 45.421875 7.597656 45.492188 8.175781 C 45.550781 8.542969 45.6875 8.890625 45.980469 9.132812 C 46.207031 9.285156 46.46875 9.3125 46.734375 9.277344 C 47.015625 9.21875 47.210938 9.089844 47.375 8.855469 C 47.683594 8.375 47.742188 7.746094 47.640625 7.191406 C 47.5625 6.859375 47.402344 6.507812 47.117188 6.308594 C 46.703125 6.074219 46.152344 6.148438 45.835938 6.507812 Z M 45.238281 12.367188 C 44.957031 12.734375 44.867188 13.113281 44.902344 13.570312 C 44.957031 13.84375 45.09375 14.058594 45.316406 14.226562 C 45.613281 14.417969 46.015625 14.496094 46.367188 14.507812 C 46.394531 14.507812 46.394531 14.507812 46.417969 14.507812 C 47.132812 14.527344 47.90625 14.457031 48.453125 13.945312 C 48.652344 13.738281 48.710938 13.515625 48.703125 13.230469 C 48.683594 12.992188 48.570312 12.800781 48.394531 12.644531 C 48.113281 12.441406 47.726562 12.449219 47.398438 12.449219 C 47.355469 12.449219 47.3125 12.449219 47.269531 12.449219 C 47.15625 12.449219 47.046875 12.449219 46.933594 12.449219 C 46.753906 12.449219 46.574219 12.445312 46.394531 12.445312 C 46.332031 12.445312 46.269531 12.445312 46.210938 12.445312 C 45.882812 12.445312 45.5625 12.414062 45.238281 12.367188 Z M 45.238281 12.367188 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 53.039062 2.382812 C 53.0625 2.390625 53.0625 2.390625 53.085938 2.398438 C 53.140625 2.429688 53.171875 2.453125 53.207031 2.503906 C 53.230469 2.617188 53.21875 2.730469 53.214844 2.84375 C 53.210938 2.878906 53.210938 2.914062 53.210938 2.953125 C 53.207031 3.027344 53.203125 3.105469 53.199219 3.183594 C 53.191406 3.371094 53.183594 3.558594 53.179688 3.746094 C 53.175781 3.792969 53.175781 3.835938 53.175781 3.882812 C 53.15625 4.441406 53.15625 5 53.15625 5.5625 C 53.15625 5.640625 53.15625 5.71875 53.15625 5.792969 C 53.15625 6.085938 53.160156 6.375 53.160156 6.664062 C 53.179688 6.644531 53.195312 6.625 53.214844 6.605469 C 53.238281 6.578125 53.261719 6.550781 53.285156 6.523438 C 53.296875 6.511719 53.3125 6.5 53.324219 6.484375 C 53.78125 5.984375 54.445312 5.601562 55.128906 5.550781 C 55.640625 5.535156 56.128906 5.578125 56.527344 5.929688 C 56.566406 5.964844 56.601562 6 56.640625 6.039062 C 56.664062 6.0625 56.664062 6.0625 56.691406 6.089844 C 57.246094 6.660156 57.203125 7.570312 57.203125 8.304688 C 57.203125 8.414062 57.203125 8.523438 57.207031 8.632812 C 57.207031 8.839844 57.207031 9.042969 57.207031 9.25 C 57.207031 9.484375 57.210938 9.722656 57.210938 9.957031 C 57.210938 10.4375 57.214844 10.921875 57.214844 11.40625 C 57.246094 11.410156 57.246094 11.410156 57.28125 11.414062 C 57.308594 11.417969 57.335938 11.421875 57.363281 11.425781 C 57.40625 11.433594 57.40625 11.433594 57.445312 11.441406 C 57.558594 11.457031 57.671875 11.480469 57.785156 11.503906 C 57.808594 11.507812 57.828125 11.511719 57.851562 11.515625 C 57.878906 11.519531 57.878906 11.519531 57.910156 11.527344 C 57.929688 11.53125 57.949219 11.535156 57.964844 11.539062 C 58.007812 11.550781 58.007812 11.550781 58.03125 11.574219 C 58.035156 11.613281 58.035156 11.65625 58.035156 11.695312 C 58.035156 11.71875 58.035156 11.746094 58.035156 11.769531 C 58.035156 11.796875 58.035156 11.824219 58.035156 11.851562 C 58.035156 11.875 58.035156 11.902344 58.035156 11.929688 C 58.035156 11.964844 58.035156 11.964844 58.035156 12.003906 C 58.035156 12.027344 58.035156 12.050781 58.035156 12.074219 C 58.03125 12.125 58.03125 12.125 58.007812 12.148438 C 57.964844 12.152344 57.921875 12.152344 57.882812 12.152344 C 57.839844 12.152344 57.839844 12.152344 57.796875 12.152344 C 57.769531 12.152344 57.738281 12.152344 57.707031 12.152344 C 57.675781 12.152344 57.640625 12.152344 57.609375 12.152344 C 57.523438 12.152344 57.433594 12.152344 57.347656 12.152344 C 57.257812 12.152344 57.164062 12.152344 57.074219 12.152344 C 56.917969 12.152344 56.765625 12.152344 56.613281 12.152344 C 56.433594 12.152344 56.257812 12.152344 56.082031 12.152344 C 55.929688 12.152344 55.777344 12.152344 55.625 12.152344 C 55.53125 12.152344 55.441406 12.152344 55.351562 12.152344 C 55.265625 12.152344 55.179688 12.152344 55.09375 12.152344 C 55.046875 12.152344 55 12.152344 54.953125 12.152344 C 54.925781 12.152344 54.898438 12.152344 54.871094 12.152344 C 54.847656 12.152344 54.824219 12.152344 54.796875 12.152344 C 54.742188 12.148438 54.742188 12.148438 54.71875 12.125 C 54.71875 12.085938 54.71875 12.042969 54.71875 12.003906 C 54.71875 11.976562 54.71875 11.953125 54.71875 11.925781 C 54.71875 11.902344 54.71875 11.875 54.71875 11.847656 C 54.71875 11.820312 54.71875 11.796875 54.71875 11.769531 C 54.71875 11.703125 54.71875 11.636719 54.71875 11.574219 C 54.8125 11.53125 54.902344 11.507812 55.003906 11.488281 C 55.03125 11.480469 55.0625 11.476562 55.09375 11.46875 C 55.113281 11.464844 55.128906 11.460938 55.144531 11.460938 C 55.191406 11.449219 55.242188 11.441406 55.289062 11.429688 C 55.527344 11.378906 55.527344 11.378906 55.585938 11.378906 C 55.582031 10.90625 55.582031 10.433594 55.578125 9.960938 C 55.578125 9.742188 55.578125 9.523438 55.574219 9.304688 C 55.574219 9.109375 55.574219 8.917969 55.574219 8.726562 C 55.574219 8.625 55.570312 8.527344 55.570312 8.425781 C 55.570312 8.328125 55.570312 8.234375 55.570312 8.136719 C 55.570312 8.101562 55.570312 8.066406 55.570312 8.03125 C 55.570312 7.664062 55.554688 7.199219 55.289062 6.917969 C 55.054688 6.722656 54.742188 6.746094 54.457031 6.761719 C 54.101562 6.800781 53.738281 7.007812 53.464844 7.234375 C 53.425781 7.265625 53.425781 7.265625 53.371094 7.300781 C 53.273438 7.371094 53.214844 7.421875 53.1875 7.539062 C 53.179688 7.640625 53.179688 7.742188 53.183594 7.84375 C 53.183594 7.882812 53.183594 7.921875 53.183594 7.960938 C 53.183594 8.066406 53.183594 8.167969 53.1875 8.273438 C 53.1875 8.386719 53.1875 8.496094 53.1875 8.605469 C 53.1875 8.8125 53.191406 9.023438 53.191406 9.230469 C 53.195312 9.46875 53.195312 9.703125 53.195312 9.941406 C 53.199219 10.429688 53.203125 10.917969 53.207031 11.40625 C 53.238281 11.410156 53.238281 11.410156 53.265625 11.414062 C 53.351562 11.429688 53.4375 11.445312 53.523438 11.464844 C 53.554688 11.46875 53.585938 11.472656 53.613281 11.480469 C 53.644531 11.484375 53.671875 11.492188 53.703125 11.496094 C 53.730469 11.5 53.753906 11.507812 53.78125 11.511719 C 53.847656 11.523438 53.910156 11.535156 53.976562 11.550781 C 53.976562 11.746094 53.976562 11.945312 53.976562 12.148438 C 52.890625 12.148438 51.804688 12.148438 50.6875 12.148438 C 50.6875 11.953125 50.6875 11.753906 50.6875 11.550781 C 50.964844 11.492188 51.242188 11.4375 51.527344 11.378906 C 51.542969 11.160156 51.554688 10.945312 51.554688 10.722656 C 51.554688 10.691406 51.554688 10.660156 51.554688 10.628906 C 51.554688 10.546875 51.558594 10.464844 51.558594 10.378906 C 51.558594 10.289062 51.558594 10.199219 51.558594 10.109375 C 51.558594 9.953125 51.558594 9.796875 51.558594 9.640625 C 51.558594 9.414062 51.558594 9.1875 51.5625 8.960938 C 51.5625 8.59375 51.5625 8.230469 51.5625 7.863281 C 51.566406 7.507812 51.566406 7.152344 51.566406 6.792969 C 51.566406 6.773438 51.566406 6.75 51.566406 6.726562 C 51.566406 6.617188 51.566406 6.507812 51.566406 6.398438 C 51.570312 5.484375 51.574219 4.570312 51.574219 3.65625 C 51.554688 3.65625 51.535156 3.652344 51.515625 3.652344 C 51.476562 3.648438 51.476562 3.648438 51.4375 3.644531 C 51.414062 3.644531 51.386719 3.640625 51.359375 3.640625 C 51.277344 3.632812 51.195312 3.621094 51.113281 3.609375 C 51.082031 3.605469 51.054688 3.601562 51.023438 3.597656 C 50.996094 3.59375 50.964844 3.589844 50.933594 3.582031 C 50.902344 3.578125 50.871094 3.574219 50.839844 3.570312 C 50.765625 3.558594 50.691406 3.546875 50.617188 3.535156 C 50.617188 3.347656 50.617188 3.15625 50.617188 2.960938 C 50.910156 2.875 51.207031 2.796875 51.5 2.722656 C 51.523438 2.714844 51.542969 2.710938 51.5625 2.707031 C 51.671875 2.679688 51.777344 2.652344 51.886719 2.625 C 51.972656 2.601562 52.0625 2.578125 52.152344 2.554688 C 52.257812 2.527344 52.367188 2.5 52.472656 2.472656 C 52.515625 2.460938 52.554688 2.453125 52.597656 2.441406 C 52.652344 2.425781 52.710938 2.410156 52.765625 2.398438 C 52.78125 2.394531 52.800781 2.386719 52.816406 2.382812 C 52.898438 2.363281 52.960938 2.351562 53.039062 2.382812 Z M 53.039062 2.382812 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 99.691406 6.011719 C 100.109375 6.40625 100.234375 7.003906 100.273438 7.554688 C 100.277344 7.667969 100.277344 7.785156 100.277344 7.898438 C 100.277344 7.933594 100.277344 7.964844 100.277344 8 C 100.277344 8.074219 100.277344 8.144531 100.277344 8.21875 C 100.277344 8.332031 100.277344 8.445312 100.277344 8.558594 C 100.28125 8.886719 100.28125 9.210938 100.28125 9.535156 C 100.28125 9.714844 100.28125 9.894531 100.285156 10.074219 C 100.285156 10.171875 100.285156 10.265625 100.285156 10.359375 C 100.285156 10.449219 100.285156 10.539062 100.285156 10.628906 C 100.285156 10.675781 100.285156 10.726562 100.285156 10.773438 C 100.289062 10.964844 100.292969 11.167969 100.417969 11.320312 C 100.53125 11.378906 100.636719 11.398438 100.757812 11.367188 C 100.898438 11.308594 101.003906 11.21875 101.113281 11.117188 C 101.226562 11.199219 101.339844 11.289062 101.449219 11.378906 C 101.394531 11.527344 101.300781 11.640625 101.207031 11.765625 C 101.179688 11.804688 101.179688 11.804688 101.152344 11.84375 C 100.859375 12.152344 100.476562 12.265625 100.058594 12.277344 C 99.699219 12.269531 99.332031 12.164062 99.066406 11.910156 C 98.933594 11.757812 98.761719 11.519531 98.761719 11.308594 C 98.582031 11.449219 98.582031 11.449219 98.417969 11.605469 C 98.289062 11.738281 98.140625 11.847656 97.992188 11.957031 C 97.96875 11.972656 97.949219 11.992188 97.925781 12.007812 C 97.488281 12.3125 96.855469 12.339844 96.34375 12.25 C 95.917969 12.15625 95.527344 11.929688 95.28125 11.558594 C 95.035156 11.136719 94.964844 10.617188 95.082031 10.140625 C 95.289062 9.527344 95.746094 9.175781 96.300781 8.894531 C 96.941406 8.582031 97.644531 8.375 98.328125 8.179688 C 98.34375 8.175781 98.359375 8.171875 98.375 8.167969 C 98.472656 8.140625 98.566406 8.113281 98.664062 8.085938 C 98.695312 7.195312 98.695312 7.195312 98.328125 6.425781 C 98.121094 6.230469 97.828125 6.203125 97.558594 6.203125 C 97.53125 6.203125 97.53125 6.203125 97.503906 6.203125 C 97.339844 6.207031 97.171875 6.21875 97.007812 6.230469 C 97.003906 6.257812 97.003906 6.289062 97 6.316406 C 96.984375 6.46875 96.957031 6.617188 96.925781 6.765625 C 96.917969 6.816406 96.910156 6.863281 96.902344 6.910156 C 96.832031 7.273438 96.738281 7.585938 96.425781 7.808594 C 96.191406 7.933594 95.945312 7.933594 95.6875 7.867188 C 95.515625 7.808594 95.40625 7.707031 95.320312 7.546875 C 95.234375 7.347656 95.238281 7.183594 95.308594 6.980469 C 95.316406 6.957031 95.316406 6.957031 95.324219 6.929688 C 95.421875 6.644531 95.574219 6.441406 95.785156 6.230469 C 95.800781 6.214844 95.816406 6.195312 95.835938 6.179688 C 96.734375 5.308594 98.742188 5.21875 99.691406 6.011719 Z M 98.394531 8.742188 C 98.292969 8.777344 98.1875 8.8125 98.082031 8.847656 C 97.574219 9.007812 97.011719 9.230469 96.746094 9.722656 C 96.582031 10.042969 96.554688 10.355469 96.648438 10.703125 C 96.71875 10.914062 96.816406 11.042969 97.011719 11.152344 C 97.296875 11.292969 97.609375 11.304688 97.910156 11.199219 C 98.058594 11.132812 98.207031 11.050781 98.34375 10.960938 C 98.398438 10.921875 98.398438 10.921875 98.46875 10.890625 C 98.558594 10.839844 98.644531 10.789062 98.679688 10.683594 C 98.703125 10.542969 98.695312 10.402344 98.691406 10.257812 C 98.6875 10.214844 98.6875 10.167969 98.6875 10.121094 C 98.6875 10 98.683594 9.878906 98.683594 9.757812 C 98.679688 9.636719 98.679688 9.511719 98.675781 9.386719 C 98.675781 9.144531 98.667969 8.902344 98.664062 8.660156 C 98.578125 8.660156 98.476562 8.714844 98.394531 8.742188 Z M 98.394531 8.742188 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 38.035156 6.242188 C 38.207031 6.40625 38.332031 6.578125 38.449219 6.785156 C 38.460938 6.808594 38.460938 6.808594 38.472656 6.832031 C 38.835938 7.472656 38.875 8.257812 38.761719 8.972656 C 38.734375 9 38.734375 9 38.671875 9 C 38.625 9 38.625 9 38.578125 9 C 38.5625 9 38.546875 9 38.53125 9 C 38.472656 9 38.417969 9 38.363281 9 C 38.324219 9 38.285156 9 38.242188 9 C 38.136719 9 38.027344 9 37.917969 9 C 37.804688 9 37.695312 9 37.582031 9 C 37.367188 9 37.152344 9 36.9375 9 C 36.695312 9 36.453125 9 36.207031 9 C 35.707031 9 35.207031 9 34.703125 9 C 34.714844 9.089844 34.726562 9.183594 34.738281 9.273438 C 34.742188 9.300781 34.742188 9.328125 34.746094 9.351562 C 34.8125 9.898438 35.007812 10.441406 35.4375 10.808594 C 35.933594 11.1875 36.476562 11.269531 37.089844 11.203125 C 37.539062 11.128906 37.90625 10.847656 38.222656 10.535156 C 38.347656 10.417969 38.347656 10.417969 38.425781 10.417969 C 38.464844 10.445312 38.464844 10.445312 38.503906 10.488281 C 38.589844 10.585938 38.683594 10.671875 38.785156 10.753906 C 38.679688 11.046875 38.46875 11.28125 38.257812 11.5 C 38.242188 11.519531 38.222656 11.535156 38.207031 11.554688 C 37.792969 12 37.171875 12.246094 36.574219 12.320312 C 36.554688 12.320312 36.535156 12.324219 36.515625 12.328125 C 35.640625 12.425781 34.773438 12.210938 34.074219 11.671875 C 33.421875 11.125 33.078125 10.363281 32.976562 9.527344 C 32.972656 9.496094 32.972656 9.496094 32.96875 9.460938 C 32.871094 8.5 33.074219 7.515625 33.675781 6.746094 C 33.707031 6.710938 33.738281 6.675781 33.769531 6.640625 C 33.78125 6.621094 33.796875 6.605469 33.8125 6.585938 C 34.316406 5.988281 35.136719 5.640625 35.902344 5.566406 C 36.699219 5.511719 37.429688 5.699219 38.035156 6.242188 Z M 35.226562 6.652344 C 34.949219 7.007812 34.820312 7.386719 34.746094 7.824219 C 34.742188 7.851562 34.738281 7.875 34.734375 7.898438 C 34.730469 7.921875 34.726562 7.949219 34.722656 7.972656 C 34.71875 7.992188 34.714844 8.015625 34.710938 8.035156 C 34.703125 8.097656 34.703125 8.15625 34.703125 8.222656 C 34.703125 8.242188 34.703125 8.261719 34.703125 8.28125 C 34.703125 8.292969 34.703125 8.308594 34.703125 8.324219 C 34.972656 8.328125 35.242188 8.328125 35.507812 8.328125 C 35.632812 8.328125 35.757812 8.328125 35.882812 8.332031 C 36.003906 8.332031 36.125 8.332031 36.246094 8.332031 C 36.289062 8.332031 36.335938 8.332031 36.382812 8.332031 C 36.445312 8.332031 36.511719 8.332031 36.574219 8.332031 C 36.59375 8.332031 36.613281 8.332031 36.632812 8.332031 C 36.800781 8.332031 36.964844 8.304688 37.085938 8.183594 C 37.273438 7.9375 37.277344 7.609375 37.246094 7.3125 C 37.195312 6.96875 37.015625 6.636719 36.730469 6.425781 C 36.226562 6.113281 35.617188 6.195312 35.226562 6.652344 Z M 35.226562 6.652344 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 112.726562 6.085938 C 112.90625 6.242188 113.058594 6.414062 113.183594 6.617188 C 113.199219 6.636719 113.210938 6.65625 113.226562 6.679688 C 113.628906 7.320312 113.699219 8.167969 113.566406 8.902344 C 113.523438 8.945312 113.449219 8.929688 113.386719 8.929688 C 113.371094 8.929688 113.355469 8.929688 113.339844 8.929688 C 113.28125 8.929688 113.226562 8.929688 113.171875 8.929688 C 113.132812 8.929688 113.089844 8.933594 113.050781 8.933594 C 112.945312 8.933594 112.835938 8.933594 112.726562 8.933594 C 112.613281 8.933594 112.5 8.933594 112.386719 8.933594 C 112.175781 8.9375 111.960938 8.9375 111.746094 8.9375 C 111.503906 8.941406 111.257812 8.941406 111.015625 8.941406 C 110.515625 8.945312 110.011719 8.949219 109.511719 8.949219 C 109.519531 9.023438 109.527344 9.097656 109.535156 9.171875 C 109.535156 9.191406 109.539062 9.210938 109.539062 9.230469 C 109.554688 9.378906 109.578125 9.523438 109.613281 9.667969 C 109.621094 9.6875 109.625 9.710938 109.628906 9.730469 C 109.703125 10.011719 109.808594 10.261719 109.992188 10.488281 C 110.003906 10.507812 110.019531 10.527344 110.035156 10.542969 C 110.320312 10.898438 110.765625 11.117188 111.214844 11.164062 C 111.839844 11.203125 112.339844 11.078125 112.820312 10.671875 C 112.9375 10.570312 113.050781 10.457031 113.160156 10.347656 C 113.230469 10.378906 113.28125 10.414062 113.339844 10.46875 C 113.355469 10.480469 113.367188 10.496094 113.382812 10.507812 C 113.398438 10.523438 113.414062 10.539062 113.429688 10.554688 C 113.445312 10.566406 113.460938 10.582031 113.476562 10.597656 C 113.515625 10.632812 113.554688 10.671875 113.59375 10.707031 C 113.324219 11.316406 112.769531 11.816406 112.15625 12.066406 C 112.054688 12.105469 111.953125 12.136719 111.847656 12.171875 C 111.832031 12.175781 111.816406 12.179688 111.800781 12.183594 C 111.507812 12.265625 111.214844 12.28125 110.914062 12.28125 C 110.898438 12.28125 110.878906 12.28125 110.859375 12.28125 C 110.554688 12.277344 110.261719 12.257812 109.96875 12.175781 C 109.941406 12.167969 109.941406 12.167969 109.914062 12.160156 C 109.203125 11.953125 108.628906 11.503906 108.238281 10.875 C 108.230469 10.859375 108.222656 10.847656 108.210938 10.832031 C 107.699219 9.980469 107.648438 8.855469 107.878906 7.90625 C 108.074219 7.136719 108.570312 6.417969 109.253906 6 C 110.304688 5.378906 111.75 5.261719 112.726562 6.085938 Z M 110.105469 6.496094 C 109.710938 6.9375 109.507812 7.546875 109.511719 8.136719 C 109.511719 8.160156 109.511719 8.179688 109.511719 8.203125 C 109.511719 8.21875 109.511719 8.234375 109.511719 8.253906 C 109.78125 8.253906 110.050781 8.253906 110.316406 8.257812 C 110.441406 8.257812 110.566406 8.257812 110.691406 8.257812 C 110.8125 8.257812 110.933594 8.257812 111.054688 8.257812 C 111.097656 8.257812 111.144531 8.261719 111.191406 8.261719 C 111.253906 8.261719 111.320312 8.261719 111.382812 8.261719 C 111.402344 8.261719 111.421875 8.261719 111.441406 8.261719 C 111.59375 8.261719 111.746094 8.234375 111.871094 8.140625 C 112.082031 7.886719 112.078125 7.605469 112.054688 7.289062 C 112.011719 6.949219 111.867188 6.6875 111.625 6.449219 C 111.609375 6.433594 111.59375 6.417969 111.582031 6.40625 C 111.164062 6.015625 110.496094 6.121094 110.105469 6.496094 Z M 110.105469 6.496094 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 119.207031 6.039062 C 119.210938 6.308594 119.203125 6.578125 119.1875 6.847656 C 119.183594 6.910156 119.183594 6.972656 119.179688 7.035156 C 119.175781 7.078125 119.175781 7.117188 119.171875 7.160156 C 119.171875 7.175781 119.171875 7.195312 119.171875 7.214844 C 119.164062 7.308594 119.152344 7.390625 119.136719 7.484375 C 118.835938 7.484375 118.535156 7.484375 118.222656 7.484375 C 118.207031 7.40625 118.191406 7.328125 118.171875 7.246094 C 118.15625 7.171875 118.140625 7.097656 118.121094 7.023438 C 118.109375 6.96875 118.101562 6.917969 118.089844 6.867188 C 118.070312 6.792969 118.054688 6.714844 118.039062 6.640625 C 118.035156 6.617188 118.027344 6.59375 118.023438 6.570312 C 118.019531 6.550781 118.015625 6.527344 118.007812 6.503906 C 118.003906 6.484375 118 6.464844 117.996094 6.445312 C 117.984375 6.398438 117.984375 6.398438 117.960938 6.351562 C 117.902344 6.332031 117.847656 6.316406 117.789062 6.300781 C 117.765625 6.296875 117.765625 6.296875 117.738281 6.289062 C 117.339844 6.1875 116.835938 6.167969 116.464844 6.375 C 116.296875 6.480469 116.203125 6.609375 116.128906 6.789062 C 116.082031 7.042969 116.105469 7.261719 116.234375 7.484375 C 116.496094 7.828125 117.082031 7.953125 117.46875 8.070312 C 118.183594 8.289062 118.960938 8.597656 119.359375 9.277344 C 119.578125 9.714844 119.621094 10.257812 119.496094 10.734375 C 119.316406 11.277344 118.957031 11.703125 118.449219 11.964844 C 117.460938 12.445312 116.246094 12.394531 115.222656 12.054688 C 115.007812 11.972656 114.804688 11.867188 114.601562 11.765625 C 114.570312 11.234375 114.574219 10.707031 114.574219 10.175781 C 114.886719 10.175781 115.195312 10.175781 115.511719 10.175781 C 115.539062 10.304688 115.539062 10.304688 115.5625 10.433594 C 115.582031 10.515625 115.597656 10.597656 115.613281 10.679688 C 115.625 10.734375 115.636719 10.792969 115.648438 10.847656 C 115.664062 10.929688 115.679688 11.011719 115.695312 11.09375 C 115.703125 11.121094 115.707031 11.144531 115.710938 11.171875 C 115.71875 11.195312 115.722656 11.21875 115.726562 11.242188 C 115.730469 11.261719 115.734375 11.285156 115.738281 11.304688 C 115.75 11.355469 115.75 11.355469 115.777344 11.40625 C 116.324219 11.617188 117.03125 11.667969 117.578125 11.4375 C 117.800781 11.332031 117.949219 11.207031 118.039062 10.972656 C 118.089844 10.761719 118.082031 10.527344 117.992188 10.328125 C 117.910156 10.191406 117.820312 10.105469 117.6875 10.023438 C 117.664062 10.003906 117.636719 9.988281 117.609375 9.972656 C 117.265625 9.769531 116.875 9.65625 116.496094 9.527344 C 116.066406 9.386719 115.683594 9.222656 115.320312 8.949219 C 115.296875 8.933594 115.273438 8.917969 115.25 8.898438 C 115.226562 8.875 115.226562 8.875 115.199219 8.855469 C 115.199219 8.839844 115.199219 8.824219 115.199219 8.804688 C 115.1875 8.800781 115.171875 8.796875 115.160156 8.789062 C 114.933594 8.65625 114.792969 8.285156 114.726562 8.046875 C 114.605469 7.507812 114.6875 6.964844 114.984375 6.496094 C 115.347656 5.957031 115.902344 5.671875 116.523438 5.542969 C 117.460938 5.367188 118.386719 5.574219 119.207031 6.039062 Z M 119.207031 6.039062 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 67.945312 6.109375 C 67.96875 6.136719 67.96875 6.136719 67.96875 6.1875 C 67.96875 6.210938 67.96875 6.234375 67.964844 6.257812 C 67.964844 6.285156 67.964844 6.3125 67.964844 6.339844 C 67.960938 6.367188 67.960938 6.398438 67.960938 6.425781 C 67.960938 6.457031 67.957031 6.484375 67.957031 6.515625 C 67.941406 6.863281 67.917969 7.207031 67.894531 7.554688 C 67.59375 7.554688 67.292969 7.554688 66.984375 7.554688 C 66.921875 7.3125 66.863281 7.070312 66.808594 6.828125 C 66.804688 6.796875 66.796875 6.769531 66.789062 6.742188 C 66.785156 6.714844 66.777344 6.6875 66.773438 6.660156 C 66.765625 6.632812 66.761719 6.609375 66.753906 6.585938 C 66.742188 6.519531 66.742188 6.519531 66.742188 6.425781 C 66.707031 6.414062 66.667969 6.402344 66.628906 6.390625 C 66.605469 6.386719 66.585938 6.378906 66.5625 6.371094 C 66.355469 6.320312 66.15625 6.296875 65.941406 6.296875 C 65.917969 6.296875 65.894531 6.296875 65.871094 6.296875 C 65.5625 6.300781 65.296875 6.351562 65.0625 6.566406 C 64.894531 6.742188 64.859375 6.90625 64.863281 7.148438 C 64.867188 7.285156 64.890625 7.390625 64.96875 7.507812 C 64.976562 7.519531 64.984375 7.535156 64.996094 7.550781 C 65.261719 7.921875 65.914062 8.0625 66.328125 8.179688 C 67.054688 8.390625 67.703125 8.726562 68.089844 9.40625 C 68.214844 9.648438 68.289062 9.90625 68.304688 10.175781 C 68.304688 10.199219 68.304688 10.21875 68.308594 10.242188 C 68.324219 10.753906 68.15625 11.1875 67.824219 11.574219 C 67.808594 11.589844 67.796875 11.605469 67.78125 11.621094 C 67.28125 12.164062 66.515625 12.347656 65.808594 12.390625 C 65.144531 12.414062 64.535156 12.34375 63.910156 12.117188 C 63.886719 12.109375 63.886719 12.109375 63.859375 12.097656 C 63.675781 12.03125 63.507812 11.929688 63.335938 11.835938 C 63.335938 11.632812 63.335938 11.429688 63.335938 11.226562 C 63.335938 11.132812 63.335938 11.039062 63.335938 10.945312 C 63.332031 10.851562 63.332031 10.761719 63.332031 10.671875 C 63.332031 10.636719 63.332031 10.601562 63.332031 10.566406 C 63.332031 10.515625 63.332031 10.46875 63.332031 10.421875 C 63.332031 10.390625 63.332031 10.363281 63.332031 10.335938 C 63.335938 10.273438 63.335938 10.273438 63.359375 10.25 C 63.421875 10.246094 63.484375 10.246094 63.550781 10.246094 C 63.570312 10.246094 63.585938 10.246094 63.605469 10.246094 C 63.648438 10.246094 63.6875 10.246094 63.726562 10.246094 C 63.789062 10.246094 63.851562 10.246094 63.914062 10.246094 C 63.953125 10.246094 63.992188 10.246094 64.03125 10.246094 C 64.050781 10.246094 64.066406 10.246094 64.085938 10.246094 C 64.21875 10.246094 64.21875 10.246094 64.273438 10.273438 C 64.285156 10.316406 64.285156 10.316406 64.296875 10.375 C 64.300781 10.394531 64.304688 10.414062 64.308594 10.4375 C 64.316406 10.460938 64.320312 10.484375 64.324219 10.507812 C 64.328125 10.53125 64.332031 10.554688 64.339844 10.578125 C 64.347656 10.628906 64.359375 10.679688 64.367188 10.730469 C 64.382812 10.808594 64.398438 10.882812 64.414062 10.960938 C 64.421875 11.007812 64.433594 11.058594 64.441406 11.105469 C 64.445312 11.128906 64.453125 11.152344 64.457031 11.175781 C 64.476562 11.285156 64.492188 11.386719 64.488281 11.5 C 64.53125 11.511719 64.53125 11.511719 64.578125 11.519531 C 64.691406 11.546875 64.804688 11.574219 64.921875 11.605469 C 65.117188 11.648438 65.308594 11.648438 65.507812 11.652344 C 65.539062 11.652344 65.570312 11.652344 65.601562 11.652344 C 65.964844 11.652344 66.320312 11.59375 66.605469 11.359375 C 66.761719 11.199219 66.820312 11.003906 66.828125 10.789062 C 66.820312 10.566406 66.761719 10.382812 66.601562 10.226562 C 66.214844 9.933594 65.765625 9.789062 65.3125 9.640625 C 64.621094 9.414062 63.949219 9.125 63.59375 8.445312 C 63.378906 8 63.375 7.464844 63.53125 6.996094 C 63.761719 6.410156 64.183594 6.027344 64.753906 5.773438 C 65.792969 5.351562 66.988281 5.59375 67.945312 6.109375 Z M 67.945312 6.109375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 105.941406 5.769531 C 105.960938 5.777344 105.976562 5.785156 105.996094 5.792969 C 106.1875 5.867188 106.351562 5.964844 106.535156 6.0625 C 106.511719 6.539062 106.488281 7.015625 106.464844 7.507812 C 106.164062 7.507812 105.863281 7.507812 105.550781 7.507812 C 105.445312 7.101562 105.445312 7.101562 105.410156 6.941406 C 105.40625 6.925781 105.402344 6.910156 105.398438 6.890625 C 105.386719 6.839844 105.375 6.789062 105.367188 6.738281 C 105.359375 6.703125 105.351562 6.667969 105.34375 6.632812 C 105.324219 6.546875 105.304688 6.460938 105.289062 6.375 C 105.234375 6.359375 105.183594 6.34375 105.128906 6.328125 C 105.097656 6.320312 105.070312 6.3125 105.039062 6.304688 C 104.859375 6.253906 104.6875 6.25 104.503906 6.25 C 104.464844 6.25 104.464844 6.25 104.421875 6.25 C 104.136719 6.246094 103.90625 6.3125 103.664062 6.464844 C 103.507812 6.621094 103.417969 6.816406 103.414062 7.042969 C 103.425781 7.25 103.492188 7.433594 103.632812 7.585938 C 103.976562 7.886719 104.484375 8.003906 104.910156 8.132812 C 105.628906 8.351562 106.285156 8.667969 106.667969 9.355469 C 106.878906 9.800781 106.9375 10.371094 106.785156 10.84375 C 106.554688 11.417969 106.144531 11.8125 105.585938 12.070312 C 104.601562 12.488281 103.335938 12.402344 102.359375 12.007812 C 102.203125 11.9375 102.046875 11.859375 101.902344 11.765625 C 101.894531 11.699219 101.894531 11.699219 101.894531 11.617188 C 101.894531 11.585938 101.894531 11.554688 101.890625 11.523438 C 101.890625 11.488281 101.890625 11.453125 101.890625 11.417969 C 101.890625 11.382812 101.890625 11.347656 101.890625 11.3125 C 101.890625 11.222656 101.886719 11.128906 101.886719 11.039062 C 101.886719 10.925781 101.886719 10.816406 101.882812 10.707031 C 101.882812 10.539062 101.882812 10.371094 101.878906 10.203125 C 102.1875 10.203125 102.496094 10.203125 102.816406 10.203125 C 102.871094 10.363281 102.871094 10.363281 102.886719 10.449219 C 102.890625 10.46875 102.894531 10.488281 102.898438 10.507812 C 102.902344 10.527344 102.90625 10.546875 102.910156 10.566406 C 102.914062 10.585938 102.917969 10.609375 102.921875 10.628906 C 102.933594 10.671875 102.941406 10.71875 102.949219 10.761719 C 102.964844 10.828125 102.976562 10.894531 102.988281 10.960938 C 103 11.003906 103.007812 11.046875 103.015625 11.089844 C 103.019531 11.109375 103.023438 11.132812 103.027344 11.152344 C 103.046875 11.246094 103.0625 11.332031 103.054688 11.429688 C 103.699219 11.59375 104.421875 11.726562 105.03125 11.386719 C 105.21875 11.265625 105.316406 11.125 105.375 10.914062 C 105.402344 10.691406 105.378906 10.496094 105.273438 10.292969 C 104.921875 9.867188 104.363281 9.730469 103.859375 9.5625 C 103.1875 9.339844 102.511719 9.058594 102.167969 8.398438 C 101.949219 7.929688 101.9375 7.414062 102.097656 6.929688 C 102.101562 6.90625 102.109375 6.886719 102.117188 6.863281 C 102.269531 6.417969 102.628906 6.066406 103.03125 5.847656 C 103.054688 5.832031 103.078125 5.820312 103.101562 5.808594 C 103.382812 5.65625 103.699219 5.574219 104.015625 5.535156 C 104.035156 5.53125 104.054688 5.527344 104.074219 5.527344 C 104.714844 5.449219 105.34375 5.535156 105.941406 5.769531 Z M 105.941406 5.769531 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 59.953125 3.921875 C 60.316406 3.921875 60.679688 3.921875 61.054688 3.921875 C 61.058594 4.292969 61.054688 4.667969 61.046875 5.039062 C 61.042969 5.066406 61.042969 5.066406 61.042969 5.09375 C 61.042969 5.144531 61.042969 5.195312 61.039062 5.246094 C 61.039062 5.277344 61.039062 5.304688 61.035156 5.335938 C 61.03125 5.472656 61.019531 5.613281 61.007812 5.75 C 61.53125 5.75 62.054688 5.75 62.59375 5.75 C 62.59375 6.035156 62.59375 6.320312 62.59375 6.617188 C 62.0625 6.617188 61.53125 6.617188 60.984375 6.617188 C 60.984375 7.128906 60.988281 7.644531 60.988281 8.160156 C 60.992188 8.398438 60.992188 8.636719 60.992188 8.875 C 60.992188 9.082031 60.992188 9.292969 60.996094 9.5 C 60.996094 9.609375 60.996094 9.71875 60.996094 9.832031 C 60.996094 9.933594 60.996094 10.039062 60.996094 10.140625 C 60.996094 10.179688 60.996094 10.21875 60.996094 10.253906 C 60.992188 10.765625 60.992188 10.765625 61.199219 11.210938 C 61.34375 11.347656 61.507812 11.40625 61.703125 11.40625 C 61.941406 11.371094 62.144531 11.289062 62.355469 11.175781 C 62.457031 11.125 62.457031 11.125 62.519531 11.117188 C 62.558594 11.140625 62.558594 11.140625 62.597656 11.183594 C 62.613281 11.195312 62.625 11.210938 62.640625 11.226562 C 62.652344 11.238281 62.667969 11.253906 62.683594 11.269531 C 62.695312 11.285156 62.710938 11.300781 62.726562 11.316406 C 62.761719 11.351562 62.796875 11.390625 62.832031 11.429688 C 62.785156 11.5625 62.707031 11.65625 62.617188 11.765625 C 62.605469 11.78125 62.59375 11.792969 62.578125 11.808594 C 62.375 12.03125 62.085938 12.183594 61.800781 12.269531 C 61.777344 12.277344 61.75 12.285156 61.726562 12.292969 C 61.511719 12.347656 61.296875 12.351562 61.078125 12.351562 C 61.046875 12.351562 61.019531 12.351562 60.988281 12.351562 C 60.523438 12.351562 60.085938 12.210938 59.730469 11.898438 C 59.542969 11.699219 59.425781 11.40625 59.375 11.140625 C 59.371094 11.117188 59.367188 11.097656 59.363281 11.074219 C 59.351562 10.988281 59.347656 10.902344 59.347656 10.8125 C 59.347656 10.792969 59.347656 10.777344 59.347656 10.757812 C 59.347656 10.695312 59.347656 10.636719 59.347656 10.578125 C 59.347656 10.535156 59.347656 10.492188 59.347656 10.449219 C 59.347656 10.332031 59.347656 10.214844 59.347656 10.097656 C 59.351562 9.972656 59.351562 9.851562 59.351562 9.730469 C 59.351562 9.496094 59.351562 9.265625 59.351562 9.035156 C 59.351562 8.769531 59.351562 8.507812 59.351562 8.242188 C 59.351562 7.703125 59.351562 7.160156 59.351562 6.617188 C 59.035156 6.617188 58.71875 6.617188 58.390625 6.617188 C 58.390625 6.371094 58.390625 6.125 58.390625 5.871094 C 58.914062 5.800781 58.914062 5.800781 59.449219 5.726562 C 59.480469 5.601562 59.515625 5.476562 59.550781 5.351562 C 59.574219 5.269531 59.59375 5.191406 59.617188 5.113281 C 59.652344 4.988281 59.6875 4.863281 59.722656 4.738281 C 59.75 4.640625 59.777344 4.539062 59.804688 4.4375 C 59.816406 4.398438 59.824219 4.359375 59.835938 4.324219 C 59.851562 4.269531 59.867188 4.214844 59.882812 4.160156 C 59.886719 4.144531 59.890625 4.128906 59.894531 4.113281 C 59.914062 4.046875 59.929688 3.984375 59.953125 3.921875 Z M 59.953125 3.921875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 93.351562 5.554688 C 93.40625 5.59375 93.429688 5.617188 93.445312 5.679688 C 93.449219 5.75 93.445312 5.8125 93.441406 5.878906 C 93.441406 5.90625 93.441406 5.929688 93.441406 5.957031 C 93.4375 6.015625 93.4375 6.070312 93.433594 6.128906 C 93.429688 6.273438 93.425781 6.417969 93.421875 6.5625 C 93.417969 6.617188 93.417969 6.671875 93.417969 6.726562 C 93.402344 7.175781 93.40625 7.625 93.40625 8.074219 C 93.40625 8.195312 93.40625 8.3125 93.40625 8.429688 C 93.40625 8.644531 93.40625 8.859375 93.40625 9.074219 C 93.40625 9.320312 93.40625 9.570312 93.40625 9.816406 C 93.40625 10.320312 93.40625 10.828125 93.40625 11.332031 C 93.425781 11.335938 93.449219 11.339844 93.46875 11.34375 C 93.542969 11.355469 93.613281 11.371094 93.6875 11.382812 C 93.734375 11.390625 93.785156 11.398438 93.832031 11.40625 C 93.859375 11.414062 93.890625 11.417969 93.921875 11.425781 C 93.949219 11.429688 93.976562 11.433594 94.003906 11.4375 C 94.070312 11.449219 94.136719 11.464844 94.199219 11.476562 C 94.199219 11.675781 94.199219 11.875 94.199219 12.078125 C 93.105469 12.078125 92.015625 12.078125 90.886719 12.078125 C 90.886719 11.878906 90.886719 11.679688 90.886719 11.476562 C 90.988281 11.457031 91.085938 11.433594 91.1875 11.414062 C 91.222656 11.40625 91.253906 11.402344 91.289062 11.394531 C 91.339844 11.382812 91.386719 11.375 91.4375 11.363281 C 91.480469 11.355469 91.480469 11.355469 91.527344 11.34375 C 91.601562 11.332031 91.675781 11.332031 91.753906 11.332031 C 91.753906 10.894531 91.753906 10.457031 91.753906 10.023438 C 91.753906 9.820312 91.753906 9.617188 91.753906 9.414062 C 91.753906 9.234375 91.753906 9.058594 91.753906 8.882812 C 91.753906 8.789062 91.753906 8.695312 91.753906 8.601562 C 91.753906 8.066406 91.746094 7.535156 91.726562 7 C 91.683594 6.996094 91.683594 6.996094 91.636719 6.988281 C 91.539062 6.976562 91.4375 6.964844 91.339844 6.953125 C 91.296875 6.945312 91.25 6.941406 91.207031 6.933594 C 91.144531 6.925781 91.082031 6.917969 91.019531 6.910156 C 90.988281 6.90625 90.988281 6.90625 90.957031 6.902344 C 90.820312 6.882812 90.820312 6.882812 90.792969 6.855469 C 90.789062 6.816406 90.789062 6.777344 90.789062 6.738281 C 90.789062 6.714844 90.789062 6.691406 90.789062 6.667969 C 90.789062 6.640625 90.789062 6.617188 90.789062 6.589844 C 90.789062 6.566406 90.789062 6.539062 90.789062 6.515625 C 90.792969 6.453125 90.792969 6.390625 90.792969 6.328125 C 90.96875 6.253906 91.148438 6.1875 91.328125 6.125 C 91.355469 6.117188 91.382812 6.105469 91.414062 6.097656 C 91.503906 6.066406 91.59375 6.03125 91.683594 6 C 91.808594 5.957031 91.929688 5.914062 92.054688 5.871094 C 92.070312 5.867188 92.085938 5.859375 92.101562 5.855469 C 92.285156 5.792969 92.46875 5.726562 92.652344 5.660156 C 92.667969 5.652344 92.6875 5.644531 92.703125 5.640625 C 92.78125 5.609375 92.859375 5.582031 92.9375 5.554688 C 92.976562 5.539062 92.976562 5.539062 93.019531 5.523438 C 93.050781 5.511719 93.050781 5.511719 93.082031 5.5 C 93.1875 5.476562 93.261719 5.503906 93.351562 5.554688 Z M 93.351562 5.554688 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 42.214844 5.652344 C 42.214844 7.542969 42.214844 9.433594 42.214844 11.378906 C 42.535156 11.441406 42.535156 11.441406 42.863281 11.5 C 42.917969 11.515625 42.976562 11.53125 43.03125 11.550781 C 43.03125 11.738281 43.03125 11.929688 43.03125 12.125 C 41.929688 12.125 40.832031 12.125 39.695312 12.125 C 39.695312 11.9375 39.695312 11.746094 39.695312 11.550781 C 39.875 11.5 40.054688 11.460938 40.234375 11.425781 C 40.265625 11.417969 40.265625 11.417969 40.296875 11.410156 C 40.316406 11.40625 40.335938 11.402344 40.355469 11.398438 C 40.375 11.394531 40.394531 11.390625 40.410156 11.386719 C 40.46875 11.378906 40.523438 11.378906 40.585938 11.378906 C 40.582031 10.886719 40.578125 10.390625 40.574219 9.898438 C 40.574219 9.667969 40.574219 9.4375 40.570312 9.207031 C 40.570312 9.007812 40.570312 8.808594 40.570312 8.605469 C 40.566406 8.5 40.566406 8.394531 40.566406 8.289062 C 40.566406 8.191406 40.566406 8.089844 40.566406 7.988281 C 40.566406 7.953125 40.566406 7.917969 40.566406 7.878906 C 40.5625 7.683594 40.558594 7.488281 40.550781 7.292969 C 40.546875 7.273438 40.546875 7.253906 40.546875 7.234375 C 40.542969 7.140625 40.542969 7.140625 40.511719 7.050781 C 40.445312 7.035156 40.378906 7.027344 40.308594 7.019531 C 40.289062 7.015625 40.269531 7.011719 40.25 7.011719 C 40.183594 7.003906 40.121094 6.996094 40.054688 6.988281 C 40.011719 6.980469 39.96875 6.976562 39.921875 6.96875 C 39.816406 6.957031 39.707031 6.941406 39.601562 6.929688 C 39.601562 6.746094 39.601562 6.5625 39.601562 6.375 C 39.964844 6.242188 40.328125 6.109375 40.695312 5.980469 C 40.777344 5.953125 40.859375 5.921875 40.945312 5.894531 C 41 5.875 41.054688 5.855469 41.109375 5.835938 C 41.246094 5.789062 41.386719 5.738281 41.523438 5.6875 C 41.550781 5.675781 41.578125 5.667969 41.605469 5.65625 C 41.660156 5.636719 41.710938 5.617188 41.761719 5.597656 C 41.785156 5.589844 41.808594 5.578125 41.835938 5.570312 C 41.863281 5.558594 41.863281 5.558594 41.894531 5.546875 C 42.027344 5.515625 42.09375 5.585938 42.214844 5.652344 Z M 42.214844 5.652344 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 8.640625 9.261719 C 8.972656 9.519531 9.191406 9.859375 9.277344 10.273438 C 9.328125 10.675781 9.265625 11.089844 9.019531 11.421875 C 8.734375 11.769531 8.371094 12.007812 7.917969 12.058594 C 7.476562 12.09375 7.078125 11.957031 6.742188 11.667969 C 6.71875 11.648438 6.71875 11.648438 6.695312 11.628906 C 6.421875 11.378906 6.261719 10.992188 6.234375 10.628906 C 6.226562 10.179688 6.355469 9.789062 6.664062 9.457031 C 7.191406 8.921875 8.019531 8.84375 8.640625 9.261719 Z M 8.640625 9.261719 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 2.855469 4.089844 C 2.941406 4.15625 3.019531 4.230469 3.097656 4.308594 C 3.113281 4.324219 3.128906 4.339844 3.148438 4.359375 C 3.414062 4.640625 3.542969 5.027344 3.539062 5.410156 C 3.519531 5.851562 3.332031 6.21875 3.015625 6.527344 C 2.707031 6.792969 2.304688 6.921875 1.898438 6.898438 C 1.578125 6.871094 1.308594 6.769531 1.054688 6.570312 C 1.03125 6.546875 1.03125 6.546875 1.003906 6.527344 C 0.699219 6.277344 0.527344 5.898438 0.484375 5.511719 C 0.453125 5.121094 0.558594 4.730469 0.804688 4.425781 C 1.003906 4.191406 1.226562 4.03125 1.511719 3.921875 C 1.53125 3.914062 1.550781 3.90625 1.570312 3.898438 C 1.988281 3.757812 2.496094 3.84375 2.855469 4.089844 Z M 2.855469 4.089844 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 2.960938 11.683594 C 3.269531 11.949219 3.492188 12.316406 3.53125 12.726562 C 3.558594 13.152344 3.449219 13.550781 3.171875 13.878906 C 2.875 14.203125 2.519531 14.375 2.082031 14.417969 C 1.671875 14.433594 1.28125 14.28125 0.972656 14.011719 C 0.660156 13.714844 0.488281 13.324219 0.476562 12.890625 C 0.480469 12.53125 0.59375 12.214844 0.816406 11.933594 C 0.828125 11.917969 0.839844 11.902344 0.851562 11.882812 C 1.078125 11.597656 1.433594 11.421875 1.785156 11.363281 C 2.207031 11.316406 2.628906 11.417969 2.960938 11.683594 Z M 2.960938 11.683594 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 14.449219 4.167969 C 14.507812 4.222656 14.5625 4.273438 14.617188 4.332031 C 14.628906 4.34375 14.640625 4.355469 14.65625 4.367188 C 14.914062 4.632812 15.015625 5.023438 15.03125 5.378906 C 15.019531 5.734375 14.902344 6.046875 14.6875 6.328125 C 14.675781 6.34375 14.664062 6.359375 14.652344 6.378906 C 14.410156 6.679688 14.042969 6.851562 13.664062 6.898438 C 13.242188 6.925781 12.84375 6.816406 12.523438 6.535156 C 12.484375 6.5 12.445312 6.460938 12.40625 6.425781 C 12.394531 6.410156 12.378906 6.394531 12.363281 6.378906 C 12.085938 6.089844 11.988281 5.707031 11.992188 5.316406 C 12.003906 4.914062 12.167969 4.53125 12.457031 4.25 C 13.023438 3.75 13.847656 3.714844 14.449219 4.167969 Z M 14.449219 4.167969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 42.046875 2.648438 C 42.253906 2.816406 42.375 3.03125 42.40625 3.296875 C 42.433594 3.558594 42.351562 3.808594 42.191406 4.019531 C 42.007812 4.214844 41.785156 4.351562 41.507812 4.363281 C 41.46875 4.363281 41.429688 4.363281 41.390625 4.363281 C 41.371094 4.363281 41.351562 4.363281 41.332031 4.363281 C 41.058594 4.355469 40.832031 4.273438 40.625 4.089844 C 40.476562 3.933594 40.359375 3.734375 40.34375 3.511719 C 40.34375 3.496094 40.339844 3.480469 40.339844 3.460938 C 40.328125 3.230469 40.390625 2.992188 40.542969 2.8125 C 40.554688 2.796875 40.570312 2.78125 40.585938 2.765625 C 40.597656 2.75 40.613281 2.734375 40.632812 2.714844 C 41.019531 2.339844 41.621094 2.332031 42.046875 2.648438 Z M 42.046875 2.648438 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 93.210938 2.566406 C 93.453125 2.757812 93.570312 2.96875 93.609375 3.273438 C 93.621094 3.53125 93.550781 3.773438 93.378906 3.972656 C 93.367188 3.988281 93.351562 4.003906 93.335938 4.019531 C 93.316406 4.039062 93.316406 4.039062 93.296875 4.058594 C 93.066406 4.28125 92.78125 4.316406 92.476562 4.3125 C 92.355469 4.308594 92.25 4.285156 92.136719 4.234375 C 92.117188 4.226562 92.101562 4.21875 92.082031 4.210938 C 91.871094 4.105469 91.703125 3.9375 91.605469 3.722656 C 91.515625 3.449219 91.515625 3.171875 91.632812 2.90625 C 91.773438 2.652344 92 2.484375 92.277344 2.402344 C 92.605469 2.324219 92.933594 2.375 93.210938 2.566406 Z M 93.210938 2.566406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 8.320312 5.960938 C 8.539062 6.117188 8.664062 6.320312 8.726562 6.582031 C 8.769531 6.839844 8.710938 7.089844 8.574219 7.3125 C 8.410156 7.535156 8.207031 7.65625 7.945312 7.722656 C 7.621094 7.753906 7.355469 7.6875 7.105469 7.484375 C 6.921875 7.3125 6.8125 7.078125 6.792969 6.832031 C 6.789062 6.535156 6.871094 6.28125 7.078125 6.0625 C 7.4375 5.738281 7.914062 5.710938 8.320312 5.960938 Z M 8.320312 5.960938 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.431373%,73.725492%,19.607843%);fill-opacity:1;" d="M 14.09375 0.820312 C 14.289062 0.96875 14.421875 1.179688 14.472656 1.417969 C 14.5 1.714844 14.464844 1.980469 14.273438 2.214844 C 14.082031 2.421875 13.890625 2.558594 13.605469 2.582031 C 13.320312 2.585938 13.078125 2.535156 12.863281 2.332031 C 12.660156 2.128906 12.550781 1.910156 12.542969 1.621094 C 12.546875 1.332031 12.644531 1.117188 12.839844 0.910156 C 13.199219 0.574219 13.6875 0.5625 14.09375 0.820312 Z M 14.09375 0.820312 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 2.574219 0.808594 C 2.769531 0.972656 2.925781 1.164062 2.976562 1.417969 C 2.996094 1.71875 2.972656 1.976562 2.777344 2.214844 C 2.585938 2.421875 2.394531 2.558594 2.109375 2.582031 C 1.824219 2.585938 1.582031 2.53125 1.367188 2.332031 C 1.226562 2.195312 1.136719 2.066406 1.078125 1.875 C 1.074219 1.863281 1.070312 1.847656 1.066406 1.832031 C 1.015625 1.570312 1.054688 1.3125 1.195312 1.089844 C 1.515625 0.644531 2.101562 0.484375 2.574219 0.808594 Z M 2.574219 0.808594 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 2.550781 8.316406 C 2.582031 8.34375 2.609375 8.371094 2.640625 8.398438 C 2.65625 8.414062 2.671875 8.429688 2.691406 8.445312 C 2.878906 8.640625 2.960938 8.847656 2.964844 9.121094 C 2.960938 9.398438 2.882812 9.613281 2.6875 9.816406 C 2.5 9.996094 2.257812 10.109375 1.992188 10.105469 C 1.695312 10.085938 1.449219 9.972656 1.246094 9.753906 C 1.074219 9.535156 1.003906 9.277344 1.03125 9 C 1.089844 8.710938 1.214844 8.484375 1.453125 8.3125 C 1.789062 8.105469 2.222656 8.085938 2.550781 8.316406 Z M 2.550781 8.316406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 14.058594 8.34375 C 14.269531 8.496094 14.425781 8.714844 14.472656 8.972656 C 14.496094 9.300781 14.441406 9.542969 14.238281 9.804688 C 14.148438 9.90625 14.042969 9.972656 13.921875 10.03125 C 13.894531 10.046875 13.894531 10.046875 13.867188 10.058594 C 13.660156 10.144531 13.386719 10.136719 13.175781 10.066406 C 12.929688 9.960938 12.714844 9.769531 12.613281 9.519531 C 12.601562 9.484375 12.585938 9.445312 12.574219 9.40625 C 12.570312 9.390625 12.566406 9.378906 12.5625 9.363281 C 12.511719 9.109375 12.550781 8.855469 12.679688 8.632812 C 12.824219 8.421875 13.003906 8.277344 13.246094 8.203125 C 13.261719 8.199219 13.277344 8.195312 13.292969 8.191406 C 13.570312 8.136719 13.820312 8.195312 14.058594 8.34375 Z M 14.058594 8.34375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 8.375 13.523438 C 8.605469 13.730469 8.71875 13.984375 8.742188 14.289062 C 8.734375 14.554688 8.621094 14.789062 8.445312 14.984375 C 8.25 15.164062 7.996094 15.25 7.734375 15.253906 C 7.46875 15.242188 7.25 15.136719 7.0625 14.953125 C 6.863281 14.730469 6.789062 14.488281 6.792969 14.195312 C 6.832031 13.894531 6.964844 13.664062 7.199219 13.472656 C 7.582031 13.230469 8.015625 13.25 8.375 13.523438 Z M 8.375 13.523438 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 14.027344 12.066406 C 14.25 12.234375 14.421875 12.449219 14.472656 12.726562 C 14.492188 13.019531 14.464844 13.269531 14.273438 13.5 C 14.089844 13.699219 13.886719 13.84375 13.609375 13.863281 C 13.3125 13.867188 13.058594 13.800781 12.832031 13.589844 C 12.730469 13.480469 12.65625 13.371094 12.601562 13.234375 C 12.589844 13.207031 12.582031 13.183594 12.570312 13.15625 C 12.519531 12.886719 12.539062 12.625 12.679688 12.386719 C 12.984375 11.945312 13.558594 11.765625 14.027344 12.066406 Z M 14.027344 12.066406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 8.269531 2.203125 C 8.492188 2.371094 8.652344 2.574219 8.703125 2.855469 C 8.738281 3.113281 8.695312 3.371094 8.535156 3.582031 C 8.355469 3.796875 8.136719 3.949219 7.851562 3.976562 C 7.539062 3.988281 7.289062 3.894531 7.054688 3.679688 C 6.851562 3.449219 6.796875 3.222656 6.808594 2.914062 C 6.824219 2.671875 6.929688 2.480469 7.105469 2.308594 C 7.445312 2.039062 7.886719 1.964844 8.269531 2.203125 Z M 8.269531 2.203125 "/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/public/tracing/weave-icon.svg b/app/components/base/icons/assets/public/tracing/weave-icon.svg
new file mode 100644
index 0000000..62e6067
--- /dev/null
+++ b/app/components/base/icons/assets/public/tracing/weave-icon.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="120px" height="16px" viewBox="0 0 120 16" version="1.1">
+<g id="surface1">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 20.847656 3.292969 C 20.875 3.292969 20.902344 3.292969 20.933594 3.292969 C 20.949219 3.292969 20.964844 3.292969 20.980469 3.292969 C 21.035156 3.292969 21.089844 3.292969 21.140625 3.292969 C 21.179688 3.292969 21.21875 3.292969 21.253906 3.292969 C 21.359375 3.292969 21.464844 3.292969 21.566406 3.292969 C 21.675781 3.292969 21.78125 3.292969 21.890625 3.292969 C 22.097656 3.292969 22.300781 3.292969 22.507812 3.292969 C 22.738281 3.292969 22.972656 3.292969 23.207031 3.296875 C 23.6875 3.296875 24.167969 3.296875 24.648438 3.296875 C 24.648438 3.519531 24.648438 3.742188 24.648438 3.96875 C 24.113281 4.042969 24.113281 4.042969 23.566406 4.113281 C 23.667969 4.496094 23.769531 4.882812 23.867188 5.265625 C 23.878906 5.308594 23.878906 5.308594 23.890625 5.351562 C 24.128906 6.269531 24.371094 7.183594 24.609375 8.097656 C 24.675781 8.339844 24.738281 8.582031 24.800781 8.824219 C 24.816406 8.878906 24.832031 8.933594 24.84375 8.992188 C 24.867188 9.078125 24.890625 9.167969 24.914062 9.257812 C 24.921875 9.289062 24.933594 9.320312 24.941406 9.355469 C 24.953125 9.398438 24.964844 9.441406 24.976562 9.484375 C 24.984375 9.523438 24.984375 9.523438 24.996094 9.558594 C 25.007812 9.625 25.007812 9.625 25.007812 9.71875 C 25.023438 9.71875 25.039062 9.71875 25.054688 9.71875 C 25.058594 9.707031 25.058594 9.695312 25.0625 9.679688 C 25.097656 9.492188 25.152344 9.3125 25.210938 9.128906 C 25.222656 9.097656 25.234375 9.0625 25.246094 9.027344 C 25.269531 8.953125 25.292969 8.882812 25.316406 8.808594 C 25.355469 8.691406 25.390625 8.574219 25.429688 8.457031 C 25.464844 8.339844 25.503906 8.21875 25.542969 8.097656 C 25.660156 7.738281 25.773438 7.375 25.890625 7.011719 C 25.902344 6.96875 25.917969 6.921875 25.933594 6.875 C 26.226562 5.945312 26.519531 5.019531 26.808594 4.089844 C 26.785156 4.089844 26.765625 4.089844 26.742188 4.085938 C 26.507812 4.074219 26.273438 4.046875 26.042969 4.015625 C 26.007812 4.011719 25.972656 4.007812 25.933594 4.003906 C 25.851562 3.992188 25.765625 3.980469 25.679688 3.96875 C 25.679688 3.746094 25.679688 3.523438 25.679688 3.296875 C 26.175781 3.296875 26.667969 3.296875 27.160156 3.296875 C 27.390625 3.292969 27.621094 3.292969 27.851562 3.292969 C 28.050781 3.292969 28.25 3.292969 28.449219 3.292969 C 28.554688 3.292969 28.660156 3.292969 28.765625 3.292969 C 28.867188 3.292969 28.964844 3.292969 29.066406 3.292969 C 29.101562 3.292969 29.140625 3.292969 29.175781 3.292969 C 29.226562 3.292969 29.273438 3.292969 29.324219 3.292969 C 29.367188 3.292969 29.367188 3.292969 29.410156 3.292969 C 29.472656 3.296875 29.472656 3.296875 29.496094 3.320312 C 29.5 3.367188 29.5 3.417969 29.5 3.464844 C 29.5 3.492188 29.5 3.515625 29.5 3.542969 C 29.496094 3.59375 29.496094 3.59375 29.496094 3.648438 C 29.496094 3.753906 29.496094 3.859375 29.496094 3.96875 C 29.09375 4.015625 28.6875 4.066406 28.273438 4.113281 C 28.679688 5.460938 28.679688 5.460938 29.089844 6.808594 C 29.105469 6.859375 29.121094 6.910156 29.136719 6.960938 C 29.234375 7.292969 29.335938 7.625 29.4375 7.960938 C 29.484375 8.113281 29.53125 8.265625 29.578125 8.417969 C 29.605469 8.507812 29.632812 8.597656 29.660156 8.691406 C 29.878906 9.40625 29.878906 9.40625 29.976562 9.746094 C 30.027344 9.664062 30.046875 9.601562 30.070312 9.507812 C 30.078125 9.484375 30.078125 9.484375 30.085938 9.457031 C 30.101562 9.402344 30.117188 9.34375 30.132812 9.289062 C 30.144531 9.25 30.152344 9.207031 30.164062 9.167969 C 30.1875 9.082031 30.214844 8.992188 30.238281 8.90625 C 30.292969 8.691406 30.351562 8.480469 30.410156 8.269531 C 30.433594 8.191406 30.453125 8.117188 30.472656 8.042969 C 30.621094 7.5 30.769531 6.960938 30.921875 6.421875 C 30.949219 6.324219 30.976562 6.226562 31 6.128906 C 31.066406 5.902344 31.128906 5.675781 31.191406 5.449219 C 31.230469 5.308594 31.269531 5.164062 31.308594 5.023438 C 31.335938 4.925781 31.363281 4.828125 31.390625 4.734375 C 31.402344 4.6875 31.414062 4.640625 31.429688 4.59375 C 31.445312 4.53125 31.464844 4.46875 31.480469 4.40625 C 31.488281 4.386719 31.492188 4.367188 31.496094 4.347656 C 31.515625 4.277344 31.535156 4.207031 31.558594 4.136719 C 31.210938 4.074219 30.855469 4.023438 30.503906 3.96875 C 30.503906 3.746094 30.503906 3.523438 30.503906 3.296875 C 30.878906 3.296875 31.253906 3.296875 31.628906 3.296875 C 31.804688 3.292969 31.976562 3.292969 32.152344 3.292969 C 32.304688 3.292969 32.457031 3.292969 32.605469 3.292969 C 32.6875 3.292969 32.769531 3.292969 32.847656 3.292969 C 32.9375 3.292969 33.027344 3.292969 33.117188 3.292969 C 33.144531 3.292969 33.171875 3.292969 33.199219 3.292969 C 33.222656 3.292969 33.246094 3.292969 33.273438 3.292969 C 33.304688 3.292969 33.304688 3.292969 33.335938 3.292969 C 33.382812 3.296875 33.382812 3.296875 33.40625 3.320312 C 33.410156 3.367188 33.410156 3.414062 33.410156 3.460938 C 33.410156 3.488281 33.410156 3.515625 33.410156 3.542969 C 33.410156 3.574219 33.410156 3.605469 33.410156 3.632812 C 33.410156 3.664062 33.410156 3.695312 33.410156 3.726562 C 33.410156 3.796875 33.410156 3.871094 33.40625 3.945312 C 33.292969 3.964844 33.175781 3.984375 33.0625 4.007812 C 33.023438 4.011719 32.984375 4.019531 32.945312 4.027344 C 32.738281 4.0625 32.535156 4.097656 32.328125 4.113281 C 32.320312 4.144531 32.320312 4.144531 32.3125 4.179688 C 32.238281 4.480469 32.15625 4.78125 32.070312 5.082031 C 32.058594 5.128906 32.042969 5.171875 32.03125 5.21875 C 31.875 5.78125 31.714844 6.347656 31.550781 6.910156 C 31.375 7.535156 31.195312 8.160156 31.019531 8.785156 C 30.992188 8.871094 30.96875 8.957031 30.945312 9.042969 C 30.835938 9.433594 30.722656 9.820312 30.613281 10.210938 C 30.566406 10.378906 30.519531 10.542969 30.472656 10.707031 C 30.445312 10.804688 30.417969 10.902344 30.390625 11 C 30.277344 11.390625 30.167969 11.785156 30.046875 12.175781 C 29.730469 12.175781 29.414062 12.175781 29.089844 12.175781 C 29.03125 12.003906 29.03125 12.003906 28.976562 11.832031 C 28.925781 11.675781 28.878906 11.523438 28.828125 11.367188 C 28.820312 11.347656 28.8125 11.328125 28.808594 11.304688 C 28.632812 10.769531 28.460938 10.230469 28.285156 9.695312 C 28.144531 9.273438 28.007812 8.847656 27.875 8.425781 C 27.695312 7.867188 27.515625 7.308594 27.332031 6.753906 C 27.304688 6.679688 27.28125 6.605469 27.257812 6.53125 C 27.238281 6.476562 27.222656 6.425781 27.207031 6.375 C 27.046875 5.894531 27.046875 5.894531 27.046875 5.796875 C 27.03125 5.796875 27.015625 5.796875 27 5.796875 C 26.996094 5.8125 26.996094 5.828125 26.992188 5.84375 C 26.964844 5.988281 26.925781 6.132812 26.882812 6.273438 C 26.875 6.296875 26.867188 6.316406 26.859375 6.339844 C 26.84375 6.390625 26.828125 6.4375 26.8125 6.488281 C 26.769531 6.625 26.726562 6.761719 26.683594 6.898438 C 26.675781 6.929688 26.664062 6.957031 26.65625 6.988281 C 26.546875 7.328125 26.445312 7.667969 26.339844 8.007812 C 26.316406 8.078125 26.296875 8.144531 26.273438 8.214844 C 26.230469 8.355469 26.1875 8.496094 26.144531 8.636719 C 26.074219 8.863281 26.007812 9.089844 25.9375 9.3125 C 25.933594 9.328125 25.925781 9.347656 25.921875 9.363281 C 25.894531 9.449219 25.871094 9.535156 25.84375 9.617188 C 25.796875 9.769531 25.75 9.921875 25.703125 10.074219 C 25.675781 10.15625 25.652344 10.242188 25.625 10.328125 C 25.613281 10.363281 25.605469 10.394531 25.59375 10.429688 C 25.414062 11.011719 25.234375 11.59375 25.054688 12.175781 C 24.738281 12.175781 24.421875 12.175781 24.097656 12.175781 C 23.816406 11.230469 23.535156 10.285156 23.261719 9.339844 C 23.253906 9.320312 23.25 9.304688 23.246094 9.285156 C 23.195312 9.117188 23.144531 8.949219 23.097656 8.78125 C 22.960938 8.3125 22.824219 7.84375 22.6875 7.375 C 22.664062 7.304688 22.644531 7.234375 22.625 7.164062 C 22.414062 6.449219 22.207031 5.738281 22 5.027344 C 21.976562 4.953125 21.953125 4.878906 21.933594 4.804688 C 21.898438 4.683594 21.859375 4.5625 21.824219 4.441406 C 21.820312 4.421875 21.8125 4.402344 21.808594 4.382812 C 21.796875 4.347656 21.785156 4.3125 21.777344 4.28125 C 21.753906 4.203125 21.742188 4.148438 21.742188 4.066406 C 21.726562 4.066406 21.710938 4.0625 21.691406 4.0625 C 21.382812 4.042969 21.070312 4.003906 20.761719 3.96875 C 20.757812 3.863281 20.757812 3.753906 20.757812 3.648438 C 20.757812 3.617188 20.757812 3.585938 20.757812 3.554688 C 20.757812 3.523438 20.757812 3.496094 20.757812 3.464844 C 20.757812 3.4375 20.757812 3.410156 20.757812 3.382812 C 20.761719 3.296875 20.761719 3.296875 20.847656 3.292969 Z M 20.847656 3.292969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 82.488281 3.25 C 83.046875 3.246094 83.605469 3.246094 84.167969 3.246094 C 84.425781 3.246094 84.6875 3.246094 84.945312 3.246094 C 85.171875 3.242188 85.398438 3.242188 85.625 3.242188 C 85.746094 3.242188 85.867188 3.242188 85.984375 3.242188 C 88.15625 3.238281 88.15625 3.238281 88.894531 3.898438 C 88.914062 3.914062 88.9375 3.929688 88.957031 3.945312 C 89.191406 4.144531 89.363281 4.402344 89.472656 4.691406 C 89.480469 4.714844 89.492188 4.742188 89.5 4.765625 C 89.65625 5.25 89.601562 5.785156 89.382812 6.234375 C 89.117188 6.753906 88.695312 7.078125 88.152344 7.265625 C 87.984375 7.320312 87.816406 7.367188 87.648438 7.410156 C 87.664062 7.414062 87.679688 7.417969 87.699219 7.421875 C 88.523438 7.605469 89.300781 7.851562 89.78125 8.597656 C 90.0625 9.0625 90.125 9.636719 90.003906 10.164062 C 89.808594 10.804688 89.363281 11.304688 88.78125 11.621094 C 88.324219 11.863281 87.820312 11.988281 87.3125 12.054688 C 87.28125 12.058594 87.253906 12.0625 87.222656 12.066406 C 86.777344 12.121094 86.332031 12.109375 85.882812 12.105469 C 85.765625 12.105469 85.644531 12.105469 85.523438 12.105469 C 85.300781 12.105469 85.074219 12.105469 84.847656 12.105469 C 84.589844 12.105469 84.332031 12.105469 84.074219 12.105469 C 83.546875 12.105469 83.015625 12.101562 82.488281 12.101562 C 82.488281 11.878906 82.488281 11.65625 82.488281 11.429688 C 82.859375 11.390625 83.234375 11.347656 83.617188 11.308594 C 83.617188 8.910156 83.617188 6.511719 83.617188 4.042969 C 83.488281 4.035156 83.363281 4.027344 83.230469 4.019531 C 83.117188 4.007812 83.003906 3.996094 82.890625 3.980469 C 82.863281 3.980469 82.832031 3.976562 82.804688 3.972656 C 82.695312 3.960938 82.59375 3.949219 82.488281 3.921875 C 82.488281 3.699219 82.488281 3.476562 82.488281 3.25 Z M 85.390625 3.96875 C 85.390625 4.242188 85.386719 4.515625 85.382812 4.785156 C 85.382812 4.914062 85.378906 5.039062 85.378906 5.164062 C 85.371094 5.824219 85.367188 6.484375 85.367188 7.144531 C 86.488281 7.183594 86.488281 7.183594 87.457031 6.691406 C 87.796875 6.320312 87.859375 5.832031 87.847656 5.351562 C 87.832031 4.992188 87.71875 4.644531 87.460938 4.378906 C 87 3.96875 86.363281 3.964844 85.78125 3.96875 C 85.742188 3.96875 85.703125 3.96875 85.667969 3.96875 C 85.574219 3.96875 85.484375 3.96875 85.390625 3.96875 Z M 85.390625 7.84375 C 85.390625 9.003906 85.390625 10.160156 85.390625 11.355469 C 86.28125 11.386719 86.28125 11.386719 87.152344 11.21875 C 87.171875 11.214844 87.1875 11.207031 87.207031 11.199219 C 87.578125 11.066406 87.886719 10.824219 88.066406 10.46875 C 88.28125 9.988281 88.289062 9.417969 88.125 8.921875 C 87.960938 8.492188 87.664062 8.234375 87.257812 8.046875 C 86.664062 7.804688 86.023438 7.84375 85.390625 7.84375 Z M 85.390625 7.84375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 76.167969 3.476562 C 76.367188 3.671875 76.507812 3.917969 76.585938 4.1875 C 76.589844 4.203125 76.59375 4.222656 76.601562 4.242188 C 76.707031 4.675781 76.621094 5.144531 76.414062 5.53125 C 76.34375 5.644531 76.265625 5.746094 76.175781 5.847656 C 76.15625 5.867188 76.136719 5.886719 76.117188 5.910156 C 75.71875 6.332031 75.199219 6.617188 74.6875 6.882812 C 74.707031 6.902344 74.726562 6.921875 74.746094 6.941406 C 74.972656 7.191406 74.972656 7.191406 75.066406 7.296875 C 75.140625 7.382812 75.21875 7.464844 75.300781 7.542969 C 75.351562 7.59375 75.394531 7.640625 75.4375 7.695312 C 75.527344 7.796875 75.621094 7.894531 75.714844 7.992188 C 76.089844 8.394531 76.089844 8.394531 76.253906 8.585938 C 76.351562 8.695312 76.449219 8.800781 76.546875 8.90625 C 76.621094 8.980469 76.691406 9.058594 76.761719 9.136719 C 76.773438 9.152344 76.789062 9.164062 76.800781 9.179688 C 76.824219 9.207031 76.851562 9.234375 76.875 9.261719 C 76.933594 9.324219 76.992188 9.382812 77.0625 9.429688 C 77.070312 9.410156 77.070312 9.410156 77.082031 9.386719 C 77.113281 9.304688 77.152344 9.230469 77.195312 9.15625 C 77.5625 8.476562 77.800781 7.753906 77.976562 7 C 77.953125 7 77.933594 6.996094 77.910156 6.996094 C 77.707031 6.96875 77.5 6.9375 77.296875 6.902344 C 77.273438 6.898438 77.25 6.894531 77.222656 6.890625 C 77.050781 6.859375 77.050781 6.859375 76.96875 6.832031 C 76.960938 6.328125 76.960938 6.328125 77.015625 6.160156 C 77.949219 6.160156 78.886719 6.160156 79.847656 6.160156 C 79.847656 6.367188 79.847656 6.574219 79.847656 6.785156 C 79.53125 6.839844 79.214844 6.894531 78.886719 6.953125 C 78.859375 7.046875 78.832031 7.140625 78.804688 7.234375 C 78.539062 8.09375 78.164062 9.035156 77.601562 9.746094 C 77.5625 9.792969 77.5625 9.792969 77.566406 9.851562 C 77.601562 9.933594 77.648438 9.980469 77.714844 10.039062 C 77.792969 10.113281 77.867188 10.1875 77.9375 10.269531 C 78.027344 10.375 78.125 10.46875 78.222656 10.566406 C 78.308594 10.65625 78.390625 10.742188 78.472656 10.839844 C 78.539062 10.914062 78.601562 10.933594 78.695312 10.949219 C 78.71875 10.953125 78.746094 10.957031 78.769531 10.960938 C 78.796875 10.964844 78.824219 10.96875 78.851562 10.972656 C 78.875 10.980469 78.902344 10.984375 78.933594 10.988281 C 79.019531 11.003906 79.105469 11.019531 79.191406 11.03125 C 79.277344 11.046875 79.363281 11.0625 79.449219 11.078125 C 79.503906 11.085938 79.558594 11.097656 79.613281 11.105469 C 79.648438 11.113281 79.648438 11.113281 79.6875 11.117188 C 79.707031 11.121094 79.730469 11.125 79.75 11.128906 C 79.800781 11.140625 79.800781 11.140625 79.824219 11.164062 C 79.820312 11.421875 79.785156 11.679688 79.753906 11.933594 C 79.691406 11.949219 79.632812 11.964844 79.570312 11.980469 C 79.546875 11.984375 79.546875 11.984375 79.519531 11.992188 C 79.214844 12.066406 78.910156 12.085938 78.597656 12.085938 C 78.539062 12.085938 78.484375 12.085938 78.425781 12.085938 C 77.847656 12.089844 77.332031 11.917969 76.894531 11.523438 C 76.855469 11.484375 76.816406 11.445312 76.777344 11.40625 C 76.71875 11.347656 76.660156 11.296875 76.601562 11.242188 C 76.578125 11.21875 76.578125 11.21875 76.554688 11.195312 C 76.515625 11.160156 76.476562 11.125 76.441406 11.089844 C 76.429688 11.101562 76.417969 11.109375 76.410156 11.117188 C 76.140625 11.351562 75.859375 11.554688 75.542969 11.71875 C 75.511719 11.738281 75.476562 11.757812 75.445312 11.777344 C 75.3125 11.847656 75.179688 11.894531 75.039062 11.9375 C 75.011719 11.945312 75.011719 11.945312 74.984375 11.953125 C 74.632812 12.058594 74.269531 12.089844 73.90625 12.085938 C 73.84375 12.085938 73.785156 12.085938 73.722656 12.089844 C 72.941406 12.089844 72.222656 11.824219 71.652344 11.28125 C 71.203125 10.820312 71.023438 10.246094 71.03125 9.609375 C 71.042969 9.058594 71.230469 8.546875 71.59375 8.132812 C 71.609375 8.113281 71.625 8.09375 71.644531 8.070312 C 71.980469 7.683594 72.398438 7.421875 72.839844 7.171875 C 72.871094 7.152344 72.902344 7.132812 72.9375 7.113281 C 72.960938 7.101562 72.984375 7.085938 73.007812 7.074219 C 72.996094 7.0625 72.988281 7.050781 72.976562 7.042969 C 72.398438 6.425781 72.09375 5.613281 72.113281 4.773438 C 72.128906 4.371094 72.257812 3.988281 72.527344 3.679688 C 72.542969 3.660156 72.558594 3.644531 72.570312 3.625 C 72.917969 3.210938 73.496094 2.996094 74.015625 2.933594 C 74.050781 2.929688 74.050781 2.929688 74.082031 2.925781 C 74.804688 2.847656 75.621094 2.964844 76.167969 3.476562 Z M 73.671875 3.796875 C 73.433594 4.113281 73.414062 4.4375 73.457031 4.820312 C 73.550781 5.460938 73.921875 5.9375 74.328125 6.425781 C 74.398438 6.390625 74.449219 6.355469 74.503906 6.300781 C 74.527344 6.28125 74.527344 6.28125 74.550781 6.257812 C 74.566406 6.242188 74.582031 6.226562 74.597656 6.210938 C 74.613281 6.191406 74.628906 6.175781 74.644531 6.160156 C 74.773438 6.03125 74.890625 5.894531 75 5.75 C 75.019531 5.726562 75.035156 5.699219 75.054688 5.675781 C 75.335938 5.292969 75.5 4.859375 75.457031 4.378906 C 75.40625 4.078125 75.289062 3.820312 75.035156 3.636719 C 74.59375 3.363281 74.03125 3.410156 73.671875 3.796875 Z M 73.046875 7.828125 C 72.664062 8.226562 72.519531 8.789062 72.519531 9.332031 C 72.53125 9.800781 72.71875 10.257812 73.039062 10.601562 C 73.46875 10.996094 73.980469 11.140625 74.550781 11.125 C 74.960938 11.105469 75.339844 11.003906 75.703125 10.8125 C 75.71875 10.804688 75.738281 10.796875 75.753906 10.785156 C 75.84375 10.738281 75.90625 10.699219 75.960938 10.609375 C 75.949219 10.601562 75.941406 10.589844 75.933594 10.582031 C 75.460938 10.074219 75.460938 10.074219 75.25 9.8125 C 75.1875 9.738281 75.125 9.664062 75.0625 9.59375 C 74.972656 9.484375 74.882812 9.375 74.796875 9.265625 C 74.695312 9.132812 74.589844 9.003906 74.480469 8.878906 C 74.390625 8.773438 74.304688 8.667969 74.214844 8.5625 C 74.152344 8.484375 74.085938 8.40625 74.019531 8.328125 C 73.921875 8.214844 73.828125 8.101562 73.734375 7.984375 C 73.726562 7.96875 73.714844 7.957031 73.703125 7.941406 C 73.683594 7.914062 73.660156 7.886719 73.640625 7.859375 C 73.589844 7.792969 73.539062 7.730469 73.488281 7.667969 C 73.460938 7.632812 73.460938 7.632812 73.433594 7.601562 C 73.414062 7.578125 73.414062 7.578125 73.390625 7.554688 C 73.265625 7.554688 73.132812 7.742188 73.046875 7.828125 Z M 73.046875 7.828125 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 49.992188 5.535156 C 50.101562 5.609375 50.101562 5.609375 50.136719 5.679688 C 50.136719 5.746094 50.140625 5.8125 50.140625 5.882812 C 50.140625 5.914062 50.140625 5.914062 50.140625 5.941406 C 50.140625 5.984375 50.140625 6.027344 50.140625 6.070312 C 50.140625 6.136719 50.140625 6.203125 50.140625 6.269531 C 50.140625 6.308594 50.140625 6.351562 50.140625 6.390625 C 50.140625 6.410156 50.140625 6.429688 50.140625 6.453125 C 50.140625 6.589844 50.140625 6.589844 50.113281 6.617188 C 50.074219 6.617188 50.035156 6.621094 49.996094 6.621094 C 49.972656 6.621094 49.949219 6.621094 49.921875 6.621094 C 49.894531 6.621094 49.871094 6.617188 49.84375 6.617188 C 49.816406 6.617188 49.789062 6.617188 49.757812 6.617188 C 49.671875 6.617188 49.585938 6.617188 49.5 6.617188 C 49.441406 6.617188 49.378906 6.617188 49.320312 6.617188 C 49.175781 6.617188 49.03125 6.617188 48.886719 6.617188 C 48.898438 6.640625 48.90625 6.660156 48.917969 6.683594 C 48.929688 6.714844 48.945312 6.746094 48.957031 6.773438 C 48.964844 6.789062 48.96875 6.804688 48.976562 6.820312 C 49.203125 7.339844 49.195312 8 48.988281 8.523438 C 48.75 9.0625 48.355469 9.457031 47.804688 9.671875 C 47.066406 9.941406 46.210938 9.941406 45.457031 9.746094 C 45.277344 10.003906 45.214844 10.273438 45.238281 10.585938 C 45.269531 10.699219 45.316406 10.761719 45.402344 10.835938 C 45.617188 10.945312 45.851562 10.949219 46.089844 10.949219 C 46.113281 10.953125 46.132812 10.953125 46.15625 10.953125 C 46.203125 10.953125 46.25 10.953125 46.292969 10.953125 C 46.367188 10.953125 46.441406 10.953125 46.515625 10.953125 C 46.726562 10.953125 46.9375 10.957031 47.144531 10.957031 C 47.273438 10.957031 47.402344 10.957031 47.53125 10.960938 C 47.582031 10.960938 47.628906 10.960938 47.675781 10.960938 C 48.324219 10.960938 49.039062 11.019531 49.53125 11.492188 C 49.546875 11.511719 49.566406 11.53125 49.585938 11.550781 C 49.601562 11.566406 49.617188 11.582031 49.636719 11.597656 C 49.957031 11.929688 50.0625 12.394531 50.066406 12.84375 C 50.054688 13.351562 49.847656 13.800781 49.511719 14.171875 C 49.496094 14.191406 49.480469 14.207031 49.460938 14.226562 C 48.8125 14.921875 47.769531 15.179688 46.855469 15.210938 C 45.890625 15.234375 44.761719 15.230469 44.015625 14.523438 C 43.738281 14.222656 43.660156 13.886719 43.671875 13.488281 C 43.679688 13.363281 43.699219 13.253906 43.753906 13.136719 C 43.761719 13.117188 43.769531 13.09375 43.78125 13.074219 C 43.996094 12.644531 44.386719 12.410156 44.785156 12.175781 C 44.765625 12.167969 44.746094 12.160156 44.730469 12.152344 C 44.398438 11.996094 44.222656 11.808594 44.089844 11.476562 C 43.988281 11.136719 44.070312 10.757812 44.222656 10.453125 C 44.421875 10.109375 44.695312 9.824219 44.976562 9.550781 C 44.960938 9.542969 44.945312 9.53125 44.925781 9.523438 C 44.757812 9.417969 44.613281 9.304688 44.472656 9.167969 C 44.457031 9.152344 44.441406 9.136719 44.425781 9.121094 C 44.214844 8.902344 44.085938 8.597656 44.015625 8.300781 C 44.011719 8.28125 44.003906 8.257812 44 8.238281 C 43.882812 7.675781 43.964844 7.042969 44.277344 6.558594 C 44.621094 6.070312 45.09375 5.773438 45.671875 5.628906 C 45.6875 5.625 45.703125 5.621094 45.71875 5.617188 C 46.25 5.492188 46.917969 5.496094 47.449219 5.628906 C 47.464844 5.632812 47.480469 5.636719 47.496094 5.640625 C 47.6875 5.691406 47.867188 5.761719 48.046875 5.84375 C 48.0625 5.851562 48.078125 5.859375 48.09375 5.867188 C 48.164062 5.902344 48.226562 5.933594 48.289062 5.980469 C 48.390625 6.066406 48.390625 6.066406 48.515625 6.082031 C 48.582031 6.0625 48.644531 6.035156 48.707031 6.003906 C 48.730469 5.996094 48.753906 5.984375 48.78125 5.976562 C 48.855469 5.941406 48.929688 5.910156 49.003906 5.875 C 49.054688 5.851562 49.101562 5.832031 49.152344 5.808594 C 49.320312 5.738281 49.488281 5.664062 49.652344 5.585938 C 49.679688 5.574219 49.703125 5.566406 49.730469 5.554688 C 49.75 5.542969 49.769531 5.535156 49.789062 5.523438 C 49.867188 5.503906 49.917969 5.515625 49.992188 5.535156 Z M 45.835938 6.507812 C 45.472656 6.984375 45.421875 7.597656 45.492188 8.175781 C 45.550781 8.542969 45.6875 8.890625 45.980469 9.132812 C 46.207031 9.285156 46.46875 9.3125 46.734375 9.277344 C 47.015625 9.21875 47.210938 9.089844 47.375 8.855469 C 47.683594 8.375 47.742188 7.746094 47.640625 7.191406 C 47.5625 6.859375 47.402344 6.507812 47.117188 6.308594 C 46.703125 6.074219 46.152344 6.148438 45.835938 6.507812 Z M 45.238281 12.367188 C 44.957031 12.734375 44.867188 13.113281 44.902344 13.570312 C 44.957031 13.84375 45.09375 14.058594 45.316406 14.226562 C 45.613281 14.417969 46.015625 14.496094 46.367188 14.507812 C 46.394531 14.507812 46.394531 14.507812 46.417969 14.507812 C 47.132812 14.527344 47.90625 14.457031 48.453125 13.945312 C 48.652344 13.738281 48.710938 13.515625 48.703125 13.230469 C 48.683594 12.992188 48.570312 12.800781 48.394531 12.644531 C 48.113281 12.441406 47.726562 12.449219 47.398438 12.449219 C 47.355469 12.449219 47.3125 12.449219 47.269531 12.449219 C 47.15625 12.449219 47.046875 12.449219 46.933594 12.449219 C 46.753906 12.449219 46.574219 12.445312 46.394531 12.445312 C 46.332031 12.445312 46.269531 12.445312 46.210938 12.445312 C 45.882812 12.445312 45.5625 12.414062 45.238281 12.367188 Z M 45.238281 12.367188 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 53.039062 2.382812 C 53.0625 2.390625 53.0625 2.390625 53.085938 2.398438 C 53.140625 2.429688 53.171875 2.453125 53.207031 2.503906 C 53.230469 2.617188 53.21875 2.730469 53.214844 2.84375 C 53.210938 2.878906 53.210938 2.914062 53.210938 2.953125 C 53.207031 3.027344 53.203125 3.105469 53.199219 3.183594 C 53.191406 3.371094 53.183594 3.558594 53.179688 3.746094 C 53.175781 3.792969 53.175781 3.835938 53.175781 3.882812 C 53.15625 4.441406 53.15625 5 53.15625 5.5625 C 53.15625 5.640625 53.15625 5.71875 53.15625 5.792969 C 53.15625 6.085938 53.160156 6.375 53.160156 6.664062 C 53.179688 6.644531 53.195312 6.625 53.214844 6.605469 C 53.238281 6.578125 53.261719 6.550781 53.285156 6.523438 C 53.296875 6.511719 53.3125 6.5 53.324219 6.484375 C 53.78125 5.984375 54.445312 5.601562 55.128906 5.550781 C 55.640625 5.535156 56.128906 5.578125 56.527344 5.929688 C 56.566406 5.964844 56.601562 6 56.640625 6.039062 C 56.664062 6.0625 56.664062 6.0625 56.691406 6.089844 C 57.246094 6.660156 57.203125 7.570312 57.203125 8.304688 C 57.203125 8.414062 57.203125 8.523438 57.207031 8.632812 C 57.207031 8.839844 57.207031 9.042969 57.207031 9.25 C 57.207031 9.484375 57.210938 9.722656 57.210938 9.957031 C 57.210938 10.4375 57.214844 10.921875 57.214844 11.40625 C 57.246094 11.410156 57.246094 11.410156 57.28125 11.414062 C 57.308594 11.417969 57.335938 11.421875 57.363281 11.425781 C 57.40625 11.433594 57.40625 11.433594 57.445312 11.441406 C 57.558594 11.457031 57.671875 11.480469 57.785156 11.503906 C 57.808594 11.507812 57.828125 11.511719 57.851562 11.515625 C 57.878906 11.519531 57.878906 11.519531 57.910156 11.527344 C 57.929688 11.53125 57.949219 11.535156 57.964844 11.539062 C 58.007812 11.550781 58.007812 11.550781 58.03125 11.574219 C 58.035156 11.613281 58.035156 11.65625 58.035156 11.695312 C 58.035156 11.71875 58.035156 11.746094 58.035156 11.769531 C 58.035156 11.796875 58.035156 11.824219 58.035156 11.851562 C 58.035156 11.875 58.035156 11.902344 58.035156 11.929688 C 58.035156 11.964844 58.035156 11.964844 58.035156 12.003906 C 58.035156 12.027344 58.035156 12.050781 58.035156 12.074219 C 58.03125 12.125 58.03125 12.125 58.007812 12.148438 C 57.964844 12.152344 57.921875 12.152344 57.882812 12.152344 C 57.839844 12.152344 57.839844 12.152344 57.796875 12.152344 C 57.769531 12.152344 57.738281 12.152344 57.707031 12.152344 C 57.675781 12.152344 57.640625 12.152344 57.609375 12.152344 C 57.523438 12.152344 57.433594 12.152344 57.347656 12.152344 C 57.257812 12.152344 57.164062 12.152344 57.074219 12.152344 C 56.917969 12.152344 56.765625 12.152344 56.613281 12.152344 C 56.433594 12.152344 56.257812 12.152344 56.082031 12.152344 C 55.929688 12.152344 55.777344 12.152344 55.625 12.152344 C 55.53125 12.152344 55.441406 12.152344 55.351562 12.152344 C 55.265625 12.152344 55.179688 12.152344 55.09375 12.152344 C 55.046875 12.152344 55 12.152344 54.953125 12.152344 C 54.925781 12.152344 54.898438 12.152344 54.871094 12.152344 C 54.847656 12.152344 54.824219 12.152344 54.796875 12.152344 C 54.742188 12.148438 54.742188 12.148438 54.71875 12.125 C 54.71875 12.085938 54.71875 12.042969 54.71875 12.003906 C 54.71875 11.976562 54.71875 11.953125 54.71875 11.925781 C 54.71875 11.902344 54.71875 11.875 54.71875 11.847656 C 54.71875 11.820312 54.71875 11.796875 54.71875 11.769531 C 54.71875 11.703125 54.71875 11.636719 54.71875 11.574219 C 54.8125 11.53125 54.902344 11.507812 55.003906 11.488281 C 55.03125 11.480469 55.0625 11.476562 55.09375 11.46875 C 55.113281 11.464844 55.128906 11.460938 55.144531 11.460938 C 55.191406 11.449219 55.242188 11.441406 55.289062 11.429688 C 55.527344 11.378906 55.527344 11.378906 55.585938 11.378906 C 55.582031 10.90625 55.582031 10.433594 55.578125 9.960938 C 55.578125 9.742188 55.578125 9.523438 55.574219 9.304688 C 55.574219 9.109375 55.574219 8.917969 55.574219 8.726562 C 55.574219 8.625 55.570312 8.527344 55.570312 8.425781 C 55.570312 8.328125 55.570312 8.234375 55.570312 8.136719 C 55.570312 8.101562 55.570312 8.066406 55.570312 8.03125 C 55.570312 7.664062 55.554688 7.199219 55.289062 6.917969 C 55.054688 6.722656 54.742188 6.746094 54.457031 6.761719 C 54.101562 6.800781 53.738281 7.007812 53.464844 7.234375 C 53.425781 7.265625 53.425781 7.265625 53.371094 7.300781 C 53.273438 7.371094 53.214844 7.421875 53.1875 7.539062 C 53.179688 7.640625 53.179688 7.742188 53.183594 7.84375 C 53.183594 7.882812 53.183594 7.921875 53.183594 7.960938 C 53.183594 8.066406 53.183594 8.167969 53.1875 8.273438 C 53.1875 8.386719 53.1875 8.496094 53.1875 8.605469 C 53.1875 8.8125 53.191406 9.023438 53.191406 9.230469 C 53.195312 9.46875 53.195312 9.703125 53.195312 9.941406 C 53.199219 10.429688 53.203125 10.917969 53.207031 11.40625 C 53.238281 11.410156 53.238281 11.410156 53.265625 11.414062 C 53.351562 11.429688 53.4375 11.445312 53.523438 11.464844 C 53.554688 11.46875 53.585938 11.472656 53.613281 11.480469 C 53.644531 11.484375 53.671875 11.492188 53.703125 11.496094 C 53.730469 11.5 53.753906 11.507812 53.78125 11.511719 C 53.847656 11.523438 53.910156 11.535156 53.976562 11.550781 C 53.976562 11.746094 53.976562 11.945312 53.976562 12.148438 C 52.890625 12.148438 51.804688 12.148438 50.6875 12.148438 C 50.6875 11.953125 50.6875 11.753906 50.6875 11.550781 C 50.964844 11.492188 51.242188 11.4375 51.527344 11.378906 C 51.542969 11.160156 51.554688 10.945312 51.554688 10.722656 C 51.554688 10.691406 51.554688 10.660156 51.554688 10.628906 C 51.554688 10.546875 51.558594 10.464844 51.558594 10.378906 C 51.558594 10.289062 51.558594 10.199219 51.558594 10.109375 C 51.558594 9.953125 51.558594 9.796875 51.558594 9.640625 C 51.558594 9.414062 51.558594 9.1875 51.5625 8.960938 C 51.5625 8.59375 51.5625 8.230469 51.5625 7.863281 C 51.566406 7.507812 51.566406 7.152344 51.566406 6.792969 C 51.566406 6.773438 51.566406 6.75 51.566406 6.726562 C 51.566406 6.617188 51.566406 6.507812 51.566406 6.398438 C 51.570312 5.484375 51.574219 4.570312 51.574219 3.65625 C 51.554688 3.65625 51.535156 3.652344 51.515625 3.652344 C 51.476562 3.648438 51.476562 3.648438 51.4375 3.644531 C 51.414062 3.644531 51.386719 3.640625 51.359375 3.640625 C 51.277344 3.632812 51.195312 3.621094 51.113281 3.609375 C 51.082031 3.605469 51.054688 3.601562 51.023438 3.597656 C 50.996094 3.59375 50.964844 3.589844 50.933594 3.582031 C 50.902344 3.578125 50.871094 3.574219 50.839844 3.570312 C 50.765625 3.558594 50.691406 3.546875 50.617188 3.535156 C 50.617188 3.347656 50.617188 3.15625 50.617188 2.960938 C 50.910156 2.875 51.207031 2.796875 51.5 2.722656 C 51.523438 2.714844 51.542969 2.710938 51.5625 2.707031 C 51.671875 2.679688 51.777344 2.652344 51.886719 2.625 C 51.972656 2.601562 52.0625 2.578125 52.152344 2.554688 C 52.257812 2.527344 52.367188 2.5 52.472656 2.472656 C 52.515625 2.460938 52.554688 2.453125 52.597656 2.441406 C 52.652344 2.425781 52.710938 2.410156 52.765625 2.398438 C 52.78125 2.394531 52.800781 2.386719 52.816406 2.382812 C 52.898438 2.363281 52.960938 2.351562 53.039062 2.382812 Z M 53.039062 2.382812 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 99.691406 6.011719 C 100.109375 6.40625 100.234375 7.003906 100.273438 7.554688 C 100.277344 7.667969 100.277344 7.785156 100.277344 7.898438 C 100.277344 7.933594 100.277344 7.964844 100.277344 8 C 100.277344 8.074219 100.277344 8.144531 100.277344 8.21875 C 100.277344 8.332031 100.277344 8.445312 100.277344 8.558594 C 100.28125 8.886719 100.28125 9.210938 100.28125 9.535156 C 100.28125 9.714844 100.28125 9.894531 100.285156 10.074219 C 100.285156 10.171875 100.285156 10.265625 100.285156 10.359375 C 100.285156 10.449219 100.285156 10.539062 100.285156 10.628906 C 100.285156 10.675781 100.285156 10.726562 100.285156 10.773438 C 100.289062 10.964844 100.292969 11.167969 100.417969 11.320312 C 100.53125 11.378906 100.636719 11.398438 100.757812 11.367188 C 100.898438 11.308594 101.003906 11.21875 101.113281 11.117188 C 101.226562 11.199219 101.339844 11.289062 101.449219 11.378906 C 101.394531 11.527344 101.300781 11.640625 101.207031 11.765625 C 101.179688 11.804688 101.179688 11.804688 101.152344 11.84375 C 100.859375 12.152344 100.476562 12.265625 100.058594 12.277344 C 99.699219 12.269531 99.332031 12.164062 99.066406 11.910156 C 98.933594 11.757812 98.761719 11.519531 98.761719 11.308594 C 98.582031 11.449219 98.582031 11.449219 98.417969 11.605469 C 98.289062 11.738281 98.140625 11.847656 97.992188 11.957031 C 97.96875 11.972656 97.949219 11.992188 97.925781 12.007812 C 97.488281 12.3125 96.855469 12.339844 96.34375 12.25 C 95.917969 12.15625 95.527344 11.929688 95.28125 11.558594 C 95.035156 11.136719 94.964844 10.617188 95.082031 10.140625 C 95.289062 9.527344 95.746094 9.175781 96.300781 8.894531 C 96.941406 8.582031 97.644531 8.375 98.328125 8.179688 C 98.34375 8.175781 98.359375 8.171875 98.375 8.167969 C 98.472656 8.140625 98.566406 8.113281 98.664062 8.085938 C 98.695312 7.195312 98.695312 7.195312 98.328125 6.425781 C 98.121094 6.230469 97.828125 6.203125 97.558594 6.203125 C 97.53125 6.203125 97.53125 6.203125 97.503906 6.203125 C 97.339844 6.207031 97.171875 6.21875 97.007812 6.230469 C 97.003906 6.257812 97.003906 6.289062 97 6.316406 C 96.984375 6.46875 96.957031 6.617188 96.925781 6.765625 C 96.917969 6.816406 96.910156 6.863281 96.902344 6.910156 C 96.832031 7.273438 96.738281 7.585938 96.425781 7.808594 C 96.191406 7.933594 95.945312 7.933594 95.6875 7.867188 C 95.515625 7.808594 95.40625 7.707031 95.320312 7.546875 C 95.234375 7.347656 95.238281 7.183594 95.308594 6.980469 C 95.316406 6.957031 95.316406 6.957031 95.324219 6.929688 C 95.421875 6.644531 95.574219 6.441406 95.785156 6.230469 C 95.800781 6.214844 95.816406 6.195312 95.835938 6.179688 C 96.734375 5.308594 98.742188 5.21875 99.691406 6.011719 Z M 98.394531 8.742188 C 98.292969 8.777344 98.1875 8.8125 98.082031 8.847656 C 97.574219 9.007812 97.011719 9.230469 96.746094 9.722656 C 96.582031 10.042969 96.554688 10.355469 96.648438 10.703125 C 96.71875 10.914062 96.816406 11.042969 97.011719 11.152344 C 97.296875 11.292969 97.609375 11.304688 97.910156 11.199219 C 98.058594 11.132812 98.207031 11.050781 98.34375 10.960938 C 98.398438 10.921875 98.398438 10.921875 98.46875 10.890625 C 98.558594 10.839844 98.644531 10.789062 98.679688 10.683594 C 98.703125 10.542969 98.695312 10.402344 98.691406 10.257812 C 98.6875 10.214844 98.6875 10.167969 98.6875 10.121094 C 98.6875 10 98.683594 9.878906 98.683594 9.757812 C 98.679688 9.636719 98.679688 9.511719 98.675781 9.386719 C 98.675781 9.144531 98.667969 8.902344 98.664062 8.660156 C 98.578125 8.660156 98.476562 8.714844 98.394531 8.742188 Z M 98.394531 8.742188 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 38.035156 6.242188 C 38.207031 6.40625 38.332031 6.578125 38.449219 6.785156 C 38.460938 6.808594 38.460938 6.808594 38.472656 6.832031 C 38.835938 7.472656 38.875 8.257812 38.761719 8.972656 C 38.734375 9 38.734375 9 38.671875 9 C 38.625 9 38.625 9 38.578125 9 C 38.5625 9 38.546875 9 38.53125 9 C 38.472656 9 38.417969 9 38.363281 9 C 38.324219 9 38.285156 9 38.242188 9 C 38.136719 9 38.027344 9 37.917969 9 C 37.804688 9 37.695312 9 37.582031 9 C 37.367188 9 37.152344 9 36.9375 9 C 36.695312 9 36.453125 9 36.207031 9 C 35.707031 9 35.207031 9 34.703125 9 C 34.714844 9.089844 34.726562 9.183594 34.738281 9.273438 C 34.742188 9.300781 34.742188 9.328125 34.746094 9.351562 C 34.8125 9.898438 35.007812 10.441406 35.4375 10.808594 C 35.933594 11.1875 36.476562 11.269531 37.089844 11.203125 C 37.539062 11.128906 37.90625 10.847656 38.222656 10.535156 C 38.347656 10.417969 38.347656 10.417969 38.425781 10.417969 C 38.464844 10.445312 38.464844 10.445312 38.503906 10.488281 C 38.589844 10.585938 38.683594 10.671875 38.785156 10.753906 C 38.679688 11.046875 38.46875 11.28125 38.257812 11.5 C 38.242188 11.519531 38.222656 11.535156 38.207031 11.554688 C 37.792969 12 37.171875 12.246094 36.574219 12.320312 C 36.554688 12.320312 36.535156 12.324219 36.515625 12.328125 C 35.640625 12.425781 34.773438 12.210938 34.074219 11.671875 C 33.421875 11.125 33.078125 10.363281 32.976562 9.527344 C 32.972656 9.496094 32.972656 9.496094 32.96875 9.460938 C 32.871094 8.5 33.074219 7.515625 33.675781 6.746094 C 33.707031 6.710938 33.738281 6.675781 33.769531 6.640625 C 33.78125 6.621094 33.796875 6.605469 33.8125 6.585938 C 34.316406 5.988281 35.136719 5.640625 35.902344 5.566406 C 36.699219 5.511719 37.429688 5.699219 38.035156 6.242188 Z M 35.226562 6.652344 C 34.949219 7.007812 34.820312 7.386719 34.746094 7.824219 C 34.742188 7.851562 34.738281 7.875 34.734375 7.898438 C 34.730469 7.921875 34.726562 7.949219 34.722656 7.972656 C 34.71875 7.992188 34.714844 8.015625 34.710938 8.035156 C 34.703125 8.097656 34.703125 8.15625 34.703125 8.222656 C 34.703125 8.242188 34.703125 8.261719 34.703125 8.28125 C 34.703125 8.292969 34.703125 8.308594 34.703125 8.324219 C 34.972656 8.328125 35.242188 8.328125 35.507812 8.328125 C 35.632812 8.328125 35.757812 8.328125 35.882812 8.332031 C 36.003906 8.332031 36.125 8.332031 36.246094 8.332031 C 36.289062 8.332031 36.335938 8.332031 36.382812 8.332031 C 36.445312 8.332031 36.511719 8.332031 36.574219 8.332031 C 36.59375 8.332031 36.613281 8.332031 36.632812 8.332031 C 36.800781 8.332031 36.964844 8.304688 37.085938 8.183594 C 37.273438 7.9375 37.277344 7.609375 37.246094 7.3125 C 37.195312 6.96875 37.015625 6.636719 36.730469 6.425781 C 36.226562 6.113281 35.617188 6.195312 35.226562 6.652344 Z M 35.226562 6.652344 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 112.726562 6.085938 C 112.90625 6.242188 113.058594 6.414062 113.183594 6.617188 C 113.199219 6.636719 113.210938 6.65625 113.226562 6.679688 C 113.628906 7.320312 113.699219 8.167969 113.566406 8.902344 C 113.523438 8.945312 113.449219 8.929688 113.386719 8.929688 C 113.371094 8.929688 113.355469 8.929688 113.339844 8.929688 C 113.28125 8.929688 113.226562 8.929688 113.171875 8.929688 C 113.132812 8.929688 113.089844 8.933594 113.050781 8.933594 C 112.945312 8.933594 112.835938 8.933594 112.726562 8.933594 C 112.613281 8.933594 112.5 8.933594 112.386719 8.933594 C 112.175781 8.9375 111.960938 8.9375 111.746094 8.9375 C 111.503906 8.941406 111.257812 8.941406 111.015625 8.941406 C 110.515625 8.945312 110.011719 8.949219 109.511719 8.949219 C 109.519531 9.023438 109.527344 9.097656 109.535156 9.171875 C 109.535156 9.191406 109.539062 9.210938 109.539062 9.230469 C 109.554688 9.378906 109.578125 9.523438 109.613281 9.667969 C 109.621094 9.6875 109.625 9.710938 109.628906 9.730469 C 109.703125 10.011719 109.808594 10.261719 109.992188 10.488281 C 110.003906 10.507812 110.019531 10.527344 110.035156 10.542969 C 110.320312 10.898438 110.765625 11.117188 111.214844 11.164062 C 111.839844 11.203125 112.339844 11.078125 112.820312 10.671875 C 112.9375 10.570312 113.050781 10.457031 113.160156 10.347656 C 113.230469 10.378906 113.28125 10.414062 113.339844 10.46875 C 113.355469 10.480469 113.367188 10.496094 113.382812 10.507812 C 113.398438 10.523438 113.414062 10.539062 113.429688 10.554688 C 113.445312 10.566406 113.460938 10.582031 113.476562 10.597656 C 113.515625 10.632812 113.554688 10.671875 113.59375 10.707031 C 113.324219 11.316406 112.769531 11.816406 112.15625 12.066406 C 112.054688 12.105469 111.953125 12.136719 111.847656 12.171875 C 111.832031 12.175781 111.816406 12.179688 111.800781 12.183594 C 111.507812 12.265625 111.214844 12.28125 110.914062 12.28125 C 110.898438 12.28125 110.878906 12.28125 110.859375 12.28125 C 110.554688 12.277344 110.261719 12.257812 109.96875 12.175781 C 109.941406 12.167969 109.941406 12.167969 109.914062 12.160156 C 109.203125 11.953125 108.628906 11.503906 108.238281 10.875 C 108.230469 10.859375 108.222656 10.847656 108.210938 10.832031 C 107.699219 9.980469 107.648438 8.855469 107.878906 7.90625 C 108.074219 7.136719 108.570312 6.417969 109.253906 6 C 110.304688 5.378906 111.75 5.261719 112.726562 6.085938 Z M 110.105469 6.496094 C 109.710938 6.9375 109.507812 7.546875 109.511719 8.136719 C 109.511719 8.160156 109.511719 8.179688 109.511719 8.203125 C 109.511719 8.21875 109.511719 8.234375 109.511719 8.253906 C 109.78125 8.253906 110.050781 8.253906 110.316406 8.257812 C 110.441406 8.257812 110.566406 8.257812 110.691406 8.257812 C 110.8125 8.257812 110.933594 8.257812 111.054688 8.257812 C 111.097656 8.257812 111.144531 8.261719 111.191406 8.261719 C 111.253906 8.261719 111.320312 8.261719 111.382812 8.261719 C 111.402344 8.261719 111.421875 8.261719 111.441406 8.261719 C 111.59375 8.261719 111.746094 8.234375 111.871094 8.140625 C 112.082031 7.886719 112.078125 7.605469 112.054688 7.289062 C 112.011719 6.949219 111.867188 6.6875 111.625 6.449219 C 111.609375 6.433594 111.59375 6.417969 111.582031 6.40625 C 111.164062 6.015625 110.496094 6.121094 110.105469 6.496094 Z M 110.105469 6.496094 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 119.207031 6.039062 C 119.210938 6.308594 119.203125 6.578125 119.1875 6.847656 C 119.183594 6.910156 119.183594 6.972656 119.179688 7.035156 C 119.175781 7.078125 119.175781 7.117188 119.171875 7.160156 C 119.171875 7.175781 119.171875 7.195312 119.171875 7.214844 C 119.164062 7.308594 119.152344 7.390625 119.136719 7.484375 C 118.835938 7.484375 118.535156 7.484375 118.222656 7.484375 C 118.207031 7.40625 118.191406 7.328125 118.171875 7.246094 C 118.15625 7.171875 118.140625 7.097656 118.121094 7.023438 C 118.109375 6.96875 118.101562 6.917969 118.089844 6.867188 C 118.070312 6.792969 118.054688 6.714844 118.039062 6.640625 C 118.035156 6.617188 118.027344 6.59375 118.023438 6.570312 C 118.019531 6.550781 118.015625 6.527344 118.007812 6.503906 C 118.003906 6.484375 118 6.464844 117.996094 6.445312 C 117.984375 6.398438 117.984375 6.398438 117.960938 6.351562 C 117.902344 6.332031 117.847656 6.316406 117.789062 6.300781 C 117.765625 6.296875 117.765625 6.296875 117.738281 6.289062 C 117.339844 6.1875 116.835938 6.167969 116.464844 6.375 C 116.296875 6.480469 116.203125 6.609375 116.128906 6.789062 C 116.082031 7.042969 116.105469 7.261719 116.234375 7.484375 C 116.496094 7.828125 117.082031 7.953125 117.46875 8.070312 C 118.183594 8.289062 118.960938 8.597656 119.359375 9.277344 C 119.578125 9.714844 119.621094 10.257812 119.496094 10.734375 C 119.316406 11.277344 118.957031 11.703125 118.449219 11.964844 C 117.460938 12.445312 116.246094 12.394531 115.222656 12.054688 C 115.007812 11.972656 114.804688 11.867188 114.601562 11.765625 C 114.570312 11.234375 114.574219 10.707031 114.574219 10.175781 C 114.886719 10.175781 115.195312 10.175781 115.511719 10.175781 C 115.539062 10.304688 115.539062 10.304688 115.5625 10.433594 C 115.582031 10.515625 115.597656 10.597656 115.613281 10.679688 C 115.625 10.734375 115.636719 10.792969 115.648438 10.847656 C 115.664062 10.929688 115.679688 11.011719 115.695312 11.09375 C 115.703125 11.121094 115.707031 11.144531 115.710938 11.171875 C 115.71875 11.195312 115.722656 11.21875 115.726562 11.242188 C 115.730469 11.261719 115.734375 11.285156 115.738281 11.304688 C 115.75 11.355469 115.75 11.355469 115.777344 11.40625 C 116.324219 11.617188 117.03125 11.667969 117.578125 11.4375 C 117.800781 11.332031 117.949219 11.207031 118.039062 10.972656 C 118.089844 10.761719 118.082031 10.527344 117.992188 10.328125 C 117.910156 10.191406 117.820312 10.105469 117.6875 10.023438 C 117.664062 10.003906 117.636719 9.988281 117.609375 9.972656 C 117.265625 9.769531 116.875 9.65625 116.496094 9.527344 C 116.066406 9.386719 115.683594 9.222656 115.320312 8.949219 C 115.296875 8.933594 115.273438 8.917969 115.25 8.898438 C 115.226562 8.875 115.226562 8.875 115.199219 8.855469 C 115.199219 8.839844 115.199219 8.824219 115.199219 8.804688 C 115.1875 8.800781 115.171875 8.796875 115.160156 8.789062 C 114.933594 8.65625 114.792969 8.285156 114.726562 8.046875 C 114.605469 7.507812 114.6875 6.964844 114.984375 6.496094 C 115.347656 5.957031 115.902344 5.671875 116.523438 5.542969 C 117.460938 5.367188 118.386719 5.574219 119.207031 6.039062 Z M 119.207031 6.039062 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 67.945312 6.109375 C 67.96875 6.136719 67.96875 6.136719 67.96875 6.1875 C 67.96875 6.210938 67.96875 6.234375 67.964844 6.257812 C 67.964844 6.285156 67.964844 6.3125 67.964844 6.339844 C 67.960938 6.367188 67.960938 6.398438 67.960938 6.425781 C 67.960938 6.457031 67.957031 6.484375 67.957031 6.515625 C 67.941406 6.863281 67.917969 7.207031 67.894531 7.554688 C 67.59375 7.554688 67.292969 7.554688 66.984375 7.554688 C 66.921875 7.3125 66.863281 7.070312 66.808594 6.828125 C 66.804688 6.796875 66.796875 6.769531 66.789062 6.742188 C 66.785156 6.714844 66.777344 6.6875 66.773438 6.660156 C 66.765625 6.632812 66.761719 6.609375 66.753906 6.585938 C 66.742188 6.519531 66.742188 6.519531 66.742188 6.425781 C 66.707031 6.414062 66.667969 6.402344 66.628906 6.390625 C 66.605469 6.386719 66.585938 6.378906 66.5625 6.371094 C 66.355469 6.320312 66.15625 6.296875 65.941406 6.296875 C 65.917969 6.296875 65.894531 6.296875 65.871094 6.296875 C 65.5625 6.300781 65.296875 6.351562 65.0625 6.566406 C 64.894531 6.742188 64.859375 6.90625 64.863281 7.148438 C 64.867188 7.285156 64.890625 7.390625 64.96875 7.507812 C 64.976562 7.519531 64.984375 7.535156 64.996094 7.550781 C 65.261719 7.921875 65.914062 8.0625 66.328125 8.179688 C 67.054688 8.390625 67.703125 8.726562 68.089844 9.40625 C 68.214844 9.648438 68.289062 9.90625 68.304688 10.175781 C 68.304688 10.199219 68.304688 10.21875 68.308594 10.242188 C 68.324219 10.753906 68.15625 11.1875 67.824219 11.574219 C 67.808594 11.589844 67.796875 11.605469 67.78125 11.621094 C 67.28125 12.164062 66.515625 12.347656 65.808594 12.390625 C 65.144531 12.414062 64.535156 12.34375 63.910156 12.117188 C 63.886719 12.109375 63.886719 12.109375 63.859375 12.097656 C 63.675781 12.03125 63.507812 11.929688 63.335938 11.835938 C 63.335938 11.632812 63.335938 11.429688 63.335938 11.226562 C 63.335938 11.132812 63.335938 11.039062 63.335938 10.945312 C 63.332031 10.851562 63.332031 10.761719 63.332031 10.671875 C 63.332031 10.636719 63.332031 10.601562 63.332031 10.566406 C 63.332031 10.515625 63.332031 10.46875 63.332031 10.421875 C 63.332031 10.390625 63.332031 10.363281 63.332031 10.335938 C 63.335938 10.273438 63.335938 10.273438 63.359375 10.25 C 63.421875 10.246094 63.484375 10.246094 63.550781 10.246094 C 63.570312 10.246094 63.585938 10.246094 63.605469 10.246094 C 63.648438 10.246094 63.6875 10.246094 63.726562 10.246094 C 63.789062 10.246094 63.851562 10.246094 63.914062 10.246094 C 63.953125 10.246094 63.992188 10.246094 64.03125 10.246094 C 64.050781 10.246094 64.066406 10.246094 64.085938 10.246094 C 64.21875 10.246094 64.21875 10.246094 64.273438 10.273438 C 64.285156 10.316406 64.285156 10.316406 64.296875 10.375 C 64.300781 10.394531 64.304688 10.414062 64.308594 10.4375 C 64.316406 10.460938 64.320312 10.484375 64.324219 10.507812 C 64.328125 10.53125 64.332031 10.554688 64.339844 10.578125 C 64.347656 10.628906 64.359375 10.679688 64.367188 10.730469 C 64.382812 10.808594 64.398438 10.882812 64.414062 10.960938 C 64.421875 11.007812 64.433594 11.058594 64.441406 11.105469 C 64.445312 11.128906 64.453125 11.152344 64.457031 11.175781 C 64.476562 11.285156 64.492188 11.386719 64.488281 11.5 C 64.53125 11.511719 64.53125 11.511719 64.578125 11.519531 C 64.691406 11.546875 64.804688 11.574219 64.921875 11.605469 C 65.117188 11.648438 65.308594 11.648438 65.507812 11.652344 C 65.539062 11.652344 65.570312 11.652344 65.601562 11.652344 C 65.964844 11.652344 66.320312 11.59375 66.605469 11.359375 C 66.761719 11.199219 66.820312 11.003906 66.828125 10.789062 C 66.820312 10.566406 66.761719 10.382812 66.601562 10.226562 C 66.214844 9.933594 65.765625 9.789062 65.3125 9.640625 C 64.621094 9.414062 63.949219 9.125 63.59375 8.445312 C 63.378906 8 63.375 7.464844 63.53125 6.996094 C 63.761719 6.410156 64.183594 6.027344 64.753906 5.773438 C 65.792969 5.351562 66.988281 5.59375 67.945312 6.109375 Z M 67.945312 6.109375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 105.941406 5.769531 C 105.960938 5.777344 105.976562 5.785156 105.996094 5.792969 C 106.1875 5.867188 106.351562 5.964844 106.535156 6.0625 C 106.511719 6.539062 106.488281 7.015625 106.464844 7.507812 C 106.164062 7.507812 105.863281 7.507812 105.550781 7.507812 C 105.445312 7.101562 105.445312 7.101562 105.410156 6.941406 C 105.40625 6.925781 105.402344 6.910156 105.398438 6.890625 C 105.386719 6.839844 105.375 6.789062 105.367188 6.738281 C 105.359375 6.703125 105.351562 6.667969 105.34375 6.632812 C 105.324219 6.546875 105.304688 6.460938 105.289062 6.375 C 105.234375 6.359375 105.183594 6.34375 105.128906 6.328125 C 105.097656 6.320312 105.070312 6.3125 105.039062 6.304688 C 104.859375 6.253906 104.6875 6.25 104.503906 6.25 C 104.464844 6.25 104.464844 6.25 104.421875 6.25 C 104.136719 6.246094 103.90625 6.3125 103.664062 6.464844 C 103.507812 6.621094 103.417969 6.816406 103.414062 7.042969 C 103.425781 7.25 103.492188 7.433594 103.632812 7.585938 C 103.976562 7.886719 104.484375 8.003906 104.910156 8.132812 C 105.628906 8.351562 106.285156 8.667969 106.667969 9.355469 C 106.878906 9.800781 106.9375 10.371094 106.785156 10.84375 C 106.554688 11.417969 106.144531 11.8125 105.585938 12.070312 C 104.601562 12.488281 103.335938 12.402344 102.359375 12.007812 C 102.203125 11.9375 102.046875 11.859375 101.902344 11.765625 C 101.894531 11.699219 101.894531 11.699219 101.894531 11.617188 C 101.894531 11.585938 101.894531 11.554688 101.890625 11.523438 C 101.890625 11.488281 101.890625 11.453125 101.890625 11.417969 C 101.890625 11.382812 101.890625 11.347656 101.890625 11.3125 C 101.890625 11.222656 101.886719 11.128906 101.886719 11.039062 C 101.886719 10.925781 101.886719 10.816406 101.882812 10.707031 C 101.882812 10.539062 101.882812 10.371094 101.878906 10.203125 C 102.1875 10.203125 102.496094 10.203125 102.816406 10.203125 C 102.871094 10.363281 102.871094 10.363281 102.886719 10.449219 C 102.890625 10.46875 102.894531 10.488281 102.898438 10.507812 C 102.902344 10.527344 102.90625 10.546875 102.910156 10.566406 C 102.914062 10.585938 102.917969 10.609375 102.921875 10.628906 C 102.933594 10.671875 102.941406 10.71875 102.949219 10.761719 C 102.964844 10.828125 102.976562 10.894531 102.988281 10.960938 C 103 11.003906 103.007812 11.046875 103.015625 11.089844 C 103.019531 11.109375 103.023438 11.132812 103.027344 11.152344 C 103.046875 11.246094 103.0625 11.332031 103.054688 11.429688 C 103.699219 11.59375 104.421875 11.726562 105.03125 11.386719 C 105.21875 11.265625 105.316406 11.125 105.375 10.914062 C 105.402344 10.691406 105.378906 10.496094 105.273438 10.292969 C 104.921875 9.867188 104.363281 9.730469 103.859375 9.5625 C 103.1875 9.339844 102.511719 9.058594 102.167969 8.398438 C 101.949219 7.929688 101.9375 7.414062 102.097656 6.929688 C 102.101562 6.90625 102.109375 6.886719 102.117188 6.863281 C 102.269531 6.417969 102.628906 6.066406 103.03125 5.847656 C 103.054688 5.832031 103.078125 5.820312 103.101562 5.808594 C 103.382812 5.65625 103.699219 5.574219 104.015625 5.535156 C 104.035156 5.53125 104.054688 5.527344 104.074219 5.527344 C 104.714844 5.449219 105.34375 5.535156 105.941406 5.769531 Z M 105.941406 5.769531 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 59.953125 3.921875 C 60.316406 3.921875 60.679688 3.921875 61.054688 3.921875 C 61.058594 4.292969 61.054688 4.667969 61.046875 5.039062 C 61.042969 5.066406 61.042969 5.066406 61.042969 5.09375 C 61.042969 5.144531 61.042969 5.195312 61.039062 5.246094 C 61.039062 5.277344 61.039062 5.304688 61.035156 5.335938 C 61.03125 5.472656 61.019531 5.613281 61.007812 5.75 C 61.53125 5.75 62.054688 5.75 62.59375 5.75 C 62.59375 6.035156 62.59375 6.320312 62.59375 6.617188 C 62.0625 6.617188 61.53125 6.617188 60.984375 6.617188 C 60.984375 7.128906 60.988281 7.644531 60.988281 8.160156 C 60.992188 8.398438 60.992188 8.636719 60.992188 8.875 C 60.992188 9.082031 60.992188 9.292969 60.996094 9.5 C 60.996094 9.609375 60.996094 9.71875 60.996094 9.832031 C 60.996094 9.933594 60.996094 10.039062 60.996094 10.140625 C 60.996094 10.179688 60.996094 10.21875 60.996094 10.253906 C 60.992188 10.765625 60.992188 10.765625 61.199219 11.210938 C 61.34375 11.347656 61.507812 11.40625 61.703125 11.40625 C 61.941406 11.371094 62.144531 11.289062 62.355469 11.175781 C 62.457031 11.125 62.457031 11.125 62.519531 11.117188 C 62.558594 11.140625 62.558594 11.140625 62.597656 11.183594 C 62.613281 11.195312 62.625 11.210938 62.640625 11.226562 C 62.652344 11.238281 62.667969 11.253906 62.683594 11.269531 C 62.695312 11.285156 62.710938 11.300781 62.726562 11.316406 C 62.761719 11.351562 62.796875 11.390625 62.832031 11.429688 C 62.785156 11.5625 62.707031 11.65625 62.617188 11.765625 C 62.605469 11.78125 62.59375 11.792969 62.578125 11.808594 C 62.375 12.03125 62.085938 12.183594 61.800781 12.269531 C 61.777344 12.277344 61.75 12.285156 61.726562 12.292969 C 61.511719 12.347656 61.296875 12.351562 61.078125 12.351562 C 61.046875 12.351562 61.019531 12.351562 60.988281 12.351562 C 60.523438 12.351562 60.085938 12.210938 59.730469 11.898438 C 59.542969 11.699219 59.425781 11.40625 59.375 11.140625 C 59.371094 11.117188 59.367188 11.097656 59.363281 11.074219 C 59.351562 10.988281 59.347656 10.902344 59.347656 10.8125 C 59.347656 10.792969 59.347656 10.777344 59.347656 10.757812 C 59.347656 10.695312 59.347656 10.636719 59.347656 10.578125 C 59.347656 10.535156 59.347656 10.492188 59.347656 10.449219 C 59.347656 10.332031 59.347656 10.214844 59.347656 10.097656 C 59.351562 9.972656 59.351562 9.851562 59.351562 9.730469 C 59.351562 9.496094 59.351562 9.265625 59.351562 9.035156 C 59.351562 8.769531 59.351562 8.507812 59.351562 8.242188 C 59.351562 7.703125 59.351562 7.160156 59.351562 6.617188 C 59.035156 6.617188 58.71875 6.617188 58.390625 6.617188 C 58.390625 6.371094 58.390625 6.125 58.390625 5.871094 C 58.914062 5.800781 58.914062 5.800781 59.449219 5.726562 C 59.480469 5.601562 59.515625 5.476562 59.550781 5.351562 C 59.574219 5.269531 59.59375 5.191406 59.617188 5.113281 C 59.652344 4.988281 59.6875 4.863281 59.722656 4.738281 C 59.75 4.640625 59.777344 4.539062 59.804688 4.4375 C 59.816406 4.398438 59.824219 4.359375 59.835938 4.324219 C 59.851562 4.269531 59.867188 4.214844 59.882812 4.160156 C 59.886719 4.144531 59.890625 4.128906 59.894531 4.113281 C 59.914062 4.046875 59.929688 3.984375 59.953125 3.921875 Z M 59.953125 3.921875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 93.351562 5.554688 C 93.40625 5.59375 93.429688 5.617188 93.445312 5.679688 C 93.449219 5.75 93.445312 5.8125 93.441406 5.878906 C 93.441406 5.90625 93.441406 5.929688 93.441406 5.957031 C 93.4375 6.015625 93.4375 6.070312 93.433594 6.128906 C 93.429688 6.273438 93.425781 6.417969 93.421875 6.5625 C 93.417969 6.617188 93.417969 6.671875 93.417969 6.726562 C 93.402344 7.175781 93.40625 7.625 93.40625 8.074219 C 93.40625 8.195312 93.40625 8.3125 93.40625 8.429688 C 93.40625 8.644531 93.40625 8.859375 93.40625 9.074219 C 93.40625 9.320312 93.40625 9.570312 93.40625 9.816406 C 93.40625 10.320312 93.40625 10.828125 93.40625 11.332031 C 93.425781 11.335938 93.449219 11.339844 93.46875 11.34375 C 93.542969 11.355469 93.613281 11.371094 93.6875 11.382812 C 93.734375 11.390625 93.785156 11.398438 93.832031 11.40625 C 93.859375 11.414062 93.890625 11.417969 93.921875 11.425781 C 93.949219 11.429688 93.976562 11.433594 94.003906 11.4375 C 94.070312 11.449219 94.136719 11.464844 94.199219 11.476562 C 94.199219 11.675781 94.199219 11.875 94.199219 12.078125 C 93.105469 12.078125 92.015625 12.078125 90.886719 12.078125 C 90.886719 11.878906 90.886719 11.679688 90.886719 11.476562 C 90.988281 11.457031 91.085938 11.433594 91.1875 11.414062 C 91.222656 11.40625 91.253906 11.402344 91.289062 11.394531 C 91.339844 11.382812 91.386719 11.375 91.4375 11.363281 C 91.480469 11.355469 91.480469 11.355469 91.527344 11.34375 C 91.601562 11.332031 91.675781 11.332031 91.753906 11.332031 C 91.753906 10.894531 91.753906 10.457031 91.753906 10.023438 C 91.753906 9.820312 91.753906 9.617188 91.753906 9.414062 C 91.753906 9.234375 91.753906 9.058594 91.753906 8.882812 C 91.753906 8.789062 91.753906 8.695312 91.753906 8.601562 C 91.753906 8.066406 91.746094 7.535156 91.726562 7 C 91.683594 6.996094 91.683594 6.996094 91.636719 6.988281 C 91.539062 6.976562 91.4375 6.964844 91.339844 6.953125 C 91.296875 6.945312 91.25 6.941406 91.207031 6.933594 C 91.144531 6.925781 91.082031 6.917969 91.019531 6.910156 C 90.988281 6.90625 90.988281 6.90625 90.957031 6.902344 C 90.820312 6.882812 90.820312 6.882812 90.792969 6.855469 C 90.789062 6.816406 90.789062 6.777344 90.789062 6.738281 C 90.789062 6.714844 90.789062 6.691406 90.789062 6.667969 C 90.789062 6.640625 90.789062 6.617188 90.789062 6.589844 C 90.789062 6.566406 90.789062 6.539062 90.789062 6.515625 C 90.792969 6.453125 90.792969 6.390625 90.792969 6.328125 C 90.96875 6.253906 91.148438 6.1875 91.328125 6.125 C 91.355469 6.117188 91.382812 6.105469 91.414062 6.097656 C 91.503906 6.066406 91.59375 6.03125 91.683594 6 C 91.808594 5.957031 91.929688 5.914062 92.054688 5.871094 C 92.070312 5.867188 92.085938 5.859375 92.101562 5.855469 C 92.285156 5.792969 92.46875 5.726562 92.652344 5.660156 C 92.667969 5.652344 92.6875 5.644531 92.703125 5.640625 C 92.78125 5.609375 92.859375 5.582031 92.9375 5.554688 C 92.976562 5.539062 92.976562 5.539062 93.019531 5.523438 C 93.050781 5.511719 93.050781 5.511719 93.082031 5.5 C 93.1875 5.476562 93.261719 5.503906 93.351562 5.554688 Z M 93.351562 5.554688 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 42.214844 5.652344 C 42.214844 7.542969 42.214844 9.433594 42.214844 11.378906 C 42.535156 11.441406 42.535156 11.441406 42.863281 11.5 C 42.917969 11.515625 42.976562 11.53125 43.03125 11.550781 C 43.03125 11.738281 43.03125 11.929688 43.03125 12.125 C 41.929688 12.125 40.832031 12.125 39.695312 12.125 C 39.695312 11.9375 39.695312 11.746094 39.695312 11.550781 C 39.875 11.5 40.054688 11.460938 40.234375 11.425781 C 40.265625 11.417969 40.265625 11.417969 40.296875 11.410156 C 40.316406 11.40625 40.335938 11.402344 40.355469 11.398438 C 40.375 11.394531 40.394531 11.390625 40.410156 11.386719 C 40.46875 11.378906 40.523438 11.378906 40.585938 11.378906 C 40.582031 10.886719 40.578125 10.390625 40.574219 9.898438 C 40.574219 9.667969 40.574219 9.4375 40.570312 9.207031 C 40.570312 9.007812 40.570312 8.808594 40.570312 8.605469 C 40.566406 8.5 40.566406 8.394531 40.566406 8.289062 C 40.566406 8.191406 40.566406 8.089844 40.566406 7.988281 C 40.566406 7.953125 40.566406 7.917969 40.566406 7.878906 C 40.5625 7.683594 40.558594 7.488281 40.550781 7.292969 C 40.546875 7.273438 40.546875 7.253906 40.546875 7.234375 C 40.542969 7.140625 40.542969 7.140625 40.511719 7.050781 C 40.445312 7.035156 40.378906 7.027344 40.308594 7.019531 C 40.289062 7.015625 40.269531 7.011719 40.25 7.011719 C 40.183594 7.003906 40.121094 6.996094 40.054688 6.988281 C 40.011719 6.980469 39.96875 6.976562 39.921875 6.96875 C 39.816406 6.957031 39.707031 6.941406 39.601562 6.929688 C 39.601562 6.746094 39.601562 6.5625 39.601562 6.375 C 39.964844 6.242188 40.328125 6.109375 40.695312 5.980469 C 40.777344 5.953125 40.859375 5.921875 40.945312 5.894531 C 41 5.875 41.054688 5.855469 41.109375 5.835938 C 41.246094 5.789062 41.386719 5.738281 41.523438 5.6875 C 41.550781 5.675781 41.578125 5.667969 41.605469 5.65625 C 41.660156 5.636719 41.710938 5.617188 41.761719 5.597656 C 41.785156 5.589844 41.808594 5.578125 41.835938 5.570312 C 41.863281 5.558594 41.863281 5.558594 41.894531 5.546875 C 42.027344 5.515625 42.09375 5.585938 42.214844 5.652344 Z M 42.214844 5.652344 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 8.640625 9.261719 C 8.972656 9.519531 9.191406 9.859375 9.277344 10.273438 C 9.328125 10.675781 9.265625 11.089844 9.019531 11.421875 C 8.734375 11.769531 8.371094 12.007812 7.917969 12.058594 C 7.476562 12.09375 7.078125 11.957031 6.742188 11.667969 C 6.71875 11.648438 6.71875 11.648438 6.695312 11.628906 C 6.421875 11.378906 6.261719 10.992188 6.234375 10.628906 C 6.226562 10.179688 6.355469 9.789062 6.664062 9.457031 C 7.191406 8.921875 8.019531 8.84375 8.640625 9.261719 Z M 8.640625 9.261719 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 2.855469 4.089844 C 2.941406 4.15625 3.019531 4.230469 3.097656 4.308594 C 3.113281 4.324219 3.128906 4.339844 3.148438 4.359375 C 3.414062 4.640625 3.542969 5.027344 3.539062 5.410156 C 3.519531 5.851562 3.332031 6.21875 3.015625 6.527344 C 2.707031 6.792969 2.304688 6.921875 1.898438 6.898438 C 1.578125 6.871094 1.308594 6.769531 1.054688 6.570312 C 1.03125 6.546875 1.03125 6.546875 1.003906 6.527344 C 0.699219 6.277344 0.527344 5.898438 0.484375 5.511719 C 0.453125 5.121094 0.558594 4.730469 0.804688 4.425781 C 1.003906 4.191406 1.226562 4.03125 1.511719 3.921875 C 1.53125 3.914062 1.550781 3.90625 1.570312 3.898438 C 1.988281 3.757812 2.496094 3.84375 2.855469 4.089844 Z M 2.855469 4.089844 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 2.960938 11.683594 C 3.269531 11.949219 3.492188 12.316406 3.53125 12.726562 C 3.558594 13.152344 3.449219 13.550781 3.171875 13.878906 C 2.875 14.203125 2.519531 14.375 2.082031 14.417969 C 1.671875 14.433594 1.28125 14.28125 0.972656 14.011719 C 0.660156 13.714844 0.488281 13.324219 0.476562 12.890625 C 0.480469 12.53125 0.59375 12.214844 0.816406 11.933594 C 0.828125 11.917969 0.839844 11.902344 0.851562 11.882812 C 1.078125 11.597656 1.433594 11.421875 1.785156 11.363281 C 2.207031 11.316406 2.628906 11.417969 2.960938 11.683594 Z M 2.960938 11.683594 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 14.449219 4.167969 C 14.507812 4.222656 14.5625 4.273438 14.617188 4.332031 C 14.628906 4.34375 14.640625 4.355469 14.65625 4.367188 C 14.914062 4.632812 15.015625 5.023438 15.03125 5.378906 C 15.019531 5.734375 14.902344 6.046875 14.6875 6.328125 C 14.675781 6.34375 14.664062 6.359375 14.652344 6.378906 C 14.410156 6.679688 14.042969 6.851562 13.664062 6.898438 C 13.242188 6.925781 12.84375 6.816406 12.523438 6.535156 C 12.484375 6.5 12.445312 6.460938 12.40625 6.425781 C 12.394531 6.410156 12.378906 6.394531 12.363281 6.378906 C 12.085938 6.089844 11.988281 5.707031 11.992188 5.316406 C 12.003906 4.914062 12.167969 4.53125 12.457031 4.25 C 13.023438 3.75 13.847656 3.714844 14.449219 4.167969 Z M 14.449219 4.167969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 42.046875 2.648438 C 42.253906 2.816406 42.375 3.03125 42.40625 3.296875 C 42.433594 3.558594 42.351562 3.808594 42.191406 4.019531 C 42.007812 4.214844 41.785156 4.351562 41.507812 4.363281 C 41.46875 4.363281 41.429688 4.363281 41.390625 4.363281 C 41.371094 4.363281 41.351562 4.363281 41.332031 4.363281 C 41.058594 4.355469 40.832031 4.273438 40.625 4.089844 C 40.476562 3.933594 40.359375 3.734375 40.34375 3.511719 C 40.34375 3.496094 40.339844 3.480469 40.339844 3.460938 C 40.328125 3.230469 40.390625 2.992188 40.542969 2.8125 C 40.554688 2.796875 40.570312 2.78125 40.585938 2.765625 C 40.597656 2.75 40.613281 2.734375 40.632812 2.714844 C 41.019531 2.339844 41.621094 2.332031 42.046875 2.648438 Z M 42.046875 2.648438 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;" d="M 93.210938 2.566406 C 93.453125 2.757812 93.570312 2.96875 93.609375 3.273438 C 93.621094 3.53125 93.550781 3.773438 93.378906 3.972656 C 93.367188 3.988281 93.351562 4.003906 93.335938 4.019531 C 93.316406 4.039062 93.316406 4.039062 93.296875 4.058594 C 93.066406 4.28125 92.78125 4.316406 92.476562 4.3125 C 92.355469 4.308594 92.25 4.285156 92.136719 4.234375 C 92.117188 4.226562 92.101562 4.21875 92.082031 4.210938 C 91.871094 4.105469 91.703125 3.9375 91.605469 3.722656 C 91.515625 3.449219 91.515625 3.171875 91.632812 2.90625 C 91.773438 2.652344 92 2.484375 92.277344 2.402344 C 92.605469 2.324219 92.933594 2.375 93.210938 2.566406 Z M 93.210938 2.566406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 8.320312 5.960938 C 8.539062 6.117188 8.664062 6.320312 8.726562 6.582031 C 8.769531 6.839844 8.710938 7.089844 8.574219 7.3125 C 8.410156 7.535156 8.207031 7.65625 7.945312 7.722656 C 7.621094 7.753906 7.355469 7.6875 7.105469 7.484375 C 6.921875 7.3125 6.8125 7.078125 6.792969 6.832031 C 6.789062 6.535156 6.871094 6.28125 7.078125 6.0625 C 7.4375 5.738281 7.914062 5.710938 8.320312 5.960938 Z M 8.320312 5.960938 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.431373%,73.725492%,19.607843%);fill-opacity:1;" d="M 14.09375 0.820312 C 14.289062 0.96875 14.421875 1.179688 14.472656 1.417969 C 14.5 1.714844 14.464844 1.980469 14.273438 2.214844 C 14.082031 2.421875 13.890625 2.558594 13.605469 2.582031 C 13.320312 2.585938 13.078125 2.535156 12.863281 2.332031 C 12.660156 2.128906 12.550781 1.910156 12.542969 1.621094 C 12.546875 1.332031 12.644531 1.117188 12.839844 0.910156 C 13.199219 0.574219 13.6875 0.5625 14.09375 0.820312 Z M 14.09375 0.820312 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 2.574219 0.808594 C 2.769531 0.972656 2.925781 1.164062 2.976562 1.417969 C 2.996094 1.71875 2.972656 1.976562 2.777344 2.214844 C 2.585938 2.421875 2.394531 2.558594 2.109375 2.582031 C 1.824219 2.585938 1.582031 2.53125 1.367188 2.332031 C 1.226562 2.195312 1.136719 2.066406 1.078125 1.875 C 1.074219 1.863281 1.070312 1.847656 1.066406 1.832031 C 1.015625 1.570312 1.054688 1.3125 1.195312 1.089844 C 1.515625 0.644531 2.101562 0.484375 2.574219 0.808594 Z M 2.574219 0.808594 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 2.550781 8.316406 C 2.582031 8.34375 2.609375 8.371094 2.640625 8.398438 C 2.65625 8.414062 2.671875 8.429688 2.691406 8.445312 C 2.878906 8.640625 2.960938 8.847656 2.964844 9.121094 C 2.960938 9.398438 2.882812 9.613281 2.6875 9.816406 C 2.5 9.996094 2.257812 10.109375 1.992188 10.105469 C 1.695312 10.085938 1.449219 9.972656 1.246094 9.753906 C 1.074219 9.535156 1.003906 9.277344 1.03125 9 C 1.089844 8.710938 1.214844 8.484375 1.453125 8.3125 C 1.789062 8.105469 2.222656 8.085938 2.550781 8.316406 Z M 2.550781 8.316406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 14.058594 8.34375 C 14.269531 8.496094 14.425781 8.714844 14.472656 8.972656 C 14.496094 9.300781 14.441406 9.542969 14.238281 9.804688 C 14.148438 9.90625 14.042969 9.972656 13.921875 10.03125 C 13.894531 10.046875 13.894531 10.046875 13.867188 10.058594 C 13.660156 10.144531 13.386719 10.136719 13.175781 10.066406 C 12.929688 9.960938 12.714844 9.769531 12.613281 9.519531 C 12.601562 9.484375 12.585938 9.445312 12.574219 9.40625 C 12.570312 9.390625 12.566406 9.378906 12.5625 9.363281 C 12.511719 9.109375 12.550781 8.855469 12.679688 8.632812 C 12.824219 8.421875 13.003906 8.277344 13.246094 8.203125 C 13.261719 8.199219 13.277344 8.195312 13.292969 8.191406 C 13.570312 8.136719 13.820312 8.195312 14.058594 8.34375 Z M 14.058594 8.34375 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 8.375 13.523438 C 8.605469 13.730469 8.71875 13.984375 8.742188 14.289062 C 8.734375 14.554688 8.621094 14.789062 8.445312 14.984375 C 8.25 15.164062 7.996094 15.25 7.734375 15.253906 C 7.46875 15.242188 7.25 15.136719 7.0625 14.953125 C 6.863281 14.730469 6.789062 14.488281 6.792969 14.195312 C 6.832031 13.894531 6.964844 13.664062 7.199219 13.472656 C 7.582031 13.230469 8.015625 13.25 8.375 13.523438 Z M 8.375 13.523438 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 14.027344 12.066406 C 14.25 12.234375 14.421875 12.449219 14.472656 12.726562 C 14.492188 13.019531 14.464844 13.269531 14.273438 13.5 C 14.089844 13.699219 13.886719 13.84375 13.609375 13.863281 C 13.3125 13.867188 13.058594 13.800781 12.832031 13.589844 C 12.730469 13.480469 12.65625 13.371094 12.601562 13.234375 C 12.589844 13.207031 12.582031 13.183594 12.570312 13.15625 C 12.519531 12.886719 12.539062 12.625 12.679688 12.386719 C 12.984375 11.945312 13.558594 11.765625 14.027344 12.066406 Z M 14.027344 12.066406 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;" d="M 8.269531 2.203125 C 8.492188 2.371094 8.652344 2.574219 8.703125 2.855469 C 8.738281 3.113281 8.695312 3.371094 8.535156 3.582031 C 8.355469 3.796875 8.136719 3.949219 7.851562 3.976562 C 7.539062 3.988281 7.289062 3.894531 7.054688 3.679688 C 6.851562 3.449219 6.796875 3.222656 6.808594 2.914062 C 6.824219 2.671875 6.929688 2.480469 7.105469 2.308594 C 7.445312 2.039062 7.886719 1.964844 8.269531 2.203125 Z M 8.269531 2.203125 "/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/features/citations.svg b/app/components/base/icons/assets/vender/features/citations.svg
new file mode 100644
index 0000000..4ee12a7
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/citations.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12ZM7 11.9702V14.958H11.0356V11.2339H8.8125C8.78418 10.8185 8.85498 10.4173 9.0249 10.0303C9.35531 9.29395 10.002 8.77474 10.9648 8.47266V7C9.67155 7.25488 8.68506 7.79297 8.00537 8.61426C7.33512 9.43555 7 10.5542 7 11.9702ZM15.0391 10.0586C15.3695 9.29395 16.0114 8.7653 16.9648 8.47266V7C15.7093 7.25488 14.7323 7.78825 14.0337 8.6001C13.3446 9.41195 13 10.5353 13 11.9702V14.958H17.0356V11.2339H14.8125C14.7747 10.8563 14.8503 10.4645 15.0391 10.0586Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/features/content-moderation.svg b/app/components/base/icons/assets/vender/features/content-moderation.svg
new file mode 100644
index 0000000..e84dd4c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/content-moderation.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.16146 3H16.8385C17.3657 2.99998 17.8205 2.99997 18.195 3.03057C18.5904 3.06287 18.9836 3.13419 19.362 3.32698C19.9265 3.6146 20.3854 4.07354 20.673 4.63803C20.8658 5.01641 20.9371 5.40963 20.9694 5.80497C21 6.17954 21 6.6343 21 7.16144V16.8386C21 17.3657 21 17.8205 20.9694 18.195C20.9371 18.5904 20.8658 18.9836 20.673 19.362C20.3854 19.9265 19.9265 20.3854 19.362 20.673C18.9836 20.8658 18.5904 20.9371 18.195 20.9694C17.8205 21 17.3657 21 16.8386 21H7.16144C6.6343 21 6.17954 21 5.80497 20.9694C5.40963 20.9371 5.01641 20.8658 4.63803 20.673C4.07354 20.3854 3.6146 19.9265 3.32698 19.362C3.13419 18.9836 3.06287 18.5904 3.03057 18.195C2.99997 17.8205 2.99998 17.3657 3 16.8386V7.16145C2.99998 6.63432 2.99997 6.17954 3.03057 5.80497C3.06287 5.40963 3.13419 5.01641 3.32698 4.63803C3.6146 4.07354 4.07354 3.6146 4.63803 3.32698C5.01641 3.13419 5.40963 3.06287 5.80497 3.03057C6.17954 2.99997 6.63432 2.99998 7.16146 3ZM17 9C17 8.44772 16.5523 8 16 8C15.4477 8 15 8.44772 15 9V15C15 15.5523 15.4477 16 16 16C16.5523 16 17 15.5523 17 15V9ZM9 12C9 12.5523 8.55229 13 8 13C7.44772 13 7 12.5523 7 12C7 11.4477 7.44772 11 8 11C8.55229 11 9 11.4477 9 12ZM12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/features/document.svg b/app/components/base/icons/assets/vender/features/document.svg
new file mode 100644
index 0000000..dca0e91
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/document.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
+<path d="M20 22H4C3.44772 22 3 21.5523 3 21V3C3 2.44772 3.44772 2 4 2H20C20.5523 2 21 2.44772 21 3V21C21 21.5523 20.5523 22 20 22ZM7 6V10H11V6H7ZM7 12V14H17V12H7ZM7 16V18H17V16H7ZM13 7V9H17V7H13Z"></path>
+</svg>
\ No newline at end of file
diff --git a/app/components/base/icons/assets/vender/features/folder-upload.svg b/app/components/base/icons/assets/vender/features/folder-upload.svg
new file mode 100644
index 0000000..b94ea94
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/folder-upload.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M2 6C2 4.34315 3.34315 3 5 3H8.92963C9.93269 3 10.8694 3.5013 11.4258 4.3359L12.5352 6H19C20.6569 6 22 7.34315 22 9V17C22 18.6569 20.6569 20 19 20H13V15.4142L13.7929 16.2071C14.1834 16.5976 14.8166 16.5976 15.2071 16.2071C15.5976 15.8166 15.5976 15.1834 15.2071 14.7929L12.7071 12.2929C12.3166 11.9024 11.6834 11.9024 11.2929 12.2929L8.79289 14.7929C8.40237 15.1834 8.40237 15.8166 8.79289 16.2071C9.18342 16.5976 9.81658 16.5976 10.2071 16.2071L11 15.4142V20H5C3.34315 20 2 18.6569 2 17V6Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/features/love-message.svg b/app/components/base/icons/assets/vender/features/love-message.svg
new file mode 100644
index 0000000..9dc0f6f
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/love-message.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M22 11.3333C22 6.73833 17.5142 3 12 3C6.48583 3 2 6.73833 2 11.3333C2 15.9283 6.48583 19.6667 11.9825 19.6667C12.8404 19.6814 13.6965 19.5839 14.5292 19.3767L19.1858 21.2725C19.2857 21.3127 19.3924 21.3333 19.5 21.3333C19.6175 21.3334 19.7337 21.3086 19.8409 21.2606C19.9481 21.2126 20.044 21.1425 20.1222 21.0548C20.2004 20.9672 20.2592 20.8639 20.2948 20.7519C20.3303 20.64 20.3417 20.5217 20.3283 20.405L19.8742 16.4733C21.1944 15.0821 21.9518 13.2507 22 11.3333ZM15.3917 12.0533L12.0317 15.47C12.0231 15.4784 12.0116 15.4831 11.9996 15.4831C11.9876 15.4831 11.9761 15.4784 11.9675 15.47L8.60917 12.0533C8.18149 11.6398 7.91983 11.0841 7.87347 10.491C7.82712 9.89789 7.99927 9.30831 8.3575 8.83333C8.57837 8.56064 8.85996 8.3434 9.17978 8.19896C9.49959 8.05451 9.84875 7.98687 10.1994 8.00145C10.55 8.01603 10.8923 8.11241 11.199 8.2829C11.5058 8.45339 11.7684 8.69325 11.9658 8.98333C11.9695 8.98883 11.9744 8.99335 11.9803 8.99647C11.9861 8.99959 11.9926 9.00122 11.9992 9.00122C12.0058 9.00122 12.0123 8.99959 12.0181 8.99647C12.0239 8.99335 12.0289 8.98883 12.0325 8.98333C12.23 8.69325 12.4926 8.45339 12.7993 8.2829C13.106 8.11241 13.4484 8.01603 13.799 8.00145C14.1496 7.98687 14.4987 8.05451 14.8186 8.19896C15.1384 8.3434 15.42 8.56064 15.6408 8.83333C15.9997 9.30788 16.1725 9.89736 16.1266 10.4906C16.0807 11.0838 15.8193 11.6397 15.3917 12.0533Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/features/message-fast.svg b/app/components/base/icons/assets/vender/features/message-fast.svg
new file mode 100644
index 0000000..66a206f
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/message-fast.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16.2414 2H7.7588C6.95383 1.99999 6.28946 1.99998 5.74827 2.04419C5.18617 2.09012 4.66947 2.18868 4.18413 2.43598C3.43149 2.81947 2.81956 3.43139 2.43607 4.18404C2.18878 4.66937 2.09022 5.18608 2.04429 5.74818C2.00007 6.28937 2.00008 6.95373 2.0001 7.7587L2.00005 14.1376C1.99962 14.933 1.9993 15.5236 2.13639 16.0353C2.50626 17.4156 3.58445 18.4938 4.96482 18.8637C5.27229 18.9461 5.60829 18.9789 6.0001 18.9918L6.00009 20.371C6.00005 20.6062 6 20.846 6.01785 21.0425C6.03492 21.2305 6.08012 21.5852 6.32778 21.8955C6.61276 22.2525 7.0449 22.4602 7.50172 22.4597C7.8987 22.4593 8.20394 22.273 8.36137 22.1689C8.52597 22.06 8.7132 21.9102 8.89688 21.7632L11.31 19.8327C11.8286 19.4178 11.9826 19.3007 12.1425 19.219C12.303 19.137 12.4738 19.0771 12.6504 19.0408C12.8263 19.0047 13.0197 19 13.6838 19H16.2414C17.0464 19 17.7107 19 18.2519 18.9558C18.814 18.9099 19.3307 18.8113 19.8161 18.564C20.5687 18.1805 21.1806 17.5686 21.5641 16.816C21.8114 16.3306 21.91 15.8139 21.9559 15.2518C22.0001 14.7106 22.0001 14.0463 22.0001 13.2413V7.75868C22.0001 6.95372 22.0001 6.28936 21.9559 5.74818C21.91 5.18608 21.8114 4.66937 21.5641 4.18404C21.1806 3.43139 20.5687 2.81947 19.8161 2.43598C19.3307 2.18868 18.814 2.09012 18.2519 2.04419C17.7107 1.99998 17.0464 1.99999 16.2414 2ZM12.681 5.5349C12.8938 5.61898 13.0218 5.83714 12.9916 6.06386L12.5688 9.23501L14.48 9.23501C14.5899 9.23498 14.7038 9.23496 14.7979 9.24356C14.8905 9.25203 15.0589 9.27446 15.2095 9.39066C15.3851 9.52617 15.4913 9.73269 15.4996 9.95432C15.5066 10.1444 15.427 10.2945 15.38 10.3747C15.3324 10.4563 15.2661 10.549 15.2022 10.6384L11.9072 15.2514C11.7743 15.4375 11.5317 15.5092 11.319 15.4251C11.1063 15.341 10.9782 15.1229 11.0084 14.8961L11.4312 11.725L9.52004 11.725C9.41011 11.725 9.29618 11.725 9.20206 11.7164C9.10948 11.708 8.94106 11.6855 8.79051 11.5693C8.61493 11.4338 8.50866 11.2273 8.50044 11.0057C8.49339 10.8156 8.57303 10.6655 8.61996 10.5853C8.66766 10.5037 8.7339 10.411 8.79781 10.3216L12.0928 5.70858C12.2257 5.52246 12.4683 5.45083 12.681 5.5349Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/features/microphone-01.svg b/app/components/base/icons/assets/vender/features/microphone-01.svg
new file mode 100644
index 0000000..ebd4115
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/microphone-01.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 1C9.79086 1 8 2.79086 8 5V12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12V5C16 2.79086 14.2091 1 12 1Z" fill="black"/>
+<path d="M6 10C6 9.44771 5.55228 9 5 9C4.44772 9 4 9.44771 4 10V12C4 16.0803 7.05466 19.4471 11.0019 19.9383C11.0006 19.9587 11 19.9793 11 20V21H8C7.44772 21 7 21.4477 7 22C7 22.5523 7.44772 23 8 23H16C16.5523 23 17 22.5523 17 22C17 21.4477 16.5523 21 16 21H13V20C13 19.9793 12.9994 19.9587 12.9981 19.9383C16.9453 19.4471 20 16.0803 20 12V10C20 9.44771 19.5523 9 19 9C18.4477 9 18 9.44771 18 10V12C18 15.3137 15.3137 18 12 18C8.68629 18 6 15.3137 6 12V10Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/features/text-to-audio.svg b/app/components/base/icons/assets/vender/features/text-to-audio.svg
new file mode 100644
index 0000000..89d2d40
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/text-to-audio.svg
@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1 5.02263C1 3.90973 1.90219 3.00754 3.01509 3.00754H9.06035C10.1733 3.00754 11.0754 3.90973 11.0754 5.02263C11.0754 5.57908 10.6243 6.03017 10.0679 6.03017C9.51144 6.03017 9.06035 5.57908 9.06035 5.02263H7.04526V12.0754C7.60171 12.0754 8.0528 12.5265 8.0528 13.083C8.0528 13.6394 7.60171 14.0905 7.04526 14.0905H5.03017C4.47372 14.0905 4.02263 13.6394 4.02263 13.083C4.02263 12.5265 4.47372 12.0754 5.03017 12.0754V5.02263H3.01509C3.01509 5.57908 2.56399 6.03017 2.00754 6.03017C1.45109 6.03017 1 5.57908 1 5.02263Z" fill="black"/>
+<path d="M19.9883 2.15888C19.8823 1.94704 19.58 1.94704 19.4741 2.15888C18.8148 3.47752 18.6898 3.6025 17.3712 4.26182C17.1593 4.36774 17.1593 4.67004 17.3712 4.77596C18.6898 5.43528 18.8148 5.56026 19.4741 6.8789C19.58 7.09074 19.8823 7.09074 19.9883 6.8789C20.6476 5.56026 20.7726 5.43528 22.0912 4.77596C22.303 4.67004 22.303 4.36774 22.0912 4.26182C20.7726 3.6025 20.6476 3.47752 19.9883 2.15888Z" fill="black"/>
+<path d="M14.4561 4.17977C14.3463 3.96019 14.033 3.96019 13.9232 4.17977C13.4339 5.15833 13.3178 5.27443 12.3393 5.76371C12.1197 5.8735 12.1197 6.18685 12.3393 6.29664C13.3178 6.78592 13.4339 6.90202 13.9232 7.88058C14.033 8.10016 14.3463 8.10016 14.4561 7.88058C14.9454 6.90202 15.0615 6.78592 16.0401 6.29664C16.2596 6.18685 16.2596 5.8735 16.0401 5.76371C15.0615 5.27443 14.9454 5.15833 14.4561 4.17977Z" fill="black"/>
+<path d="M4.78347 16.2645C4.67755 16.0527 4.37525 16.0526 4.26933 16.2645C3.61002 17.5831 3.48505 17.7081 2.16642 18.3674C1.95458 18.4733 1.95458 18.7756 2.16642 18.8815C3.48505 19.5408 3.61002 19.6658 4.26933 20.9844C4.37525 21.1963 4.67755 21.1963 4.78347 20.9844C5.44278 19.6658 5.56776 19.5408 6.88638 18.8815C7.09822 18.7756 7.09822 18.4733 6.88638 18.3674C5.56776 17.7081 5.44278 17.5831 4.78347 16.2645Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M21.1611 12.97C21.4558 12.7644 21.8613 12.8367 22.0668 13.1313C22.655 13.9746 23 15.0008 23 16.1056C23 17.2105 22.655 18.2367 22.0668 19.0799C21.8613 19.3745 21.4558 19.4468 21.1611 19.2413C20.8664 19.0357 20.7942 18.6302 20.9997 18.3355C21.4405 17.7036 21.699 16.9358 21.699 16.1056C21.699 15.2755 21.4405 14.5076 20.9997 13.8757C20.7942 13.581 20.8664 13.1755 21.1611 12.97Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M18.2666 10.0664C18.578 10.0419 18.8823 10.1679 19.0852 10.4054C19.2668 10.6181 19.2957 10.8739 19.3067 10.9981C19.319 11.1373 19.319 11.3102 19.319 11.4861C19.319 11.4942 19.319 11.5022 19.319 11.5103L19.319 20.7312C19.319 20.9071 19.319 21.0799 19.3067 21.2191C19.2957 21.3433 19.2668 21.5991 19.0852 21.8118C18.8823 22.0493 18.578 22.1754 18.2666 22.1509C17.9878 22.1289 17.7865 21.9684 17.6909 21.8884C17.5838 21.7987 17.4615 21.6764 17.3372 21.552L15.2607 19.4756C15.2004 19.4153 15.1702 19.3853 15.1474 19.3645L15.1457 19.3629L15.1433 19.3628C15.1124 19.3614 15.0699 19.3612 14.9847 19.3612L13.8338 19.3612C13.6696 19.3613 13.5097 19.3613 13.3743 19.3502C13.2256 19.3381 13.0502 19.3094 12.8736 19.2194C12.6288 19.0947 12.4297 18.8957 12.305 18.6509C12.215 18.4743 12.1864 18.2988 12.1742 18.1501C12.1632 18.0147 12.1632 17.8548 12.1632 17.6906L12.1632 14.5474C12.1632 14.5404 12.1632 14.5335 12.1632 14.5266C12.1632 14.3624 12.1632 14.2025 12.1742 14.0671C12.1864 13.9184 12.215 13.743 12.305 13.5664C12.4297 13.3216 12.6288 13.1225 12.8736 12.9978C13.0502 12.9078 13.2256 12.8792 13.3743 12.867C13.5097 12.856 13.6696 12.856 13.8338 12.856C13.8407 12.856 13.8476 12.856 13.8546 12.856H14.9847C15.0699 12.856 15.1124 12.8558 15.1433 12.8544L15.1457 12.8543L15.1474 12.8528C15.1702 12.8319 15.2004 12.8019 15.2607 12.7417L17.32 10.6823C17.3258 10.6766 17.3315 10.6709 17.3372 10.6652C17.4615 10.5408 17.5838 10.4185 17.6909 10.3288C17.7865 10.2488 17.9878 10.0883 18.2666 10.0664Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/features/virtual-assistant.svg b/app/components/base/icons/assets/vender/features/virtual-assistant.svg
new file mode 100644
index 0000000..f4b2101
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/virtual-assistant.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M21.1667 7.16667H18.6667V13C18.6667 13.663 18.4033 14.2989 17.9344 14.7678C17.4656 15.2366 16.8297 15.5 16.1667 15.5H11.5L8.5 18H14.095L17.9792 21.2367C18.0549 21.3004 18.151 21.3347 18.25 21.3333C18.311 21.3332 18.3713 21.3198 18.4267 21.2942C18.4984 21.2606 18.5591 21.2072 18.6016 21.1404C18.6441 21.0735 18.6667 20.9959 18.6667 20.9167V18H21.1667C21.3877 18 21.5996 17.9122 21.7559 17.7559C21.9122 17.5996 22 17.3877 22 17.1667V8C22 7.77899 21.9122 7.56703 21.7559 7.41074C21.5996 7.25446 21.3877 7.16667 21.1667 7.16667Z" fill="black"/>
+<path d="M16.1667 3H2.83333C2.61232 3 2.40036 3.0878 2.24408 3.24408C2.0878 3.40036 2 3.61232 2 3.83333V13C2 13.221 2.0878 13.433 2.24408 13.5893C2.40036 13.7455 2.61232 13.8333 2.83333 13.8333H5.33333V17.5833C5.33331 17.6626 5.35587 17.7402 5.39838 17.807C5.44089 17.8739 5.50158 17.9272 5.57333 17.9608C5.6287 17.9865 5.68897 17.9999 5.75 18C5.84753 18.0004 5.94204 17.9661 6.01667 17.9033L10.9008 13.8333H16.1667C16.3877 13.8333 16.5996 13.7455 16.7559 13.5893C16.9122 13.433 17 13.221 17 13V3.83333C17 3.61232 16.9122 3.40036 16.7559 3.24408C16.5996 3.0878 16.3877 3 16.1667 3Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/features/vision.svg b/app/components/base/icons/assets/vender/features/vision.svg
new file mode 100644
index 0000000..1c4c86c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/features/vision.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M22.357 10.5831C19.7908 6.27233 15.952 3.99997 12.0002 4C8.04853 4.00003 4.20967 6.27243 1.64354 10.5832C1.12403 11.4559 1.12403 12.5442 1.64354 13.4169C4.20968 17.7277 8.04854 20 12.0003 20C15.952 20 19.7908 17.7276 22.357 13.4168C22.8765 12.5441 22.8765 11.4558 22.357 10.5831ZM11.5528 8.89443L10.7412 10.5176C10.6928 10.6144 10.6144 10.6928 10.5176 10.7412L8.89443 11.5528C8.5259 11.737 8.5259 12.263 8.89443 12.4472L10.5176 13.2588C10.6144 13.3072 10.6928 13.3856 10.7412 13.4824L11.5528 15.1056C11.737 15.4741 12.263 15.4741 12.4472 15.1056L13.2588 13.4824C13.3072 13.3856 13.3856 13.3072 13.4824 13.2588L15.1056 12.4472C15.4741 12.263 15.4741 11.737 15.1056 11.5528L13.4824 10.7412C13.3856 10.6928 13.3072 10.6144 13.2588 10.5176L12.4472 8.89443C12.263 8.5259 11.737 8.5259 11.5528 8.89443Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/alertsAndFeedback/alert-triangle.svg b/app/components/base/icons/assets/vender/line/alertsAndFeedback/alert-triangle.svg
new file mode 100644
index 0000000..05f15c9
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/alertsAndFeedback/alert-triangle.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="alert-triangle">
+<path id="Icon" d="M7.99977 5.33314V7.99981M7.99977 10.6665H8.00644M6.85977 1.90648L1.2131 11.3331C1.09668 11.5348 1.03508 11.7633 1.03443 11.9962C1.03378 12.229 1.0941 12.4579 1.20939 12.6602C1.32468 12.8624 1.49092 13.031 1.69157 13.149C1.89223 13.2671 2.1203 13.3306 2.3531 13.3331H13.6464C13.8792 13.3306 14.1073 13.2671 14.308 13.149C14.5086 13.031 14.6749 12.8624 14.7902 12.6602C14.9054 12.4579 14.9658 12.229 14.9651 11.9962C14.9645 11.7633 14.9029 11.5348 14.7864 11.3331L9.13977 1.90648C9.02092 1.71055 8.85358 1.54856 8.6539 1.43613C8.45422 1.32371 8.22893 1.26465 7.99977 1.26465C7.77061 1.26465 7.54532 1.32371 7.34564 1.43613C7.14596 1.54856 6.97862 1.71055 6.85977 1.90648Z" stroke="#F79009" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-down.svg b/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-down.svg
new file mode 100644
index 0000000..5435445
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-down.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon" clip-path="url(#clip0_17340_934)">
+<path id="Icon_2" d="M11.3333 1.33398V8.66732M14.6666 6.53398V3.46732C14.6666 2.72058 14.6666 2.34721 14.5213 2.062C14.3935 1.81111 14.1895 1.60714 13.9386 1.47931C13.6534 1.33398 13.28 1.33398 12.5333 1.33398H5.41196C4.43764 1.33398 3.95048 1.33398 3.55701 1.51227C3.21022 1.66941 2.91549 1.92227 2.70745 2.24113C2.4714 2.60291 2.39732 3.08441 2.24917 4.0474L1.90045 6.31407C1.70505 7.58419 1.60735 8.21926 1.79582 8.7134C1.96125 9.14711 2.27239 9.50978 2.6759 9.73923C3.13564 10.0007 3.77818 10.0007 5.06324 10.0007H5.59995C5.97332 10.0007 6.16001 10.0007 6.30261 10.0733C6.42806 10.1372 6.53004 10.2392 6.59396 10.3647C6.66662 10.5073 6.66662 10.6939 6.66662 11.0673V13.0234C6.66662 13.9313 7.40262 14.6673 8.31051 14.6673C8.52706 14.6673 8.7233 14.5398 8.81125 14.3419L11.0518 9.30077C11.1537 9.07148 11.2046 8.95684 11.2852 8.87278C11.3563 8.79847 11.4438 8.74165 11.5406 8.70678C11.6501 8.66732 11.7756 8.66732 12.0265 8.66732H12.5333C13.28 8.66732 13.6534 8.66732 13.9386 8.52199C14.1895 8.39416 14.3935 8.19019 14.5213 7.93931C14.6666 7.65409 14.6666 7.28072 14.6666 6.53398Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_17340_934">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-up.svg b/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-up.svg
new file mode 100644
index 0000000..797213f
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-up.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon" clip-path="url(#clip0_17340_931)">
+<path id="Icon_2" d="M4.66671 14.6673V7.33398M1.33337 8.66732V13.334C1.33337 14.0704 1.93033 14.6673 2.66671 14.6673H11.6175C12.6047 14.6673 13.4442 13.9471 13.5943 12.9714L14.3122 8.30477C14.4986 7.09325 13.5613 6.00065 12.3355 6.00065H10C9.63185 6.00065 9.33337 5.70217 9.33337 5.33398V2.97788C9.33337 2.06998 8.59738 1.33398 7.68948 1.33398C7.47293 1.33398 7.27669 1.46151 7.18875 1.6594L4.84267 6.93808C4.73567 7.17883 4.49692 7.33398 4.23346 7.33398H2.66671C1.93033 7.33398 1.33337 7.93094 1.33337 8.66732Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_17340_931">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/arrows/arrow-narrow-left.svg b/app/components/base/icons/assets/vender/line/arrows/arrow-narrow-left.svg
new file mode 100644
index 0000000..1e75ead
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/arrows/arrow-narrow-left.svg
@@ -0,0 +1,3 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M13.3625 8H2.6958M2.6958 8L6.6958 12M2.6958 8L6.6958 4" stroke="#155EEF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/arrows/arrow-up-right.svg b/app/components/base/icons/assets/vender/line/arrows/arrow-up-right.svg
new file mode 100644
index 0000000..43a151c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/arrows/arrow-up-right.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="arrow-up-right">
+<path id="Icon" d="M4.08325 9.91665L9.91659 4.08331M9.91659 4.08331H4.08325M9.91659 4.08331V9.91665" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/arrows/chevron-down-double.svg b/app/components/base/icons/assets/vender/line/arrows/chevron-down-double.svg
new file mode 100644
index 0000000..bb77f89
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/arrows/chevron-down-double.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="13" viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="chevron-down-double">
+<path id="Icon" d="M3.5 7L6 9.5L8.5 7M3.5 3.5L6 6L8.5 3.5" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/arrows/chevron-right.svg b/app/components/base/icons/assets/vender/line/arrows/chevron-right.svg
new file mode 100644
index 0000000..4a46879
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/arrows/chevron-right.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="chevron-right">
+<path id="Icon" d="M5.25 10.5L8.75 7L5.25 3.5" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/arrows/chevron-selector-vertical.svg b/app/components/base/icons/assets/vender/line/arrows/chevron-selector-vertical.svg
new file mode 100644
index 0000000..342d6bb
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/arrows/chevron-selector-vertical.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7 15L12 20L17 15M7 9L12 4L17 9" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/arrows/refresh-ccw-01.svg b/app/components/base/icons/assets/vender/line/arrows/refresh-ccw-01.svg
new file mode 100644
index 0000000..706c677
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/arrows/refresh-ccw-01.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M2 10C2 10 4.00498 7.26822 5.63384 5.63824C7.26269 4.00827 9.5136 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.89691 21 4.43511 18.2543 3.35177 14.5M2 10V4M2 10H8" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/arrows/refresh-cw-05.svg b/app/components/base/icons/assets/vender/line/arrows/refresh-cw-05.svg
new file mode 100644
index 0000000..795077a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/arrows/refresh-cw-05.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.69773 13.1783C7.29715 13.8879 9.20212 13.8494 10.8334 12.9075C13.5438 11.3427 14.4724 7.87704 12.9076 5.16672L12.7409 4.87804M3.09233 10.8335C1.52752 8.12314 2.45615 4.65746 5.16647 3.09265C6.7978 2.15081 8.70277 2.11227 10.3022 2.82185M1.66226 10.8892L3.48363 11.3773L3.97166 9.5559M12.0284 6.44393L12.5164 4.62256L14.3378 5.1106" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/arrows/reverse-left.svg b/app/components/base/icons/assets/vender/line/arrows/reverse-left.svg
new file mode 100644
index 0000000..34313b1
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/arrows/reverse-left.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<path id="Icon_2" d="M2.66699 4.66667H9.33366C11.5428 4.66667 13.3337 6.45753 13.3337 8.66667C13.3337 10.8758 11.5428 12.6667 9.33366 12.6667H2.66699M2.66699 4.66667L5.33366 2M2.66699 4.66667L5.33366 7.33333" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/communication/ai-text.svg b/app/components/base/icons/assets/vender/line/communication/ai-text.svg
new file mode 100644
index 0000000..709ede7
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/communication/ai-text.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="ai-text">
+<path id="Vector" d="M2.33301 10.5H4.08301M2.33301 7H5.24967M2.33301 3.5H11.6663M9.91634 5.83333L10.7913 7.875L12.833 8.75L10.7913 9.625L9.91634 11.6667L9.04134 9.625L6.99967 8.75L9.04134 7.875L9.91634 5.83333Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/communication/chat-bot-slim.svg b/app/components/base/icons/assets/vender/line/communication/chat-bot-slim.svg
new file mode 100644
index 0000000..daceae7
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/communication/chat-bot-slim.svg
@@ -0,0 +1,9 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="chat-bot">
+<g id="Vector">
+<path d="M13.0909 11.2727C14.0951 11.2727 14.9091 10.4587 14.9091 9.45455C14.9091 8.45039 14.0951 7.63636 13.0909 7.63636C12.0868 7.63636 11.2727 8.45039 11.2727 9.45455C11.2727 10.4587 12.0868 11.2727 13.0909 11.2727Z" fill="#D0D5DD"/>
+<path d="M20.3636 22.1818H7.63636C5.62727 22.1818 4 23.8091 4 25.8182V40.3636C4 42.3727 5.62727 44 7.63636 44H33.0909C35.1 44 36.7273 42.3727 36.7273 40.3636V25.8182M13.0909 15.9998V11.2727M13.0909 11.2727C14.0951 11.2727 14.9091 10.4587 14.9091 9.45455C14.9091 8.45039 14.0951 7.63636 13.0909 7.63636C12.0868 7.63636 11.2727 8.45039 11.2727 9.45455C11.2727 10.4587 12.0868 11.2727 13.0909 11.2727ZM27.6364 5.81818C27.6364 4.81455 28.4509 4 29.4545 4H42.1818C43.1855 4 44 4.81455 44 5.81818V14.9091C44 15.9127 43.1855 16.7273 42.1818 16.7273H33.0909L27.6364 20.3636V5.81818Z" stroke="#D0D5DD" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<path id="Vector_2" d="M15.7275 30.364C15.7275 31.3179 14.9542 32.0913 14.0002 32.0913C13.0463 32.0913 12.2729 31.3179 12.2729 30.364C12.2729 29.41 13.0463 28.6367 14.0002 28.6367C14.9542 28.6367 15.7275 29.41 15.7275 30.364ZM28.4548 30.364C28.4548 31.3179 27.6814 32.0913 26.7275 32.0913C25.7735 32.0913 25.0002 31.3179 25.0002 30.364C25.0002 29.41 25.7735 28.6367 26.7275 28.6367C27.6814 28.6367 28.4548 29.41 28.4548 30.364Z" fill="#D0D5DD" stroke="#D0D5DD" stroke-width="2"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/communication/chat-bot.svg b/app/components/base/icons/assets/vender/line/communication/chat-bot.svg
new file mode 100644
index 0000000..ef29114
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/communication/chat-bot.svg
@@ -0,0 +1,14 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon" clip-path="url(#clip0_3167_27725)">
+<path id="Vector" d="M5.93972 6.47002H2.2276C1.64161 6.47002 1.16699 6.94464 1.16699 7.53063V11.7731C1.16699 12.359 1.64161 12.8337 2.2276 12.8337H9.65184C10.2378 12.8337 10.7124 12.359 10.7124 11.7731V7.53063M3.81851 4.66693V3.2882M3.81851 3.2882C4.11139 3.2882 4.34881 3.05078 4.34881 2.7579C4.34881 2.46502 4.11139 2.2276 3.81851 2.2276C3.52563 2.2276 3.2882 2.46502 3.2882 2.7579C3.2882 3.05078 3.52563 3.2882 3.81851 3.2882ZM8.06093 1.6973C8.06093 1.40457 8.29851 1.16699 8.59123 1.16699H12.3034C12.5961 1.16699 12.8337 1.40457 12.8337 1.6973V4.34881C12.8337 4.64154 12.5961 4.87911 12.3034 4.87911H9.65184L8.06093 5.93972V1.6973Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<g id="Vector_2">
+<path d="M4.08354 9.65146C4.52286 9.65146 4.87899 9.29532 4.87899 8.856C4.87899 8.41668 4.52286 8.06055 4.08354 8.06055C3.64422 8.06055 3.28809 8.41668 3.28809 8.856C3.28809 9.29532 3.64422 9.65146 4.08354 9.65146Z" fill="#344054"/>
+<path d="M7.79566 9.65146C8.23498 9.65146 8.59112 9.29532 8.59112 8.856C8.59112 8.41668 8.23498 8.06055 7.79566 8.06055C7.35634 8.06055 7.00021 8.41668 7.00021 8.856C7.00021 9.29532 7.35634 9.65146 7.79566 9.65146Z" fill="#344054"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_3167_27725">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/communication/cute-robot.svg b/app/components/base/icons/assets/vender/line/communication/cute-robot.svg
new file mode 100644
index 0000000..8273dc8
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/communication/cute-robot.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="cute-robot">
+<path id="Vector" d="M6.99967 2.33366H4.08301C3.43868 2.33366 2.91634 2.85599 2.91634 3.50033V6.41699C2.91634 7.06134 3.43868 7.58366 4.08301 7.58366H9.91634C10.5607 7.58366 11.083 7.06134 11.083 6.41699V3.50033C11.083 2.85599 10.5607 2.33366 9.91634 2.33366H6.99967ZM6.99967 2.33366V1.16699M3.49967 8.75033L2.33301 9.91699M3.49967 8.75033C3.49967 10.6833 5.06668 12.2503 6.99967 12.2503C8.93267 12.2503 10.4997 10.6833 10.4997 8.75033M3.49967 8.75033V7.58366M10.4997 8.75033L11.6663 9.91699M10.4997 8.75033V7.58366M5.24967 4.66699V5.25033M8.74967 4.66699V5.25033" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/communication/message-check-remove.svg b/app/components/base/icons/assets/vender/line/communication/message-check-remove.svg
new file mode 100644
index 0000000..ea0c2d5
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/communication/message-check-remove.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="message-check-remove">
+<path id="Vector" d="M15.2 2.99994H7.8C6.11984 2.99994 5.27976 2.99994 4.63803 3.32693C4.07354 3.61455 3.6146 4.07349 3.32698 4.63797C3 5.27971 3 6.11979 3 7.79994V13.9999C3 14.9299 3 15.3949 3.10222 15.7764C3.37962 16.8117 4.18827 17.6203 5.22354 17.8977C5.60504 17.9999 6.07003 17.9999 7 17.9999V20.3354C7 20.8683 7 21.1347 7.10923 21.2716C7.20422 21.3906 7.34827 21.4598 7.50054 21.4596C7.67563 21.4594 7.88367 21.293 8.29976 20.9601L10.6852 19.0518C11.1725 18.6619 11.4162 18.467 11.6875 18.3284C11.9282 18.2054 12.1844 18.1155 12.4492 18.0612C12.7477 17.9999 13.0597 17.9999 13.6837 17.9999H16.2C17.8802 17.9999 18.7202 17.9999 19.362 17.673C19.9265 17.3853 20.3854 16.9264 20.673 16.3619C21 15.7202 21 14.8801 21 13.1999V8.79994M12.3333 13.4999L14 10.4999H10L11.6667 7.49994M19.2322 4.76771L21 2.99994M21 2.99994L22.7678 1.23218M21 2.99994L19.2322 1.23218M21 2.99994L22.7678 4.76771" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/communication/message-fast-plus.svg b/app/components/base/icons/assets/vender/line/communication/message-fast-plus.svg
new file mode 100644
index 0000000..4d399f0
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/communication/message-fast-plus.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M15.2 3H7.8C6.11984 3 5.27976 3 4.63803 3.32698C4.07354 3.6146 3.6146 4.07354 3.32698 4.63803C3 5.27976 3 6.11984 3 7.8V14C3 14.93 3 15.395 3.10222 15.7765C3.37962 16.8117 4.18827 17.6204 5.22354 17.8978C5.60504 18 6.07003 18 7 18V20.3355C7 20.8684 7 21.1348 7.10923 21.2716C7.20422 21.3906 7.34827 21.4599 7.50054 21.4597C7.67563 21.4595 7.88367 21.2931 8.29976 20.9602L10.6852 19.0518C11.1725 18.662 11.4162 18.4671 11.6875 18.3285C11.9282 18.2055 12.1844 18.1156 12.4492 18.0613C12.7477 18 13.0597 18 13.6837 18H16.2C17.8802 18 18.7202 18 19.362 17.673C19.9265 17.3854 20.3854 16.9265 20.673 16.362C21 15.7202 21 14.8802 21 13.2V8.8M12.3333 13.5L14 10.5H10L11.6667 7.5M21 5V3M21 3V1M21 3H19M21 3H23" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/artificial-brain.svg b/app/components/base/icons/assets/vender/line/development/artificial-brain.svg
new file mode 100644
index 0000000..f06d706
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/artificial-brain.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M17.4542 11.9996H11.9999V13.8177M17.4542 11.9996C17.4542 13.0037 18.2682 13.8177 19.2724 13.8177C20.2765 13.8177 21.0905 13.0037 21.0905 11.9996C21.0905 10.9955 20.2765 10.1815 19.2724 10.1815C18.2682 10.1815 17.4542 10.9955 17.4542 11.9996ZM6.54554 12.9087C5.318 12.9012 4.14258 12.4115 3.27293 11.5451M6.54554 12.9087C6.53904 13.471 6.71172 14.0207 7.03861 14.4783C7.36549 14.936 7.82958 15.2776 8.36365 15.4539M6.54554 12.9087C6.54223 12.5292 6.62185 12.1534 6.77888 11.808C6.9359 11.4625 7.16652 11.1556 7.45459 10.9086M3.27293 11.5451C2.8848 11.7842 2.56415 12.1184 2.34142 12.5161C2.1187 12.9139 2.00125 13.3619 2.00022 13.8177C1.99583 14.2518 2.10201 14.6799 2.30876 15.0616C2.51552 15.4433 2.81603 15.766 3.182 15.9995C3.00399 16.4639 2.91159 16.9567 2.90928 17.454C2.90333 18.0525 3.01683 18.6463 3.24315 19.2004C3.46946 19.7546 3.80404 20.258 4.2273 20.6813C4.65056 21.1045 5.154 21.4391 5.70815 21.6654C6.2623 21.8917 6.85603 22.0052 7.45458 21.9993C8.05314 22.0052 8.64686 21.8917 9.20101 21.6654C9.75516 21.4391 10.2586 21.1045 10.6819 20.6813C11.1051 20.258 11.4397 19.7546 11.666 19.2004C11.8923 18.6463 12.0058 18.0525 11.9999 17.454V16.5449H14.7271L16.1688 17.9867M3.27293 11.5451C2.44984 10.6912 1.9931 9.54938 2.00022 8.36339C1.99427 7.76484 2.10777 7.17111 2.33409 6.61696C2.5604 6.06281 2.89498 5.55937 3.31824 5.13611C3.7415 4.71285 4.24494 4.37827 4.79909 4.15195C5.35324 3.92564 5.94697 3.81214 6.54552 3.81809H6.72733C6.90356 3.28402 7.24525 2.81993 7.70289 2.49304C8.16052 2.16616 8.71035 1.99346 9.2727 1.99997C9.63267 1.99331 9.99029 2.0593 10.3242 2.19399C10.6581 2.32869 10.9614 2.52933 11.2159 2.78391C11.4705 3.03849 11.6712 3.34179 11.8059 3.67567C11.9406 4.00956 12.0065 4.36718 11.9999 4.72715M16.1688 6.0126L14.7271 7.45437H11.9999V9.27249M19.2724 19.2721C19.2724 20.2762 18.4584 21.0902 17.4542 21.0902C16.4501 21.0902 15.6361 20.2762 15.6361 19.2721C15.6361 18.268 16.4501 17.454 17.4542 17.454C18.4584 17.454 19.2724 18.268 19.2724 19.2721ZM19.2724 4.72714C19.2724 5.73126 18.4584 6.54526 17.4542 6.54526C16.4501 6.54526 15.6361 5.73126 15.6361 4.72714C15.6361 3.72302 16.4501 2.90902 17.4542 2.90902C18.4584 2.90902 19.2724 3.72302 19.2724 4.72714Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/bar-chart-square-02.svg b/app/components/base/icons/assets/vender/line/development/bar-chart-square-02.svg
new file mode 100644
index 0000000..f421104
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/bar-chart-square-02.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="bar-chart-square-02">
+<path id="Icon" d="M5.33333 10V11.3333M8 7.33333V11.3333M10.6667 4.66667V11.3333M5.2 14H10.8C11.9201 14 12.4802 14 12.908 13.782C13.2843 13.5903 13.5903 13.2843 13.782 12.908C14 12.4802 14 11.9201 14 10.8V5.2C14 4.0799 14 3.51984 13.782 3.09202C13.5903 2.71569 13.2843 2.40973 12.908 2.21799C12.4802 2 11.9201 2 10.8 2H5.2C4.0799 2 3.51984 2 3.09202 2.21799C2.71569 2.40973 2.40973 2.71569 2.21799 3.09202C2 3.51984 2 4.0799 2 5.2V10.8C2 11.9201 2 12.4802 2.21799 12.908C2.40973 13.2843 2.71569 13.5903 3.09202 13.782C3.51984 14 4.0799 14 5.2 14Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/brackets-x.svg b/app/components/base/icons/assets/vender/line/development/brackets-x.svg
new file mode 100644
index 0000000..cd3daec
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/brackets-x.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M18.5708 20C19.8328 20 20.8568 18.977 20.8568 17.714V13.143L21.9998 12L20.8568 10.857V6.286C20.8568 5.023 19.8338 4 18.5708 4M5.429 4C4.166 4 3.143 5.023 3.143 6.286V10.857L2 12L3.143 13.143V17.714C3.143 18.977 4.166 20 5.429 20M15 9L9 15M9 9L15 15" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/code-browser.svg b/app/components/base/icons/assets/vender/line/development/code-browser.svg
new file mode 100644
index 0000000..1a960fe
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/code-browser.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="code-browser">
+<path id="Icon" d="M22 9H2M14 17.5L16.5 15L14 12.5M10 12.5L7.5 15L10 17.5M2 7.8L2 16.2C2 17.8802 2 18.7202 2.32698 19.362C2.6146 19.9265 3.07354 20.3854 3.63803 20.673C4.27976 21 5.11984 21 6.8 21H17.2C18.8802 21 19.7202 21 20.362 20.673C20.9265 20.3854 21.3854 19.9265 21.673 19.362C22 18.7202 22 17.8802 22 16.2V7.8C22 6.11984 22 5.27977 21.673 4.63803C21.3854 4.07354 20.9265 3.6146 20.362 3.32698C19.7202 3 18.8802 3 17.2 3L6.8 3C5.11984 3 4.27976 3 3.63803 3.32698C3.07354 3.6146 2.6146 4.07354 2.32698 4.63803C2 5.27976 2 6.11984 2 7.8Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/container.svg b/app/components/base/icons/assets/vender/line/development/container.svg
new file mode 100644
index 0000000..657ede2
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/container.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M13.6666 4.85185L7.99998 8M7.99998 8L2.33331 4.85185M7.99998 8L8 14.3333M14 10.7057V5.29431C14 5.06588 14 4.95167 13.9663 4.8498C13.9366 4.75969 13.8879 4.67696 13.8236 4.60717C13.7509 4.52828 13.651 4.47281 13.4514 4.36188L8.51802 1.62114C8.32895 1.5161 8.23442 1.46358 8.1343 1.44299C8.0457 1.42477 7.95431 1.42477 7.8657 1.44299C7.76559 1.46358 7.67105 1.5161 7.48198 1.62114L2.54865 4.36188C2.34896 4.47281 2.24912 4.52828 2.17642 4.60717C2.11211 4.67697 2.06343 4.75969 2.03366 4.84981C2 4.95167 2 5.06588 2 5.29431V10.7057C2 10.9341 2 11.0484 2.03366 11.1502C2.06343 11.2403 2.11211 11.3231 2.17642 11.3929C2.24912 11.4718 2.34897 11.5272 2.54865 11.6382L7.48198 14.3789C7.67105 14.4839 7.76559 14.5365 7.8657 14.557C7.95431 14.5753 8.0457 14.5753 8.1343 14.557C8.23442 14.5365 8.32895 14.4839 8.51802 14.3789L13.4514 11.6382C13.651 11.5272 13.7509 11.4718 13.8236 11.3929C13.8879 11.3231 13.9366 11.2403 13.9663 11.1502C14 11.0484 14 10.9341 14 10.7057Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/database-01.svg b/app/components/base/icons/assets/vender/line/development/database-01.svg
new file mode 100644
index 0000000..087f5be
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/database-01.svg
@@ -0,0 +1,3 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.5 3.33337C14.5 4.43794 11.8137 5.33337 8.5 5.33337C5.18629 5.33337 2.5 4.43794 2.5 3.33337M14.5 3.33337C14.5 2.2288 11.8137 1.33337 8.5 1.33337C5.18629 1.33337 2.5 2.2288 2.5 3.33337M14.5 3.33337V12.6667C14.5 13.7734 11.8333 14.6667 8.5 14.6667C5.16667 14.6667 2.5 13.7734 2.5 12.6667V3.33337M14.5 8.00004C14.5 9.10671 11.8333 10 8.5 10C5.16667 10 2.5 9.10671 2.5 8.00004" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/database-03.svg b/app/components/base/icons/assets/vender/line/development/database-03.svg
new file mode 100644
index 0000000..a2c11b4
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/database-03.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.33333 13.3333C9.33333 14.0696 8.73638 14.6666 8 14.6666C7.26362 14.6666 6.66667 14.0696 6.66667 13.3333M9.33333 13.3333C9.33333 12.5969 8.73638 11.9999 8 11.9999M9.33333 13.3333H14M6.66667 13.3333C6.66667 12.5969 7.26362 11.9999 8 11.9999M6.66667 13.3333H2M8 11.9999V9.33325M14 3.33325C14 4.43782 11.3137 5.33325 8 5.33325C4.68629 5.33325 2 4.43782 2 3.33325M14 3.33325C14 2.22868 11.3137 1.33325 8 1.33325C4.68629 1.33325 2 2.22868 2 3.33325M14 3.33325V7.33325C14 8.43992 11.3333 9.33325 8 9.33325M2 3.33325V7.33325C2 8.43992 4.66667 9.33325 8 9.33325" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/file-heart-02.svg b/app/components/base/icons/assets/vender/line/development/file-heart-02.svg
new file mode 100644
index 0000000..5761099
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/file-heart-02.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-heart-02">
+<path id="Icon" d="M13.5709 13.9883C13.5108 14.3786 13.175 14.6666 12.7802 14.6666H9.19984C8.90529 14.6666 8.6665 14.4279 8.6665 14.1333V12.2666C8.6665 11.9721 8.90529 11.7333 9.19984 11.7333H9.82654C9.93192 11.7333 10.0274 11.6713 10.0702 11.5749L11.0087 9.46348C11.0438 9.38432 11.1223 9.33331 11.2089 9.33331C11.5721 9.33331 11.8665 9.62771 11.8665 9.99087V10.9333C11.8665 11.0806 11.9859 11.2 12.1332 11.2H13.0673C13.5577 11.2 13.9326 11.637 13.858 12.1216L13.5709 13.9883Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Vector" d="M13.3332 6.66665V4.53331C13.3332 3.41321 13.3332 2.85316 13.1152 2.42533C12.9234 2.04901 12.6175 1.74305 12.2412 1.5513C11.8133 1.33331 11.2533 1.33331 10.1332 1.33331H5.8665C4.7464 1.33331 4.18635 1.33331 3.75852 1.5513C3.3822 1.74305 3.07624 2.04901 2.88449 2.42533C2.6665 2.85316 2.6665 3.41321 2.6665 4.53331V11.3333C2.6665 11.9533 2.6665 12.2633 2.73465 12.5176C2.91959 13.2078 3.45868 13.7469 4.14887 13.9318C4.4032 14 4.71319 14 5.33317 14M8.33317 7.33331H5.33317M5.99984 9.99998H5.33317M10.6665 4.66665H5.33317" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/git-branch-01.svg b/app/components/base/icons/assets/vender/line/development/git-branch-01.svg
new file mode 100644
index 0000000..1f4c7d2
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/git-branch-01.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="git-branch-01">
+<path id="Icon" d="M2 2V8.8C2 9.92011 2 10.4802 2.21799 10.908C2.40973 11.2843 2.71569 11.5903 3.09202 11.782C3.51984 12 4.0799 12 5.2 12H10M10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12ZM2 5.33333L10 5.33333M10 5.33333C10 6.4379 10.8954 7.33333 12 7.33333C13.1046 7.33333 14 6.4379 14 5.33333C14 4.22876 13.1046 3.33333 12 3.33333C10.8954 3.33333 10 4.22876 10 5.33333Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/prompt-engineering.svg b/app/components/base/icons/assets/vender/line/development/prompt-engineering.svg
new file mode 100644
index 0000000..ef027e3
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/prompt-engineering.svg
@@ -0,0 +1,7 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="prompt-engineering">
+<path id="Icon" d="M14 6V5.2C14 4.0799 14 3.51984 13.782 3.09202C13.5903 2.7157 13.2843 2.40974 12.908 2.21799C12.4802 2 11.9201 2 10.8 2H5.2C4.0799 2 3.51984 2 3.09202 2.21799C2.7157 2.40973 2.40973 2.7157 2.21799 3.09202C2 3.51984 2 4.0799 2 5.2V10.8C2 11.9201 2 12.4802 2.21799 12.908C2.40973 13.2843 2.71569 13.5903 3.09202 13.782C3.51984 14 4.07989 14 5.2 14H6" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Vector" d="M4.6665 4.66669H4.67317M6.6665 4.66669H6.67317M8.6665 4.66669H8.67317" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Icon_2" d="M11.3333 8L11.5343 8.80399C11.7036 9.48123 11.7883 9.81985 11.9646 10.0954C12.1206 10.3391 12.3275 10.5461 12.5713 10.7021C12.8468 10.8784 13.1854 10.963 13.8627 11.1323L14.6667 11.3333L13.8627 11.5343C13.1854 11.7036 12.8468 11.7883 12.5713 11.9646C12.3275 12.1206 12.1206 12.3275 11.9646 12.5713C11.7883 12.8468 11.7036 13.1854 11.5343 13.8627L11.3333 14.6667L11.1323 13.8627C10.963 13.1854 10.8784 12.8468 10.7021 12.5713C10.5461 12.3275 10.3391 12.1206 10.0954 11.9646C9.81985 11.7883 9.48123 11.7036 8.80399 11.5343L8 11.3333L8.80399 11.1323C9.48123 10.963 9.81985 10.8784 10.0954 10.7021C10.3391 10.5461 10.5461 10.3391 10.7021 10.0954C10.8784 9.81985 10.963 9.48123 11.1323 8.80399L11.3333 8Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/puzzle-piece-01.svg b/app/components/base/icons/assets/vender/line/development/puzzle-piece-01.svg
new file mode 100644
index 0000000..2498711
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/puzzle-piece-01.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="puzzle-piece-01" clip-path="url(#clip0_6770_9698)">
+<path id="Icon" d="M4.99992 3.00004C4.99992 2.07957 5.74611 1.33337 6.66659 1.33337C7.58706 1.33337 8.33325 2.07957 8.33325 3.00004V4.00004H8.99992C9.9318 4.00004 10.3977 4.00004 10.7653 4.15228C11.2553 4.35527 11.6447 4.74462 11.8477 5.23467C11.9999 5.60222 11.9999 6.06816 11.9999 7.00004H12.9999C13.9204 7.00004 14.6666 7.74623 14.6666 8.66671C14.6666 9.58718 13.9204 10.3334 12.9999 10.3334H11.9999V11.4667C11.9999 12.5868 11.9999 13.1469 11.7819 13.5747C11.5902 13.951 11.2842 14.257 10.9079 14.4487C10.4801 14.6667 9.92002 14.6667 8.79992 14.6667H8.33325V13.5C8.33325 12.6716 7.66168 12 6.83325 12C6.00483 12 5.33325 12.6716 5.33325 13.5V14.6667H4.53325C3.41315 14.6667 2.85309 14.6667 2.42527 14.4487C2.04895 14.257 1.74299 13.951 1.55124 13.5747C1.33325 13.1469 1.33325 12.5868 1.33325 11.4667V10.3334H2.33325C3.25373 10.3334 3.99992 9.58718 3.99992 8.66671C3.99992 7.74623 3.25373 7.00004 2.33325 7.00004H1.33325C1.33325 6.06816 1.33325 5.60222 1.48549 5.23467C1.68848 4.74462 2.07783 4.35527 2.56789 4.15228C2.93543 4.00004 3.40137 4.00004 4.33325 4.00004H4.99992V3.00004Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_6770_9698">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/terminal-square.svg b/app/components/base/icons/assets/vender/line/development/terminal-square.svg
new file mode 100644
index 0000000..89bb153
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/terminal-square.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="terminal-square">
+<path id="Icon" d="M7 15L10 12L7 9M13 15H17M7.8 21H16.2C17.8802 21 18.7202 21 19.362 20.673C19.9265 20.3854 20.3854 19.9265 20.673 19.362C21 18.7202 21 17.8802 21 16.2V7.8C21 6.11984 21 5.27976 20.673 4.63803C20.3854 4.07354 19.9265 3.6146 19.362 3.32698C18.7202 3 17.8802 3 16.2 3H7.8C6.11984 3 5.27976 3 4.63803 3.32698C4.07354 3.6146 3.6146 4.07354 3.32698 4.63803C3 5.27976 3 6.11984 3 7.8V16.2C3 17.8802 3 18.7202 3.32698 19.362C3.6146 19.9265 4.07354 20.3854 4.63803 20.673C5.27976 21 6.11984 21 7.8 21Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/variable.svg b/app/components/base/icons/assets/vender/line/development/variable.svg
new file mode 100644
index 0000000..65c0552
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/variable.svg
@@ -0,0 +1,9 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="variable">
+<g id="Solid">
+<path d="M13.8686 1.70487C13.7055 1.37481 13.3056 1.23952 12.9756 1.40268C12.6455 1.56585 12.5102 1.9657 12.6734 2.29576C13.5225 4.01329 14.0003 5.94969 14.0003 8.00031C14.0003 10.0509 13.5225 11.9873 12.6734 13.7049C12.5102 14.0349 12.6455 14.4348 12.9756 14.5979C13.3056 14.7611 13.7055 14.6258 13.8686 14.2958C14.8066 12.3984 15.3336 10.2602 15.3336 8.00031C15.3336 5.74041 14.8066 3.60221 13.8686 1.70487Z" fill="#2970FF"/>
+<path d="M3.32724 2.29576C3.49041 1.9657 3.35511 1.56585 3.02506 1.40268C2.695 1.23952 2.29515 1.37481 2.13198 1.70487C1.19401 3.60221 0.666992 5.74041 0.666992 8.00031C0.666992 10.2602 1.19401 12.3984 2.13198 14.2958C2.29515 14.6258 2.695 14.7611 3.02506 14.5979C3.35511 14.4348 3.49041 14.0349 3.32724 13.7049C2.47815 11.9873 2.00033 10.0509 2.00033 8.00031C2.00033 5.94969 2.47815 4.01329 3.32724 2.29576Z" fill="#2970FF"/>
+<path d="M9.33274 5.84142C9.74245 5.36093 10.3415 5.0835 10.973 5.0835H11.0328C11.4009 5.0835 11.6994 5.38197 11.6994 5.75016C11.6994 6.11835 11.4009 6.41683 11.0328 6.41683H10.973C10.7333 6.41683 10.5046 6.52209 10.3473 6.70653L8.78729 8.53612L9.28122 10.2739C9.29182 10.3112 9.32425 10.3335 9.35733 10.3335H10.2867C10.6549 10.3335 10.9534 10.632 10.9534 11.0002C10.9534 11.3684 10.6549 11.6668 10.2867 11.6668H9.35733C8.72419 11.6668 8.17111 11.2451 7.99868 10.6385L7.74768 9.75536L6.7641 10.9089C6.35439 11.3894 5.75537 11.6668 5.12387 11.6668H5.06409C4.6959 11.6668 4.39742 11.3684 4.39742 11.0002C4.39742 10.632 4.6959 10.3335 5.06409 10.3335H5.12387C5.36357 10.3335 5.59225 10.2282 5.74952 10.0438L7.30963 8.21412L6.81573 6.47639C6.80513 6.43909 6.7727 6.41683 6.73962 6.41683H5.81022C5.44203 6.41683 5.14355 6.11835 5.14355 5.75016C5.14355 5.38197 5.44203 5.0835 5.81022 5.0835H6.73962C7.37276 5.0835 7.92584 5.5052 8.09826 6.11186L8.34924 6.99487L9.33274 5.84142Z" fill="#2970FF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/development/webhooks.svg b/app/components/base/icons/assets/vender/line/development/webhooks.svg
new file mode 100644
index 0000000..e1f693f
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/development/webhooks.svg
@@ -0,0 +1,12 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="webhooks">
+<g id="Vector">
+<path d="M12.0007 11.9999C12.5529 11.9999 13.0007 11.5522 13.0007 10.9999C13.0007 10.4476 12.5529 9.99993 12.0007 9.99993C11.4484 9.99993 11.0007 10.4476 11.0007 10.9999C11.0007 11.5522 11.4484 11.9999 12.0007 11.9999Z" fill="#155EEF"/>
+<path d="M8.00065 5.49993C8.55294 5.49993 9.00065 5.05222 9.00065 4.49993C9.00065 3.94765 8.55294 3.49993 8.00065 3.49993C7.44837 3.49993 7.00065 3.94765 7.00065 4.49993C7.00065 5.05222 7.44837 5.49993 8.00065 5.49993Z" fill="#155EEF"/>
+<path d="M4.00065 11.9999C4.55294 11.9999 5.00065 11.5522 5.00065 10.9999C5.00065 10.4476 4.55294 9.99993 4.00065 9.99993C3.44837 9.99993 3.00065 10.4476 3.00065 10.9999C3.00065 11.5522 3.44837 11.9999 4.00065 11.9999Z" fill="#155EEF"/>
+<path d="M2.40065 8.9666C2.6952 9.18751 2.7549 9.60538 2.53398 9.89993C2.35969 10.1323 2.24311 10.4028 2.19386 10.6891C2.14461 10.9754 2.16409 11.2693 2.25071 11.5466C2.33733 11.8239 2.48859 12.0766 2.69205 12.2839C2.8955 12.4913 3.14531 12.6473 3.4209 12.7392C3.69649 12.831 3.98996 12.8561 4.27713 12.8123C4.56431 12.7685 4.83696 12.6571 5.07262 12.4872C5.30828 12.3174 5.50021 12.0939 5.63258 11.8353C5.76495 11.5768 5.83398 11.2904 5.83398 10.9999C5.83398 10.6317 6.13246 10.3333 6.50065 10.3333H12.0007C12.3688 10.3333 12.6673 10.6317 12.6673 10.9999C12.6673 11.3681 12.3688 11.6666 12.0007 11.6666H7.09635C7.03846 11.9354 6.94561 12.1965 6.81944 12.4429C6.5908 12.8896 6.25929 13.2755 5.85223 13.5689C5.44518 13.8623 4.97424 14.0547 4.47821 14.1304C3.98219 14.2061 3.47528 14.1628 2.99926 14.0041C2.52325 13.8454 2.09175 13.5759 1.74033 13.2178C1.38891 12.8596 1.12763 12.4231 0.978025 11.9441C0.828415 11.4652 0.794759 10.9575 0.879828 10.463C0.964898 9.96855 1.16626 9.50134 1.46732 9.09993C1.68823 8.80538 2.1061 8.74568 2.40065 8.9666Z" fill="#155EEF"/>
+<path d="M7.22821 1.43134C7.70981 1.31005 8.21318 1.30373 8.69767 1.41291C9.18216 1.52208 9.63418 1.74367 10.0172 2.05979C10.4003 2.37591 10.7036 2.77769 10.9027 3.23268C11.0503 3.56999 10.8965 3.96309 10.5592 4.11069C10.2218 4.25828 9.82874 4.10449 9.68115 3.76718C9.56589 3.50377 9.39028 3.27116 9.16852 3.08814C8.94676 2.90512 8.68507 2.77683 8.40458 2.71363C8.12408 2.65042 7.83265 2.65408 7.55383 2.7243C7.27501 2.79452 7.01662 2.92933 6.79952 3.11785C6.58242 3.30637 6.41271 3.54331 6.30409 3.80953C6.19547 4.07575 6.15099 4.36379 6.17424 4.65038C6.19749 4.93696 6.28782 5.21406 6.43794 5.45929C6.58806 5.70452 6.79375 5.911 7.0384 6.06206C7.35127 6.25524 7.44865 6.66527 7.25605 6.9785L4.56855 11.3491C4.37569 11.6628 3.96509 11.7607 3.65145 11.5678C3.33781 11.375 3.2399 10.9644 3.43276 10.6507L5.80875 6.7867C5.61374 6.59953 5.44284 6.38752 5.30076 6.15541C5.04146 5.73184 4.88544 5.25321 4.84527 4.7582C4.80511 4.26319 4.88194 3.76567 5.06956 3.30584C5.25717 2.846 5.55031 2.43674 5.9253 2.11111C6.30029 1.78549 6.74661 1.55262 7.22821 1.43134Z" fill="#155EEF"/>
+<path d="M7.65145 3.93204C7.96509 3.73918 8.37569 3.83709 8.56855 4.15073L10.944 8.01384C11.1917 7.9264 11.4501 7.86984 11.7135 7.84608C12.2008 7.80211 12.6917 7.87167 13.1476 8.04931C13.6036 8.22695 14.0121 8.50783 14.3413 8.86991C14.6704 9.23199 14.9111 9.66542 15.0446 10.1362C15.1781 10.6069 15.2006 11.1022 15.1105 11.5832C15.0204 12.0641 14.82 12.5176 14.5252 12.9081C14.2303 13.2986 13.849 13.6155 13.4111 13.8338C12.9732 14.0522 12.4907 14.1661 12.0014 14.1666C11.6332 14.167 11.3344 13.8688 11.334 13.5006C11.3336 13.1324 11.6318 12.8337 12 12.8333C12.2832 12.833 12.5626 12.767 12.8161 12.6406C13.0696 12.5142 13.2904 12.3308 13.4611 12.1047C13.6318 11.8786 13.7478 11.616 13.8 11.3376C13.8522 11.0592 13.8391 10.7724 13.7618 10.4999C13.6846 10.2273 13.5452 9.97639 13.3546 9.76676C13.1641 9.55714 12.9276 9.39452 12.6636 9.29168C12.3996 9.18884 12.1154 9.14856 11.8333 9.17402C11.5511 9.19947 11.2787 9.28996 11.0375 9.43839C10.8868 9.53104 10.7056 9.56006 10.5336 9.51905C10.3616 9.47805 10.2129 9.37039 10.1203 9.21975L7.43276 4.84913C7.2399 4.53549 7.33781 4.12489 7.65145 3.93204Z" fill="#155EEF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/editor/align-left.svg b/app/components/base/icons/assets/vender/line/editor/align-left.svg
new file mode 100644
index 0000000..086ff82
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/editor/align-left.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="align-left">
+<path id="Icon" d="M16 10H3M20 6H3M20 14H3M16 18H3" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/editor/bezier-curve-03.svg b/app/components/base/icons/assets/vender/line/editor/bezier-curve-03.svg
new file mode 100644
index 0000000..56befa3
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/editor/bezier-curve-03.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="bezier-curve-03">
+<path id="Icon" d="M5.42857 3.5L2.57143 8.5M3 9.5H8.9999M9.42857 8.5L6.57143 3.5M1.8 10.5H2.2C2.48003 10.5 2.62004 10.5 2.727 10.4455C2.82108 10.3976 2.89757 10.3211 2.9455 10.227C3 10.12 3 9.98003 3 9.7V9.3C3 9.01997 3 8.87996 2.9455 8.773C2.89757 8.67892 2.82108 8.60243 2.727 8.5545C2.62004 8.5 2.48003 8.5 2.2 8.5H1.8C1.51997 8.5 1.37996 8.5 1.273 8.5545C1.17892 8.60243 1.10243 8.67892 1.0545 8.773C1 8.87996 1 9.01997 1 9.3V9.7C1 9.98003 1 10.12 1.0545 10.227C1.10243 10.3211 1.17892 10.3976 1.273 10.4455C1.37996 10.5 1.51997 10.5 1.8 10.5ZM9.8 10.5H10.2C10.48 10.5 10.62 10.5 10.727 10.4455C10.8211 10.3976 10.8976 10.3211 10.9455 10.227C11 10.12 11 9.98003 11 9.7V9.3C11 9.01997 11 8.87996 10.9455 8.773C10.8976 8.67892 10.8211 8.60243 10.727 8.5545C10.62 8.5 10.48 8.5 10.2 8.5H9.8C9.51997 8.5 9.37996 8.5 9.273 8.5545C9.17892 8.60243 9.10243 8.67892 9.0545 8.773C9 8.87996 9 9.01997 9 9.3V9.7C9 9.98003 9 10.12 9.0545 10.227C9.10243 10.3211 9.17892 10.3976 9.273 10.4455C9.37996 10.5 9.51997 10.5 9.8 10.5ZM5.8 3.5H6.2C6.48003 3.5 6.62004 3.5 6.727 3.4455C6.82108 3.39757 6.89757 3.32108 6.9455 3.227C7 3.12004 7 2.98003 7 2.7V2.3C7 2.01997 7 1.87996 6.9455 1.773C6.89757 1.67892 6.82108 1.60243 6.727 1.5545C6.62004 1.5 6.48003 1.5 6.2 1.5H5.8C5.51997 1.5 5.37996 1.5 5.273 1.5545C5.17892 1.60243 5.10243 1.67892 5.0545 1.773C5 1.87996 5 2.01997 5 2.3V2.7C5 2.98003 5 3.12004 5.0545 3.227C5.10243 3.32108 5.17892 3.39757 5.273 3.4455C5.37996 3.5 5.51997 3.5 5.8 3.5Z" stroke="#667085" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/editor/collapse.svg b/app/components/base/icons/assets/vender/line/editor/collapse.svg
new file mode 100644
index 0000000..b54e046
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/editor/collapse.svg
@@ -0,0 +1,9 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon L">
+<g id="Vector">
+<path d="M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z" fill="#354052"/>
+<path d="M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z" fill="#354052"/>
+<path d="M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z" fill="#354052"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/editor/colors.svg b/app/components/base/icons/assets/vender/line/editor/colors.svg
new file mode 100644
index 0000000..685c175
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/editor/colors.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="colors">
+<path id="Icon" d="M12 20.4722C13.0615 21.4223 14.4633 22 16 22C19.3137 22 22 19.3137 22 16C22 13.2331 20.1271 10.9036 17.5798 10.2102M6.42018 10.2102C3.87293 10.9036 2 13.2331 2 16C2 19.3137 4.68629 22 8 22C11.3137 22 14 19.3137 14 16C14 15.2195 13.851 14.4738 13.5798 13.7898M18 8C18 11.3137 15.3137 14 12 14C8.68629 14 6 11.3137 6 8C6 4.68629 8.68629 2 12 2C15.3137 2 18 4.68629 18 8Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/editor/image-indent-left.svg b/app/components/base/icons/assets/vender/line/editor/image-indent-left.svg
new file mode 100644
index 0000000..8419f7b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/editor/image-indent-left.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="image-indent-left">
+<path id="Icon" d="M21 9.25H15M21 4H3M21 14.75H15M21 20H3M4.6 16H9.4C9.96005 16 10.2401 16 10.454 15.891C10.6422 15.7951 10.7951 15.6422 10.891 15.454C11 15.2401 11 14.9601 11 14.4V9.6C11 9.03995 11 8.75992 10.891 8.54601C10.7951 8.35785 10.6422 8.20487 10.454 8.10899C10.2401 8 9.96005 8 9.4 8H4.6C4.03995 8 3.75992 8 3.54601 8.10899C3.35785 8.20487 3.20487 8.35785 3.10899 8.54601C3 8.75992 3 9.03995 3 9.6V14.4C3 14.9601 3 15.2401 3.10899 15.454C3.20487 15.6422 3.35785 15.7951 3.54601 15.891C3.75992 16 4.03995 16 4.6 16Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/editor/left-indent-02.svg b/app/components/base/icons/assets/vender/line/editor/left-indent-02.svg
new file mode 100644
index 0000000..25cecb2
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/editor/left-indent-02.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M21 9.24995H12M21 3.99995L12 3.99995M21 14.75H3M21 20H3M4.28 2.95995L8.14667 5.85995C8.43616 6.07707 8.5809 6.18563 8.63266 6.31872C8.678 6.43529 8.678 6.56462 8.63266 6.68119C8.5809 6.81427 8.43616 6.92283 8.14667 7.13995L4.28 10.04C3.86802 10.3489 3.66203 10.5034 3.48961 10.4998C3.33956 10.4967 3.19885 10.4264 3.10632 10.3082C3 10.1724 3 9.91493 3 9.39995V3.59995C3 3.08498 3 2.82749 3.10632 2.6917C3.19885 2.57354 3.33956 2.50318 3.48961 2.50006C3.66203 2.49648 3.86802 2.65097 4.28 2.95995Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/editor/letter-spacing-01.svg b/app/components/base/icons/assets/vender/line/editor/letter-spacing-01.svg
new file mode 100644
index 0000000..4f0c99e
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/editor/letter-spacing-01.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="letter-spacing-01">
+<path id="Icon" d="M9 13L15 13M7 17L11.2717 7.60225C11.5031 7.09323 11.6188 6.83872 11.7791 6.75976C11.9184 6.69115 12.0816 6.69115 12.2209 6.75976C12.3812 6.83872 12.4969 7.09323 12.7283 7.60225L17 17M21 3V21M3 3L3 21" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/editor/type-square.svg b/app/components/base/icons/assets/vender/line/editor/type-square.svg
new file mode 100644
index 0000000..3a8fce2
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/editor/type-square.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="type-square">
+<path id="Icon" d="M4 3.5H8M6 3.5V8.5M3.9 10.5H8.1C8.94008 10.5 9.36012 10.5 9.68099 10.3365C9.96323 10.1927 10.1927 9.96323 10.3365 9.68099C10.5 9.36012 10.5 8.94008 10.5 8.1V3.9C10.5 3.05992 10.5 2.63988 10.3365 2.31901C10.1927 2.03677 9.96323 1.8073 9.68099 1.66349C9.36012 1.5 8.94008 1.5 8.1 1.5H3.9C3.05992 1.5 2.63988 1.5 2.31901 1.66349C2.03677 1.8073 1.8073 2.03677 1.66349 2.31901C1.5 2.63988 1.5 3.05992 1.5 3.9V8.1C1.5 8.94008 1.5 9.36012 1.66349 9.68099C1.8073 9.96323 2.03677 10.1927 2.31901 10.3365C2.63988 10.5 3.05992 10.5 3.9 10.5Z" stroke="#667085" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/education/book-open-01.svg b/app/components/base/icons/assets/vender/line/education/book-open-01.svg
new file mode 100644
index 0000000..c1809ba
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/education/book-open-01.svg
@@ -0,0 +1,6 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="book-open-01">
+<path id="Fill" opacity="0.12" d="M1 3.1C1 2.53995 1 2.25992 1.10899 2.04601C1.20487 1.85785 1.35785 1.70487 1.54601 1.60899C1.75992 1.5 2.03995 1.5 2.6 1.5H2.8C3.9201 1.5 4.48016 1.5 4.90798 1.71799C5.28431 1.90973 5.59027 2.21569 5.78201 2.59202C6 3.01984 6 3.5799 6 4.7V10.5L5.94997 10.425C5.60265 9.90398 5.42899 9.64349 5.19955 9.45491C4.99643 9.28796 4.76238 9.1627 4.5108 9.0863C4.22663 9 3.91355 9 3.28741 9H2.6C2.03995 9 1.75992 9 1.54601 8.89101C1.35785 8.79513 1.20487 8.64215 1.10899 8.45399C1 8.24008 1 7.96005 1 7.4V3.1Z" fill="#667085"/>
+<path id="Icon" d="M6 10.5L5.94997 10.425C5.60265 9.90398 5.42899 9.64349 5.19955 9.45491C4.99643 9.28796 4.76238 9.1627 4.5108 9.0863C4.22663 9 3.91355 9 3.28741 9H2.6C2.03995 9 1.75992 9 1.54601 8.89101C1.35785 8.79513 1.20487 8.64215 1.10899 8.45399C1 8.24008 1 7.96005 1 7.4V3.1C1 2.53995 1 2.25992 1.10899 2.04601C1.20487 1.85785 1.35785 1.70487 1.54601 1.60899C1.75992 1.5 2.03995 1.5 2.6 1.5H2.8C3.9201 1.5 4.48016 1.5 4.90798 1.71799C5.28431 1.90973 5.59027 2.21569 5.78201 2.59202C6 3.01984 6 3.5799 6 4.7M6 10.5V4.7M6 10.5L6.05003 10.425C6.39735 9.90398 6.57101 9.64349 6.80045 9.45491C7.00357 9.28796 7.23762 9.1627 7.4892 9.0863C7.77337 9 8.08645 9 8.71259 9H9.4C9.96005 9 10.2401 9 10.454 8.89101C10.6422 8.79513 10.7951 8.64215 10.891 8.45399C11 8.24008 11 7.96005 11 7.4V3.1C11 2.53995 11 2.25992 10.891 2.04601C10.7951 1.85785 10.6422 1.70487 10.454 1.60899C10.2401 1.5 9.96005 1.5 9.4 1.5H9.2C8.07989 1.5 7.51984 1.5 7.09202 1.71799C6.71569 1.90973 6.40973 2.21569 6.21799 2.59202C6 3.01984 6 3.5799 6 4.7" stroke="#667085" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/clipboard-check.svg b/app/components/base/icons/assets/vender/line/files/clipboard-check.svg
new file mode 100644
index 0000000..48c70ed
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/clipboard-check.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M16 4C16.93 4 17.395 4 17.7765 4.10222C18.8117 4.37962 19.6204 5.18827 19.8978 6.22354C20 6.60504 20 7.07003 20 8V17.2C20 18.8802 20 19.7202 19.673 20.362C19.3854 20.9265 18.9265 21.3854 18.362 21.673C17.7202 22 16.8802 22 15.2 22H8.8C7.11984 22 6.27976 22 5.63803 21.673C5.07354 21.3854 4.6146 20.9265 4.32698 20.362C4 19.7202 4 18.8802 4 17.2V8C4 7.07003 4 6.60504 4.10222 6.22354C4.37962 5.18827 5.18827 4.37962 6.22354 4.10222C6.60504 4 7.07003 4 8 4M9 15L11 17L15.5 12.5M9.6 6H14.4C14.9601 6 15.2401 6 15.454 5.89101C15.6422 5.79513 15.7951 5.64215 15.891 5.45399C16 5.24008 16 4.96005 16 4.4V3.6C16 3.03995 16 2.75992 15.891 2.54601C15.7951 2.35785 15.6422 2.20487 15.454 2.10899C15.2401 2 14.9601 2 14.4 2H9.6C9.03995 2 8.75992 2 8.54601 2.10899C8.35785 2.20487 8.20487 2.35785 8.10899 2.54601C8 2.75992 8 3.03995 8 3.6V4.4C8 4.96005 8 5.24008 8.10899 5.45399C8.20487 5.64215 8.35785 5.79513 8.54601 5.89101C8.75992 6 9.03995 6 9.6 6Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/clipboard.svg b/app/components/base/icons/assets/vender/line/files/clipboard.svg
new file mode 100644
index 0000000..8abaaa9
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/clipboard.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M16 4C16.93 4 17.395 4 17.7765 4.10222C18.8117 4.37962 19.6204 5.18827 19.8978 6.22354C20 6.60504 20 7.07003 20 8V17.2C20 18.8802 20 19.7202 19.673 20.362C19.3854 20.9265 18.9265 21.3854 18.362 21.673C17.7202 22 16.8802 22 15.2 22H8.8C7.11984 22 6.27976 22 5.63803 21.673C5.07354 21.3854 4.6146 20.9265 4.32698 20.362C4 19.7202 4 18.8802 4 17.2V8C4 7.07003 4 6.60504 4.10222 6.22354C4.37962 5.18827 5.18827 4.37962 6.22354 4.10222C6.60504 4 7.07003 4 8 4M9.6 6H14.4C14.9601 6 15.2401 6 15.454 5.89101C15.6422 5.79513 15.7951 5.64215 15.891 5.45399C16 5.24008 16 4.96005 16 4.4V3.6C16 3.03995 16 2.75992 15.891 2.54601C15.7951 2.35785 15.6422 2.20487 15.454 2.10899C15.2401 2 14.9601 2 14.4 2H9.6C9.03995 2 8.75992 2 8.54601 2.10899C8.35785 2.20487 8.20487 2.35785 8.10899 2.54601C8 2.75992 8 3.03995 8 3.6V4.4C8 4.96005 8 5.24008 8.10899 5.45399C8.20487 5.64215 8.35785 5.79513 8.54601 5.89101C8.75992 6 9.03995 6 9.6 6Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/file-02.svg b/app/components/base/icons/assets/vender/line/files/file-02.svg
new file mode 100644
index 0000000..b6d34bf
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/file-02.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<path id="Icon_2" d="M9.33366 7.3335H5.33366M6.66699 10.0002H5.33366M10.667 4.66683H5.33366M13.3337 4.5335V11.4668C13.3337 12.5869 13.3337 13.147 13.1157 13.5748C12.9239 13.9511 12.618 14.2571 12.2416 14.4488C11.8138 14.6668 11.2538 14.6668 10.1337 14.6668H5.86699C4.74689 14.6668 4.18683 14.6668 3.75901 14.4488C3.38269 14.2571 3.07673 13.9511 2.88498 13.5748C2.66699 13.147 2.66699 12.5869 2.66699 11.4668V4.5335C2.66699 3.41339 2.66699 2.85334 2.88498 2.42552C3.07673 2.04919 3.38269 1.74323 3.75901 1.55148C4.18683 1.3335 4.74689 1.3335 5.86699 1.3335H10.1337C11.2538 1.3335 11.8138 1.3335 12.2416 1.55148C12.618 1.74323 12.9239 2.04919 13.1157 2.42552C13.3337 2.85334 13.3337 3.41339 13.3337 4.5335Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/file-arrow-01.svg b/app/components/base/icons/assets/vender/line/files/file-arrow-01.svg
new file mode 100644
index 0000000..e8db342
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/file-arrow-01.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-arrow-01">
+<path id="Vector" d="M3.33333 12.333C3.33333 12.6426 3.33333 12.7974 3.35044 12.9274C3.4686 13.8249 4.17481 14.5311 5.07228 14.6492C5.20225 14.6663 5.35705 14.6663 5.66667 14.6663H10.8C11.9201 14.6663 12.4802 14.6663 12.908 14.4484C13.2843 14.2566 13.5903 13.9506 13.782 13.5743C14 13.1465 14 12.5864 14 11.4663V6.65849C14 6.16931 14 5.92472 13.9447 5.69454C13.8957 5.49047 13.8149 5.29538 13.7053 5.11644C13.5816 4.91461 13.4086 4.74165 13.0627 4.39575L10.9373 2.27027C10.5914 1.92436 10.4184 1.75141 10.2166 1.62773C10.0376 1.51807 9.84254 1.43726 9.63846 1.38827C9.40829 1.33301 9.1637 1.33301 8.67452 1.33301H5.66667C5.35705 1.33301 5.20225 1.33301 5.07228 1.35012C4.17481 1.46827 3.4686 2.17449 3.35044 3.07196M5.33333 5.99967L7.33333 7.99967M7.33333 7.99967L5.33333 9.99967M7.33333 7.99967H2" stroke="#475467" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/file-check-02.svg b/app/components/base/icons/assets/vender/line/files/file-check-02.svg
new file mode 100644
index 0000000..931593c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/file-check-02.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-check-02">
+<path id="Icon" d="M13.3337 8.33301V4.53301C13.3337 3.4129 13.3337 2.85285 13.1157 2.42503C12.9239 2.0487 12.618 1.74274 12.2416 1.55099C11.8138 1.33301 11.2538 1.33301 10.1337 1.33301H5.86699C4.74689 1.33301 4.18683 1.33301 3.75901 1.55099C3.38269 1.74274 3.07673 2.0487 2.88498 2.42503C2.66699 2.85285 2.66699 3.4129 2.66699 4.53301V11.4663C2.66699 12.5864 2.66699 13.1465 2.88498 13.5743C3.07673 13.9506 3.38269 14.2566 3.75901 14.4484C4.18683 14.6663 4.74689 14.6663 5.86699 14.6663H8.00033M9.33366 7.33301H5.33366M6.66699 9.99967H5.33366M10.667 4.66634H5.33366M9.66699 12.6663L11.0003 13.9997L14.0003 10.9997" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/file-download-02.svg b/app/components/base/icons/assets/vender/line/files/file-download-02.svg
new file mode 100644
index 0000000..e96132b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/file-download-02.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M20 12.5V6.8C20 5.11984 20 4.27976 19.673 3.63803C19.3854 3.07354 18.9265 2.6146 18.362 2.32698C17.7202 2 16.8802 2 15.2 2H8.8C7.11984 2 6.27976 2 5.63803 2.32698C5.07354 2.6146 4.6146 3.07354 4.32698 3.63803C4 4.27976 4 5.11984 4 6.8V17.2C4 18.8802 4 19.7202 4.32698 20.362C4.6146 20.9265 5.07354 21.3854 5.63803 21.673C6.27976 22 7.1198 22 8.79986 22H12.5M14 11H8M10 15H8M16 7H8M15 19L18 22M18 22L21 19M18 22V16" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/file-plus-01.svg b/app/components/base/icons/assets/vender/line/files/file-plus-01.svg
new file mode 100644
index 0000000..e312cd9
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/file-plus-01.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-plus-01">
+<path id="Icon" d="M13.3332 6.99967V4.53301C13.3332 3.4129 13.3332 2.85285 13.1152 2.42503C12.9234 2.0487 12.6175 1.74274 12.2412 1.55099C11.8133 1.33301 11.2533 1.33301 10.1332 1.33301H5.8665C4.7464 1.33301 4.18635 1.33301 3.75852 1.55099C3.3822 1.74274 3.07624 2.0487 2.88449 2.42503C2.6665 2.85285 2.6665 3.4129 2.6665 4.53301V11.4663C2.6665 12.5864 2.6665 13.1465 2.88449 13.5743C3.07624 13.9506 3.3822 14.2566 3.75852 14.4484C4.18635 14.6663 4.7464 14.6663 5.8665 14.6663H7.99984M11.9998 13.9997V9.99967M9.99984 11.9997H13.9998" stroke="#475467" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/file-plus-02.svg b/app/components/base/icons/assets/vender/line/files/file-plus-02.svg
new file mode 100644
index 0000000..aab093a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/file-plus-02.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M13.3333 6.99992V4.53325C13.3333 3.41315 13.3333 2.85309 13.1153 2.42527C12.9236 2.04895 12.6176 1.74299 12.2413 1.55124C11.8135 1.33325 11.2534 1.33325 10.1333 1.33325H5.86666C4.74655 1.33325 4.1865 1.33325 3.75868 1.55124C3.38235 1.74299 3.07639 2.04895 2.88464 2.42527C2.66666 2.85309 2.66666 3.41315 2.66666 4.53325V11.4666C2.66666 12.5867 2.66666 13.1467 2.88464 13.5746C3.07639 13.9509 3.38235 14.2569 3.75868 14.4486C4.1865 14.6666 4.74655 14.6666 5.86666 14.6666H7.99999M9.33332 7.33325H5.33332M6.66666 9.99992H5.33332M10.6667 4.66659H5.33332M12 13.9999V9.99992M9.99999 11.9999H14" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/file-text.svg b/app/components/base/icons/assets/vender/line/files/file-text.svg
new file mode 100644
index 0000000..25760e5
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/file-text.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-text">
+<path id="Icon" d="M14 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579C4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142C4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V8M14 2L20 8M14 2V8H20M16 13H8M16 17H8M10 9H8" stroke="#101828" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/file-upload.svg b/app/components/base/icons/assets/vender/line/files/file-upload.svg
new file mode 100644
index 0000000..e8b7095
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/file-upload.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-upload">
+<path id="Icon" d="M20 10.5V6.8C20 5.11984 20 4.27976 19.673 3.63803C19.3854 3.07354 18.9265 2.6146 18.362 2.32698C17.7202 2 16.8802 2 15.2 2H8.8C7.11984 2 6.27976 2 5.63803 2.32698C5.07354 2.6146 4.6146 3.07354 4.32698 3.63803C4 4.27976 4 5.11984 4 6.8V17.2C4 18.8802 4 19.7202 4.32698 20.362C4.6146 20.9265 5.07354 21.3854 5.63803 21.673C6.27976 22 7.11984 22 8.8 22H12M14 11H8M10 15H8M16 7H8" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Icon_2" d="M15 18L18 15M18 15L21 18M18 15L18 21" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/files/folder.svg b/app/components/base/icons/assets/vender/line/files/folder.svg
new file mode 100644
index 0000000..248708b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/files/folder.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="folder">
+<path id="Icon" d="M12.8327 11.0833C12.8327 11.3928 12.7098 11.6895 12.491 11.9083C12.2722 12.1271 11.9754 12.25 11.666 12.25H2.33268C2.02326 12.25 1.72652 12.1271 1.50772 11.9083C1.28893 11.6895 1.16602 11.3928 1.16602 11.0833V2.91667C1.16602 2.60725 1.28893 2.3105 1.50772 2.09171C1.72652 1.87292 2.02326 1.75 2.33268 1.75H5.24935L6.41602 3.5H11.666C11.9754 3.5 12.2722 3.62292 12.491 3.84171C12.7098 4.0605 12.8327 4.35725 12.8327 4.66667V11.0833Z" stroke="#344054" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/financeAndECommerce/balance.svg b/app/components/base/icons/assets/vender/line/financeAndECommerce/balance.svg
new file mode 100644
index 0000000..428967a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/financeAndECommerce/balance.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12 3V20M12 20H6.99999M12 20H17M2.99999 6H7.52785C7.83834 6 8.14457 5.92771 8.42228 5.78885L9.5777 5.21115C9.85541 5.07229 10.1616 5 10.4721 5H13.5279C13.8384 5 14.1446 5.07229 14.4223 5.21115L15.5777 5.78885C15.8554 5.92771 16.1616 6 16.4721 6H21M5.49999 6L3.02043 13.4387C2.71807 14.3458 3.08918 15.3834 4.0053 15.657C5.0117 15.9577 5.98828 15.9577 6.99468 15.657C7.9108 15.3834 8.28191 14.3457 7.97955 13.4387L5.49999 6ZM18.5 6L16.0204 13.4387C15.7181 14.3458 16.0892 15.3834 17.0053 15.657C18.0117 15.9577 18.9883 15.9577 19.9947 15.657C20.9108 15.3834 21.2819 14.3457 20.9796 13.4387L18.5 6Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/financeAndECommerce/coins-stacked-01.svg b/app/components/base/icons/assets/vender/line/financeAndECommerce/coins-stacked-01.svg
new file mode 100644
index 0000000..00f371a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/financeAndECommerce/coins-stacked-01.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="coins-stacked-01">
+<path id="Icon" d="M12 17C12 19.7614 14.2386 22 17 22C19.7614 22 22 19.7614 22 17C22 14.2386 19.7614 12 17 12C14.2386 12 12 14.2386 12 17ZM12 17C12 15.8742 12.3721 14.8353 13 13.9995V5M12 17C12 17.8254 12.2 18.604 12.5541 19.2901C11.7117 20.0018 9.76584 20.5 7.5 20.5C4.46243 20.5 2 19.6046 2 18.5V5M13 5C13 6.10457 10.5376 7 7.5 7C4.46243 7 2 6.10457 2 5M13 5C13 3.89543 10.5376 3 7.5 3C4.46243 3 2 3.89543 2 5M2 14C2 15.1046 4.46243 16 7.5 16C9.689 16 11.5793 15.535 12.4646 14.8618M13 9.5C13 10.6046 10.5376 11.5 7.5 11.5C4.46243 11.5 2 10.6046 2 9.5" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/financeAndECommerce/gold-coin.svg b/app/components/base/icons/assets/vender/line/financeAndECommerce/gold-coin.svg
new file mode 100644
index 0000000..798e5d0
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/financeAndECommerce/gold-coin.svg
@@ -0,0 +1,16 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_7056_1808)">
+<path d="M8.00003 4.82855L8.93639 6.72613L11.0303 7.03037L9.51518 8.50734L9.87276 10.5928L8.00003 9.60795L6.1273 10.5928L6.48488 8.50734L4.96973 7.03037L7.06367 6.72613L8.00003 4.82855Z" stroke="#344054" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M8.00016 14.6666C11.6821 14.6666 14.6668 11.6819 14.6668 7.99998C14.6668 4.31808 11.6821 1.33331 8.00016 1.33331C4.31826 1.33331 1.3335 4.31808 1.3335 7.99998C1.3335 11.6819 4.31826 14.6666 8.00016 14.6666Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M8.0001 12.8485C8.33482 12.8485 8.60616 12.5771 8.60616 12.2424C8.60616 11.9077 8.33482 11.6364 8.0001 11.6364C7.66539 11.6364 7.39404 11.9077 7.39404 12.2424C7.39404 12.5771 7.66539 12.8485 8.0001 12.8485Z" fill="#344054"/>
+<path d="M12.0348 9.91702C12.3695 9.91702 12.6408 9.64567 12.6408 9.31096C12.6408 8.97624 12.3695 8.7049 12.0348 8.7049C11.7001 8.7049 11.4287 8.97624 11.4287 9.31096C11.4287 9.64567 11.7001 9.91702 12.0348 9.91702Z" fill="#344054"/>
+<path d="M10.4933 5.17391C10.828 5.17391 11.0993 4.90257 11.0993 4.56785C11.0993 4.23313 10.828 3.96179 10.4933 3.96179C10.1585 3.96179 9.88721 4.23313 9.88721 4.56785C9.88721 4.90257 10.1585 5.17391 10.4933 5.17391Z" fill="#344054"/>
+<path d="M5.50645 5.17391C5.84117 5.17391 6.11251 4.90257 6.11251 4.56785C6.11251 4.23313 5.84117 3.96179 5.50645 3.96179C5.17173 3.96179 4.90039 4.23313 4.90039 4.56785C4.90039 4.90257 5.17173 5.17391 5.50645 5.17391Z" fill="#344054"/>
+<path d="M3.96544 9.91702C4.30015 9.91702 4.5715 9.64567 4.5715 9.31096C4.5715 8.97624 4.30015 8.7049 3.96544 8.7049C3.63072 8.7049 3.35938 8.97624 3.35938 9.31096C3.35938 9.64567 3.63072 9.91702 3.96544 9.91702Z" fill="#344054"/>
+</g>
+<defs>
+<clipPath id="clip0_7056_1808">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/financeAndECommerce/receipt-list.svg b/app/components/base/icons/assets/vender/line/financeAndECommerce/receipt-list.svg
new file mode 100644
index 0000000..2f7caeb
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/financeAndECommerce/receipt-list.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.55556 8.33333H12M15.5556 8.33333H16.4444M7.55556 11.8889H12M15.5556 11.8889H16.4444M7.55556 15.4444H12M15.5556 15.4444H16.4444M20 21.6667V5C20 3.89543 19.1046 3 18 3H6C4.89543 3 4 3.89543 4 5V21.6667L6.66667 19.8889L9.33333 21.6667L12 19.8889L14.6667 21.6667L17.3333 19.8889L20 21.6667Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-01.svg b/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-01.svg
new file mode 100644
index 0000000..286322d
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-01.svg
@@ -0,0 +1,10 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon" clip-path="url(#clip0_17795_9693)">
+<path id="Icon_2" d="M4.66699 4.6665H4.67283M1.16699 3.03317L1.16699 5.6433C1.16699 5.92866 1.16699 6.07134 1.19923 6.20561C1.22781 6.32465 1.27495 6.43845 1.33891 6.54284C1.41106 6.66057 1.51195 6.76146 1.71373 6.96324L6.18709 11.4366C6.88012 12.1296 7.22664 12.4761 7.62621 12.606C7.97769 12.7202 8.35629 12.7202 8.70777 12.606C9.10735 12.4761 9.45386 12.1296 10.1469 11.4366L11.4371 10.1464C12.1301 9.45337 12.4766 9.10686 12.6065 8.70728C12.7207 8.35581 12.7207 7.9772 12.6065 7.62572C12.4766 7.22615 12.1301 6.87963 11.4371 6.1866L6.96372 1.71324C6.76195 1.51146 6.66106 1.41057 6.54332 1.33842C6.43894 1.27446 6.32514 1.22732 6.20609 1.19874C6.07183 1.1665 5.92915 1.1665 5.64379 1.1665L3.03366 1.1665C2.38026 1.1665 2.05357 1.1665 1.804 1.29366C1.58448 1.40552 1.406 1.58399 1.29415 1.80352C1.16699 2.05308 1.16699 2.37978 1.16699 3.03317ZM4.95866 4.6665C4.95866 4.82759 4.82808 4.95817 4.66699 4.95817C4.50591 4.95817 4.37533 4.82759 4.37533 4.6665C4.37533 4.50542 4.50591 4.37484 4.66699 4.37484C4.82808 4.37484 4.95866 4.50542 4.95866 4.6665Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_17795_9693">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-03.svg b/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-03.svg
new file mode 100644
index 0000000..a8eeebf
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-03.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="tag-03">
+<path id="Icon" d="M14 7.3335L8.93726 2.27075C8.59135 1.92485 8.4184 1.7519 8.21657 1.62822C8.03762 1.51856 7.84254 1.43775 7.63846 1.38876C7.40829 1.3335 7.16369 1.3335 6.67452 1.3335L4 1.3335M2 5.80016L2 7.11651C2 7.44263 2 7.60569 2.03684 7.75914C2.0695 7.89519 2.12337 8.02525 2.19648 8.14454C2.27894 8.2791 2.39424 8.3944 2.62484 8.625L7.82484 13.825C8.35286 14.353 8.61687 14.617 8.92131 14.716C9.1891 14.803 9.47757 14.803 9.74536 14.716C10.0498 14.617 10.3138 14.353 10.8418 13.825L12.4915 12.1753C13.0195 11.6473 13.2835 11.3833 13.3825 11.0789C13.4695 10.8111 13.4695 10.5226 13.3825 10.2548C13.2835 9.95037 13.0195 9.68636 12.4915 9.15834L7.62484 4.29167C7.39424 4.06107 7.27894 3.94577 7.14438 3.86331C7.02508 3.7902 6.89502 3.73633 6.75898 3.70367C6.60553 3.66683 6.44247 3.66683 6.11634 3.66683H4.13333C3.3866 3.66683 3.01323 3.66683 2.72801 3.81215C2.47713 3.93999 2.27316 4.14396 2.14532 4.39484C2 4.68006 2 5.05343 2 5.80016Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/at-sign.svg b/app/components/base/icons/assets/vender/line/general/at-sign.svg
new file mode 100644
index 0000000..c88c4ee
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/at-sign.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="at-sign" clip-path="url(#clip0_8902_1909)">
+<path id="Icon" d="M10.6666 5.33333V8.66666C10.6666 9.19709 10.8773 9.7058 11.2524 10.0809C11.6275 10.4559 12.1362 10.6667 12.6666 10.6667C13.197 10.6667 13.7057 10.4559 14.0808 10.0809C14.4559 9.7058 14.6666 9.19709 14.6666 8.66666V7.99999C14.6665 6.49535 14.1574 5.03498 13.2221 3.85635C12.2868 2.67772 10.9803 1.85014 9.51502 1.50819C8.04974 1.16624 6.51188 1.33002 5.15149 1.9729C3.7911 2.61579 2.68819 3.69996 2.0221 5.04914C1.356 6.39832 1.1659 7.93315 1.4827 9.40407C1.7995 10.875 2.60458 12.1955 3.76701 13.1508C4.92945 14.1062 6.38088 14.6402 7.8853 14.6661C9.38973 14.692 10.8587 14.2082 12.0533 13.2933M10.6666 7.99999C10.6666 9.47275 9.47269 10.6667 7.99993 10.6667C6.52717 10.6667 5.33326 9.47275 5.33326 7.99999C5.33326 6.52723 6.52717 5.33333 7.99993 5.33333C9.47269 5.33333 10.6666 6.52723 10.6666 7.99999Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_8902_1909">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/bookmark.svg b/app/components/base/icons/assets/vender/line/general/bookmark.svg
new file mode 100644
index 0000000..576abcd
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/bookmark.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5 7.8C5 6.11984 5 5.27976 5.32698 4.63803C5.6146 4.07354 6.07354 3.6146 6.63803 3.32698C7.27976 3 8.11984 3 9.8 3H14.2C15.8802 3 16.7202 3 17.362 3.32698C17.9265 3.6146 18.3854 4.07354 18.673 4.63803C19 5.27976 19 6.11984 19 7.8V21L12 17L5 21V7.8Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/check-done-01.svg b/app/components/base/icons/assets/vender/line/general/check-done-01.svg
new file mode 100644
index 0000000..6603f3d
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/check-done-01.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="check-done-01">
+<path id="Icon" d="M6 15L8 17L12.5 12.5M8 8V5.2C8 4.0799 8 3.51984 8.21799 3.09202C8.40973 2.71569 8.71569 2.40973 9.09202 2.21799C9.51984 2 10.0799 2 11.2 2H18.8C19.9201 2 20.4802 2 20.908 2.21799C21.2843 2.40973 21.5903 2.71569 21.782 3.09202C22 3.51984 22 4.0799 22 5.2V12.8C22 13.9201 22 14.4802 21.782 14.908C21.5903 15.2843 21.2843 15.5903 20.908 15.782C20.4802 16 19.9201 16 18.8 16H16M5.2 22H12.8C13.9201 22 14.4802 22 14.908 21.782C15.2843 21.5903 15.5903 21.2843 15.782 20.908C16 20.4802 16 19.9201 16 18.8V11.2C16 10.0799 16 9.51984 15.782 9.09202C15.5903 8.71569 15.2843 8.40973 14.908 8.21799C14.4802 8 13.9201 8 12.8 8H5.2C4.0799 8 3.51984 8 3.09202 8.21799C2.71569 8.40973 2.40973 8.71569 2.21799 9.09202C2 9.51984 2 10.0799 2 11.2V18.8C2 19.9201 2 20.4802 2.21799 20.908C2.40973 21.2843 2.71569 21.5903 3.09202 21.782C3.51984 22 4.07989 22 5.2 22Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/check.svg b/app/components/base/icons/assets/vender/line/general/check.svg
new file mode 100644
index 0000000..4fe24c8
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/check.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="check">
+<path id="Icon" d="M13.3334 4L6.00008 11.3333L2.66675 8" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/checklist-square.svg b/app/components/base/icons/assets/vender/line/general/checklist-square.svg
new file mode 100644
index 0000000..8fdddfa
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/checklist-square.svg
@@ -0,0 +1,5 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="checklist-square">
+<path id="Vector" d="M9.7823 11.9146C9.32278 11.6082 8.70191 11.7324 8.39554 12.1919C8.08918 12.6514 8.21333 13.2723 8.67285 13.5787L9.7823 11.9146ZM10.9151 13.8717L10.3603 14.7037C10.8019 14.9982 11.3966 14.8963 11.7151 14.4717L10.9151 13.8717ZM14.5226 10.7284C14.8539 10.2865 14.7644 9.65973 14.3225 9.32836C13.8807 8.99699 13.2539 9.08653 12.9225 9.52836L14.5226 10.7284ZM19.3333 11C18.781 11 18.3333 11.4477 18.3333 12C18.3333 12.5523 18.781 13 19.3333 13V11ZM22 13C22.5523 13 23 12.5523 23 12C23 11.4477 22.5523 11 22 11V13ZM19.3333 19C18.781 19 18.3333 19.4477 18.3333 20C18.3333 20.5523 18.781 21 19.3333 21V19ZM22 21C22.5523 21 23 20.5523 23 20C23 19.4477 22.5523 19 22 19V21ZM9.86913 19.9163C9.4096 19.6099 8.78873 19.7341 8.48238 20.1937C8.17602 20.6532 8.3002 21.274 8.75973 21.5804L9.86913 19.9163ZM11.0019 21.8734L10.4472 22.7054C10.8888 22.9998 11.4835 22.8979 11.8019 22.4734L11.0019 21.8734ZM14.6094 18.7301C14.9408 18.2883 14.8512 17.6615 14.4094 17.3301C13.9676 16.9987 13.3408 17.0883 13.0094 17.5301L14.6094 18.7301ZM6.18404 27.564L5.73005 28.455H5.73005L6.18404 27.564ZM4.43597 25.816L3.54497 26.27H3.54497L4.43597 25.816ZM27.564 25.816L28.455 26.27L27.564 25.816ZM25.816 27.564L26.27 28.455L25.816 27.564ZM25.816 4.43597L26.27 3.54497V3.54497L25.816 4.43597ZM27.564 6.18404L28.455 5.73005V5.73005L27.564 6.18404ZM6.18404 4.43597L5.73005 3.54497L6.18404 4.43597ZM4.43597 6.18404L3.54497 5.73005L4.43597 6.18404ZM8.67285 13.5787L10.3603 14.7037L11.4698 13.0397L9.7823 11.9146L8.67285 13.5787ZM11.7151 14.4717L14.5226 10.7284L12.9225 9.52836L10.1151 13.2717L11.7151 14.4717ZM19.3333 13H22V11H19.3333V13ZM19.3333 21H22V19H19.3333V21ZM8.75973 21.5804L10.4472 22.7054L11.5566 21.0413L9.86913 19.9163L8.75973 21.5804ZM11.8019 22.4734L14.6094 18.7301L13.0094 17.5301L10.2019 21.2733L11.8019 22.4734ZM10.4 5H21.6V3H10.4V5ZM27 10.4V21.6H29V10.4H27ZM21.6 27H10.4V29H21.6V27ZM5 21.6V10.4H3V21.6H5ZM10.4 27C9.26339 27 8.47108 26.9992 7.85424 26.9488C7.24907 26.8994 6.90138 26.8072 6.63803 26.673L5.73005 28.455C6.32234 28.7568 6.96253 28.8826 7.69138 28.9422C8.40855 29.0008 9.2964 29 10.4 29V27ZM3 21.6C3 22.7036 2.99922 23.5914 3.05782 24.3086C3.11737 25.0375 3.24318 25.6777 3.54497 26.27L5.32698 25.362C5.19279 25.0986 5.10062 24.7509 5.05118 24.1458C5.00078 23.5289 5 22.7366 5 21.6H3ZM6.63803 26.673C6.07354 26.3854 5.6146 25.9265 5.32698 25.362L3.54497 26.27C4.02433 27.2108 4.78924 27.9757 5.73005 28.455L6.63803 26.673ZM27 21.6C27 22.7366 26.9992 23.5289 26.9488 24.1458C26.8994 24.7509 26.8072 25.0986 26.673 25.362L28.455 26.27C28.7568 25.6777 28.8826 25.0375 28.9422 24.3086C29.0008 23.5914 29 22.7036 29 21.6H27ZM21.6 29C22.7036 29 23.5914 29.0008 24.3086 28.9422C25.0375 28.8826 25.6777 28.7568 26.27 28.455L25.362 26.673C25.0986 26.8072 24.7509 26.8994 24.1458 26.9488C23.5289 26.9992 22.7366 27 21.6 27V29ZM26.673 25.362C26.3854 25.9265 25.9265 26.3854 25.362 26.673L26.27 28.455C27.2108 27.9757 27.9757 27.2108 28.455 26.27L26.673 25.362ZM21.6 5C22.7366 5 23.5289 5.00078 24.1458 5.05118C24.7509 5.10062 25.0986 5.19279 25.362 5.32698L26.27 3.54497C25.6777 3.24318 25.0375 3.11737 24.3086 3.05782C23.5914 2.99922 22.7036 3 21.6 3V5ZM29 10.4C29 9.2964 29.0008 8.40855 28.9422 7.69138C28.8826 6.96253 28.7568 6.32234 28.455 5.73005L26.673 6.63803C26.8072 6.90138 26.8994 7.24907 26.9488 7.85424C26.9992 8.47108 27 9.26339 27 10.4H29ZM25.362 5.32698C25.9265 5.6146 26.3854 6.07354 26.673 6.63803L28.455 5.73005C27.9757 4.78924 27.2108 4.02433 26.27 3.54497L25.362 5.32698ZM10.4 3C9.2964 3 8.40855 2.99922 7.69138 3.05782C6.96253 3.11737 6.32234 3.24318 5.73005 3.54497L6.63803 5.32698C6.90138 5.19279 7.24907 5.10062 7.85424 5.05118C8.47108 5.00078 9.26339 5 10.4 5V3ZM5 10.4C5 9.26339 5.00078 8.47108 5.05118 7.85424C5.10062 7.24907 5.19279 6.90138 5.32698 6.63803L3.54497 5.73005C3.24318 6.32234 3.11737 6.96253 3.05782 7.69138C2.99922 8.40855 3 9.2964 3 10.4H5ZM5.73005 3.54497C4.78924 4.02433 4.02433 4.78924 3.54497 5.73005L5.32698 6.63803C5.6146 6.07354 6.07354 5.6146 6.63803 5.32698L5.73005 3.54497Z" fill="#D0D5DD"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/dots-grid.svg b/app/components/base/icons/assets/vender/line/general/dots-grid.svg
new file mode 100644
index 0000000..b572f6a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/dots-grid.svg
@@ -0,0 +1,15 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.83333 2.91667C5.83333 2.27233 6.35567 1.75 7 1.75C7.64433 1.75 8.16667 2.27233 8.16667 2.91667C8.16667 3.561 7.64433 4.08333 7 4.08333C6.35567 4.08333 5.83333 3.561 5.83333 2.91667Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.83333 7C5.83333 6.35567 6.35567 5.83333 7 5.83333C7.64433 5.83333 8.16667 6.35567 8.16667 7C8.16667 7.64433 7.64433 8.16667 7 8.16667C6.35567 8.16667 5.83333 7.64433 5.83333 7Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.83333 11.0833C5.83333 10.439 6.35567 9.91667 7 9.91667C7.64433 9.91667 8.16667 10.439 8.16667 11.0833C8.16667 11.7277 7.64433 12.25 7 12.25C6.35567 12.25 5.83333 11.7277 5.83333 11.0833Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.91667 2.91667C9.91667 2.27233 10.439 1.75 11.0833 1.75C11.7277 1.75 12.25 2.27233 12.25 2.91667C12.25 3.561 11.7277 4.08333 11.0833 4.08333C10.439 4.08333 9.91667 3.561 9.91667 2.91667Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.91667 7C9.91667 6.35567 10.439 5.83333 11.0833 5.83333C11.7277 5.83333 12.25 6.35567 12.25 7C12.25 7.64433 11.7277 8.16667 11.0833 8.16667C10.439 8.16667 9.91667 7.64433 9.91667 7Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.91667 11.0833C9.91667 10.439 10.439 9.91667 11.0833 9.91667C11.7277 9.91667 12.25 10.439 12.25 11.0833C12.25 11.7277 11.7277 12.25 11.0833 12.25C10.439 12.25 9.91667 11.7277 9.91667 11.0833Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.75 2.91667C1.75 2.27233 2.27233 1.75 2.91667 1.75C3.561 1.75 4.08333 2.27233 4.08333 2.91667C4.08333 3.561 3.561 4.08333 2.91667 4.08333C2.27233 4.08333 1.75 3.561 1.75 2.91667Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.75 7C1.75 6.35567 2.27233 5.83333 2.91667 5.83333C3.561 5.83333 4.08333 6.35567 4.08333 7C4.08333 7.64433 3.561 8.16667 2.91667 8.16667C2.27233 8.16667 1.75 7.64433 1.75 7Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.75 11.0833C1.75 10.439 2.27233 9.91667 2.91667 9.91667C3.561 9.91667 4.08333 10.439 4.08333 11.0833C4.08333 11.7277 3.561 12.25 2.91667 12.25C2.27233 12.25 1.75 11.7277 1.75 11.0833Z" fill="#155EEF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/edit-02.svg b/app/components/base/icons/assets/vender/line/general/edit-02.svg
new file mode 100644
index 0000000..6a209c8
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/edit-02.svg
@@ -0,0 +1,10 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Left Icon" clip-path="url(#clip0_12284_22440)">
+<path id="Icon" d="M10.5007 5.83319L8.16733 3.49985M1.45898 12.5415L3.4332 12.3222C3.6744 12.2954 3.795 12.282 3.90773 12.2455C4.00774 12.2131 4.10291 12.1673 4.19067 12.1095C4.28958 12.0443 4.37539 11.9585 4.54699 11.7868L12.2507 4.08319C12.895 3.43885 12.895 2.39418 12.2507 1.74985C11.6063 1.10552 10.5617 1.10552 9.91733 1.74985L2.21366 9.45351C2.04205 9.62512 1.95625 9.71092 1.89102 9.80983C1.83315 9.89759 1.78741 9.99277 1.75503 10.0928C1.71854 10.2055 1.70514 10.3261 1.67834 10.5673L1.45898 12.5415Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_12284_22440">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/edit-04.svg b/app/components/base/icons/assets/vender/line/general/edit-04.svg
new file mode 100644
index 0000000..9318930
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/edit-04.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M21 18L19.9999 19.094C19.4695 19.6741 18.7502 20 18.0002 20C17.2501 20 16.5308 19.6741 16.0004 19.094C15.4693 18.5151 14.75 18.1901 14.0002 18.1901C13.2504 18.1901 12.5312 18.5151 12 19.094M3.00003 20H4.67457C5.16376 20 5.40835 20 5.63852 19.9447C5.84259 19.8957 6.03768 19.8149 6.21663 19.7053C6.41846 19.5816 6.59141 19.4086 6.93732 19.0627L19.5001 6.49998C20.3285 5.67156 20.3285 4.32841 19.5001 3.49998C18.6716 2.67156 17.3285 2.67156 16.5001 3.49998L3.93729 16.0627C3.59139 16.4086 3.41843 16.5816 3.29475 16.7834C3.18509 16.9624 3.10428 17.1574 3.05529 17.3615C3.00003 17.5917 3.00003 17.8363 3.00003 18.3255V20Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/edit-05.svg b/app/components/base/icons/assets/vender/line/general/edit-05.svg
new file mode 100644
index 0000000..4328c4b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/edit-05.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="edit-05" clip-path="url(#clip0_17249_52683)">
+<path id="Icon" d="M7.33325 2.66617H4.53325C3.41315 2.66617 2.85309 2.66617 2.42527 2.88415C2.04895 3.0759 1.74299 3.38186 1.55124 3.75819C1.33325 4.18601 1.33325 4.74606 1.33325 5.86617V11.4662C1.33325 12.5863 1.33325 13.1463 1.55124 13.5741C1.74299 13.9505 2.04895 14.2564 2.42527 14.4482C2.85309 14.6662 3.41315 14.6662 4.53325 14.6662H10.1333C11.2534 14.6662 11.8134 14.6662 12.2412 14.4482C12.6176 14.2564 12.9235 13.9505 13.1153 13.5741C13.3333 13.1463 13.3333 12.5863 13.3333 11.4662V8.66617M5.33323 10.6662H6.4496C6.77572 10.6662 6.93878 10.6662 7.09223 10.6293C7.22828 10.5967 7.35834 10.5428 7.47763 10.4697C7.61219 10.3872 7.72749 10.2719 7.95809 10.0413L14.3333 3.66617C14.8855 3.11388 14.8855 2.21845 14.3333 1.66617C13.781 1.11388 12.8855 1.11388 12.3333 1.66617L5.95808 8.04133C5.72747 8.27193 5.61217 8.38723 5.52971 8.52179C5.45661 8.64108 5.40274 8.77114 5.37007 8.90719C5.33323 9.06064 5.33323 9.2237 5.33323 9.54982V10.6662Z" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_17249_52683">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/hash-02.svg b/app/components/base/icons/assets/vender/line/general/hash-02.svg
new file mode 100644
index 0000000..bc7a9dd
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/hash-02.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="hash-02">
+<path id="Icon" d="M4.74999 1.5L3.24999 10.5M8.74998 1.5L7.24998 10.5M10.25 4H1.75M9.75 8H1.25" stroke="#98A2B3" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/info-circle.svg b/app/components/base/icons/assets/vender/line/general/info-circle.svg
new file mode 100644
index 0000000..1c0e19c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/info-circle.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="info-circle" clip-path="url(#clip0_7880_62014)">
+<path id="Icon" d="M6 8V6M6 4H6.005M11 6C11 8.76142 8.76142 11 6 11C3.23858 11 1 8.76142 1 6C1 3.23858 3.23858 1 6 1C8.76142 1 11 3.23858 11 6Z" stroke="#98A2B3" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_7880_62014">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/link-03.svg b/app/components/base/icons/assets/vender/line/general/link-03.svg
new file mode 100644
index 0000000..7749dab
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/link-03.svg
@@ -0,0 +1,8 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="link-03">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.01569 1.83378C9.7701 1.10515 10.7805 0.701975 11.8293 0.711089C12.8781 0.720202 13.8813 1.14088 14.623 1.88251C15.3646 2.62414 15.7853 3.62739 15.7944 4.67618C15.8035 5.72497 15.4003 6.73538 14.6717 7.48979L14.6636 7.49805L12.6637 9.49796C12.2581 9.90362 11.7701 10.2173 11.2327 10.4178C10.6953 10.6183 10.1211 10.7008 9.54897 10.6598C8.97686 10.6189 8.42025 10.4553 7.91689 10.1803C7.41354 9.90531 6.97522 9.52527 6.63165 9.06596C6.41112 8.77113 6.47134 8.35334 6.76618 8.1328C7.06101 7.91226 7.4788 7.97249 7.69934 8.26732C7.92838 8.57353 8.2206 8.82689 8.55617 9.01023C8.89174 9.19356 9.26281 9.30259 9.64422 9.3299C10.0256 9.35722 10.4085 9.30219 10.7667 9.16854C11.125 9.0349 11.4503 8.82576 11.7207 8.55532L13.7164 6.55956C14.1998 6.05705 14.4672 5.38513 14.4611 4.68777C14.455 3.98857 14.1746 3.31974 13.6802 2.82532C13.1857 2.3309 12.5169 2.05045 11.8177 2.04437C11.12 2.03831 10.4478 2.30591 9.94526 2.78967L8.80219 3.92609C8.54108 4.18568 8.11898 4.18445 7.85939 3.92334C7.5998 3.66223 7.60103 3.24012 7.86214 2.98053L9.0088 1.84053L9.01569 1.83378Z" fill="#667085"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.76493 5.58217C6.30234 5.3817 6.87657 5.29915 7.44869 5.34012C8.0208 5.3811 8.57741 5.54463 9.08077 5.81964C9.58412 6.09465 10.0224 6.47469 10.366 6.93399C10.5865 7.22882 10.5263 7.64662 10.2315 7.86715C9.93665 8.08769 9.51886 8.02746 9.29832 7.73263C9.06928 7.42643 8.77706 7.17307 8.44149 6.98973C8.10592 6.80639 7.73485 6.69737 7.35344 6.67005C6.97203 6.64274 6.58921 6.69777 6.23094 6.83141C5.87266 6.96506 5.54733 7.17419 5.27699 7.44463L3.28123 9.44039C2.79787 9.94291 2.5305 10.6148 2.53656 11.3122C2.54263 12.0114 2.82309 12.6802 3.31751 13.1746C3.81193 13.6691 4.48076 13.9495 5.17995 13.9556C5.87732 13.9616 6.54923 13.6943 7.05174 13.2109L8.18743 12.0752C8.44777 11.8149 8.86988 11.8149 9.13023 12.0752C9.39058 12.3356 9.39058 12.7577 9.13023 13.018L7.99023 14.158L7.98197 14.1662C7.22756 14.8948 6.21715 15.298 5.16837 15.2889C4.11958 15.2798 3.11633 14.8591 2.3747 14.1174C1.63307 13.3758 1.21239 12.3726 1.20328 11.3238C1.19416 10.275 1.59734 9.26458 2.32597 8.51017L2.33409 8.50191L4.33401 6.50199C4.33398 6.50202 4.33404 6.50196 4.33401 6.50199C4.7395 6.09638 5.22756 5.78262 5.76493 5.58217Z" fill="#667085"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/link-external-02.svg b/app/components/base/icons/assets/vender/line/general/link-external-02.svg
new file mode 100644
index 0000000..71936fb
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/link-external-02.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="link-external-02">
+<path id="Icon" d="M10.5 4.5L10.5 1.5M10.5 1.5H7.49999M10.5 1.5L6 6M5 1.5H3.9C3.05992 1.5 2.63988 1.5 2.31901 1.66349C2.03677 1.8073 1.8073 2.03677 1.66349 2.31901C1.5 2.63988 1.5 3.05992 1.5 3.9V8.1C1.5 8.94008 1.5 9.36012 1.66349 9.68099C1.8073 9.96323 2.03677 10.1927 2.31901 10.3365C2.63988 10.5 3.05992 10.5 3.9 10.5H8.1C8.94008 10.5 9.36012 10.5 9.68099 10.3365C9.96323 10.1927 10.1927 9.96323 10.3365 9.68099C10.5 9.36012 10.5 8.94008 10.5 8.1V7" stroke="#155EEF" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/log-in-04.svg b/app/components/base/icons/assets/vender/line/general/log-in-04.svg
new file mode 100644
index 0000000..f18c50c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/log-in-04.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="log-in-04">
+<g id="Solid">
+<path d="M8.00016 1.99984C5.78015 1.99984 3.84088 3.20518 2.80244 5.00032C2.61808 5.31903 2.21026 5.42794 1.89155 5.24357C1.57285 5.05921 1.46394 4.65139 1.6483 4.33269C2.91526 2.14249 5.28495 0.666504 8.00016 0.666504C12.0502 0.666504 15.3335 3.94975 15.3335 7.99984C15.3335 12.0499 12.0502 15.3332 8.00016 15.3332C5.28495 15.3332 2.91526 13.8572 1.6483 11.667C1.46394 11.3483 1.57285 10.9405 1.89155 10.7561C2.21026 10.5717 2.61808 10.6806 2.80244 10.9994C3.84088 12.7945 5.78015 13.9998 8.00016 13.9998C11.3139 13.9998 14.0002 11.3135 14.0002 7.99984C14.0002 4.68613 11.3139 1.99984 8.00016 1.99984Z" fill="#344054"/>
+<path d="M7.52876 4.86177C7.78911 4.60142 8.21122 4.60142 8.47157 4.86177L11.1382 7.52843C11.3986 7.78878 11.3986 8.21089 11.1382 8.47124L8.47157 11.1379C8.21122 11.3983 7.78911 11.3983 7.52876 11.1379C7.26841 10.8776 7.26841 10.4554 7.52876 10.1951L9.05735 8.6665H2.00016C1.63197 8.6665 1.3335 8.36803 1.3335 7.99984C1.3335 7.63165 1.63197 7.33317 2.00016 7.33317H9.05735L7.52876 5.80457C7.26841 5.54423 7.26841 5.12212 7.52876 4.86177Z" fill="#344054"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/log-out-01.svg b/app/components/base/icons/assets/vender/line/general/log-out-01.svg
new file mode 100644
index 0000000..f1789d7
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/log-out-01.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="log-out-01">
+<path id="Icon" d="M9.33333 9.91667L12.25 7M12.25 7L9.33333 4.08333M12.25 7H5.25M5.25 1.75H4.55C3.56991 1.75 3.07986 1.75 2.70552 1.94074C2.37623 2.10852 2.10852 2.37623 1.94074 2.70552C1.75 3.07986 1.75 3.56991 1.75 4.55V9.45C1.75 10.4301 1.75 10.9201 1.94074 11.2945C2.10852 11.6238 2.37623 11.8915 2.70552 12.0593C3.07986 12.25 3.56991 12.25 4.55 12.25H5.25" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/log-out-04.svg b/app/components/base/icons/assets/vender/line/general/log-out-04.svg
new file mode 100644
index 0000000..317023e
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/log-out-04.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="log-out-04">
+<g id="Solid">
+<path d="M0.666504 8.00016C0.666504 4.3422 3.52829 1.3335 7.11095 1.3335C8.28872 1.3335 9.3935 1.66091 10.3431 2.23137C10.6588 2.42097 10.7609 2.83053 10.5713 3.14615C10.3817 3.46177 9.97216 3.56394 9.65654 3.37434C8.90651 2.92378 8.03794 2.66683 7.11095 2.66683C4.31165 2.66683 1.99984 5.03071 1.99984 8.00016C1.99984 10.9696 4.31165 13.3335 7.11095 13.3335C8.03794 13.3335 8.90651 13.0765 9.65654 12.626C9.97216 12.4364 10.3817 12.5386 10.5713 12.8542C10.7609 13.1698 10.6588 13.5794 10.3431 13.769C9.3935 14.3394 8.28872 14.6668 7.11095 14.6668C3.52829 14.6668 0.666504 11.6581 0.666504 8.00016Z" fill="#98A2B3"/>
+<path d="M11.5284 4.86209C11.7888 4.60174 12.2109 4.60174 12.4712 4.86209L15.1379 7.52876C15.3983 7.78911 15.3983 8.21122 15.1379 8.47157L12.4712 11.1382C12.2109 11.3986 11.7888 11.3986 11.5284 11.1382C11.2681 10.8779 11.2681 10.4558 11.5284 10.1954L13.057 8.66683H5.99984C5.63165 8.66683 5.33317 8.36835 5.33317 8.00016C5.33317 7.63197 5.63165 7.3335 5.99984 7.3335H13.057L11.5284 5.8049C11.2681 5.54455 11.2681 5.12244 11.5284 4.86209Z" fill="#98A2B3"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/menu-01.svg b/app/components/base/icons/assets/vender/line/general/menu-01.svg
new file mode 100644
index 0000000..d540518
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/menu-01.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="menu-01">
+<path id="Icon" d="M2 8H14M2 4H14M2 12H14" stroke="#344054" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/pin-01.svg b/app/components/base/icons/assets/vender/line/general/pin-01.svg
new file mode 100644
index 0000000..314a582
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/pin-01.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="pin-01">
+<path id="Icon" d="M8.00037 10.0007L8.00037 14.6673M5.3337 4.87274V6.29315C5.3337 6.43183 5.3337 6.50117 5.32009 6.56749C5.30801 6.62633 5.28804 6.68327 5.26071 6.73677C5.22991 6.79706 5.18659 6.8512 5.09996 6.95949L4.05344 8.26764C3.60962 8.82242 3.3877 9.09982 3.38745 9.33326C3.38723 9.53629 3.47954 9.72835 3.63822 9.85501C3.82067 10.0007 4.1759 10.0007 4.88637 10.0007H11.1144C11.8248 10.0007 12.1801 10.0007 12.3625 9.85501C12.5212 9.72835 12.6135 9.53629 12.6133 9.33326C12.613 9.09982 12.3911 8.82242 11.9473 8.26764L10.9008 6.95949C10.8141 6.8512 10.7708 6.79706 10.74 6.73677C10.7127 6.68327 10.6927 6.62633 10.6806 6.56749C10.667 6.50117 10.667 6.43183 10.667 6.29315V4.87274C10.667 4.79599 10.667 4.75761 10.6714 4.71977C10.6752 4.68615 10.6816 4.65287 10.6905 4.62023C10.7006 4.58348 10.7148 4.54785 10.7433 4.47659L11.4152 2.7968C11.6113 2.30674 11.7093 2.06171 11.6684 1.86502C11.6327 1.693 11.5305 1.54206 11.384 1.44499C11.2166 1.33398 10.9527 1.33398 10.4249 1.33398H5.57587C5.04806 1.33398 4.78416 1.33398 4.61671 1.44499C4.47027 1.54206 4.36808 1.693 4.33233 1.86502C4.29146 2.06171 4.38947 2.30674 4.58549 2.7968L5.25741 4.47659C5.28591 4.54785 5.30017 4.58348 5.31019 4.62023C5.3191 4.65287 5.32551 4.68615 5.32936 4.71977C5.3337 4.75761 5.3337 4.79599 5.3337 4.87274Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/pin-02.svg b/app/components/base/icons/assets/vender/line/general/pin-02.svg
new file mode 100644
index 0000000..023e6e4
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/pin-02.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.3767 15.6163L2.71985 21.2732M11.6944 6.64181L10.1335 8.2027C10.0062 8.33003 9.94252 8.39369 9.86999 8.44427C9.80561 8.48917 9.73616 8.52634 9.66309 8.555C9.58077 8.58729 9.49249 8.60495 9.31592 8.64026L5.65145 9.37315C4.69915 9.56361 4.223 9.65884 4.00024 9.9099C3.80617 10.1286 3.71755 10.4213 3.75771 10.7109C3.8038 11.0434 4.14715 11.3867 4.83387 12.0735L11.9196 19.1592C12.6063 19.8459 12.9497 20.1893 13.2821 20.2354C13.5718 20.2755 13.8645 20.1869 14.0832 19.9928C14.3342 19.7701 14.4294 19.2939 14.6199 18.3416L15.3528 14.6771C15.3881 14.5006 15.4058 14.4123 15.4381 14.33C15.4667 14.2569 15.5039 14.1875 15.5488 14.1231C15.5994 14.0505 15.663 13.9869 15.7904 13.8596L17.3512 12.2987C17.4326 12.2173 17.4734 12.1766 17.5181 12.141C17.5578 12.1095 17.5999 12.081 17.644 12.0558C17.6936 12.0274 17.7465 12.0048 17.8523 11.9594L20.3467 10.8904C21.0744 10.5785 21.4383 10.4226 21.6035 10.1706C21.7481 9.95025 21.7998 9.68175 21.7474 9.42348C21.6875 9.12813 21.4076 8.84822 20.8478 8.28839L15.7047 3.14526C15.1448 2.58543 14.8649 2.30552 14.5696 2.24565C14.3113 2.19329 14.0428 2.245 13.8225 2.38953C13.5705 2.55481 13.4145 2.91866 13.1027 3.64636L12.0337 6.14071C11.9883 6.24653 11.9656 6.29944 11.9373 6.34905C11.9121 6.39313 11.8836 6.43522 11.852 6.47496C11.8165 6.51971 11.7758 6.56041 11.6944 6.64181Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/plus-02.svg b/app/components/base/icons/assets/vender/line/general/plus-02.svg
new file mode 100644
index 0000000..4358325
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/plus-02.svg
@@ -0,0 +1,5 @@
+<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="plus">
+<path id="Icon" d="M5.00004 2.08325V7.91659M2.08337 4.99992H7.91671" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/refresh.svg b/app/components/base/icons/assets/vender/line/general/refresh.svg
new file mode 100644
index 0000000..05cf986
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/refresh.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M5.46257 4.43262C7.21556 2.91688 9.5007 2 12 2C17.5228 2 22 6.47715 22 12C22 14.1361 21.3302 16.1158 20.1892 17.7406L17 12H20C20 7.58172 16.4183 4 12 4C9.84982 4 7.89777 4.84827 6.46023 6.22842L5.46257 4.43262ZM18.5374 19.5674C16.7844 21.0831 14.4993 22 12 22C6.47715 22 2 17.5228 2 12C2 9.86386 2.66979 7.88416 3.8108 6.25944L7 12H4C4 16.4183 7.58172 20 12 20C14.1502 20 16.1022 19.1517 17.5398 17.7716L18.5374 19.5674Z"></path></svg>
\ No newline at end of file
diff --git a/app/components/base/icons/assets/vender/line/general/settings-01.svg b/app/components/base/icons/assets/vender/line/general/settings-01.svg
new file mode 100644
index 0000000..db8cbd1
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/settings-01.svg
@@ -0,0 +1,13 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Left Icon" clip-path="url(#clip0_11961_30603)">
+<g id="Icon">
+<path d="M6.99935 8.74984C7.96585 8.74984 8.74935 7.96634 8.74935 6.99984C8.74935 6.03334 7.96585 5.24984 6.99935 5.24984C6.03285 5.24984 5.24935 6.03334 5.24935 6.99984C5.24935 7.96634 6.03285 8.74984 6.99935 8.74984Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M10.9236 8.59075C10.853 8.75069 10.8319 8.92812 10.8631 9.10015C10.8943 9.27218 10.9763 9.43092 11.0986 9.5559L11.1304 9.58772C11.229 9.68622 11.3073 9.80319 11.3606 9.93195C11.414 10.0607 11.4415 10.1987 11.4415 10.3381C11.4415 10.4775 11.414 10.6155 11.3606 10.7442C11.3073 10.873 11.229 10.99 11.1304 11.0885C11.0319 11.1871 10.9149 11.2653 10.7862 11.3187C10.6574 11.3721 10.5194 11.3995 10.38 11.3995C10.2407 11.3995 10.1026 11.3721 9.97388 11.3187C9.84513 11.2653 9.72815 11.1871 9.62965 11.0885L9.59783 11.0567C9.47285 10.9344 9.31411 10.8524 9.14209 10.8212C8.97006 10.79 8.79263 10.8111 8.63268 10.8817C8.47583 10.9489 8.34207 11.0605 8.24785 11.2028C8.15362 11.345 8.10306 11.5118 8.10238 11.6824V11.7726C8.10238 12.0539 7.99064 12.3236 7.79173 12.5225C7.59283 12.7214 7.32306 12.8332 7.04177 12.8332C6.76048 12.8332 6.49071 12.7214 6.29181 12.5225C6.09291 12.3236 5.98117 12.0539 5.98117 11.7726V11.7248C5.97706 11.5493 5.92025 11.3791 5.8181 11.2363C5.71596 11.0935 5.57322 10.9847 5.40844 10.9241C5.24849 10.8535 5.07106 10.8324 4.89904 10.8636C4.72701 10.8948 4.56827 10.9768 4.44329 11.0991L4.41147 11.1309C4.31297 11.2295 4.196 11.3077 4.06724 11.3611C3.93848 11.4145 3.80047 11.442 3.66109 11.442C3.52171 11.442 3.3837 11.4145 3.25494 11.3611C3.12619 11.3077 3.00921 11.2295 2.91071 11.1309C2.8121 11.0324 2.73387 10.9154 2.6805 10.7867C2.62712 10.6579 2.59965 10.5199 2.59965 10.3805C2.59965 10.2411 2.62712 10.1031 2.6805 9.97437C2.73387 9.84561 2.8121 9.72864 2.91071 9.63014L2.94253 9.59832C3.06479 9.47334 3.1468 9.3146 3.17799 9.14257C3.20918 8.97055 3.18812 8.79312 3.11753 8.63317C3.05031 8.47632 2.93869 8.34256 2.79641 8.24833C2.65414 8.15411 2.48742 8.10355 2.31677 8.10287H2.22662C1.94533 8.10287 1.67556 7.99112 1.47666 7.79222C1.27776 7.59332 1.16602 7.32355 1.16602 7.04226C1.16602 6.76097 1.27776 6.4912 1.47666 6.2923C1.67556 6.0934 1.94533 5.98166 2.22662 5.98166H2.27435C2.44988 5.97755 2.62011 5.92073 2.76292 5.81859C2.90572 5.71645 3.0145 5.57371 3.07511 5.40893C3.1457 5.24898 3.16676 5.07155 3.13556 4.89953C3.10437 4.7275 3.02236 4.56876 2.90011 4.44378L2.86829 4.41196C2.76968 4.31346 2.69145 4.19648 2.63807 4.06773C2.5847 3.93897 2.55723 3.80096 2.55723 3.66158C2.55723 3.5222 2.5847 3.38419 2.63807 3.25543C2.69145 3.12668 2.76968 3.0097 2.86829 2.9112C2.96679 2.81259 3.08376 2.73436 3.21252 2.68099C3.34127 2.62761 3.47929 2.60014 3.61867 2.60014C3.75805 2.60014 3.89606 2.62761 4.02482 2.68099C4.15357 2.73436 4.27054 2.81259 4.36905 2.9112L4.40086 2.94302C4.52585 3.06527 4.68458 3.14728 4.85661 3.17848C5.02864 3.20967 5.20607 3.18861 5.36602 3.11802H5.40844C5.56529 3.0508 5.69906 2.93918 5.79328 2.7969C5.8875 2.65463 5.93806 2.48791 5.93874 2.31726V2.22711C5.93874 1.94582 6.05049 1.67605 6.24939 1.47715C6.44829 1.27825 6.71806 1.1665 6.99935 1.1665C7.28064 1.1665 7.55041 1.27825 7.74931 1.47715C7.94821 1.67605 8.05995 1.94582 8.05995 2.22711V2.27484C8.06064 2.44548 8.1112 2.6122 8.20542 2.75448C8.29964 2.89675 8.43341 3.00837 8.59026 3.07559C8.75021 3.14619 8.92763 3.16724 9.09966 3.13605C9.27169 3.10486 9.43043 3.02285 9.55541 2.90059L9.58723 2.86878C9.68573 2.77017 9.8027 2.69194 9.93146 2.63856C10.0602 2.58519 10.1982 2.55772 10.3376 2.55772C10.477 2.55772 10.615 2.58519 10.7438 2.63856C10.8725 2.69194 10.9895 2.77017 11.088 2.86878C11.1866 2.96728 11.2648 3.08425 11.3182 3.21301C11.3716 3.34176 11.399 3.47978 11.399 3.61916C11.399 3.75854 11.3716 3.89655 11.3182 4.0253C11.2648 4.15406 11.1866 4.27103 11.088 4.36953L11.0562 4.40135C10.9339 4.52633 10.8519 4.68507 10.8207 4.8571C10.7895 5.02913 10.8106 5.20656 10.8812 5.3665V5.40893C10.9484 5.56578 11.06 5.69954 11.2023 5.79377C11.3446 5.88799 11.5113 5.93855 11.6819 5.93923H11.7721C12.0534 5.93923 12.3231 6.05097 12.522 6.24988C12.7209 6.44878 12.8327 6.71855 12.8327 6.99984C12.8327 7.28113 12.7209 7.5509 12.522 7.7498C12.3231 7.9487 12.0534 8.06044 11.7721 8.06044H11.7243C11.5537 8.06112 11.387 8.11169 11.2447 8.20591C11.1024 8.30013 10.9908 8.4339 10.9236 8.59075Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_11961_30603">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/settings-04.svg b/app/components/base/icons/assets/vender/line/general/settings-04.svg
new file mode 100644
index 0000000..176fe3a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/settings-04.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Left Icon">
+<path id="Icon" d="M1.75 4.6665L8.75 4.6665M8.75 4.6665C8.75 5.633 9.5335 6.4165 10.5 6.4165C11.4665 6.4165 12.25 5.633 12.25 4.6665C12.25 3.70001 11.4665 2.9165 10.5 2.9165C9.5335 2.9165 8.75 3.70001 8.75 4.6665ZM5.25 9.33317L12.25 9.33317M5.25 9.33317C5.25 10.2997 4.4665 11.0832 3.5 11.0832C2.5335 11.0832 1.75 10.2997 1.75 9.33317C1.75 8.36667 2.5335 7.58317 3.5 7.58317C4.4665 7.58317 5.25 8.36667 5.25 9.33317Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/target-04.svg b/app/components/base/icons/assets/vender/line/general/target-04.svg
new file mode 100644
index 0000000..2e2f1ff
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/target-04.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Left Icon" clip-path="url(#clip0_10386_42171)">
+<path id="Icon" d="M7.99998 4V2.5L9.49998 1L9.99998 2L11 2.5L9.49998 4H7.99998ZM7.99998 4L5.99999 5.99997M11 6C11 8.76142 8.76142 11 6 11C3.23858 11 1 8.76142 1 6C1 3.23858 3.23858 1 6 1M8.5 6C8.5 7.38071 7.38071 8.5 6 8.5C4.61929 8.5 3.5 7.38071 3.5 6C3.5 4.61929 4.61929 3.5 6 3.5" stroke="#667085" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_10386_42171">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/upload-03.svg b/app/components/base/icons/assets/vender/line/general/upload-03.svg
new file mode 100644
index 0000000..3b4228b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/upload-03.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Left Icon" clip-path="url(#clip0_12728_40636)">
+<path id="Icon" d="M10.6654 8.00016L7.9987 5.3335M7.9987 5.3335L5.33203 8.00016M7.9987 5.3335V10.6668M14.6654 8.00016C14.6654 11.6821 11.6806 14.6668 7.9987 14.6668C4.3168 14.6668 1.33203 11.6821 1.33203 8.00016C1.33203 4.31826 4.3168 1.3335 7.9987 1.3335C11.6806 1.3335 14.6654 4.31826 14.6654 8.00016Z" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_12728_40636">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/upload-cloud-01.svg b/app/components/base/icons/assets/vender/line/general/upload-cloud-01.svg
new file mode 100644
index 0000000..c85fd5e
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/upload-cloud-01.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.4" d="M4 16.2422C2.79401 15.435 2 14.0602 2 12.5C2 10.1564 3.79151 8.23129 6.07974 8.01937C6.54781 5.17213 9.02024 3 12 3C14.9798 3 17.4522 5.17213 17.9203 8.01937C20.2085 8.23129 22 10.1564 22 12.5C22 14.0602 21.206 15.435 20 16.2422" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M8 16L12 12M12 12L16 16M12 12L12 21" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/general/x.svg b/app/components/base/icons/assets/vender/line/general/x.svg
new file mode 100644
index 0000000..04815e5
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/general/x.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="x">
+<path id="Icon" d="M11.3334 4.66663L4.66675 11.3333M4.66675 4.66663L11.3334 11.3333" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/images/image-plus.svg b/app/components/base/icons/assets/vender/line/images/image-plus.svg
new file mode 100644
index 0000000..affaf19
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/images/image-plus.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="image-plus">
+<path id="Icon" d="M8.33333 2.00016H5.2C4.0799 2.00016 3.51984 2.00016 3.09202 2.21815C2.71569 2.4099 2.40973 2.71586 2.21799 3.09218C2 3.52001 2 4.08006 2 5.20016V10.8002C2 11.9203 2 12.4803 2.21799 12.9081C2.40973 13.2845 2.71569 13.5904 3.09202 13.7822C3.51984 14.0002 4.07989 14.0002 5.2 14.0002H11.3333C11.9533 14.0002 12.2633 14.0002 12.5176 13.932C13.2078 13.7471 13.7469 13.208 13.9319 12.5178C14 12.2635 14 11.9535 14 11.3335M12.6667 5.3335V1.3335M10.6667 3.3335H14.6667M7 5.66683C7 6.40321 6.40305 7.00016 5.66667 7.00016C4.93029 7.00016 4.33333 6.40321 4.33333 5.66683C4.33333 4.93045 4.93029 4.3335 5.66667 4.3335C6.40305 4.3335 7 4.93045 7 5.66683ZM9.99336 7.94559L4.3541 13.0722C4.03691 13.3605 3.87831 13.5047 3.86429 13.6296C3.85213 13.7379 3.89364 13.8453 3.97546 13.9172C4.06985 14.0002 4.28419 14.0002 4.71286 14.0002H10.9707C11.9301 14.0002 12.4098 14.0002 12.7866 13.839C13.2596 13.6366 13.6365 13.2598 13.8388 12.7868C14 12.41 14 11.9303 14 10.9708C14 10.648 14 10.4866 13.9647 10.3363C13.9204 10.1474 13.8353 9.9704 13.7155 9.81776C13.6202 9.6963 13.4941 9.59546 13.242 9.3938L11.3772 7.90194C11.1249 7.7001 10.9988 7.59919 10.8599 7.56357C10.7374 7.53218 10.6086 7.53624 10.4884 7.57529C10.352 7.61959 10.2324 7.72826 9.99336 7.94559Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/layout/align-left-01.svg b/app/components/base/icons/assets/vender/line/layout/align-left-01.svg
new file mode 100644
index 0000000..70b6627
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/layout/align-left-01.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="align-left-01">
+<path id="Icon" d="M3 3V21M21 12H7M7 12L14 19M7 12L14 5" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/layout/align-right-01.svg b/app/components/base/icons/assets/vender/line/layout/align-right-01.svg
new file mode 100644
index 0000000..1e711ea
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/layout/align-right-01.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="align-right-01">
+<path id="Icon" d="M21 21V3M3 12H17M17 12L10 5M17 12L10 19" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/layout/grid-01.svg b/app/components/base/icons/assets/vender/line/layout/grid-01.svg
new file mode 100644
index 0000000..9970181
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/layout/grid-01.svg
@@ -0,0 +1,10 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="grid-01">
+<g id="Icon">
+<path d="M6.1 2H3.56667C3.1933 2 3.00661 2 2.86401 2.07266C2.73856 2.13658 2.63658 2.23856 2.57266 2.36401C2.5 2.50661 2.5 2.6933 2.5 3.06667V5.6C2.5 5.97337 2.5 6.16005 2.57266 6.30266C2.63658 6.4281 2.73856 6.53009 2.86401 6.594C3.00661 6.66667 3.1933 6.66667 3.56667 6.66667H6.1C6.47337 6.66667 6.66005 6.66667 6.80266 6.594C6.9281 6.53009 7.03009 6.4281 7.094 6.30266C7.16667 6.16005 7.16667 5.97337 7.16667 5.6V3.06667C7.16667 2.6933 7.16667 2.50661 7.094 2.36401C7.03009 2.23856 6.9281 2.13658 6.80266 2.07266C6.66005 2 6.47337 2 6.1 2Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M13.4333 2H10.9C10.5266 2 10.3399 2 10.1973 2.07266C10.0719 2.13658 9.96991 2.23856 9.906 2.36401C9.83333 2.50661 9.83333 2.6933 9.83333 3.06667V5.6C9.83333 5.97337 9.83333 6.16005 9.906 6.30266C9.96991 6.4281 10.0719 6.53009 10.1973 6.594C10.3399 6.66667 10.5266 6.66667 10.9 6.66667H13.4333C13.8067 6.66667 13.9934 6.66667 14.136 6.594C14.2614 6.53009 14.3634 6.4281 14.4273 6.30266C14.5 6.16005 14.5 5.97337 14.5 5.6V3.06667C14.5 2.6933 14.5 2.50661 14.4273 2.36401C14.3634 2.23856 14.2614 2.13658 14.136 2.07266C13.9934 2 13.8067 2 13.4333 2Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M13.4333 9.33333H10.9C10.5266 9.33333 10.3399 9.33333 10.1973 9.406C10.0719 9.46991 9.96991 9.5719 9.906 9.69734C9.83333 9.83995 9.83333 10.0266 9.83333 10.4V12.9333C9.83333 13.3067 9.83333 13.4934 9.906 13.636C9.96991 13.7614 10.0719 13.8634 10.1973 13.9273C10.3399 14 10.5266 14 10.9 14H13.4333C13.8067 14 13.9934 14 14.136 13.9273C14.2614 13.8634 14.3634 13.7614 14.4273 13.636C14.5 13.4934 14.5 13.3067 14.5 12.9333V10.4C14.5 10.0266 14.5 9.83995 14.4273 9.69734C14.3634 9.5719 14.2614 9.46991 14.136 9.406C13.9934 9.33333 13.8067 9.33333 13.4333 9.33333Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M6.1 9.33333H3.56667C3.1933 9.33333 3.00661 9.33333 2.86401 9.406C2.73856 9.46991 2.63658 9.5719 2.57266 9.69734C2.5 9.83995 2.5 10.0266 2.5 10.4V12.9333C2.5 13.3067 2.5 13.4934 2.57266 13.636C2.63658 13.7614 2.73856 13.8634 2.86401 13.9273C3.00661 14 3.1933 14 3.56667 14H6.1C6.47337 14 6.66005 14 6.80266 13.9273C6.9281 13.8634 7.03009 13.7614 7.094 13.636C7.16667 13.4934 7.16667 13.3067 7.16667 12.9333V10.4C7.16667 10.0266 7.16667 9.83995 7.094 9.69734C7.03009 9.5719 6.9281 9.46991 6.80266 9.406C6.66005 9.33333 6.47337 9.33333 6.1 9.33333Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/layout/layout-grid-02.svg b/app/components/base/icons/assets/vender/line/layout/layout-grid-02.svg
new file mode 100644
index 0000000..7a39660
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/layout/layout-grid-02.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M3 9H21M3 15H21M12 3V21M7.8 3H16.2C17.8802 3 18.7202 3 19.362 3.32698C19.9265 3.6146 20.3854 4.07354 20.673 4.63803C21 5.27976 21 6.11984 21 7.8V16.2C21 17.8802 21 18.7202 20.673 19.362C20.3854 19.9265 19.9265 20.3854 19.362 20.673C18.7202 21 17.8802 21 16.2 21H7.8C6.11984 21 5.27976 21 4.63803 20.673C4.07354 20.3854 3.6146 19.9265 3.32698 19.362C3 18.7202 3 17.8802 3 16.2V7.8C3 6.11984 3 5.27976 3.32698 4.63803C3.6146 4.07354 4.07354 3.6146 4.63803 3.32698C5.27976 3 6.11984 3 7.8 3Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/mapsAndTravel/globe-01.svg b/app/components/base/icons/assets/vender/line/mapsAndTravel/globe-01.svg
new file mode 100644
index 0000000..88898bb
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/mapsAndTravel/globe-01.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="globe-01" clip-path="url(#clip0_8902_1914)">
+<path id="Icon" d="M1.33325 7.99998H14.6666M1.33325 7.99998C1.33325 11.6819 4.31802 14.6666 7.99992 14.6666M1.33325 7.99998C1.33325 4.31808 4.31802 1.33331 7.99992 1.33331M14.6666 7.99998C14.6666 11.6819 11.6818 14.6666 7.99992 14.6666M14.6666 7.99998C14.6666 4.31808 11.6818 1.33331 7.99992 1.33331M7.99992 1.33331C9.66744 3.15888 10.6151 5.528 10.6666 7.99998C10.6151 10.472 9.66744 12.8411 7.99992 14.6666M7.99992 1.33331C6.3324 3.15888 5.38475 5.528 5.33325 7.99998C5.38475 10.472 6.3324 12.8411 7.99992 14.6666" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_8902_1914">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/mapsAndTravel/route.svg b/app/components/base/icons/assets/vender/line/mapsAndTravel/route.svg
new file mode 100644
index 0000000..b1543cc
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/mapsAndTravel/route.svg
@@ -0,0 +1,10 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="route" clip-path="url(#clip0_3167_28693)">
+<path id="Icon" d="M6.70866 2.91699H6.96206C8.73962 2.91699 9.6284 2.91699 9.96578 3.23624C10.2574 3.51221 10.3867 3.91874 10.3079 4.31245C10.2168 4.76792 9.49122 5.28116 8.03999 6.30763L5.66899 7.98468C4.21777 9.01116 3.49215 9.5244 3.40106 9.97987C3.32233 10.3736 3.45157 10.7801 3.7432 11.0561C4.08059 11.3753 4.96937 11.3753 6.74693 11.3753H7.29199M4.66699 2.91699C4.66699 3.88349 3.88349 4.66699 2.91699 4.66699C1.95049 4.66699 1.16699 3.88349 1.16699 2.91699C1.16699 1.95049 1.95049 1.16699 2.91699 1.16699C3.88349 1.16699 4.66699 1.95049 4.66699 2.91699ZM12.8337 11.0837C12.8337 12.0502 12.0502 12.8337 11.0837 12.8337C10.1172 12.8337 9.33366 12.0502 9.33366 11.0837C9.33366 10.1172 10.1172 9.33366 11.0837 9.33366C12.0502 9.33366 12.8337 10.1172 12.8337 11.0837Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_3167_28693">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/mediaAndDevices/microphone-01.svg b/app/components/base/icons/assets/vender/line/mediaAndDevices/microphone-01.svg
new file mode 100644
index 0000000..46d6818
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/mediaAndDevices/microphone-01.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="microphone-01">
+<path id="Icon" d="M12.6666 6.66732V8.00065C12.6666 10.578 10.5772 12.6673 7.99992 12.6673M3.33325 6.66732V8.00065C3.33325 10.578 5.42259 12.6673 7.99992 12.6673M7.99992 12.6673V14.6673M5.33325 14.6673H10.6666M7.99992 10.0007C6.89535 10.0007 5.99992 9.10522 5.99992 8.00065V3.33398C5.99992 2.22941 6.89535 1.33398 7.99992 1.33398C9.10449 1.33398 9.99992 2.22941 9.99992 3.33398V8.00065C9.99992 9.10522 9.10449 10.0007 7.99992 10.0007Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/mediaAndDevices/play-circle.svg b/app/components/base/icons/assets/vender/line/mediaAndDevices/play-circle.svg
new file mode 100644
index 0000000..9ef6c7b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/mediaAndDevices/play-circle.svg
@@ -0,0 +1,13 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="play-circle" clip-path="url(#clip0_3607_26538)">
+<g id="Icon">
+<path d="M7.99992 14.6666C11.6818 14.6666 14.6666 11.6819 14.6666 7.99998C14.6666 4.31808 11.6818 1.33331 7.99992 1.33331C4.31802 1.33331 1.33325 4.31808 1.33325 7.99998C1.33325 11.6819 4.31802 14.6666 7.99992 14.6666Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M6.66659 5.33331L10.6666 7.99998L6.66659 10.6666V5.33331Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_3607_26538">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/mediaAndDevices/sliders-h.svg b/app/components/base/icons/assets/vender/line/mediaAndDevices/sliders-h.svg
new file mode 100644
index 0000000..453aa8a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/mediaAndDevices/sliders-h.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M3 5H9M9 5C9 6.10457 9.89543 7 11 7C12.1046 7 13 6.10457 13 5C13 3.89543 12.1046 3 11 3C9.89543 3 9 3.89543 9 5ZM17 5L21 5M3 12H9M17 12H21M17 12C17 10.8954 16.1046 10 15 10C13.8954 10 13 10.8954 13 12C13 13.1046 13.8954 14 15 14C16.1046 14 17 13.1046 17 12ZM3 19H7M7 19C7 20.1046 7.89543 21 9 21C10.1046 21 11 20.1046 11 19C11 17.8954 10.1046 17 9 17C7.89543 17 7 17.8954 7 19ZM15 19H21" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/mediaAndDevices/speaker.svg b/app/components/base/icons/assets/vender/line/mediaAndDevices/speaker.svg
new file mode 100644
index 0000000..f769c7e
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/mediaAndDevices/speaker.svg
@@ -0,0 +1,15 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_109_6694)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.86666C0 2.05664 0.656649 1.39999 1.46667 1.39999H5.86667C6.67668 1.39999 7.33333 2.05664 7.33333 2.86666C7.33333 3.27167 7.00501 3.59999 6.6 3.59999C6.19499 3.59999 5.86667 3.27167 5.86667 2.86666H4.4V7.99999C4.80501 7.99999 5.13333 8.32831 5.13333 8.73332C5.13333 9.13833 4.80501 9.46666 4.4 9.46666H2.93333C2.52832 9.46666 2.2 9.13833 2.2 8.73332C2.2 8.32831 2.52832 7.99999 2.93333 7.99999V2.86666H1.46667C1.46667 3.27167 1.13834 3.59999 0.733333 3.59999C0.328324 3.59999 0 3.27167 0 2.86666Z" fill="#444CE7"/>
+<path d="M13.8205 0.782296C13.7434 0.62811 13.5233 0.62811 13.4462 0.782296C12.9664 1.74206 12.8754 1.83302 11.9156 2.3129C11.7615 2.39 11.7615 2.61003 11.9156 2.68712C12.8754 3.167 12.9664 3.25797 13.4462 4.21773C13.5233 4.37191 13.7434 4.37191 13.8205 4.21773C14.3003 3.25797 14.3913 3.167 15.3511 2.68712C15.5053 2.61003 15.5053 2.39 15.3511 2.3129C14.3913 1.83302 14.3003 1.74206 13.8205 0.782296Z" fill="#444CE7"/>
+<path d="M9.79394 2.25319C9.71404 2.09337 9.48596 2.09337 9.40605 2.25319C9.04994 2.96543 8.96544 3.04993 8.2532 3.40605C8.09338 3.48595 8.09338 3.71402 8.2532 3.79393C8.96544 4.15005 9.04994 4.23455 9.40606 4.94679C9.48596 5.10661 9.71404 5.10661 9.79394 4.94679C10.1501 4.23455 10.2346 4.15005 10.9468 3.79393C11.1066 3.71402 11.1066 3.48595 10.9468 3.40605C10.2346 3.04993 10.1501 2.96543 9.79394 2.25319Z" fill="#444CE7"/>
+<path d="M2.75377 11.049C2.67668 10.8948 2.45665 10.8948 2.37956 11.049C1.89969 12.0087 1.80872 12.0997 0.848971 12.5796C0.694788 12.6566 0.694787 12.8767 0.848971 12.9538C1.80872 13.4336 1.89969 13.5246 2.37956 14.4844C2.45665 14.6385 2.67668 14.6385 2.75377 14.4844C3.23365 13.5246 3.32461 13.4336 4.28436 12.9538C4.43855 12.8767 4.43855 12.6566 4.28436 12.5796C3.32461 12.0997 3.23365 12.0087 2.75377 11.049Z" fill="#444CE7"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14.6741 8.65106C14.8886 8.50146 15.1837 8.55405 15.3333 8.76853C15.7614 9.38226 16.0125 10.1292 16.0125 10.9333C16.0125 11.7375 15.7614 12.4844 15.3333 13.0981C15.1837 13.3126 14.8886 13.3652 14.6741 13.2156C14.4596 13.066 14.407 12.7708 14.5567 12.5564C14.8775 12.0964 15.0656 11.5375 15.0656 10.9333C15.0656 10.3291 14.8775 9.77025 14.5567 9.31028C14.407 9.09581 14.4596 8.80066 14.6741 8.65106Z" fill="#444CE7"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.5674 6.53771C12.794 6.51987 13.0155 6.61161 13.1632 6.78449C13.2954 6.93929 13.3164 7.12549 13.3244 7.21587C13.3334 7.31718 13.3334 7.44301 13.3333 7.57103C13.3333 7.57691 13.3333 7.58278 13.3333 7.58866L13.3333 14.3C13.3334 14.428 13.3334 14.5539 13.3244 14.6552C13.3164 14.7455 13.2954 14.9317 13.1632 15.0865C13.0155 15.2594 12.794 15.3512 12.5674 15.3333C12.3644 15.3173 12.2179 15.2005 12.1484 15.1423C12.0704 15.077 11.9814 14.988 11.8909 14.8975L10.3795 13.3861C10.3357 13.3423 10.3137 13.3205 10.2971 13.3053L10.2958 13.3041L10.2941 13.3041C10.2716 13.303 10.2407 13.3029 10.1787 13.3029L9.34101 13.3029C9.22151 13.3029 9.10513 13.3029 9.00657 13.2949C8.89833 13.286 8.77062 13.2652 8.6421 13.1997C8.46392 13.1089 8.31906 12.964 8.22827 12.7859C8.16279 12.6574 8.14192 12.5296 8.13308 12.4214C8.12503 12.3228 8.12504 12.2065 8.12505 12.087V9.79916C8.12505 9.79413 8.12505 9.78909 8.12505 9.78406C8.12504 9.66456 8.12503 9.54819 8.13308 9.44963C8.14192 9.34139 8.16279 9.21368 8.22827 9.08517C8.31906 8.90699 8.46392 8.76212 8.6421 8.67133C8.77062 8.60585 8.89833 8.58498 9.00657 8.57614C9.10512 8.56809 9.2215 8.5681 9.341 8.56812C9.34603 8.56812 9.35106 8.56812 9.3561 8.56812H10.1787C10.2407 8.56812 10.2716 8.56801 10.2941 8.56698L10.2958 8.5669L10.2971 8.56575C10.3137 8.55058 10.3357 8.52877 10.3795 8.48491L11.8784 6.98602C11.8826 6.98186 11.8867 6.97771 11.8909 6.97355C11.9814 6.88302 12.0704 6.79403 12.1484 6.72874C12.2179 6.67049 12.3644 6.55368 12.5674 6.53771Z" fill="#444CE7"/>
+</g>
+<defs>
+<clipPath id="clip0_109_6694">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg b/app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg
new file mode 100644
index 0000000..7a7983a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg
@@ -0,0 +1,8 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<g id="Icon_2">
+<path d="M8.49967 14.6663C12.1816 14.6663 15.1663 11.6816 15.1663 7.99967C15.1663 4.31778 12.1816 1.33301 8.49967 1.33301C4.81778 1.33301 1.83301 4.31778 1.83301 7.99967C1.83301 11.6816 4.81778 14.6663 8.49967 14.6663Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M10.4997 5.99967H6.49967V9.99967H10.4997V5.99967Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/mediaAndDevices/stop.svg b/app/components/base/icons/assets/vender/line/mediaAndDevices/stop.svg
new file mode 100644
index 0000000..c6ec6d4
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/mediaAndDevices/stop.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon" clip-path="url(#clip0_467_1645)">
+<path id="Icon_2" d="M1.5 3.9C1.5 3.05992 1.5 2.63988 1.66349 2.31901C1.8073 2.03677 2.03677 1.8073 2.31901 1.66349C2.63988 1.5 3.05992 1.5 3.9 1.5H8.1C8.94008 1.5 9.36012 1.5 9.68099 1.66349C9.96323 1.8073 10.1927 2.03677 10.3365 2.31901C10.5 2.63988 10.5 3.05992 10.5 3.9V8.1C10.5 8.94008 10.5 9.36012 10.3365 9.68099C10.1927 9.96323 9.96323 10.1927 9.68099 10.3365C9.36012 10.5 8.94008 10.5 8.1 10.5H3.9C3.05992 10.5 2.63988 10.5 2.31901 10.3365C2.03677 10.1927 1.8073 9.96323 1.66349 9.68099C1.5 9.36012 1.5 8.94008 1.5 8.1V3.9Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_467_1645">
+<rect width="12" height="12" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/apps-02.svg b/app/components/base/icons/assets/vender/line/others/apps-02.svg
new file mode 100644
index 0000000..8e1fec9
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/apps-02.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="apps-2-line">
+<path id="Vector" d="M4.66602 7.6665C3.00916 7.6665 1.66602 6.32336 1.66602 4.6665C1.66602 3.00965 3.00916 1.6665 4.66602 1.6665C6.32287 1.6665 7.66602 3.00965 7.66602 4.6665C7.66602 6.32336 6.32287 7.6665 4.66602 7.6665ZM4.66602 14.3332C3.00916 14.3332 1.66602 12.99 1.66602 11.3332C1.66602 9.6763 3.00916 8.33317 4.66602 8.33317C6.32287 8.33317 7.66602 9.6763 7.66602 11.3332C7.66602 12.99 6.32287 14.3332 4.66602 14.3332ZM11.3327 7.6665C9.67582 7.6665 8.33268 6.32336 8.33268 4.6665C8.33268 3.00965 9.67582 1.6665 11.3327 1.6665C12.9895 1.6665 14.3327 3.00965 14.3327 4.6665C14.3327 6.32336 12.9895 7.6665 11.3327 7.6665ZM11.3327 14.3332C9.67582 14.3332 8.33268 12.99 8.33268 11.3332C8.33268 9.6763 9.67582 8.33317 11.3327 8.33317C12.9895 8.33317 14.3327 9.6763 14.3327 11.3332C14.3327 12.99 12.9895 14.3332 11.3327 14.3332ZM4.66602 6.33317C5.58649 6.33317 6.33268 5.58698 6.33268 4.6665C6.33268 3.74603 5.58649 2.99984 4.66602 2.99984C3.74554 2.99984 2.99935 3.74603 2.99935 4.6665C2.99935 5.58698 3.74554 6.33317 4.66602 6.33317ZM4.66602 12.9998C5.58649 12.9998 6.33268 12.2536 6.33268 11.3332C6.33268 10.4127 5.58649 9.6665 4.66602 9.6665C3.74554 9.6665 2.99935 10.4127 2.99935 11.3332C2.99935 12.2536 3.74554 12.9998 4.66602 12.9998ZM11.3327 6.33317C12.2531 6.33317 12.9993 5.58698 12.9993 4.6665C12.9993 3.74603 12.2531 2.99984 11.3327 2.99984C10.4122 2.99984 9.66602 3.74603 9.66602 4.6665C9.66602 5.58698 10.4122 6.33317 11.3327 6.33317ZM11.3327 12.9998C12.2531 12.9998 12.9993 12.2536 12.9993 11.3332C12.9993 10.4127 12.2531 9.6665 11.3327 9.6665C10.4122 9.6665 9.66602 10.4127 9.66602 11.3332C9.66602 12.2536 10.4122 12.9998 11.3327 12.9998Z" fill="#155EEF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/bubble-x.svg b/app/components/base/icons/assets/vender/line/others/bubble-x.svg
new file mode 100644
index 0000000..6e4df5b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/bubble-x.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon L">
+<g id="Vector">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.33463 3.33333C2.96643 3.33333 2.66796 3.63181 2.66796 4V10.6667C2.66796 11.0349 2.96643 11.3333 3.33463 11.3333H4.66796C5.03615 11.3333 5.33463 11.6318 5.33463 12V12.8225L7.65833 11.4283C7.76194 11.3662 7.8805 11.3333 8.00132 11.3333H12.0013C12.3695 11.3333 12.668 11.0349 12.668 10.6667C12.668 10.2985 12.9665 10 13.3347 10C13.7028 10 14.0013 10.2985 14.0013 10.6667C14.0013 11.7713 13.1058 12.6667 12.0013 12.6667H8.18598L5.01095 14.5717C4.805 14.6952 4.5485 14.6985 4.33949 14.5801C4.13049 14.4618 4.00129 14.2402 4.00129 14V12.6667H3.33463C2.23006 12.6667 1.33463 11.7713 1.33463 10.6667V4C1.33463 2.89543 2.23006 2 3.33463 2H6.66798C7.03617 2 7.33464 2.29848 7.33464 2.66667C7.33464 3.03486 7.03617 3.33333 6.66798 3.33333H3.33463Z" fill="#354052"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.74113 2.66667C8.74113 2.29848 9.03961 2 9.4078 2H10.331C10.9721 2 11.5177 2.43571 11.6859 3.04075L11.933 3.93004L12.8986 2.77189C13.3045 2.28508 13.9018 2 14.536 2H14.5954C14.9636 2 15.2621 2.29848 15.2621 2.66667C15.2621 3.03486 14.9636 3.33333 14.5954 3.33333H14.536C14.3048 3.33333 14.08 3.43702 13.9227 3.6257L12.367 5.49165L12.8609 7.2689C12.8746 7.31803 12.9105 7.33333 12.9312 7.33333H13.8543C14.2225 7.33333 14.521 7.63181 14.521 8C14.521 8.36819 14.2225 8.66667 13.8543 8.66667H12.9312C12.29 8.66667 11.7444 8.23095 11.5763 7.62591L11.3291 6.73654L10.3634 7.89478C9.95758 8.38159 9.36022 8.66667 8.72604 8.66667H8.66666C8.29847 8.66667 7.99999 8.36819 7.99999 8C7.99999 7.63181 8.29847 7.33333 8.66666 7.33333H8.72604C8.95723 7.33333 9.18204 7.22965 9.33935 7.04096L10.8951 5.17493L10.4012 3.39777C10.3876 3.34863 10.3516 3.33333 10.331 3.33333H9.4078C9.03961 3.33333 8.74113 3.03486 8.74113 2.66667Z" fill="#354052"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/colors.svg b/app/components/base/icons/assets/vender/line/others/colors.svg
new file mode 100644
index 0000000..3173ef4
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/colors.svg
@@ -0,0 +1,10 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="colors" clip-path="url(#clip0_18499_53582)">
+<path id="Icon" d="M7.00032 11.9422C7.61954 12.4964 8.43724 12.8334 9.33366 12.8334C11.2667 12.8334 12.8337 11.2664 12.8337 9.33342C12.8337 7.71938 11.7411 6.36051 10.2552 5.95602M3.74543 5.95601C2.25954 6.3605 1.16699 7.71937 1.16699 9.33341C1.16699 11.2664 2.734 12.8334 4.66699 12.8334C6.59999 12.8334 8.16699 11.2664 8.16699 9.33341C8.16699 8.87813 8.08006 8.44314 7.92189 8.04415M10.5003 4.66675C10.5003 6.59974 8.93332 8.16675 7.00033 8.16675C5.06733 8.16675 3.50033 6.59974 3.50033 4.66675C3.50033 2.73375 5.06733 1.16675 7.00033 1.16675C8.93332 1.16675 10.5003 2.73375 10.5003 4.66675Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_18499_53582">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/drag-handle.svg b/app/components/base/icons/assets/vender/line/others/drag-handle.svg
new file mode 100644
index 0000000..773953e
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/drag-handle.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Drag Handle">
+<path id="drag-handle" fill-rule="evenodd" clip-rule="evenodd" d="M6 5C6.55228 5 7 4.55228 7 4C7 3.44772 6.55228 3 6 3C5.44772 3 5 3.44772 5 4C5 4.55228 5.44772 5 6 5ZM6 9C6.55228 9 7 8.55228 7 8C7 7.44772 6.55228 7 6 7C5.44772 7 5 7.44772 5 8C5 8.55228 5.44772 9 6 9ZM11 4C11 4.55228 10.5523 5 10 5C9.44772 5 9 4.55228 9 4C9 3.44772 9.44772 3 10 3C10.5523 3 11 3.44772 11 4ZM10 9C10.5523 9 11 8.55228 11 8C11 7.44772 10.5523 7 10 7C9.44772 7 9 7.44772 9 8C9 8.55228 9.44772 9 10 9ZM7 12C7 12.5523 6.55228 13 6 13C5.44772 13 5 12.5523 5 12C5 11.4477 5.44772 11 6 11C6.55228 11 7 11.4477 7 12ZM10 13C10.5523 13 11 12.5523 11 12C11 11.4477 10.5523 11 10 11C9.44772 11 9 11.4477 9 12C9 12.5523 9.44772 13 10 13Z" fill="#98A2B3"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/env.svg b/app/components/base/icons/assets/vender/line/others/env.svg
new file mode 100644
index 0000000..b183d40
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/env.svg
@@ -0,0 +1,11 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="env">
+<g id="Vector">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.33325 3.33325C1.33325 2.22868 2.22868 1.33325 3.33325 1.33325H12.6666C13.7712 1.33325 14.6666 2.22869 14.6666 3.33325V3.66659C14.6666 4.03478 14.3681 4.33325 13.9999 4.33325C13.6317 4.33325 13.3333 4.03478 13.3333 3.66659V3.33325C13.3333 2.96506 13.0348 2.66659 12.6666 2.66659H3.33325C2.96506 2.66659 2.66659 2.96506 2.66659 3.33325V3.66659C2.66659 4.03478 2.36811 4.33325 1.99992 4.33325C1.63173 4.33325 1.33325 4.03478 1.33325 3.66659V3.33325Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14.6666 12.6666C14.6666 13.7712 13.7712 14.6666 12.6666 14.6666L3.33325 14.6666C2.22866 14.6666 1.33325 13.7711 1.33325 12.6666L1.33325 12.3333C1.33325 11.9651 1.63173 11.6666 1.99992 11.6666C2.36811 11.6666 2.66659 11.9651 2.66659 12.3333V12.6666C2.66659 13.0348 2.96505 13.3333 3.33325 13.3333L12.6666 13.3333C13.0348 13.3333 13.3333 13.0348 13.3333 12.6666V12.3333C13.3333 11.9651 13.6317 11.6666 13.9999 11.6666C14.3681 11.6666 14.6666 11.9651 14.6666 12.3333V12.6666Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.33325 5.99992C1.33325 5.63173 1.63173 5.33325 1.99992 5.33325H4.33325C4.70144 5.33325 4.99992 5.63173 4.99992 5.99992C4.99992 6.36811 4.70144 6.66658 4.33325 6.66658H2.66659V7.33325H3.99992C4.36811 7.33325 4.66659 7.63173 4.66659 7.99992C4.66659 8.36811 4.36811 8.66658 3.99992 8.66658H2.66659V9.33325H4.33325C4.70144 9.33325 4.99992 9.63173 4.99992 9.99992C4.99992 10.3681 4.70144 10.6666 4.33325 10.6666H1.99992C1.63173 10.6666 1.33325 10.3681 1.33325 9.99992V5.99992Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.4734 5.36186C6.75457 5.27673 7.05833 5.38568 7.22129 5.63012L8.66659 7.79807V5.99992C8.66659 5.63173 8.96506 5.33325 9.33325 5.33325C9.70144 5.33325 9.99992 5.63173 9.99992 5.99992V9.99992C9.99992 10.2937 9.80761 10.5528 9.52644 10.638C9.24527 10.7231 8.94151 10.6142 8.77855 10.3697L7.33325 8.20177V9.99992C7.33325 10.3681 7.03478 10.6666 6.66659 10.6666C6.2984 10.6666 5.99992 10.3681 5.99992 9.99992V5.99992C5.99992 5.70614 6.19222 5.44699 6.4734 5.36186Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M11.0768 5.38453C11.4167 5.24292 11.807 5.40364 11.9486 5.74351L12.9999 8.26658L14.0512 5.74351C14.1928 5.40364 14.5831 5.24292 14.923 5.38453C15.2629 5.52614 15.4236 5.91646 15.282 6.25633L13.6153 10.2563C13.5118 10.5048 13.2691 10.6666 12.9999 10.6666C12.7308 10.6666 12.488 10.5048 12.3845 10.2563L10.7179 6.25633C10.5763 5.91646 10.737 5.52614 11.0768 5.38453Z" fill="black"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/exchange-02.svg b/app/components/base/icons/assets/vender/line/others/exchange-02.svg
new file mode 100644
index 0000000..45d2770
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/exchange-02.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.66602 14.3334C3.00916 14.3334 1.66602 12.9903 1.66602 11.3334C1.66602 9.67655 3.00916 8.33342 4.66602 8.33342C6.32287 8.33342 7.66602 9.67655 7.66602 11.3334C7.66602 12.9903 6.32287 14.3334 4.66602 14.3334ZM11.3327 7.66675C9.67582 7.66675 8.33268 6.3236 8.33268 4.66675C8.33268 3.00989 9.67582 1.66675 11.3327 1.66675C12.9895 1.66675 14.3327 3.00989 14.3327 4.66675C14.3327 6.3236 12.9895 7.66675 11.3327 7.66675ZM4.66602 13.0001C5.58649 13.0001 6.33268 12.2539 6.33268 11.3334C6.33268 10.4129 5.58649 9.66675 4.66602 9.66675C3.74554 9.66675 2.99935 10.4129 2.99935 11.3334C2.99935 12.2539 3.74554 13.0001 4.66602 13.0001ZM11.3327 6.33342C12.2531 6.33342 12.9993 5.58722 12.9993 4.66675C12.9993 3.74627 12.2531 3.00008 11.3327 3.00008C10.4122 3.00008 9.66602 3.74627 9.66602 4.66675C9.66602 5.58722 10.4122 6.33342 11.3327 6.33342ZM1.99935 5.33341C1.99935 3.49247 3.49174 2.00008 5.33268 2.00008H7.33268V3.33341H5.33268C4.22812 3.33341 3.33268 4.22885 3.33268 5.33341V7.33342H1.99935V5.33341ZM13.9993 8.66675H12.666V10.6667C12.666 11.7713 11.7706 12.6667 10.666 12.6667H8.66602V14.0001H10.666C12.5069 14.0001 13.9993 12.5077 13.9993 10.6667V8.66675Z" fill="#344054"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/file-code.svg b/app/components/base/icons/assets/vender/line/others/file-code.svg
new file mode 100644
index 0000000..eb77033
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/file-code.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10 2.66659H3.33333V13.3333H12.6667V5.33325H10V2.66659ZM2 1.99445C2 1.62929 2.29833 1.33325 2.66567 1.33325H10.6667L13.9998 4.66658L14 13.9949C14 14.3659 13.7034 14.6666 13.3377 14.6666H2.66227C2.29651 14.6666 2 14.3631 2 14.0054V1.99445ZM11.7713 7.99992L9.4142 10.3569L8.4714 9.41412L9.8856 7.99992L8.4714 6.58571L9.4142 5.6429L11.7713 7.99992ZM4.22877 7.99992L6.58579 5.6429L7.5286 6.58571L6.11438 7.99992L7.5286 9.41412L6.58579 10.3569L4.22877 7.99992Z" fill="#344054"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/global-variable.svg b/app/components/base/icons/assets/vender/line/others/global-variable.svg
new file mode 100644
index 0000000..e7bdacc
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/global-variable.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.23814 1.33333H9.76188C10.4844 1.33332 11.0672 1.33332 11.5391 1.37187C12.025 1.41157 12.4518 1.49545 12.8466 1.69664C13.4739 2.01622 13.9838 2.52615 14.3034 3.15336C14.5046 3.54822 14.5884 3.97501 14.6281 4.46091C14.6667 4.93283 14.6667 5.51559 14.6667 6.23811V9.76188C14.6667 10.4844 14.6667 11.0672 14.6281 11.5391C14.5884 12.025 14.5046 12.4518 14.3034 12.8466C13.9838 13.4738 13.4739 13.9838 12.8466 14.3033C12.4518 14.5045 12.025 14.5884 11.5391 14.6281C11.0672 14.6667 10.4844 14.6667 9.7619 14.6667H6.23812C5.51561 14.6667 4.93284 14.6667 4.46093 14.6281C3.97503 14.5884 3.54824 14.5045 3.15338 14.3033C2.52617 13.9838 2.01623 13.4738 1.69666 12.8466C1.49546 12.4518 1.41159 12.025 1.37189 11.5391C1.33333 11.0672 1.33334 10.4844 1.33334 9.76187V6.23812C1.33334 5.5156 1.33333 4.93283 1.37189 4.46091C1.41159 3.97501 1.49546 3.54822 1.69666 3.15336C2.01623 2.52615 2.52617 2.01622 3.15338 1.69664C3.54824 1.49545 3.97503 1.41157 4.46093 1.37187C4.93285 1.33332 5.51561 1.33332 6.23814 1.33333ZM4.5695 2.70078C4.16606 2.73374 3.93427 2.79519 3.7587 2.88465C3.38237 3.0764 3.07641 3.38236 2.88466 3.75868C2.79521 3.93425 2.73376 4.16604 2.70079 4.56949C2.6672 4.98072 2.66668 5.50892 2.66668 6.26666V9.73333C2.66668 10.4911 2.6672 11.0193 2.70079 11.4305C2.73376 11.8339 2.79521 12.0657 2.88466 12.2413C3.07641 12.6176 3.38237 12.9236 3.7587 13.1153C3.93427 13.2048 4.16606 13.2662 4.5695 13.2992C4.98073 13.3328 5.50894 13.3333 6.26668 13.3333H9.73334C10.4911 13.3333 11.0193 13.3328 11.4305 13.2992C11.834 13.2662 12.0658 13.2048 12.2413 13.1153C12.6176 12.9236 12.9236 12.6176 13.1154 12.2413C13.2048 12.0657 13.2663 11.8339 13.2992 11.4305C13.3328 11.0193 13.3333 10.4911 13.3333 9.73333V6.26666C13.3333 5.50892 13.3328 4.98072 13.2992 4.56949C13.2663 4.16604 13.2048 3.93425 13.1154 3.75868C12.9236 3.38236 12.6176 3.0764 12.2413 2.88465C12.0658 2.79519 11.834 2.73374 11.4305 2.70078C11.0193 2.66718 10.4911 2.66666 9.73334 2.66666H6.26668C5.50894 2.66666 4.98073 2.66718 4.5695 2.70078ZM5.08339 5.33333C5.08339 4.96514 5.38187 4.66666 5.75006 4.66666H6.68433C7.324 4.66666 7.87606 5.09677 8.04724 5.70542L8.30138 6.60902L9.2915 5.43554C9.7018 4.94926 10.3035 4.66666 10.9399 4.66666H11C11.3682 4.66666 11.6667 4.96514 11.6667 5.33333C11.6667 5.70152 11.3682 5.99999 11 5.99999H10.9399C10.7005 5.99999 10.4702 6.10616 10.3106 6.29537L8.73751 8.15972L9.23641 9.93357C9.24921 9.97909 9.28574 10 9.31579 10H10.2501C10.6182 10 10.9167 10.2985 10.9167 10.6667C10.9167 11.0349 10.6182 11.3333 10.2501 11.3333H9.31579C8.67612 11.3333 8.12406 10.9032 7.95288 10.2946L7.69871 9.39088L6.70852 10.5644C6.29822 11.0507 5.6965 11.3333 5.06011 11.3333H5.00001C4.63182 11.3333 4.33334 11.0349 4.33334 10.6667C4.33334 10.2985 4.63182 10 5.00001 10H5.06011C5.29949 10 5.52982 9.89383 5.68946 9.70462L7.26258 7.84019L6.76371 6.06642C6.75091 6.0209 6.71438 5.99999 6.68433 5.99999H5.75006C5.38187 5.99999 5.08339 5.70152 5.08339 5.33333Z" fill="#354052"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/icon-3-dots.svg b/app/components/base/icons/assets/vender/line/others/icon-3-dots.svg
new file mode 100644
index 0000000..bba4285
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/icon-3-dots.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon-3-dots">
+<path id="Icon" d="M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103" stroke="#374151" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/long-arrow-left.svg b/app/components/base/icons/assets/vender/line/others/long-arrow-left.svg
new file mode 100644
index 0000000..7320664
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/long-arrow-left.svg
@@ -0,0 +1,3 @@
+<svg width="21" height="8" viewBox="0 0 21 8" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0.646446 3.64645C0.451185 3.84171 0.451185 4.15829 0.646446 4.35355L3.82843 7.53553C4.02369 7.7308 4.34027 7.7308 4.53553 7.53553C4.7308 7.34027 4.7308 7.02369 4.53553 6.82843L1.70711 4L4.53553 1.17157C4.7308 0.976311 4.7308 0.659728 4.53553 0.464466C4.34027 0.269204 4.02369 0.269204 3.82843 0.464466L0.646446 3.64645ZM21 3.5L1 3.5V4.5L21 4.5V3.5Z" fill="#101828" fill-opacity="0.3"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/long-arrow-right.svg b/app/components/base/icons/assets/vender/line/others/long-arrow-right.svg
new file mode 100644
index 0000000..733785a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/long-arrow-right.svg
@@ -0,0 +1,3 @@
+<svg width="26" height="8" viewBox="0 0 26 8" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M25.3536 4.35355C25.5488 4.15829 25.5488 3.84171 25.3536 3.64644L22.1716 0.464465C21.9763 0.269202 21.6597 0.269202 21.4645 0.464465C21.2692 0.659727 21.2692 0.976309 21.4645 1.17157L24.2929 4L21.4645 6.82843C21.2692 7.02369 21.2692 7.34027 21.4645 7.53553C21.6597 7.73079 21.9763 7.73079 22.1716 7.53553L25.3536 4.35355ZM3.59058e-08 4.5L25 4.5L25 3.5L-3.59058e-08 3.5L3.59058e-08 4.5Z" fill="#101828" fill-opacity="0.3"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/others/tools.svg b/app/components/base/icons/assets/vender/line/others/tools.svg
new file mode 100644
index 0000000..a10f539
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/others/tools.svg
@@ -0,0 +1,14 @@
+<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Tools" clip-path="url(#clip0_5381_39479)">
+<path id="vector" d="M13.4375 14.4375V6.8125H2.5625V14.4375C2.5625 14.9898 3.01022 15.4375 3.5625 15.4375H12.4375C12.9898 15.4375 13.4375 14.9898 13.4375 14.4375Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="vector_2" d="M13.6254 2.875L11.1738 6.47327" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="vector_3" d="M6.3125 9.8125H9.6875" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="vector_4" d="M8.63355 1.88044L8.75 1.64754L8.86645 1.88044C8.97531 2.09816 9.15184 2.27469 9.36956 2.38355L9.60246 2.5L9.36956 2.61645C9.15184 2.72531 8.97531 2.90184 8.86645 3.11956L8.75 3.35246L8.63355 3.11956C8.52469 2.90184 8.34816 2.72531 8.13044 2.61645L7.89754 2.5L8.13044 2.38355C8.34816 2.27469 8.52469 2.09816 8.63355 1.88044Z" stroke="#344054" stroke-width="1.25" stroke-linecap="square" stroke-linejoin="round"/>
+<path id="vector_5" d="M4.625 3.14754L4.61865 3.16025C4.51946 3.35862 4.35862 3.51946 4.16025 3.61865L4.14754 3.625L4.16025 3.63135C4.35862 3.73054 4.51946 3.89138 4.61865 4.08975L4.625 4.10246L4.63135 4.08975C4.73054 3.89138 4.89138 3.73054 5.08975 3.63135L5.10246 3.625L5.08975 3.61865C4.89138 3.51946 4.73054 3.35862 4.63135 3.16025L4.625 3.14754ZM4.625 3.14754L4.63135 3.16025L4.625 3.14754Z" stroke="#344054" stroke-width="1.25" stroke-linecap="square" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_5381_39479">
+<rect width="16" height="16" fill="white" transform="translate(0 0.5)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/shapes/cube-outline.svg b/app/components/base/icons/assets/vender/line/shapes/cube-outline.svg
new file mode 100644
index 0000000..eebcef3
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/shapes/cube-outline.svg
@@ -0,0 +1,13 @@
+<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="cube-outline">
+<g id="Solid">
+<path d="M8.26865 1.29003C8.09143 1.25358 7.90866 1.25358 7.73144 1.29003C7.52659 1.33216 7.3435 1.43471 7.19794 1.51624L7.15826 1.53841L6.17628 2.08395C5.85443 2.26276 5.73846 2.66863 5.91727 2.99049C6.09608 3.31234 6.50195 3.4283 6.82381 3.24949L7.80579 2.70395C7.90681 2.64782 7.95839 2.61946 7.99686 2.60091L8.00004 2.59938L8.00323 2.60091C8.0417 2.61946 8.09327 2.64782 8.1943 2.70395L9.17628 3.24949C9.49814 3.4283 9.90401 3.31234 10.0828 2.99048C10.2616 2.66863 10.1457 2.26276 9.82381 2.08395L8.84183 1.53841L8.80215 1.51624C8.65659 1.43471 8.4735 1.33216 8.26865 1.29003Z" fill="#155EEF"/>
+<path d="M12.8238 3.75062C12.5019 3.57181 12.0961 3.68777 11.9173 4.00963C11.7385 4.33148 11.8544 4.73735 12.1763 4.91616L12.6272 5.16668L12.1763 5.41719C11.8545 5.596 11.7385 6.00186 11.9173 6.32372C12.0961 6.64558 12.502 6.76154 12.8238 6.58273L13.3334 6.29966V6.83339C13.3334 7.20158 13.6319 7.50006 14 7.50006C14.3682 7.50006 14.6667 7.20158 14.6667 6.83339V5.79435L14.6668 5.74627C14.6673 5.62441 14.6678 5.48084 14.6452 5.33482C14.6869 5.17472 14.6696 4.99892 14.5829 4.84286C14.4904 4.6764 14.3371 4.56501 14.1662 4.52099C14.0496 4.43038 13.9239 4.36116 13.8173 4.3024L13.7752 4.27915L12.8238 3.75062Z" fill="#155EEF"/>
+<path d="M3.8238 4.91616C4.14566 4.73735 4.26162 4.33148 4.08281 4.00963C3.90401 3.68777 3.49814 3.57181 3.17628 3.75062L2.22493 4.27915L2.18284 4.3024C2.07615 4.36116 1.95045 4.4304 1.83382 4.52102C1.66295 4.56506 1.50977 4.67643 1.41731 4.84286C1.33065 4.99886 1.31323 5.17459 1.35493 5.33464C1.33229 5.48072 1.33281 5.62436 1.33326 5.74627L1.33338 5.79435V6.83339C1.33338 7.20158 1.63185 7.50006 2.00004 7.50006C2.36823 7.50006 2.66671 7.20158 2.66671 6.83339V6.29961L3.17632 6.58273C3.49817 6.76154 3.90404 6.64558 4.08285 6.32372C4.26166 6.00186 4.1457 5.596 3.82384 5.41719L3.3729 5.16666L3.8238 4.91616Z" fill="#155EEF"/>
+<path d="M2.66671 10.1667C2.66671 9.79853 2.36823 9.50006 2.00004 9.50006C1.63185 9.50006 1.33338 9.79853 1.33338 10.1667V11.2058L1.33326 11.2538C1.33262 11.4298 1.33181 11.6509 1.40069 11.8594C1.46024 12.0397 1.55759 12.2051 1.68622 12.3447C1.835 12.5061 2.02873 12.6128 2.18281 12.6977L2.22493 12.721L3.17628 13.2495C3.49814 13.4283 3.90401 13.3123 4.08281 12.9905C4.26162 12.6686 4.14566 12.2628 3.8238 12.084L2.87245 11.5554C2.76582 11.4962 2.71137 11.4656 2.67318 11.4413L2.66995 11.4392L2.66971 11.4354C2.66699 11.3902 2.66671 11.3277 2.66671 11.2058V10.1667Z" fill="#155EEF"/>
+<path d="M14.6667 10.1667C14.6667 9.79853 14.3682 9.50006 14 9.50006C13.6319 9.50006 13.3334 9.79853 13.3334 10.1667V11.2058C13.3334 11.3277 13.3331 11.3902 13.3304 11.4354L13.3301 11.4392L13.3269 11.4413C13.2887 11.4656 13.2343 11.4962 13.1276 11.5554L12.1763 12.084C11.8544 12.2628 11.7385 12.6686 11.9173 12.9905C12.0961 13.3123 12.5019 13.4283 12.8238 13.2495L13.7752 12.721L13.8172 12.6977C13.9713 12.6128 14.1651 12.5061 14.3139 12.3447C14.4425 12.2051 14.5398 12.0397 14.5994 11.8594C14.6683 11.6509 14.6675 11.4298 14.6668 11.2538L14.6667 11.2058V10.1667Z" fill="#155EEF"/>
+<path d="M6.82381 13.7506C6.50195 13.5718 6.09608 13.6878 5.91727 14.0096C5.73846 14.3315 5.85443 14.7374 6.17628 14.9162L7.15826 15.4617L7.19793 15.4839C7.29819 15.54 7.41625 15.6061 7.54696 15.6556C7.66589 15.7659 7.82512 15.8333 8.00008 15.8333C8.17507 15.8333 8.33431 15.7659 8.45324 15.6556C8.58391 15.6061 8.70193 15.54 8.80215 15.4839L8.84183 15.4617L9.82381 14.9162C10.1457 14.7374 10.2616 14.3315 10.0828 14.0096C9.90401 13.6878 9.49814 13.5718 9.17628 13.7506L8.66675 14.0337V13.5C8.66675 13.1318 8.36827 12.8333 8.00008 12.8333C7.63189 12.8333 7.33341 13.1318 7.33341 13.5V14.0337L6.82381 13.7506Z" fill="#155EEF"/>
+<path d="M6.82384 7.08385C6.50199 6.90505 6.09612 7.02101 5.91731 7.34286C5.7385 7.66472 5.85446 8.07059 6.17632 8.2494L7.33341 8.89223V10.1666C7.33341 10.5348 7.63189 10.8333 8.00008 10.8333C8.36827 10.8333 8.66675 10.5348 8.66675 10.1666V8.89223L9.82384 8.2494C10.1457 8.07059 10.2617 7.66472 10.0829 7.34286C9.90404 7.02101 9.49817 6.90505 9.17632 7.08385L8.00008 7.73732L6.82384 7.08385Z" fill="#155EEF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/time/clock-fast-forward.svg b/app/components/base/icons/assets/vender/line/time/clock-fast-forward.svg
new file mode 100644
index 0000000..5e499f5
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/time/clock-fast-forward.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M22.7 11.5L20.7005 13.5L18.7 11.5M20.9451 13C20.9814 12.6717 21 12.338 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C14.8273 21 17.35 19.6963 19 17.6573M12 7V12L15 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/time/clock-play-slim.svg b/app/components/base/icons/assets/vender/line/time/clock-play-slim.svg
new file mode 100644
index 0000000..be884b4
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/time/clock-play-slim.svg
@@ -0,0 +1,5 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<path id="Vector" d="M29.2673 17.3332C29.3109 16.8946 29.3332 16.4498 29.3332 15.9998C29.3332 8.63604 23.3636 2.6665 15.9998 2.6665C8.63604 2.6665 2.6665 8.63604 2.6665 15.9998C2.6665 23.3636 8.63604 29.3332 15.9998 29.3332C16.2234 29.3332 16.4457 29.3277 16.6665 29.3168C16.8902 29.3058 17.1125 29.2892 17.3332 29.2673M15.9998 7.99984V15.9998L10.8458 18.5102M23.7065 19.9464L28.8621 23.8131C29.2481 24.1026 29.441 24.2473 29.5101 24.4248C29.5705 24.5802 29.5705 24.7527 29.5101 24.9081C29.441 25.0855 29.2481 25.2303 28.8621 25.5198L23.7065 29.3864C23.1572 29.7984 22.8825 30.0044 22.6526 29.9996C22.4526 29.9955 22.265 29.9017 22.1416 29.7441C21.9998 29.5631 21.9998 29.2197 21.9998 28.5331V20.7998C21.9998 20.1131 21.9998 19.7698 22.1416 19.5888C22.265 19.4312 22.4526 19.3374 22.6526 19.3333C22.8825 19.3285 23.1572 19.5345 23.7065 19.9464Z" stroke="#D0D5DD" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/time/clock-play.svg b/app/components/base/icons/assets/vender/line/time/clock-play.svg
new file mode 100644
index 0000000..e6c79b1
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/time/clock-play.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon" clip-path="url(#clip0_635_10941)">
+<path id="Vector" d="M14.6334 8.66683C14.6552 8.44756 14.6663 8.22516 14.6663 8.00016C14.6663 4.31826 11.6816 1.3335 7.99967 1.3335C4.31778 1.3335 1.33301 4.31826 1.33301 8.00016C1.33301 11.6821 4.31778 14.6668 7.99967 14.6668C8.11145 14.6668 8.22258 14.6641 8.33301 14.6586C8.44487 14.6531 8.556 14.6449 8.66634 14.6339M7.99967 4.00016V8.00016L5.42265 9.25534M11.853 9.97346L14.4308 11.9068C14.6238 12.0515 14.7203 12.1239 14.7548 12.2126C14.785 12.2904 14.785 12.3766 14.7548 12.4543C14.7203 12.543 14.6238 12.6154 14.4308 12.7601L11.853 14.6935C11.5784 14.8995 11.441 15.0024 11.3261 15.0001C11.226 14.998 11.1322 14.9511 11.0706 14.8723C10.9997 14.7818 10.9997 14.6101 10.9997 14.2668V10.4001C10.9997 10.0568 10.9997 9.88516 11.0706 9.79463C11.1322 9.71585 11.226 9.66895 11.3261 9.66687C11.441 9.66448 11.5784 9.76747 11.853 9.97346Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_635_10941">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/time/clock-refresh.svg b/app/components/base/icons/assets/vender/line/time/clock-refresh.svg
new file mode 100644
index 0000000..9cef4e7
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/time/clock-refresh.svg
@@ -0,0 +1,9 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="clock-refresh">
+<g id="Solid">
+<path d="M9.76984 2.8375L9.71551 3.04027C8.27602 1.22839 5.68891 0.69459 3.62457 1.88644C2.25681 2.67611 1.43067 4.04369 1.27558 5.50073C1.24636 5.77532 1.44526 6.02161 1.71985 6.05084C1.99444 6.08007 2.24074 5.88116 2.26997 5.60657C2.39268 4.4537 3.04533 3.37556 4.12456 2.75247C5.7025 1.84145 7.66731 2.20754 8.82211 3.53002L8.65016 3.48395C8.38343 3.41248 8.10926 3.57077 8.03779 3.8375C7.96632 4.10424 8.12461 4.37841 8.39134 4.44988L9.75737 4.8159C10.0241 4.88737 10.2983 4.72908 10.3697 4.46235L10.7358 3.09632C10.8072 2.82959 10.6489 2.55542 10.3822 2.48395C10.1155 2.41248 9.84131 2.57077 9.76984 2.8375Z" fill="#667085"/>
+<path d="M10.2792 5.94921C10.5538 5.97844 10.7527 6.22473 10.7235 6.49932C10.5684 7.95635 9.74225 9.32394 8.3745 10.1136C6.31011 11.3055 3.72295 10.7716 2.28347 8.95968L2.22918 9.1623C2.15771 9.42903 1.88354 9.58732 1.61681 9.51585C1.35008 9.44438 1.19178 9.17021 1.26325 8.90348L1.62928 7.53746C1.70075 7.27072 1.97492 7.11243 2.24165 7.1839L3.60768 7.54993C3.87441 7.6214 4.0327 7.89557 3.96123 8.1623C3.88976 8.42903 3.61559 8.58732 3.34886 8.51585L3.17668 8.46972C4.33144 9.79246 6.29644 10.1587 7.8745 9.24758C8.95373 8.62449 9.60638 7.54634 9.72909 6.39348C9.75832 6.11889 10.0046 5.91998 10.2792 5.94921Z" fill="#667085"/>
+<path d="M6.49954 3.74997C6.49954 3.47382 6.27568 3.24997 5.99954 3.24997C5.7234 3.24997 5.49954 3.47382 5.49954 3.74997V5.99997C5.49954 6.1756 5.59169 6.33835 5.74229 6.42871L6.99229 7.17871C7.22908 7.32079 7.53621 7.244 7.67828 7.00721C7.82036 6.77042 7.74358 6.46329 7.50679 6.32122L6.49954 5.71687V3.74997Z" fill="#667085"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/users/user-01.svg b/app/components/base/icons/assets/vender/line/users/user-01.svg
new file mode 100644
index 0000000..3217c92
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/users/user-01.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="user-01">
+<path id="Icon" d="M13.3334 14C13.3334 13.0696 13.3334 12.6044 13.2186 12.2259C12.9601 11.3736 12.2931 10.7067 11.4408 10.4482C11.0623 10.3333 10.5971 10.3333 9.66675 10.3333H6.33342C5.40304 10.3333 4.93785 10.3333 4.55932 10.4482C3.70705 10.7067 3.04011 11.3736 2.78157 12.2259C2.66675 12.6044 2.66675 13.0696 2.66675 14M11.0001 5C11.0001 6.65685 9.65694 8 8.00008 8C6.34323 8 5.00008 6.65685 5.00008 5C5.00008 3.34315 6.34323 2 8.00008 2C9.65694 2 11.0001 3.34315 11.0001 5Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/users/users-01.svg b/app/components/base/icons/assets/vender/line/users/users-01.svg
new file mode 100644
index 0000000..665534b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/users/users-01.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="users-01">
+<path id="Icon" d="M14.6666 14V12.6667C14.6666 11.4241 13.8167 10.38 12.6666 10.084M10.3333 2.19384C11.3105 2.58943 11.9999 3.54754 11.9999 4.66667C11.9999 5.78579 11.3105 6.7439 10.3333 7.13949M11.3333 14C11.3333 12.7575 11.3333 12.1362 11.1303 11.6462C10.8596 10.9928 10.3405 10.4736 9.68707 10.203C9.19702 10 8.57576 10 7.33325 10H5.33325C4.09074 10 3.46949 10 2.97943 10.203C2.32602 10.4736 1.80689 10.9928 1.53624 11.6462C1.33325 12.1362 1.33325 12.7575 1.33325 14M8.99992 4.66667C8.99992 6.13943 7.80601 7.33333 6.33325 7.33333C4.86049 7.33333 3.66659 6.13943 3.66659 4.66667C3.66659 3.19391 4.86049 2 6.33325 2C7.80601 2 8.99992 3.19391 8.99992 4.66667Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/line/weather/stars-02.svg b/app/components/base/icons/assets/vender/line/weather/stars-02.svg
new file mode 100644
index 0000000..324aa94
--- /dev/null
+++ b/app/components/base/icons/assets/vender/line/weather/stars-02.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.5 22V17M4.5 7V2M2 4.5H7M2 19.5H7M13 3L11.2658 7.50886C10.9838 8.24209 10.8428 8.60871 10.6235 8.91709C10.4292 9.1904 10.1904 9.42919 9.91709 9.62353C9.60871 9.8428 9.24209 9.98381 8.50886 10.2658L4 12L8.50886 13.7342C9.24209 14.0162 9.60871 14.1572 9.91709 14.3765C10.1904 14.5708 10.4292 14.8096 10.6235 15.0829C10.8428 15.3913 10.9838 15.7579 11.2658 16.4911L13 21L14.7342 16.4911C15.0162 15.7579 15.1572 15.3913 15.3765 15.0829C15.5708 14.8096 15.8096 14.5708 16.0829 14.3765C16.3913 14.1572 16.7579 14.0162 17.4911 13.7342L22 12L17.4911 10.2658C16.7579 9.98381 16.3913 9.8428 16.0829 9.62353C15.8096 9.42919 15.5708 9.1904 15.3765 8.91709C15.1572 8.60871 15.0162 8.24209 14.7342 7.50886L13 3Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/other/anthropic-text.svg b/app/components/base/icons/assets/vender/other/anthropic-text.svg
new file mode 100644
index 0000000..cace17d
--- /dev/null
+++ b/app/components/base/icons/assets/vender/other/anthropic-text.svg
@@ -0,0 +1,78 @@
+<svg width="90" height="20" viewBox="0 0 90 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_8587_60274)">
+<mask id="mask0_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M89.375 4.99805H0V14.998H89.375V4.99805Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_8587_60274)">
+<mask id="mask1_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99609H89.375V14.9961H0V4.99609Z" fill="white"/>
+</mask>
+<g mask="url(#mask1_8587_60274)">
+<mask id="mask2_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99414H89.375V14.9941H0V4.99414Z" fill="white"/>
+</mask>
+<g mask="url(#mask2_8587_60274)">
+<mask id="mask3_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask3_8587_60274)">
+<path d="M18.1273 11.9244L13.7773 5.15625H11.4297V14.825H13.4321V8.05688L17.7821 14.825H20.1297V5.15625H18.1273V11.9244Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask4_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask4_8587_60274)">
+<path d="M21.7969 7.02094H25.0423V14.825H27.1139V7.02094H30.3594V5.15625H21.7969V7.02094Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask5_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask5_8587_60274)">
+<path d="M38.6442 9.00994H34.0871V5.15625H32.0156V14.825H34.0871V10.8746H38.6442V14.825H40.7156V5.15625H38.6442V9.00994Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask6_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask6_8587_60274)">
+<path d="M45.3376 7.02094H47.893C48.9152 7.02094 49.4539 7.39387 49.4539 8.09831C49.4539 8.80275 48.9152 9.17569 47.893 9.17569H45.3376V7.02094ZM51.5259 8.09831C51.5259 6.27506 50.186 5.15625 47.9897 5.15625H43.2656V14.825H45.3376V11.0404H47.6443L49.7164 14.825H52.0094L49.715 10.7521C50.8666 10.3094 51.5259 9.37721 51.5259 8.09831Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask7_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask7_8587_60274)">
+<path d="M57.8732 13.0565C56.2438 13.0565 55.2496 11.8963 55.2496 10.004C55.2496 8.08416 56.2438 6.92394 57.8732 6.92394C59.4887 6.92394 60.4691 8.08416 60.4691 10.004C60.4691 11.8963 59.4887 13.0565 57.8732 13.0565ZM57.8732 4.99023C55.0839 4.99023 53.1094 7.06206 53.1094 10.004C53.1094 12.9184 55.0839 14.9902 57.8732 14.9902C60.6486 14.9902 62.6094 12.9184 62.6094 10.004C62.6094 7.06206 60.6486 4.99023 57.8732 4.99023Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask8_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask8_8587_60274)">
+<path d="M69.1794 9.45194H66.6233V7.02094H69.1794C70.2019 7.02094 70.7407 7.43532 70.7407 8.23644C70.7407 9.03756 70.2019 9.45194 69.1794 9.45194ZM69.2762 5.15625H64.5508V14.825H66.6233V11.3166H69.2762C71.473 11.3166 72.8133 10.1564 72.8133 8.23644C72.8133 6.3165 71.473 5.15625 69.2762 5.15625Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask9_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask9_8587_60274)">
+<path d="M86.8413 11.5786C86.4823 12.5179 85.7642 13.0565 84.7837 13.0565C83.1542 13.0565 82.16 11.8963 82.16 10.004C82.16 8.08416 83.1542 6.92394 84.7837 6.92394C85.7642 6.92394 86.4823 7.46261 86.8413 8.40183H89.0369C88.4984 6.33002 86.8827 4.99023 84.7837 4.99023C81.9942 4.99023 80.0195 7.06206 80.0195 10.004C80.0195 12.9184 81.9942 14.9902 84.7837 14.9902C86.8965 14.9902 88.5122 13.6366 89.0508 11.5786H86.8413Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask10_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask10_8587_60274)">
+<path d="M73.6484 5.15625L77.5033 14.825H79.6172L75.7624 5.15625H73.6484Z" fill="black" fill-opacity="0.92"/>
+</g>
+<mask id="mask11_8587_60274" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="4" width="90" height="11">
+<path d="M0 4.99219H89.375V14.9922H0V4.99219Z" fill="white"/>
+</mask>
+<g mask="url(#mask11_8587_60274)">
+<path d="M3.64038 10.9989L4.95938 7.60106L6.27838 10.9989H3.64038ZM3.85422 5.15625L0 14.825H2.15505L2.9433 12.7946H6.97558L7.76371 14.825H9.91875L6.06453 5.15625H3.85422Z" fill="black" fill-opacity="0.92"/>
+</g>
+</g>
+</g>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_8587_60274">
+<rect width="89.375" height="10" fill="white" transform="translate(0 5)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/other/generator.svg b/app/components/base/icons/assets/vender/other/generator.svg
new file mode 100644
index 0000000..a38efb5
--- /dev/null
+++ b/app/components/base/icons/assets/vender/other/generator.svg
@@ -0,0 +1,4 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.5" d="M10.5402 2.95679L10.5402 2.95685C10.4455 3.05146 10.3424 3.13459 10.2314 3.2072C10.3429 3.27923 10.4468 3.36165 10.5422 3.45535L10.5402 2.95679ZM10.5402 2.95679C10.6348 2.86217 10.718 2.75907 10.7906 2.64807C10.8626 2.75955 10.945 2.86339 11.0387 2.95881L11.0388 2.95888C11.1304 3.05224 11.2302 3.13482 11.3377 3.20717C11.2297 3.27895 11.1292 3.36081 11.0367 3.45327L11.0366 3.45333C10.9442 3.5458 10.8623 3.64635 10.7905 3.75431M10.5402 2.95679L10.7905 3.75431M10.7905 3.75431C10.7182 3.64686 10.6356 3.54707 10.5422 3.45538L10.7905 3.75431Z" stroke="#155EEF" stroke-width="1.25"/>
+<path d="M6.99659 2.85105C6.96323 2.55641 6.71414 2.33368 6.41758 2.33337C6.12107 2.33307 5.87146 2.55529 5.83751 2.84987C5.67932 4.2213 5.27205 5.16213 4.6339 5.80028C3.99575 6.43841 3.05492 6.84569 1.68349 7.00389C1.3889 7.03784 1.16669 7.28745 1.16699 7.58396C1.1673 7.88052 1.39002 8.12961 1.68467 8.16297C3.03291 8.31569 3.99517 8.72292 4.64954 9.36546C5.30035 10.0045 5.71535 10.944 5.83593 12.3017C5.86271 12.6029 6.11523 12.8337 6.41763 12.8334C6.72009 12.833 6.97209 12.6016 6.99817 12.3003C7.11367 10.9656 7.52836 10.005 8.18344 9.34982C8.83858 8.69474 9.79922 8.28005 11.1339 8.16455C11.4352 8.13847 11.6666 7.88647 11.667 7.58402C11.6673 7.28162 11.4365 7.02909 11.1353 7.00232C9.77758 6.88174 8.83812 6.46676 8.19908 5.81592C7.55653 5.16155 7.14931 4.19929 6.99659 2.85105Z" fill="#155EEF"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/other/group.svg b/app/components/base/icons/assets/vender/other/group.svg
new file mode 100644
index 0000000..90f1e6b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/other/group.svg
@@ -0,0 +1,8 @@
+<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Group">
+<path id="Vector" d="M5.6475 8.0115L0.333496 5.05884V11.3335C0.333491 11.4524 0.365258 11.569 0.425506 11.6715C0.485754 11.7739 0.572294 11.8584 0.676163 11.9162L6.3335 15.0588V9.17684C6.33344 8.93907 6.26981 8.70565 6.14919 8.50075C6.02857 8.29586 5.85536 8.12694 5.6475 8.0115Z" fill="#354052"/>
+<path id="Vector_2" d="M7.66699 9.17684V15.0588L13.3243 11.9162C13.4282 11.8584 13.5147 11.7739 13.575 11.6715C13.6352 11.569 13.667 11.4524 13.667 11.3335V5.05884L8.35299 8.0115C8.14513 8.12694 7.97192 8.29586 7.8513 8.50075C7.73068 8.70565 7.66705 8.93907 7.66699 9.17684Z" fill="#676F83"/>
+<path id="Vector_3" d="M10.1913 2.34351C9.804 3.33351 8.588 4.00017 7 4.00017C5.412 4.00017 4.196 3.33351 3.80867 2.34351L1 3.90417L6.35267 6.87817C6.5507 6.98815 6.77348 7.04586 7 7.04586C7.22652 7.04586 7.4493 6.98815 7.64733 6.87817L13 3.90417L10.1913 2.34351Z" fill="#676F83"/>
+<path id="Vector_4" d="M7 2.66675C8.10457 2.66675 9 2.21903 9 1.66675C9 1.11446 8.10457 0.666748 7 0.666748C5.89543 0.666748 5 1.11446 5 1.66675C5 2.21903 5.89543 2.66675 7 2.66675Z" fill="#354052"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/other/openai.svg b/app/components/base/icons/assets/vender/other/openai.svg
new file mode 100644
index 0000000..5a9a93b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/other/openai.svg
@@ -0,0 +1,9 @@
+<svg width="80" height="22" viewBox="0 0 80 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M25.1152 10.5767C25.1152 14.1738 27.4253 16.6818 30.6264 16.6818C33.8274 16.6818 36.1375 14.1738 36.1375 10.5767C36.1375 6.97961 33.8274 4.47156 30.6264 4.47156C27.4253 4.47156 25.1152 6.97961 25.1152 10.5767ZM34.0254 10.5767C34.0254 13.1507 32.6229 14.8173 30.6264 14.8173C28.6298 14.8173 27.2273 13.1507 27.2273 10.5767C27.2273 8.00263 28.6298 6.3361 30.6264 6.3361C32.6229 6.3361 34.0254 8.00263 34.0254 10.5767Z" fill="black"/>
+<path d="M42.0868 16.6819C44.5124 16.6819 45.8984 14.6358 45.8984 12.1773C45.8984 9.71871 44.5124 7.67267 42.0868 7.67267C40.9648 7.67267 40.1398 8.11818 39.5953 8.76169V7.83767H37.6152V19.4704H39.5953V15.5928C40.1398 16.2364 40.9648 16.6819 42.0868 16.6819ZM39.5458 11.9298C39.5458 10.2962 40.4698 9.40521 41.6908 9.40521C43.1264 9.40521 43.9019 10.5272 43.9019 12.1773C43.9019 13.8273 43.1264 14.9493 41.6908 14.9493C40.4698 14.9493 39.5458 14.0418 39.5458 12.4413V11.9298Z" fill="black"/>
+<path d="M51.2545 16.6819C52.987 16.6819 54.3565 15.7743 54.967 14.2563L53.2675 13.6128C53.0035 14.5038 52.228 14.9988 51.2545 14.9988C49.9839 14.9988 49.0929 14.0913 48.9444 12.6063H55.0165V11.9463C55.0165 9.57021 53.68 7.67267 51.172 7.67267C48.6639 7.67267 47.0469 9.63621 47.0469 12.1773C47.0469 14.8503 48.7794 16.6819 51.2545 16.6819ZM51.1555 9.3392C52.4095 9.3392 53.0035 10.1642 53.02 11.1212H49.0434C49.3404 9.94972 50.1324 9.3392 51.1555 9.3392Z" fill="black"/>
+<path d="M56.5039 16.5004H58.484V11.4182C58.484 10.1807 59.3915 9.52071 60.2825 9.52071C61.3715 9.52071 61.8005 10.2962 61.8005 11.3687V16.5004H63.7806V10.7912C63.7806 8.9267 62.6915 7.67267 60.8765 7.67267C59.7545 7.67267 58.979 8.18418 58.484 8.76169V7.83767H56.5039V16.5004Z" fill="black"/>
+<path d="M69.5799 4.65308L65.0918 16.5003H67.1873L68.1939 13.7943H73.309L74.332 16.5003H76.4605L71.9724 4.65308H69.5799ZM70.7349 6.99613L72.616 11.9462H68.8869L70.7349 6.99613Z" fill="black"/>
+<path d="M79.8581 4.6875H77.7461V16.5348H79.8581V4.6875Z" fill="black"/>
+<path d="M20.2769 9.00436C20.776 7.50627 20.6041 5.86517 19.8059 4.50251C18.6055 2.41247 16.1924 1.3372 13.8356 1.84321C12.7871 0.662057 11.2808 -0.00964523 9.70154 -2.00271e-05C7.29248 -0.00552014 5.155 1.54551 4.41386 3.83769C2.86626 4.15463 1.53042 5.12334 0.748717 6.49631C-0.460621 8.58085 -0.184928 11.2085 1.43073 12.9961C0.931596 14.4942 1.10348 16.1353 1.90168 17.4979C3.10208 19.588 5.51526 20.6632 7.87206 20.1572C8.91983 21.3384 10.4269 22.0101 12.0061 21.9998C14.4165 22.006 16.5547 20.4535 17.2958 18.1593C18.8434 17.8424 20.1793 16.8737 20.961 15.5007C22.1689 13.4161 21.8925 10.7905 20.2776 9.00298L20.2769 9.00436ZM12.0075 20.5622C11.0429 20.5635 10.1085 20.226 9.36809 19.6079C9.40178 19.59 9.46022 19.5577 9.49803 19.5343L13.8789 17.0043C14.103 16.8771 14.2405 16.6385 14.2391 16.3807V10.2048L16.0906 11.2738C16.1105 11.2835 16.1236 11.3027 16.1264 11.3247V16.4391C16.1236 18.7134 14.2818 20.5574 12.0075 20.5622ZM3.14952 16.7788C2.6662 15.9441 2.49225 14.9658 2.65795 14.0163C2.69026 14.0356 2.74732 14.0707 2.78789 14.094L7.16873 16.6241C7.3908 16.754 7.6658 16.754 7.88856 16.6241L13.2367 13.5358V15.6739C13.2381 15.6959 13.2278 15.7173 13.2106 15.731L8.78233 18.2879C6.80985 19.4236 4.29079 18.7485 3.15021 16.7788H3.14952ZM1.99656 7.21613C2.47782 6.38012 3.23752 5.74073 4.14229 5.40866C4.14229 5.44647 4.14023 5.51316 4.14023 5.55991V10.6207C4.13885 10.8778 4.27636 11.1164 4.4998 11.2436L9.84798 14.3312L7.9965 15.4003C7.97794 15.4127 7.95456 15.4147 7.93393 15.4058L3.50496 12.8469C1.53661 11.707 0.86147 9.18861 1.99587 7.21682L1.99656 7.21613ZM17.2085 10.7561L11.8603 7.66783L13.7118 6.59943C13.7304 6.58706 13.7537 6.585 13.7744 6.59393L18.2033 9.1508C20.1751 10.29 20.851 12.8125 19.7118 14.7843C19.2298 15.6189 18.4708 16.2583 17.5667 16.5911V11.379C17.5688 11.1219 17.432 10.884 17.2092 10.7561H17.2085ZM19.0511 7.98271C19.0187 7.96278 18.9617 7.9284 18.9211 7.90502L14.5403 5.37497C14.3182 5.24503 14.0432 5.24503 13.8204 5.37497L8.47226 8.46329V6.32512C8.47088 6.30311 8.4812 6.2818 8.49838 6.26805L12.9267 3.71325C14.8991 2.57541 17.4209 3.25261 18.5581 5.22578C19.0387 6.05905 19.2126 7.03463 19.0497 7.98271H19.0511ZM7.46574 11.7936L5.61357 10.7245C5.59363 10.7149 5.58057 10.6956 5.57782 10.6736V5.55922C5.5792 3.28218 7.42655 1.43689 9.7036 1.43826C10.6668 1.43826 11.5991 1.77652 12.3395 2.39253C12.3058 2.41041 12.2481 2.44272 12.2096 2.46609L7.82874 4.99615C7.60461 5.12334 7.46711 5.36122 7.46849 5.61904L7.46574 11.7922V11.7936ZM8.47157 9.62519L10.8538 8.24947L13.236 9.6245V12.3752L10.8538 13.7503L8.47157 12.3752V9.62519Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/other/replay-line.svg b/app/components/base/icons/assets/vender/other/replay-line.svg
new file mode 100644
index 0000000..c220747
--- /dev/null
+++ b/app/components/base/icons/assets/vender/other/replay-line.svg
@@ -0,0 +1,5 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Retry">
+<path id="Vector" d="M9.99996 1.66669C14.6023 1.66669 18.3333 5.39765 18.3333 10C18.3333 14.6024 14.6023 18.3334 9.99996 18.3334C5.39758 18.3334 1.66663 14.6024 1.66663 10H3.33329C3.33329 13.6819 6.31806 16.6667 9.99996 16.6667C13.6819 16.6667 16.6666 13.6819 16.6666 10C16.6666 6.31812 13.6819 3.33335 9.99996 3.33335C7.70848 3.33335 5.68702 4.48947 4.48705 6.25022L6.66663 6.25002V7.91669H1.66663V2.91669H3.33329L3.3332 4.99934C4.85358 2.97565 7.2739 1.66669 9.99996 1.66669Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/plugin/box-sparkle-fill.svg b/app/components/base/icons/assets/vender/plugin/box-sparkle-fill.svg
new file mode 100644
index 0000000..3ec651f
--- /dev/null
+++ b/app/components/base/icons/assets/vender/plugin/box-sparkle-fill.svg
@@ -0,0 +1,9 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M11.3891 2.41987C11.6635 2.58871 11.749 2.94802 11.5802 3.22239L10.3324 5.25H11.0833C11.4055 5.25 11.6667 5.51117 11.6667 5.83334V11.6667C11.6667 12.311 11.1444 12.8333 10.5 12.8333H3.50001C2.85568 12.8333 2.33334 12.311 2.33334 11.6667V5.83334C2.33334 5.51117 2.59451 5.25 2.91668 5.25H8.96252L10.5865 2.61094C10.7554 2.33657 11.1147 2.25102 11.3891 2.41987ZM5.83334 7.58334C5.51118 7.58334 5.25001 7.84449 5.25001 8.16667C5.25001 8.48884 5.51118 8.75 5.83334 8.75H8.16668C8.48885 8.75 8.75001 8.48884 8.75001 8.16667C8.75001 7.84449 8.48885 7.58334 8.16668 7.58334H5.83334Z" fill="#676F83"/>
+<g id="Vector_2" opacity="0.5">
+<path d="M6.91257 1.79347C6.96898 1.76525 7.01477 1.71948 7.043 1.66303L7.32195 1.10508C7.42946 0.890105 7.73623 0.890105 7.84374 1.10508L8.12269 1.66303C8.15093 1.71948 8.19672 1.76525 8.25313 1.79347L8.81108 2.07245C9.0261 2.17994 9.0261 2.48672 8.81108 2.5942L8.25313 2.87318C8.19672 2.9014 8.15093 2.94717 8.12269 3.00362L7.84374 3.56158C7.73623 3.77655 7.42946 3.77655 7.32195 3.56158L7.043 3.00362C7.01477 2.94717 6.96898 2.9014 6.91257 2.87318L6.35461 2.5942C6.13965 2.48672 6.13965 2.17994 6.35461 2.07245L6.91257 1.79347Z" fill="#676F83"/>
+<path d="M3.80145 2.7657C3.85789 2.73748 3.90366 2.69171 3.93189 2.63526L4.11364 2.27174C4.22113 2.05677 4.5279 2.05677 4.63539 2.27174L4.81715 2.63526C4.84537 2.6917 4.89114 2.73748 4.94759 2.7657L5.3111 2.94745C5.52607 3.05494 5.52607 3.36172 5.3111 3.4692L4.94759 3.65096C4.89114 3.67919 4.84537 3.72495 4.81715 3.7814L4.63539 4.14491C4.5279 4.35988 4.22113 4.35988 4.11364 4.14491L3.93189 3.7814C3.90366 3.72495 3.85789 3.67919 3.80145 3.65096L3.43793 3.4692C3.22296 3.36172 3.22296 3.05494 3.43793 2.94745L3.80145 2.7657Z" fill="#676F83"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/plugin/left-corner.svg b/app/components/base/icons/assets/vender/plugin/left-corner.svg
new file mode 100644
index 0000000..9b360e4
--- /dev/null
+++ b/app/components/base/icons/assets/vender/plugin/left-corner.svg
@@ -0,0 +1,3 @@
+<svg width="13" height="20" viewBox="0 0 13 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path id="Shape" d="M0 0H13V20C9.98017 20 7.26458 18.1615 6.14305 15.3576L0 0Z" fill="#F9FAFB"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/gold-coin.svg b/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/gold-coin.svg
new file mode 100644
index 0000000..b3830db
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/gold-coin.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12 1C9.82441 1 7.69767 1.64514 5.88873 2.85383C4.07979 4.06253 2.66989 5.7805 1.83733 7.79048C1.00477 9.80047 0.786929 12.0122 1.21137 14.146C1.6358 16.2798 2.68345 18.2398 4.22183 19.7782C5.76021 21.3166 7.72022 22.3642 9.85401 22.7886C11.9878 23.2131 14.1995 22.9952 16.2095 22.1627C18.2195 21.3301 19.9375 19.9202 21.1462 18.1113C22.3549 16.3023 23 14.1756 23 12C23 9.08262 21.8411 6.28473 19.7782 4.22183C17.7153 2.15893 14.9174 1 12 1ZM15.0296 6.26992L16.1076 4.78675C16.1784 4.6893 16.2677 4.60675 16.3703 4.54381C16.473 4.48087 16.5871 4.43877 16.7061 4.41992C16.825 4.40106 16.9465 4.40582 17.0636 4.43393C17.1807 4.46203 17.2912 4.51293 17.3886 4.58371C17.4861 4.65449 17.5686 4.74377 17.6316 4.84646C17.6945 4.94915 17.7366 5.06322 17.7555 5.18218C17.7743 5.30113 17.7696 5.42264 17.7415 5.53975C17.7134 5.65687 17.6625 5.7673 17.5917 5.86475L16.5137 7.34792C16.3707 7.54472 16.1554 7.67667 15.9152 7.71475C15.675 7.75283 15.4294 7.69391 15.2326 7.55096C15.0358 7.40801 14.9039 7.19273 14.8658 6.95249C14.8277 6.71225 14.8866 6.46672 15.0296 6.26992ZM6.61184 4.58417C6.70931 4.51294 6.81989 4.46167 6.93722 4.4333C7.05456 4.40493 7.17635 4.40002 7.29559 4.41884C7.41484 4.43766 7.52919 4.47985 7.63208 4.54299C7.73497 4.60613 7.82438 4.68897 7.89517 4.78675L8.97501 6.26992C9.11796 6.46733 9.17663 6.71344 9.13813 6.95411C9.09962 7.19478 8.96708 7.4103 8.76967 7.55325C8.57226 7.6962 8.32615 7.75488 8.08548 7.71637C7.84481 7.67786 7.62929 7.54533 7.48634 7.34792L6.40834 5.86475C6.33759 5.76731 6.28673 5.65689 6.25867 5.5398C6.23061 5.4227 6.22589 5.30122 6.24479 5.1823C6.26368 5.06338 6.30583 4.94935 6.36881 4.84672C6.43179 4.74409 6.51437 4.65487 6.61184 4.58417ZM6.18101 14.8508L4.43934 15.4173C4.32353 15.4604 4.2002 15.4797 4.07677 15.4739C3.95333 15.4681 3.83234 15.4375 3.72106 15.3837C3.60978 15.33 3.51051 15.2544 3.42922 15.1613C3.34793 15.0682 3.28629 14.9597 3.24801 14.8422C3.20973 14.7247 3.19561 14.6007 3.20648 14.4776C3.21735 14.3545 3.253 14.2349 3.31128 14.1259C3.36955 14.017 3.44926 13.9209 3.54561 13.8435C3.64195 13.7662 3.75295 13.7091 3.87192 13.6757L5.61359 13.1092C5.72952 13.0656 5.85308 13.046 5.9768 13.0515C6.10053 13.057 6.22185 13.0875 6.33345 13.1412C6.44505 13.1949 6.54461 13.2707 6.62613 13.3639C6.70764 13.4572 6.76941 13.566 6.80772 13.6837C6.84603 13.8015 6.86007 13.9258 6.84901 14.0492C6.83794 14.1725 6.802 14.2923 6.74334 14.4014C6.68468 14.5105 6.60453 14.6065 6.50773 14.6838C6.41092 14.761 6.30038 14.8179 6.18101 14.8508ZM12.9167 20.25C12.9167 20.4931 12.8201 20.7263 12.6482 20.8982C12.4763 21.0701 12.2431 21.1667 12 21.1667C11.7569 21.1667 11.5237 21.0701 11.3518 20.8982C11.1799 20.7263 11.0833 20.4931 11.0833 20.25V18.4167C11.0833 18.1736 11.1799 17.9404 11.3518 17.7685C11.5237 17.5966 11.7569 17.5 12 17.5C12.2431 17.5 12.4763 17.5966 12.6482 17.7685C12.8201 17.9404 12.9167 18.1736 12.9167 18.4167V20.25ZM12 14.9333L8.54967 16.7483L9.20876 12.9066L6.4175 10.1859L10.2748 9.62583L12 6.13333L13.7252 9.62583L17.5825 10.1859L14.7913 12.9066L15.4503 16.7483L12 14.9333ZM19.5625 15.4192L17.8208 14.8527C17.7015 14.8197 17.59 14.7629 17.4932 14.6856C17.3964 14.6084 17.3162 14.5123 17.2576 14.4032C17.1989 14.2942 17.163 14.1743 17.1519 14.051C17.1409 13.9276 17.1549 13.8033 17.1932 13.6856C17.2315 13.5678 17.2933 13.459 17.3748 13.3658C17.4563 13.2725 17.5559 13.1968 17.6675 13.1431C17.7791 13.0894 17.9004 13.0588 18.0241 13.0533C18.1479 13.0478 18.2714 13.0674 18.3873 13.111L20.129 13.6775C20.248 13.7109 20.359 13.768 20.4553 13.8454C20.5517 13.9227 20.6314 14.0188 20.6897 14.1278C20.7479 14.2367 20.7836 14.3563 20.7944 14.4794C20.8053 14.6025 20.7912 14.7265 20.7529 14.844C20.7146 14.9615 20.653 15.0701 20.5717 15.1631C20.4904 15.2562 20.3911 15.3319 20.2799 15.3856C20.1686 15.4393 20.0476 15.47 19.9242 15.4757C19.8007 15.4815 19.6783 15.4623 19.5625 15.4192Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/scales-02.svg b/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/scales-02.svg
new file mode 100644
index 0000000..8ebaef5
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/scales-02.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.64494 5.5L4 5.50001C3.44772 5.50001 3 5.05229 3 4.50001C3 3.94772 3.44771 3.50001 4 3.50001L8.64494 3.5C9.07521 2.05426 10.4145 1 12 1C13.5855 1 14.9248 2.05426 15.3551 3.5L20 3.5C20.5523 3.5 21 3.94772 21 4.5C21 5.05229 20.5523 5.5 20 5.5L15.3551 5.5C15.0191 6.62889 14.1289 7.51909 13 7.85506V20H20C20.5523 20 21 20.4477 21 21C21 21.5523 20.5523 22 20 22L4 22C3.44772 22 3 21.5523 3 21C3 20.4477 3.44772 20 4 20H11V7.85506C9.87111 7.51909 8.98091 6.62889 8.64494 5.5Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.49998 7C5.83892 7 6.15479 7.17168 6.33914 7.4561L9.34294 12.0905C9.5058 12.3416 9.65261 12.5678 9.77323 12.9247C9.82544 13.0792 9.86232 13.2714 9.88454 13.4092C9.90677 13.5471 9.93212 13.7411 9.93109 13.9042C9.9302 14.0459 9.92522 14.1726 9.90862 14.2966C9.89198 14.421 9.86633 14.5189 9.85041 14.5797L9.84797 14.5891C9.33962 16.5355 7.60137 18 5.49998 18C3.3986 18 1.66034 16.5355 1.152 14.5891L1.14959 14.5798C1.13367 14.5191 1.108 14.421 1.09135 14.2966C1.07475 14.1726 1.06977 14.0459 1.06888 13.9042C1.06785 13.7411 1.0932 13.5471 1.11542 13.4092C1.13765 13.2714 1.17453 13.0792 1.22674 12.9247C1.34736 12.5678 1.49417 12.3416 1.65703 12.0905L4.66083 7.4561C4.84518 7.17168 5.16105 7 5.49998 7ZM5.49998 9.83859L4.09907 12H6.9009L5.49998 9.83859Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19.3391 7.4561C19.1548 7.17168 18.8389 7 18.5 7C18.161 7 17.8452 7.17168 17.6608 7.4561L14.657 12.0905C14.4942 12.3416 14.3474 12.5678 14.2267 12.9247C14.1745 13.0792 14.1376 13.2714 14.1154 13.4092C14.0932 13.5471 14.0679 13.7411 14.0689 13.9042C14.0698 14.0459 14.0748 14.1726 14.0914 14.2966C14.108 14.421 14.1337 14.519 14.1496 14.5798L14.152 14.5891C14.6603 16.5355 16.3986 18 18.5 18C20.6014 18 22.3396 16.5355 22.848 14.5891L22.8504 14.5798C22.8663 14.5191 22.892 14.421 22.9086 14.2966C22.9252 14.1726 22.9302 14.0459 22.9311 13.9042C22.9321 13.7411 22.9068 13.5471 22.8845 13.4092C22.8623 13.2714 22.8254 13.0792 22.7732 12.9247C22.6526 12.5678 22.5058 12.3416 22.3429 12.0905L19.3391 7.4561ZM17.0991 12L18.5 9.83859L19.9009 12H17.0991Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/alertsAndFeedback/alert-triangle.svg b/app/components/base/icons/assets/vender/solid/alertsAndFeedback/alert-triangle.svg
new file mode 100644
index 0000000..d740738
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/alertsAndFeedback/alert-triangle.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="alert-triangle">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M6.40616 0.834185C6.14751 0.719172 5.85222 0.719172 5.59356 0.834185C5.3938 0.923011 5.26403 1.07947 5.17373 1.20696C5.08495 1.3323 4.9899 1.49651 4.88536 1.67711L0.751783 8.81693C0.646828 8.99818 0.551451 9.16289 0.486781 9.30268C0.421056 9.44475 0.349754 9.63572 0.372478 9.85369C0.401884 10.1357 0.549654 10.392 0.779012 10.5588C0.956259 10.6877 1.15726 10.7217 1.31314 10.736C1.46651 10.75 1.65684 10.75 1.86628 10.75H10.1334C10.3429 10.75 10.5332 10.75 10.6866 10.736C10.8425 10.7217 11.0435 10.6877 11.2207 10.5588C11.4501 10.392 11.5978 10.1357 11.6272 9.85369C11.65 9.63572 11.5787 9.44475 11.5129 9.30268C11.4483 9.1629 11.3529 8.9982 11.248 8.81697L7.11436 1.67709C7.00983 1.49651 6.91477 1.3323 6.82599 1.20696C6.73569 1.07947 6.60593 0.923011 6.40616 0.834185ZM6.49988 4.5C6.49988 4.22386 6.27602 4 5.99988 4C5.72374 4 5.49988 4.22386 5.49988 4.5V6.5C5.49988 6.77614 5.72374 7 5.99988 7C6.27602 7 6.49988 6.77614 6.49988 6.5V4.5ZM5.99988 8C5.72374 8 5.49988 8.22386 5.49988 8.5C5.49988 8.77614 5.72374 9 5.99988 9H6.00488C6.28102 9 6.50488 8.77614 6.50488 8.5C6.50488 8.22386 6.28102 8 6.00488 8H5.99988Z" fill="#F79009"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/arrows/chevron-down.svg b/app/components/base/icons/assets/vender/solid/arrows/chevron-down.svg
new file mode 100644
index 0000000..c766447
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/arrows/chevron-down.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="chevron-down">
+<path id="Icon" d="M6 9L12 15L18 9" stroke="#101828" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/arrows/high-priority.svg b/app/components/base/icons/assets/vender/solid/arrows/high-priority.svg
new file mode 100644
index 0000000..cfb965c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/arrows/high-priority.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.01488 2.54553C8.91549 2.45869 8.79321 2.40229 8.66264 2.38306C8.53206 2.36384 8.39872 2.38261 8.27852 2.43712C8.15833 2.49164 8.05636 2.5796 7.98481 2.6905C7.91325 2.8014 7.87513 2.93055 7.875 3.06253V6.50003C6.05164 6.50003 4.30295 7.22436 3.01364 8.51367C1.72433 9.80299 1 11.5517 1 13.375C1 15.1984 1.72433 16.9471 3.01364 18.2364C4.30295 19.5257 6.05164 20.25 7.875 20.25H12C12.3647 20.25 12.7144 20.1052 12.9723 19.8473C13.2301 19.5894 13.375 19.2397 13.375 18.875C13.375 18.5104 13.2301 18.1606 12.9723 17.9028C12.7144 17.6449 12.3647 17.5 12 17.5H7.875C6.78098 17.5 5.73177 17.0654 4.95818 16.2919C4.1846 15.5183 3.75 14.4691 3.75 13.375C3.75 12.281 4.1846 11.2318 4.95818 10.4582C5.73177 9.68463 6.78098 9.25003 7.875 9.25003V12.6875C7.87513 12.8195 7.91325 12.9487 7.98481 13.0596C8.05636 13.1705 8.15833 13.2584 8.27852 13.3129C8.39872 13.3675 8.53206 13.3862 8.66264 13.367C8.79321 13.3478 8.91549 13.2914 9.01488 13.2045L14.5149 8.39203C14.5885 8.32751 14.6475 8.24801 14.6879 8.15885C14.7283 8.06969 14.7492 7.97292 14.7492 7.87503C14.7492 7.77714 14.7283 7.68038 14.6879 7.59122C14.6475 7.50206 14.5885 7.42256 14.5149 7.35803L9.01488 2.54553Z" fill="#212121"/>
+<path d="M21.625 17.5H17.5C17.1353 17.5 16.7856 17.6449 16.5277 17.9028C16.2699 18.1606 16.125 18.5104 16.125 18.875C16.125 19.2397 16.2699 19.5894 16.5277 19.8473C16.7856 20.1052 17.1353 20.25 17.5 20.25H21.625C21.9897 20.25 22.3394 20.1052 22.5973 19.8473C22.8551 19.5894 23 19.2397 23 18.875C23 18.5104 22.8551 18.1606 22.5973 17.9028C22.3394 17.6449 21.9897 17.5 21.625 17.5Z" fill="#212121"/>
+<path d="M21.625 12H17.5C17.1353 12 16.7856 12.1449 16.5277 12.4028C16.2699 12.6606 16.125 13.0104 16.125 13.375C16.125 13.7397 16.2699 14.0894 16.5277 14.3473C16.7856 14.6052 17.1353 14.75 17.5 14.75H21.625C21.9897 14.75 22.3394 14.6052 22.5973 14.3473C22.8551 14.0894 23 13.7397 23 13.375C23 13.0104 22.8551 12.6606 22.5973 12.4028C22.3394 12.1449 21.9897 12 21.625 12Z" fill="#212121"/>
+<path d="M17.5 9.25003H21.625C21.9897 9.25003 22.3394 9.10517 22.5973 8.8473C22.8551 8.58944 23 8.23971 23 7.87503C23 7.51036 22.8551 7.16062 22.5973 6.90276C22.3394 6.6449 21.9897 6.50003 21.625 6.50003H17.5C17.1353 6.50003 16.7856 6.6449 16.5277 6.90276C16.2699 7.16062 16.125 7.51036 16.125 7.87503C16.125 8.23971 16.2699 8.58944 16.5277 8.8473C16.7856 9.10517 17.1353 9.25003 17.5 9.25003Z" fill="#212121"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/ai-text.svg b/app/components/base/icons/assets/vender/solid/communication/ai-text.svg
new file mode 100644
index 0000000..dcda2ef
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/ai-text.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4 5C3.44772 5 3 5.44772 3 6C3 6.55228 3.44772 7 4 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5H4Z" fill="black"/>
+<path d="M17.9191 9.60608C17.7616 9.2384 17.4 9 17 9C16.6 9 16.2384 9.2384 16.0809 9.60608L14.7384 12.7384L11.6061 14.0809C11.2384 14.2384 11 14.6 11 15C11 15.4 11.2384 15.7616 11.6061 15.9191L14.7384 17.2616L16.0809 20.3939C16.2384 20.7616 16.6 21 17 21C17.4 21 17.7616 20.7616 17.9191 20.3939L19.2616 17.2616L22.3939 15.9191C22.7616 15.7616 23 15.4 23 15C23 14.6 22.7616 14.2384 22.3939 14.0809L19.2616 12.7384L17.9191 9.60608Z" fill="black"/>
+<path d="M4 11C3.44772 11 3 11.4477 3 12C3 12.5523 3.44772 13 4 13H9C9.55228 13 10 12.5523 10 12C10 11.4477 9.55228 11 9 11H4Z" fill="black"/>
+<path d="M4 17C3.44772 17 3 17.4477 3 18C3 18.5523 3.44772 19 4 19H7C7.55228 19 8 18.5523 8 18C8 17.4477 7.55228 17 7 17H4Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/bubble-text-mod.svg b/app/components/base/icons/assets/vender/solid/communication/bubble-text-mod.svg
new file mode 100644
index 0000000..7a37245
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/bubble-text-mod.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M2 9C2 5.68629 4.68629 3 8 3H16C19.3137 3 22 5.68629 22 9V15C22 18.3137 19.3137 21 16 21H3C2.44772 21 2 20.5523 2 20V9ZM9 9C8.44772 9 8 9.44772 8 10C8 10.5523 8.44772 11 9 11H15C15.5523 11 16 10.5523 16 10C16 9.44772 15.5523 9 15 9H9ZM9 13C8.44772 13 8 13.4477 8 14C8 14.5523 8.44772 15 9 15H12C12.5523 15 13 14.5523 13 14C13 13.4477 12.5523 13 12 13H9Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/chat-bot.svg b/app/components/base/icons/assets/vender/solid/communication/chat-bot.svg
new file mode 100644
index 0000000..53ee1bb
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/chat-bot.svg
@@ -0,0 +1,7 @@
+<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="chat-bot">
+<path id="Vector" d="M4.20913 2.76912L4.09542 2.83543L3.98172 2.76912C3.90566 2.72476 3.86328 2.64979 3.86328 2.57101C3.86328 2.44347 3.96789 2.33887 4.09542 2.33887C4.22296 2.33887 4.32757 2.44347 4.32757 2.57101C4.32757 2.64979 4.28519 2.72476 4.20913 2.76912Z" fill="#1570EF" stroke="#1570EF" stroke-width="1.25"/>
+<path id="Vector_2" d="M10.0174 6.00058C10.0123 5.98686 10.0097 5.97229 10.0046 5.95858C9.81684 5.48158 9.35398 5.14258 8.81056 5.14258H8.66784L7.52484 5.99972C7.33713 6.14029 7.11556 6.21444 6.88284 6.21444C6.29184 6.21444 5.81056 5.73358 5.81056 5.14258H2.81013C2.10127 5.14258 1.52441 5.71944 1.52441 6.42829V9.85686C1.52441 10.5657 2.10127 11.1426 2.81013 11.1426H8.81013C9.51899 11.1426 10.0958 10.5657 10.0958 9.85686V6.42829C10.0958 6.34386 10.0868 6.26158 10.071 6.18186C10.0586 6.11886 10.0384 6.05972 10.0174 6.00058ZM3.88156 8.57115C3.52713 8.57115 3.2387 8.28272 3.2387 7.92829C3.2387 7.57386 3.52713 7.28544 3.88156 7.28544C4.23599 7.28544 4.52441 7.57386 4.52441 7.92829C4.52441 8.28272 4.23599 8.57115 3.88156 8.57115ZM7.7387 8.57115C7.38427 8.57115 7.09584 8.28272 7.09584 7.92829C7.09584 7.57386 7.38427 7.28544 7.7387 7.28544C8.09313 7.28544 8.38156 7.57386 8.38156 7.92829C8.38156 8.28272 8.09313 8.57115 7.7387 8.57115Z" fill="#1570EF"/>
+<path id="Vector_3" d="M6.66699 5.14314V1.71456C6.66699 1.24099 7.05056 0.857422 7.52413 0.857422H10.9527C11.4263 0.857422 11.8098 1.24099 11.8098 1.71456V3.42885C11.8098 3.90242 11.4263 4.28599 10.9527 4.28599H8.38128L7.00985 5.31456C6.86842 5.42042 6.66699 5.31971 6.66699 5.14314Z" fill="#1570EF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/cute-robot.svg b/app/components/base/icons/assets/vender/solid/communication/cute-robot.svg
new file mode 100644
index 0000000..8fa74ce
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/cute-robot.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="cute-robot">
+<path id="Icon" fill-rule="evenodd" clip-rule="evenodd" d="M12 1C12.5523 1 13 1.44772 13 2V3H17C18.6569 3 20 4.34315 20 6V11C20 11.8885 19.6138 12.6868 19 13.2361V14.5858L20.7071 16.2929C21.0976 16.6834 21.0976 17.3166 20.7071 17.7071C20.3166 18.0976 19.6834 18.0976 19.2929 17.7071L18.681 17.0952C17.7905 19.9377 15.1361 22 12 22C8.8639 22 6.20948 19.9377 5.31897 17.0952L4.70711 17.7071C4.31658 18.0976 3.68342 18.0976 3.29289 17.7071C2.90237 17.3166 2.90237 16.6834 3.29289 16.2929L5 14.5858V13.2361C4.38625 12.6868 4 11.8885 4 11V6C4 4.34315 5.34315 3 7 3H11V2C11 1.44772 11.4477 1 12 1ZM7 5C6.44772 5 6 5.44772 6 6V11C6 11.5523 6.44772 12 7 12H17C17.5523 12 18 11.5523 18 11V6C18 5.44772 17.5523 5 17 5H7ZM9 7C9.55228 7 10 7.44772 10 8V9C10 9.55228 9.55228 10 9 10C8.44772 10 8 9.55228 8 9V8C8 7.44772 8.44772 7 9 7ZM15 7C15.5523 7 16 7.44772 16 8V9C16 9.55228 15.5523 10 15 10C14.4477 10 14 9.55228 14 9V8C14 7.44772 14.4477 7 15 7Z" fill="black"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/edit-list.svg b/app/components/base/icons/assets/vender/solid/communication/edit-list.svg
new file mode 100644
index 0000000..e6fdc2d
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/edit-list.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M3.00195 4C3.00195 3.44772 3.44967 3 4.00195 3H20.002C20.5542 3 21.002 3.44772 21.002 4C21.002 4.55228 20.5542 5 20.002 5H4.00195C3.44967 5 3.00195 4.55228 3.00195 4Z" fill="black"/>
+<path d="M3.00195 8C3.00195 7.44772 3.44967 7 4.00195 7H10.502C11.0542 7 11.502 7.44772 11.502 8C11.502 8.55228 11.0542 9 10.502 9H4.00195C3.44967 9 3.00195 8.55228 3.00195 8Z" fill="black"/>
+<path d="M4 11C3.44772 11 3 11.4477 3 12C3 12.5523 3.44772 13 4 13H7.0022C7.55448 13 8.0022 12.5523 8.0022 12C8.0022 11.4477 7.55448 11 7.0022 11H4Z" fill="black"/>
+<path d="M19.2584 8.70705C18.0868 7.53548 16.1873 7.53547 15.0158 8.70705L7.29485 16.428C7.10731 16.6155 7.00195 16.8699 7.00195 17.1351V20.9999C7.00195 21.5522 7.44967 21.9999 8.00195 21.9999H11.8668C12.132 21.9999 12.3864 21.8946 12.5739 21.7071L20.2948 13.9861C21.4664 12.8146 21.4664 10.9151 20.2948 9.74349L19.2584 8.70705Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/list-sparkle.svg b/app/components/base/icons/assets/vender/solid/communication/list-sparkle.svg
new file mode 100644
index 0000000..dcda2ef
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/list-sparkle.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4 5C3.44772 5 3 5.44772 3 6C3 6.55228 3.44772 7 4 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5H4Z" fill="black"/>
+<path d="M17.9191 9.60608C17.7616 9.2384 17.4 9 17 9C16.6 9 16.2384 9.2384 16.0809 9.60608L14.7384 12.7384L11.6061 14.0809C11.2384 14.2384 11 14.6 11 15C11 15.4 11.2384 15.7616 11.6061 15.9191L14.7384 17.2616L16.0809 20.3939C16.2384 20.7616 16.6 21 17 21C17.4 21 17.7616 20.7616 17.9191 20.3939L19.2616 17.2616L22.3939 15.9191C22.7616 15.7616 23 15.4 23 15C23 14.6 22.7616 14.2384 22.3939 14.0809L19.2616 12.7384L17.9191 9.60608Z" fill="black"/>
+<path d="M4 11C3.44772 11 3 11.4477 3 12C3 12.5523 3.44772 13 4 13H9C9.55228 13 10 12.5523 10 12C10 11.4477 9.55228 11 9 11H4Z" fill="black"/>
+<path d="M4 17C3.44772 17 3 17.4477 3 18C3 18.5523 3.44772 19 4 19H7C7.55228 19 8 18.5523 8 18C8 17.4477 7.55228 17 7 17H4Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/logic.svg b/app/components/base/icons/assets/vender/solid/communication/logic.svg
new file mode 100644
index 0000000..4c019e3
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/logic.svg
@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="logic">
+<g id="Vector">
+<path d="M12.9089 11.9999C13.913 11.9999 14.727 11.186 14.727 10.1819C14.727 9.17775 13.913 8.36376 12.9089 8.36376C11.9048 8.36376 11.0908 9.17775 11.0908 10.1819C11.0908 11.186 11.9048 11.9999 12.9089 11.9999Z" fill="black"/>
+<path d="M12.2871 1.11229C9.95219 1.3228 7.78275 2.40696 6.21264 4.14796C4.64254 5.88897 3.78749 8.15849 3.81849 10.5027V10.8763L2.09676 14.3207C2.04261 14.4277 2.01016 14.5444 2.00129 14.6639C1.99241 14.7835 2.00729 14.9037 2.04506 15.0175C2.08283 15.1313 2.14275 15.2366 2.22136 15.3271C2.29997 15.4177 2.39573 15.4918 2.50311 15.5452L3.81849 16.1979V18.3632C3.81849 19.0865 4.10581 19.7802 4.61725 20.2916C5.12869 20.803 5.82234 21.0904 6.54562 21.0904H9.27276V22.9084H19.2722V16.6606C20.5995 15.3604 21.496 13.6844 21.8409 11.8588C22.1858 10.0331 21.9625 8.14562 21.2012 6.45084C20.4398 4.75606 19.1769 3.33556 17.583 2.38094C15.989 1.42633 14.1406 0.983541 12.2871 1.11229ZM17.4542 11.0909H16.416C16.3316 11.4163 16.2016 11.7282 16.0297 12.0172L16.7651 12.7526C16.8519 12.8365 16.9212 12.9368 16.9688 13.0477C17.0165 13.1586 17.0415 13.2779 17.0426 13.3986C17.0436 13.5193 17.0206 13.639 16.9749 13.7507C16.9292 13.8624 16.8617 13.9639 16.7764 14.0493C16.691 14.1346 16.5895 14.2021 16.4778 14.2478C16.3661 14.2935 16.2464 14.3165 16.1257 14.3155C16.005 14.3144 15.8857 14.2893 15.7748 14.2417C15.6639 14.1941 15.5636 14.1248 15.4797 14.038L14.7443 13.3026C14.4553 13.4745 14.1434 13.6045 13.818 13.6889V14.727C13.818 14.9681 13.7222 15.1994 13.5517 15.3698C13.3812 15.5403 13.15 15.6361 12.9089 15.6361C12.6678 15.6361 12.4366 15.5403 12.2661 15.3698C12.0957 15.1994 11.9999 14.9681 11.9999 14.727V13.6889C11.6744 13.6045 11.3625 13.4745 11.0736 13.3026L10.3382 14.038C10.1667 14.2036 9.93708 14.2952 9.69873 14.2931C9.46038 14.2911 9.23239 14.1955 9.06384 14.0269C8.8953 13.8584 8.79969 13.6304 8.79762 13.392C8.79555 13.1537 8.88718 12.924 9.05277 12.7526L9.78818 12.0172C9.61629 11.7282 9.48622 11.4163 9.40184 11.0909H8.36371C8.12262 11.0909 7.8914 10.9951 7.72092 10.8246C7.55044 10.6541 7.45467 10.4229 7.45467 10.1818C7.45467 9.94073 7.55044 9.70951 7.72092 9.53903C7.8914 9.36855 8.12262 9.27278 8.36371 9.27278H9.40184C9.48622 8.94731 9.61629 8.63544 9.78818 8.34647L9.05277 7.61105C8.88718 7.4396 8.79555 7.20997 8.79762 6.97163C8.79969 6.73328 8.8953 6.50528 9.06384 6.33673C9.23239 6.16819 9.46038 6.07259 9.69873 6.07052C9.93708 6.06844 10.1667 6.16007 10.3382 6.32566L11.0736 7.06108C11.3625 6.88918 11.6744 6.75911 11.9999 6.67473V5.63661C11.9999 5.39551 12.0957 5.16429 12.2661 4.99381C12.4366 4.82334 12.6678 4.72756 12.9089 4.72756C13.15 4.72756 13.3812 4.82334 13.5517 4.99381C13.7222 5.16429 13.818 5.39551 13.818 5.63661V6.67473C14.1434 6.75911 14.4553 6.88918 14.7443 7.06108L15.4797 6.32566C15.5636 6.23884 15.6639 6.16958 15.7748 6.12194C15.8857 6.0743 16.005 6.04922 16.1257 6.04817C16.2464 6.04713 16.3661 6.07013 16.4778 6.11583C16.5895 6.16154 16.691 6.22904 16.7764 6.31439C16.8617 6.39975 16.9292 6.50124 16.9749 6.61296C17.0206 6.72468 17.0436 6.84438 17.0426 6.96508C17.0415 7.08578 17.0165 7.20507 16.9688 7.31598C16.9212 7.42688 16.8519 7.52719 16.7651 7.61105L16.0297 8.34647C16.2016 8.63544 16.3316 8.94731 16.416 9.27278H17.4542C17.6952 9.27278 17.9265 9.36855 18.0969 9.53903C18.2674 9.70951 18.3632 9.94073 18.3632 10.1818C18.3632 10.4229 18.2674 10.6541 18.0969 10.8246C17.9265 10.9951 17.6952 11.0909 17.4542 11.0909Z" fill="black"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/message-dots-circle.svg b/app/components/base/icons/assets/vender/solid/communication/message-dots-circle.svg
new file mode 100644
index 0000000..18ccff8
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/message-dots-circle.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="message-dots-circle">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.47715 2 2 6.47715 2 12C2 13.3283 2.25952 14.5985 2.73156 15.7608C2.77419 15.8658 2.79872 15.9264 2.81552 15.9711L2.82063 15.9849L2.82 15.9897C2.815 16.0266 2.80672 16.0769 2.79071 16.173L2.19294 19.7596C2.16612 19.9202 2.13611 20.0999 2.12433 20.256C2.11148 20.4261 2.10701 20.6969 2.22973 20.983C2.38144 21.3367 2.6633 21.6186 3.017 21.7703C3.30312 21.893 3.57386 21.8885 3.74404 21.8757C3.90013 21.8639 4.07985 21.8339 4.24049 21.8071L7.82705 21.2093C7.92309 21.1933 7.97339 21.185 8.0103 21.18L8.01505 21.1794L8.02887 21.1845C8.07362 21.2013 8.13423 21.2258 8.23921 21.2684C9.4015 21.7405 10.6717 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM6 12C6 11.1716 6.67157 10.5 7.5 10.5C8.32843 10.5 9 11.1716 9 12C9 12.8284 8.32843 13.5 7.5 13.5C6.67157 13.5 6 12.8284 6 12ZM10.5 12C10.5 11.1716 11.1716 10.5 12 10.5C12.8284 10.5 13.5 11.1716 13.5 12C13.5 12.8284 12.8284 13.5 12 13.5C11.1716 13.5 10.5 12.8284 10.5 12ZM16.5 10.5C15.6716 10.5 15 11.1716 15 12C15 12.8284 15.6716 13.5 16.5 13.5C17.3284 13.5 18 12.8284 18 12C18 11.1716 17.3284 10.5 16.5 10.5Z" fill="black"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/message-fast.svg b/app/components/base/icons/assets/vender/solid/communication/message-fast.svg
new file mode 100644
index 0000000..66a206f
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/message-fast.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16.2414 2H7.7588C6.95383 1.99999 6.28946 1.99998 5.74827 2.04419C5.18617 2.09012 4.66947 2.18868 4.18413 2.43598C3.43149 2.81947 2.81956 3.43139 2.43607 4.18404C2.18878 4.66937 2.09022 5.18608 2.04429 5.74818C2.00007 6.28937 2.00008 6.95373 2.0001 7.7587L2.00005 14.1376C1.99962 14.933 1.9993 15.5236 2.13639 16.0353C2.50626 17.4156 3.58445 18.4938 4.96482 18.8637C5.27229 18.9461 5.60829 18.9789 6.0001 18.9918L6.00009 20.371C6.00005 20.6062 6 20.846 6.01785 21.0425C6.03492 21.2305 6.08012 21.5852 6.32778 21.8955C6.61276 22.2525 7.0449 22.4602 7.50172 22.4597C7.8987 22.4593 8.20394 22.273 8.36137 22.1689C8.52597 22.06 8.7132 21.9102 8.89688 21.7632L11.31 19.8327C11.8286 19.4178 11.9826 19.3007 12.1425 19.219C12.303 19.137 12.4738 19.0771 12.6504 19.0408C12.8263 19.0047 13.0197 19 13.6838 19H16.2414C17.0464 19 17.7107 19 18.2519 18.9558C18.814 18.9099 19.3307 18.8113 19.8161 18.564C20.5687 18.1805 21.1806 17.5686 21.5641 16.816C21.8114 16.3306 21.91 15.8139 21.9559 15.2518C22.0001 14.7106 22.0001 14.0463 22.0001 13.2413V7.75868C22.0001 6.95372 22.0001 6.28936 21.9559 5.74818C21.91 5.18608 21.8114 4.66937 21.5641 4.18404C21.1806 3.43139 20.5687 2.81947 19.8161 2.43598C19.3307 2.18868 18.814 2.09012 18.2519 2.04419C17.7107 1.99998 17.0464 1.99999 16.2414 2ZM12.681 5.5349C12.8938 5.61898 13.0218 5.83714 12.9916 6.06386L12.5688 9.23501L14.48 9.23501C14.5899 9.23498 14.7038 9.23496 14.7979 9.24356C14.8905 9.25203 15.0589 9.27446 15.2095 9.39066C15.3851 9.52617 15.4913 9.73269 15.4996 9.95432C15.5066 10.1444 15.427 10.2945 15.38 10.3747C15.3324 10.4563 15.2661 10.549 15.2022 10.6384L11.9072 15.2514C11.7743 15.4375 11.5317 15.5092 11.319 15.4251C11.1063 15.341 10.9782 15.1229 11.0084 14.8961L11.4312 11.725L9.52004 11.725C9.41011 11.725 9.29618 11.725 9.20206 11.7164C9.10948 11.708 8.94106 11.6855 8.79051 11.5693C8.61493 11.4338 8.50866 11.2273 8.50044 11.0057C8.49339 10.8156 8.57303 10.6655 8.61996 10.5853C8.66766 10.5037 8.7339 10.411 8.79781 10.3216L12.0928 5.70858C12.2257 5.52246 12.4683 5.45083 12.681 5.5349Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/message-heart-circle.svg b/app/components/base/icons/assets/vender/solid/communication/message-heart-circle.svg
new file mode 100644
index 0000000..306ed02
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/message-heart-circle.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="message-heart-circle">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M8.33334 1.3335C4.83554 1.3335 2.00001 4.16903 2.00001 7.66683C2.00001 8.3735 2.116 9.05444 2.33051 9.69084C2.36824 9.80278 2.39045 9.86902 2.40488 9.91786L2.40961 9.93431L2.40711 9.93952C2.38997 9.97486 2.36451 10.0223 2.31687 10.1105L1.21562 12.1489C1.14736 12.2751 1.07614 12.4069 1.02717 12.5214C0.978485 12.6353 0.89963 12.8442 0.93843 13.0919C0.983911 13.3822 1.15477 13.6378 1.40562 13.7908C1.61963 13.9213 1.84282 13.9283 1.96665 13.9269C2.09123 13.9254 2.24018 13.91 2.38296 13.8952L5.8196 13.54C5.87464 13.5343 5.90342 13.5314 5.92449 13.5297L5.92721 13.5295L5.93545 13.5325C5.96135 13.5418 5.99648 13.5553 6.05711 13.5786C6.76441 13.8511 7.53226 14.0002 8.33334 14.0002C11.8311 14.0002 14.6667 11.1646 14.6667 7.66683C14.6667 4.16903 11.8311 1.3335 8.33334 1.3335ZM5.97972 5.72165C6.73124 5.08746 7.73145 5.27376 8.33126 5.96633C8.93106 5.27376 9.91836 5.09414 10.6828 5.72165C11.4472 6.34916 11.5401 7.41616 10.9499 8.16621C10.5843 8.63089 9.66661 9.4796 9.02123 10.0581C8.78417 10.2706 8.66564 10.3769 8.52339 10.4197C8.40136 10.4564 8.26116 10.4564 8.13913 10.4197C7.99688 10.3769 7.87835 10.2706 7.64128 10.0581C6.9959 9.4796 6.0782 8.63089 5.71257 8.16621C5.1224 7.41616 5.22821 6.35583 5.97972 5.72165Z" fill="#DD2590"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/message-smile-square.svg b/app/components/base/icons/assets/vender/solid/communication/message-smile-square.svg
new file mode 100644
index 0000000..105541f
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/message-smile-square.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="message-smile-square">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M10.8273 1.33337H5.17221C4.63556 1.33337 4.19265 1.33336 3.83185 1.36284C3.45712 1.39345 3.11265 1.45916 2.7891 1.62402C2.28733 1.87969 1.87938 2.28763 1.62372 2.7894C1.45886 3.11296 1.39315 3.45743 1.36253 3.83216C1.33306 4.19295 1.33306 4.63586 1.33307 5.17251L1.33304 9.42509C1.33275 9.95535 1.33254 10.3491 1.42394 10.6902C1.67052 11.6105 2.38931 12.3293 3.30955 12.5758C3.51453 12.6308 3.73853 12.6526 3.99974 12.6612L3.99974 13.5807C3.99971 13.7375 3.99967 13.8974 4.01157 14.0284C4.02296 14.1537 4.05309 14.3902 4.2182 14.597C4.40818 14.835 4.69628 14.9735 5.00082 14.9732C5.26547 14.9729 5.46897 14.8487 5.57392 14.7793C5.68366 14.7067 5.80847 14.6068 5.93093 14.5088L7.53968 13.2218C7.8854 12.9453 7.98804 12.8672 8.0947 12.8127C8.20168 12.758 8.31556 12.7181 8.43324 12.6939C8.55057 12.6699 8.6795 12.6667 9.12224 12.6667H10.8273C11.3639 12.6667 11.8068 12.6667 12.1676 12.6372C12.5424 12.6066 12.8868 12.5409 13.2104 12.3761C13.7121 12.1204 14.1201 11.7124 14.3758 11.2107C14.5406 10.8871 14.6063 10.5427 14.6369 10.1679C14.6664 9.80713 14.6664 9.36423 14.6664 8.82759V5.17249C14.6664 4.63585 14.6664 4.19295 14.6369 3.83216C14.6063 3.45743 14.5406 3.11296 14.3758 2.7894C14.1201 2.28763 13.7121 1.87969 13.2104 1.62402C12.8868 1.45916 12.5424 1.39345 12.1676 1.36284C11.8068 1.33336 11.3639 1.33337 10.8273 1.33337ZM8.99479 5.00004C8.99479 4.44776 9.44251 4.00004 9.99479 4.00004C10.5471 4.00004 10.9948 4.44776 10.9948 5.00004C10.9948 5.55233 10.5471 6.00004 9.99479 6.00004C9.44251 6.00004 8.99479 5.55233 8.99479 5.00004ZM4.92813 7.80008C5.22175 7.57986 5.63792 7.63849 5.85937 7.93064C5.90047 7.98307 5.94569 8.03241 5.99175 8.08048C6.08995 8.18295 6.23751 8.32196 6.42858 8.46092C6.81329 8.74071 7.34515 9.00008 7.9948 9.00008C8.64444 9.00008 9.17631 8.74071 9.56102 8.46092C9.75209 8.32196 9.89965 8.18295 9.99785 8.08048C10.0439 8.03242 10.0891 7.98306 10.1302 7.93064C10.3517 7.63849 10.7678 7.57986 11.0615 7.80008C11.356 8.02099 11.4157 8.43886 11.1948 8.73341C11.1965 8.73124 11.1925 8.73622 11.1857 8.74479C11.1695 8.76522 11.137 8.8061 11.1259 8.81929C11.0868 8.86587 11.0315 8.92896 10.9605 9.00302C10.8191 9.15055 10.6125 9.34486 10.3452 9.53924C9.81328 9.92612 9.01182 10.3334 7.9948 10.3334C6.97778 10.3334 6.17631 9.92612 5.64435 9.53924C5.37709 9.34486 5.17048 9.15055 5.0291 9.00302C4.95813 8.92896 4.9028 8.86587 4.8637 8.81929C4.84413 8.79597 4.82856 8.77671 4.81707 8.76219C4.58678 8.46467 4.61774 8.03288 4.92813 7.80008ZM5.99479 4.00004C5.44251 4.00004 4.99479 4.44776 4.99479 5.00004C4.99479 5.55233 5.44251 6.00004 5.99479 6.00004C6.54708 6.00004 6.99479 5.55233 6.99479 5.00004C6.99479 4.44776 6.54708 4.00004 5.99479 4.00004Z" fill="#06AED4"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/communication/send-03.svg b/app/components/base/icons/assets/vender/solid/communication/send-03.svg
new file mode 100644
index 0000000..c2e8f1f
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/communication/send-03.svg
@@ -0,0 +1,5 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="send-03">
+<path id="Solid" d="M18.4385 10.5535C18.6111 10.2043 18.6111 9.79465 18.4385 9.44548C18.2865 9.13803 18.0197 8.97682 17.8815 8.89905C17.7327 8.81532 17.542 8.72955 17.3519 8.64403L3.36539 2.35014C3.17087 2.26257 2.97694 2.17526 2.81335 2.11859C2.66315 2.06656 2.36076 1.97151 2.02596 2.06467C1.64761 2.16994 1.34073 2.4469 1.19734 2.81251C1.07045 3.13604 1.13411 3.44656 1.17051 3.60129C1.21017 3.76983 1.27721 3.9717 1.34445 4.17418L2.69818 8.25278C2.80718 8.58118 2.86168 8.74537 2.96302 8.86678C3.05252 8.97399 3.16752 9.05699 3.29746 9.10816C3.44462 9.1661 3.61762 9.1661 3.96363 9.1661H10.0001C10.4603 9.1661 10.8334 9.53919 10.8334 9.99943C10.8334 10.4597 10.4603 10.8328 10.0001 10.8328H3.97939C3.63425 10.8328 3.46168 10.8328 3.3148 10.8905C3.18508 10.9414 3.07022 11.0241 2.98072 11.1309C2.87937 11.2519 2.82459 11.4155 2.71502 11.7428L1.3504 15.8191C1.28243 16.0221 1.21472 16.2242 1.17455 16.3929C1.13773 16.5476 1.07301 16.8587 1.19956 17.1831C1.34245 17.5493 1.64936 17.827 2.02806 17.9327C2.36342 18.0263 2.6665 17.9309 2.81674 17.8789C2.98066 17.8221 3.17507 17.7346 3.37023 17.6467L17.3518 11.355C17.542 11.2695 17.7327 11.1837 17.8815 11.0999C18.0197 11.0222 18.2865 10.861 18.4385 10.5535Z" fill="#D0D5DD"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/api-connection-mod.svg b/app/components/base/icons/assets/vender/solid/development/api-connection-mod.svg
new file mode 100644
index 0000000..9e4b0c8
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/api-connection-mod.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon L">
+<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M7.99996 3.33333C5.42263 3.33333 3.33329 5.42267 3.33329 8C3.33329 10.5773 5.42263 12.6667 7.99996 12.6667C9.72643 12.6667 11.2348 11.7295 12.0427 10.3329C12.227 10.0141 12.6349 9.90523 12.9536 10.0896C13.2723 10.274 13.3812 10.6818 13.1968 11.0005C12.1604 12.7921 10.2216 14 7.99996 14C4.91159 14 2.36821 11.6666 2.03658 8.66667H1.33329C0.965103 8.66667 0.666626 8.36819 0.666626 8C0.666626 7.63181 0.965103 7.33333 1.33329 7.33333H2.03658C2.36821 4.33337 4.91159 2 7.99996 2C10.2216 2 12.1604 3.20785 13.1968 4.99952C13.3812 5.31823 13.2723 5.72605 12.9536 5.91041C12.6349 6.09477 12.227 5.98585 12.0427 5.66714C11.2348 4.27054 9.72643 3.33333 7.99996 3.33333ZM7.99996 6C6.89539 6 5.99996 6.89543 5.99996 8C5.99996 9.10455 6.89539 10 7.99996 10C9.1045 10 9.99996 9.10454 9.99996 8C9.99996 6.89543 9.10451 6 7.99996 6ZM4.66663 8C4.66663 6.15905 6.15901 4.66667 7.99996 4.66667C9.61257 4.66667 10.9578 5.81184 11.2666 7.33333H14.6666C15.0348 7.33333 15.3333 7.63181 15.3333 8C15.3333 8.36819 15.0348 8.66667 14.6666 8.66667H11.2666C10.9578 10.1881 9.61257 11.3333 7.99996 11.3333C6.159 11.3333 4.66663 9.84092 4.66663 8Z" fill="#354052"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/api-connection.svg b/app/components/base/icons/assets/vender/solid/development/api-connection.svg
new file mode 100644
index 0000000..5eddeeb
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/api-connection.svg
@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="api-connection">
+<g id="vector">
+<path d="M4.36364 11.8182C4.36364 7.60073 7.78255 4.18182 12 4.18182C14.8252 4.18182 17.2934 5.71543 18.6154 8.00079C18.9171 8.52231 19.5844 8.70053 20.106 8.39884C20.6275 8.09716 20.8057 7.42982 20.504 6.9083C18.8081 3.97648 15.6355 2 12 2C6.9463 2 2.78441 5.81824 2.24174 10.7273H1.09091C0.488417 10.7273 0 11.2157 0 11.8182C0 12.4207 0.488417 12.9091 1.09091 12.9091H2.24174C2.78441 17.8181 6.9463 21.6364 12 21.6364C15.6355 21.6364 18.8081 19.6599 20.504 16.7281C20.8057 16.2065 20.6275 15.5392 20.106 15.2375C19.5844 14.9358 18.9171 15.1141 18.6154 15.6356C17.2934 17.9209 14.8252 19.4545 12 19.4545C7.78255 19.4545 4.36364 16.0356 4.36364 11.8182Z" fill="black"/>
+<path d="M12 6.36364C8.98754 6.36364 6.54545 8.80572 6.54545 11.8182C6.54545 14.8306 8.98754 17.2727 12 17.2727C14.6389 17.2727 16.84 15.3988 17.3454 12.9091H22.9091C23.5116 12.9091 24 12.4207 24 11.8182C24 11.2157 23.5116 10.7273 22.9091 10.7273H17.3454C16.84 8.23756 14.6389 6.36364 12 6.36364Z" fill="black"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/bar-chart-square-02.svg b/app/components/base/icons/assets/vender/solid/development/bar-chart-square-02.svg
new file mode 100644
index 0000000..517d119
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/bar-chart-square-02.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="bar-chart-square-02">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M11.8925 1.33331H4.1078C3.75638 1.3333 3.45319 1.33329 3.20348 1.35369C2.93992 1.37523 2.67777 1.42277 2.42552 1.5513C2.04919 1.74305 1.74323 2.04901 1.55148 2.42533C1.42296 2.67759 1.37541 2.93973 1.35388 3.2033C1.33348 3.453 1.33349 3.75617 1.3335 4.10759V11.8923C1.33349 12.2438 1.33348 12.547 1.35388 12.7967C1.37541 13.0602 1.42296 13.3224 1.55148 13.5746C1.74323 13.951 2.04919 14.2569 2.42552 14.4487C2.67777 14.5772 2.93992 14.6247 3.20348 14.6463C3.45319 14.6667 3.75636 14.6667 4.10779 14.6666H11.8925C12.244 14.6667 12.5471 14.6667 12.7969 14.6463C13.0604 14.6247 13.3226 14.5772 13.5748 14.4487C13.9511 14.2569 14.2571 13.951 14.4488 13.5746C14.5774 13.3224 14.6249 13.0602 14.6465 12.7967C14.6669 12.547 14.6668 12.2438 14.6668 11.8924V4.1076C14.6668 3.75618 14.6669 3.45301 14.6465 3.2033C14.6249 2.93973 14.5774 2.67759 14.4488 2.42533C14.2571 2.04901 13.9511 1.74305 13.5748 1.5513C13.3226 1.42277 13.0604 1.37523 12.7969 1.35369C12.5471 1.33329 12.2439 1.3333 11.8925 1.33331ZM11.3335 4.66665C11.3335 4.29846 11.035 3.99998 10.6668 3.99998C10.2986 3.99998 10.0002 4.29846 10.0002 4.66665V11.3333C10.0002 11.7015 10.2986 12 10.6668 12C11.035 12 11.3335 11.7015 11.3335 11.3333V4.66665ZM8.00016 6.66665C8.36835 6.66665 8.66683 6.96512 8.66683 7.33331V11.3333C8.66683 11.7015 8.36835 12 8.00016 12C7.63197 12 7.3335 11.7015 7.3335 11.3333V7.33331C7.3335 6.96512 7.63197 6.66665 8.00016 6.66665ZM5.3335 9.33331C5.70169 9.33331 6.00016 9.63179 6.00016 9.99998V11.3333C6.00016 11.7015 5.70169 12 5.3335 12C4.96531 12 4.66683 11.7015 4.66683 11.3333V9.99998C4.66683 9.63179 4.96531 9.33331 5.3335 9.33331Z" fill="#155EEF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/container.svg b/app/components/base/icons/assets/vender/solid/development/container.svg
new file mode 100644
index 0000000..e5f1da9
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/container.svg
@@ -0,0 +1,5 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.29782 0.790031C8.12061 0.753584 7.93783 0.753584 7.76062 0.790031C7.55577 0.832161 7.37268 0.934712 7.22712 1.01624L7.18744 1.03841C6.01215 1.69134 4.02394 2.79644 2.90301 3.41952C2.63085 3.5708 2.49477 3.64644 2.44929 3.74641C2.40965 3.83357 2.4094 3.93356 2.4486 4.02091C2.49357 4.12111 2.62938 4.19751 2.90101 4.3503L7.76772 7.08785C7.8631 7.1415 7.91079 7.16832 7.96135 7.17884C8.0061 7.18814 8.05229 7.18814 8.09703 7.17884C8.1476 7.16832 8.19529 7.1415 8.29067 7.08785L13.1574 4.35029C13.429 4.1975 13.5649 4.12111 13.6098 4.02091C13.649 3.93355 13.6488 3.83356 13.6091 3.74641C13.5637 3.64644 13.4276 3.57079 13.1554 3.41951C12.0345 2.79644 10.0463 1.69134 8.871 1.03841L8.83132 1.01624C8.68576 0.934713 8.50267 0.832161 8.29782 0.790031Z" fill="#155EEF"/>
+<path d="M14.6932 5.92676C14.6929 5.62787 14.6928 5.47842 14.6297 5.39117C14.5748 5.31504 14.4902 5.26564 14.3969 5.25511C14.2899 5.24305 14.1594 5.31646 13.8984 5.46329L8.96774 8.23679C8.86877 8.29246 8.81928 8.3203 8.78326 8.35968C8.75139 8.39452 8.72729 8.43573 8.71254 8.48059C8.69588 8.53129 8.69588 8.58807 8.69588 8.70163V14.1518C8.69588 14.4499 8.69588 14.599 8.75856 14.6862C8.81326 14.7623 8.89744 14.8118 8.9905 14.8227C9.09716 14.8352 9.22706 14.763 9.48688 14.6188C10.5978 14.0019 12.6169 12.8807 13.8043 12.221L13.8464 12.1977C14.0005 12.1128 14.1943 12.0061 14.343 11.8447C14.4717 11.7051 14.569 11.5397 14.6286 11.3594C14.6975 11.1509 14.6966 10.9298 14.696 10.7538L14.6959 10.7058C14.6959 9.39704 14.6942 7.17087 14.6932 5.92676Z" fill="#155EEF"/>
+<path d="M6.57155 14.6187C6.83137 14.763 6.96128 14.8352 7.06793 14.8227C7.16099 14.8118 7.24518 14.7623 7.29987 14.6862C7.36255 14.599 7.36255 14.4499 7.36255 14.1518V8.70166C7.36255 8.5881 7.36255 8.53132 7.34589 8.48062C7.33114 8.43576 7.30704 8.39455 7.27517 8.35971C7.23915 8.32033 7.18966 8.29249 7.09069 8.23682L2.16004 5.4633C1.89902 5.31648 1.76851 5.24306 1.66154 5.25513C1.56823 5.26565 1.48367 5.31506 1.42869 5.39118C1.36566 5.47844 1.36553 5.62789 1.36528 5.92678C1.36424 7.17088 1.36255 9.39704 1.36255 10.7058L1.36243 10.7538C1.36179 10.9298 1.36099 11.1509 1.42986 11.3594C1.48941 11.5397 1.58676 11.7051 1.71539 11.8447C1.86417 12.0061 2.0579 12.1128 2.21199 12.1977L2.2541 12.221C3.44156 12.8807 5.46065 14.0019 6.57155 14.6187Z" fill="#155EEF"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/database-02.svg b/app/components/base/icons/assets/vender/solid/development/database-02.svg
new file mode 100644
index 0000000..85b6b4c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/database-02.svg
@@ -0,0 +1,5 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15.1956 4.66669V3.33335C15.1956 2.76539 14.8497 2.33041 14.4701 2.03126C14.083 1.72618 13.5641 1.48059 12.9824 1.28668C11.812 0.896551 10.2375 0.666687 8.52897 0.666687C6.8204 0.666687 5.24591 0.896551 4.07551 1.28668C3.4938 1.48059 2.97495 1.72618 2.58783 2.03126C2.20823 2.33041 1.8623 2.76539 1.8623 3.33335V4.66669C1.8623 5.23294 2.20443 5.66805 2.58368 5.96857C2.96958 6.27436 3.48705 6.52014 4.06786 6.71405C5.23637 7.10415 6.81113 7.33335 8.52897 7.33335C10.2468 7.33335 11.8216 7.10415 12.9901 6.71405C13.5709 6.52014 14.0884 6.27436 14.4743 5.96857C14.8535 5.66805 15.1956 5.23294 15.1956 4.66669ZM3.19564 3.33353C3.19564 3.33353 3.19576 3.33725 3.19767 3.34355C3.19994 3.35098 3.20552 3.36565 3.21902 3.38764C3.24732 3.43374 3.30502 3.50304 3.41313 3.58824C3.63325 3.76171 3.99308 3.94709 4.49715 4.11511C5.49832 4.44884 6.92383 4.66669 8.52897 4.66669C10.1341 4.66669 11.5596 4.44884 12.5608 4.11511C13.0649 3.94709 13.4247 3.76171 13.6448 3.58824C13.7529 3.50304 13.8106 3.43374 13.8389 3.38764C13.8524 3.36565 13.858 3.35098 13.8603 3.34355C13.8622 3.33716 13.8623 3.33335 13.8623 3.33335C13.8623 3.33335 13.8624 3.33006 13.8603 3.32316C13.858 3.31573 13.8524 3.30105 13.8389 3.27907C13.8106 3.23297 13.7529 3.16367 13.6448 3.07847C13.4247 2.905 13.0649 2.71962 12.5608 2.5516C11.5596 2.21787 10.1341 2.00002 8.52897 2.00002C6.92383 2.00002 5.49832 2.21787 4.49715 2.5516C3.99308 2.71962 3.63325 2.905 3.41313 3.07847C3.30502 3.16367 3.24732 3.23297 3.21902 3.27907C3.20552 3.30105 3.19994 3.31573 3.19767 3.32316C3.19563 3.32988 3.19564 3.33353 3.19564 3.33353Z" fill="#155EEF"/>
+<path d="M14.9234 7.00002C14.8447 7.00002 14.7705 7.03473 14.7155 7.09102C14.6407 7.16749 14.5613 7.23785 14.4802 7.30206C14.0939 7.60785 13.5759 7.85363 12.9945 8.04753C11.8249 8.43764 10.2485 8.66684 8.52896 8.66684C6.8094 8.66684 5.23307 8.43764 4.06339 8.04753C3.48201 7.85363 2.96401 7.60785 2.57773 7.30206C2.49661 7.23784 2.41719 7.16749 2.34244 7.09101C2.28743 7.03473 2.21322 7.00002 2.13452 7.00002C1.98418 7.00002 1.8623 7.12189 1.8623 7.27223V8.66669C1.8623 9.23294 2.20443 9.66805 2.58368 9.96857C2.96958 10.2744 3.48705 10.5201 4.06786 10.714C5.23637 11.1041 6.81113 11.3334 8.52897 11.3334C10.2468 11.3334 11.8216 11.1041 12.9901 10.714C13.5709 10.5201 14.0884 10.2744 14.4743 9.96857C14.8535 9.66805 15.1956 9.23294 15.1956 8.66669V7.27224C15.1956 7.1219 15.0738 7.00002 14.9234 7.00002Z" fill="#155EEF"/>
+<path d="M14.9234 11C14.8447 11 14.7705 11.0347 14.7155 11.091C14.6407 11.1675 14.5613 11.2378 14.4802 11.3021C14.0939 11.6079 13.5759 11.8536 12.9945 12.0475C11.8249 12.4376 10.2485 12.6668 8.52896 12.6668C6.8094 12.6668 5.23307 12.4376 4.06339 12.0475C3.48201 11.8536 2.96401 11.6079 2.57773 11.3021C2.49661 11.2378 2.41719 11.1675 2.34244 11.091C2.28743 11.0347 2.21322 11 2.13452 11C1.98418 11 1.8623 11.1219 1.8623 11.2722V12.6667C1.8623 13.2329 2.20443 13.668 2.58368 13.9686C2.96958 14.2744 3.48705 14.5201 4.06786 14.714C5.23637 15.1041 6.81113 15.3334 8.52897 15.3334C10.2468 15.3334 11.8216 15.1041 12.9901 14.714C13.5709 14.5201 14.0884 14.2744 14.4743 13.9686C14.8535 13.668 15.1956 13.2329 15.1956 12.6667V11.2722C15.1956 11.1219 15.0738 11 14.9234 11Z" fill="#155EEF"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/database-03.svg b/app/components/base/icons/assets/vender/solid/development/database-03.svg
new file mode 100644
index 0000000..461b2c0
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/database-03.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.66659 9.98845C10.1231 9.93732 11.4455 9.71981 12.461 9.38077C13.0418 9.18687 13.5593 8.94109 13.9452 8.6353C14.3245 8.33478 14.6666 7.89967 14.6666 7.33341V3.33341C14.6666 2.76545 14.3207 2.33047 13.9411 2.03132C13.5539 1.72624 13.0351 1.48065 12.4534 1.28675C11.283 0.896612 9.70849 0.666748 7.99992 0.666748C6.29135 0.666748 4.71686 0.896612 3.54646 1.28675C2.96474 1.48065 2.44589 1.72624 2.05878 2.03132C1.67918 2.33047 1.33325 2.76545 1.33325 3.33341V7.33341C1.33325 7.89967 1.67538 8.33478 2.05463 8.6353C2.44053 8.94109 2.958 9.18687 3.53881 9.38077C4.55435 9.71981 5.87675 9.93732 7.33325 9.98845V11.4472C6.76498 11.6481 6.31458 12.0985 6.11372 12.6667H1.99992C1.63173 12.6667 1.33325 12.9652 1.33325 13.3334C1.33325 13.7016 1.63173 14.0001 1.99992 14.0001H6.11372C6.38828 14.7769 7.12911 15.3334 7.99992 15.3334C8.87073 15.3334 9.61156 14.7769 9.88612 14.0001H13.9999C14.3681 14.0001 14.6666 13.7016 14.6666 13.3334C14.6666 12.9652 14.3681 12.6667 13.9999 12.6667H9.88612C9.68526 12.0985 9.23486 11.6481 8.66659 11.4472V9.98845ZM2.66659 3.33337C2.66659 3.33337 2.66657 3.32994 2.66862 3.32322C2.67089 3.31579 2.67647 3.30111 2.68997 3.27913C2.71827 3.23303 2.77597 3.16373 2.88408 3.07853C3.1042 2.90506 3.46403 2.71968 3.9681 2.55166C4.96927 2.21793 6.39478 2.00008 7.99992 2.00008C9.60506 2.00008 11.0306 2.21793 12.0317 2.55166C12.5358 2.71968 12.8956 2.90506 13.1158 3.07853C13.2239 3.16373 13.2816 3.23303 13.3099 3.27913C13.3234 3.30111 13.329 3.31579 13.3312 3.32322C13.3333 3.32994 13.3333 3.33337 13.3333 3.33337C13.3333 3.33337 13.3332 3.33722 13.3312 3.34361C13.329 3.35104 13.3234 3.36572 13.3099 3.3877C13.2816 3.4338 13.2239 3.5031 13.1158 3.5883C12.8956 3.76177 12.5358 3.94715 12.0317 4.11517C11.0306 4.4489 9.60506 4.66675 7.99992 4.66675C6.39478 4.66675 4.96927 4.4489 3.9681 4.11517C3.46403 3.94715 3.1042 3.76177 2.88408 3.5883C2.77597 3.5031 2.71827 3.4338 2.68997 3.3877C2.67647 3.36572 2.67089 3.35104 2.66862 3.34361C2.6667 3.33731 2.66659 3.33337 2.66659 3.33337Z" fill="#155EEF"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/file-heart-02.svg b/app/components/base/icons/assets/vender/solid/development/file-heart-02.svg
new file mode 100644
index 0000000..fa778b9
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/file-heart-02.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-heart-02">
+<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M5.8392 0.666687H10.1609C10.6976 0.666679 11.1405 0.666673 11.5013 0.696151C11.876 0.726767 12.2205 0.792477 12.544 0.957337C13.0458 1.213 13.4538 1.62095 13.7094 2.12271C13.8743 2.44627 13.94 2.79074 13.9706 3.16547C14.0001 3.52626 14.0001 3.96917 14.0001 4.50581V10.0803C13.7558 9.96135 13.4846 9.88753 13.1964 9.87049C13.1342 8.82702 12.2682 8.00002 11.2091 8.00002C10.5956 8.00002 10.0396 8.36134 9.7904 8.922L9.13298 10.4012C8.13309 10.4365 7.33333 11.2582 7.33333 12.2667V14.1334C7.33333 14.3187 7.36034 14.4977 7.41064 14.6667L5.24168 14.6667C4.71142 14.667 4.31765 14.6672 3.97655 14.5758C3.0563 14.3292 2.33751 13.6104 2.09093 12.6902C1.99953 12.3491 1.99974 11.9553 2.00003 11.4251L2.00006 4.50582C2.00006 3.96918 2.00005 3.52627 2.02953 3.16547C2.06014 2.79074 2.12585 2.44627 2.29071 2.12271C2.54638 1.62095 2.95432 1.213 3.45609 0.957337C3.77965 0.792477 4.12412 0.726767 4.49885 0.696151C4.85964 0.666673 5.30256 0.666679 5.8392 0.666687ZM4.66667 4.66669C4.66667 4.2985 4.96514 4.00002 5.33333 4.00002H10.6667C11.0349 4.00002 11.3333 4.2985 11.3333 4.66669C11.3333 5.03488 11.0349 5.33335 10.6667 5.33335H5.33333C4.96514 5.33335 4.66667 5.03488 4.66667 4.66669ZM4.66667 7.33335C4.66667 6.96516 4.96514 6.66669 5.33333 6.66669H8.33333C8.70152 6.66669 9 6.96516 9 7.33335C9 7.70154 8.70152 8.00002 8.33333 8.00002H5.33333C4.96514 8.00002 4.66667 7.70154 4.66667 7.33335ZM4.66667 10C4.66667 9.63183 4.96514 9.33335 5.33333 9.33335H6C6.36819 9.33335 6.66667 9.63183 6.66667 10C6.66667 10.3682 6.36819 10.6667 6 10.6667H5.33333C4.96514 10.6667 4.66667 10.3682 4.66667 10Z" fill="#155EEF"/>
+<path id="Icon (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M10.7044 9.32812C10.7931 9.12859 10.9909 9 11.2093 9C11.7565 9 12.2002 9.44364 12.2002 9.99089V10.8667H13.0677C13.7623 10.8667 14.2934 11.4858 14.1878 12.1723L13.9006 14.039C13.8156 14.5919 13.3399 15 12.7805 15H9.20016C8.72152 15 8.3335 14.612 8.3335 14.1333V12.2667C8.3335 11.788 8.72152 11.4 9.20016 11.4H9.78354L10.7044 9.32812Z" fill="#155EEF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/pattern-recognition.svg b/app/components/base/icons/assets/vender/solid/development/pattern-recognition.svg
new file mode 100644
index 0000000..f026dff
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/pattern-recognition.svg
@@ -0,0 +1,11 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.72727 22C4.18787 22 3.66058 21.84 3.21208 21.5404C2.76359 21.2407 2.41402 20.8148 2.2076 20.3164C2.00118 19.8181 1.94717 19.2697 2.05241 18.7407C2.15764 18.2116 2.41739 17.7257 2.7988 17.3443C3.18022 16.9628 3.66617 16.7031 4.19521 16.5979C4.72425 16.4926 5.27261 16.5466 5.77096 16.7531C6.2693 16.9595 6.69524 17.309 6.99492 17.7575C7.2946 18.206 7.45455 18.7333 7.45455 19.2727C7.45455 19.996 7.16721 20.6897 6.65575 21.2012C6.14429 21.7127 5.45059 22 4.72727 22Z" fill="#212121"/>
+<path d="M12 9.27273C11.4606 9.27273 10.9333 9.43268 10.4848 9.73236C10.0363 10.032 9.68675 10.458 9.48033 10.9563C9.27391 11.4547 9.2199 12.003 9.32513 12.5321C9.43036 13.0611 9.69011 13.5471 10.0715 13.9285C10.4529 14.3099 10.9389 14.5696 11.4679 14.6749C11.997 14.7801 12.5453 14.7261 13.0437 14.5197C13.542 14.3133 13.968 13.9637 14.2676 13.5152C14.5673 13.0667 14.7273 12.5394 14.7273 12C14.7273 11.2767 14.4399 10.583 13.9285 10.0715C13.417 9.56006 12.7233 9.27273 12 9.27273Z" fill="#212121"/>
+<path d="M4.72727 2C4.18787 2 3.66058 2.15995 3.21208 2.45963C2.76358 2.7593 2.41402 3.18525 2.2076 3.68359C2.00118 4.18193 1.94717 4.7303 2.05241 5.25934C2.15764 5.78838 2.41738 6.27433 2.7988 6.65575C3.18022 7.03716 3.66617 7.29691 4.19521 7.40214C4.72425 7.50737 5.27261 7.45336 5.77096 7.24694C6.2693 7.04052 6.69524 6.69096 6.99492 6.24246C7.29459 5.79397 7.45455 5.26668 7.45455 4.72727C7.45455 4.00395 7.16721 3.31026 6.65575 2.7988C6.14428 2.28734 5.45059 2 4.72727 2Z" fill="#212121"/>
+<path d="M19.2727 2C18.7333 2 18.206 2.15995 17.7575 2.45963C17.309 2.75931 16.9595 3.18525 16.7531 3.68359C16.5466 4.18194 16.4926 4.7303 16.5979 5.25934C16.7031 5.78838 16.9628 6.27433 17.3443 6.65575C17.7257 7.03716 18.2116 7.29691 18.7407 7.40214C19.2697 7.50737 19.8181 7.45337 20.3164 7.24694C20.8148 7.04052 21.2407 6.69096 21.5404 6.24247C21.84 5.79397 22 5.26668 22 4.72727C22 4.00396 21.7127 3.31026 21.2012 2.7988C20.6897 2.28734 19.996 2 19.2727 2Z" fill="#212121"/>
+<path d="M19.2727 16.5455C18.7333 16.5455 18.206 16.7054 17.7575 17.0051C17.309 17.3048 16.9595 17.7307 16.7531 18.229C16.5466 18.7274 16.4926 19.2758 16.5979 19.8048C16.7031 20.3338 16.9628 20.8198 17.3443 21.2012C17.7257 21.5826 18.2116 21.8424 18.7407 21.9476C19.2697 22.0528 19.8181 21.9988 20.3164 21.7924C20.8148 21.586 21.2407 21.2364 21.5404 20.7879C21.84 20.3394 22 19.8121 22 19.2727C22 18.5494 21.7127 17.8557 21.2012 17.3443C20.6897 16.8328 19.996 16.5455 19.2727 16.5455Z" fill="#212121"/>
+<path d="M7.45455 9.27273H2V14.7273H7.45455V9.27273Z" fill="#212121"/>
+<path d="M22 9.27273H16.5455V14.7273H22V9.27273Z" fill="#212121"/>
+<path d="M14.7273 2H9.27273V7.45455H14.7273V2Z" fill="#212121"/>
+<path d="M14.7273 16.5455H9.27273V22H14.7273V16.5455Z" fill="#212121"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/prompt-engineering.svg b/app/components/base/icons/assets/vender/solid/development/prompt-engineering.svg
new file mode 100644
index 0000000..65915e3
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/prompt-engineering.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="prompt-engineering">
+<g id="Vector">
+<path d="M5.17263 1.33331H10.8277C11.3643 1.33331 11.8073 1.3333 12.168 1.36278C12.5428 1.39339 12.8872 1.4591 13.2108 1.62396C13.7126 1.87963 14.1205 2.28758 14.3762 2.78934C14.541 3.1129 14.6068 3.45737 14.6374 3.8321C14.6668 4.19289 14.6668 4.63579 14.6668 5.17243V9.61535L14.2671 9.51541C13.9093 9.42597 13.7127 9.37607 13.5686 9.33055C13.506 9.31079 13.4738 9.2979 13.4609 9.29232C13.427 9.26909 13.3977 9.23979 13.3745 9.2059C13.3689 9.19304 13.356 9.16081 13.3363 9.09826C13.2907 8.95416 13.2408 8.7575 13.1514 8.39975L12.9504 7.59575C12.7649 6.85381 12.0983 6.33331 11.3335 6.33331C10.5687 6.33331 9.90208 6.85381 9.71659 7.59576L9.51559 8.39975C9.42616 8.7575 9.37626 8.95416 9.33074 9.09826C9.31097 9.16081 9.29808 9.19303 9.29251 9.2059C9.26927 9.23979 9.23997 9.26909 9.20609 9.29232C9.19322 9.2979 9.16099 9.31079 9.09844 9.33055C8.95434 9.37607 8.75769 9.42597 8.39993 9.51541L7.59594 9.71641C6.85399 9.9019 6.3335 10.5685 6.3335 11.3333C6.3335 12.0981 6.85399 12.7647 7.59594 12.9502L8.39993 13.1512C8.75769 13.2407 8.95434 13.2906 9.09844 13.3361C9.16099 13.3558 9.19322 13.3687 9.20609 13.3743C9.23997 13.3975 9.26927 13.4268 9.29251 13.4607C9.29808 13.4736 9.31098 13.5058 9.33074 13.5684C9.37626 13.7125 9.42616 13.9091 9.51559 14.2669L9.61553 14.6666H5.17268C4.63601 14.6667 4.19309 14.6667 3.83228 14.6372C3.45755 14.6066 3.11308 14.5409 2.78952 14.376C2.28776 14.1203 1.87981 13.7124 1.62415 13.2106C1.45929 12.8871 1.39358 12.5426 1.36296 12.1679C1.33348 11.8071 1.33349 11.3642 1.3335 10.8275V5.17245C1.33349 4.63581 1.33348 4.19289 1.36296 3.8321C1.39358 3.45737 1.45929 3.1129 1.62415 2.78934C1.87981 2.28757 2.28776 1.87963 2.78952 1.62396C3.11308 1.4591 3.45755 1.39339 3.83228 1.36278C4.19307 1.3333 4.636 1.33331 5.17263 1.33331ZM4.66683 3.99998C4.29864 3.99998 4.00016 4.29846 4.00016 4.66665C4.00016 5.03484 4.29864 5.33331 4.66683 5.33331H4.6735C5.04169 5.33331 5.34016 5.03484 5.34016 4.66665C5.34016 4.29846 5.04169 3.99998 4.6735 3.99998H4.66683ZM6.66683 3.99998C6.29864 3.99998 6.00016 4.29846 6.00016 4.66665C6.00016 5.03484 6.29864 5.33331 6.66683 5.33331H6.6735C7.04169 5.33331 7.34016 5.03484 7.34016 4.66665C7.34016 4.29846 7.04169 3.99998 6.6735 3.99998H6.66683ZM8.66683 3.99998C8.29864 3.99998 8.00016 4.29846 8.00016 4.66665C8.00016 5.03484 8.29864 5.33331 8.66683 5.33331H8.6735C9.04169 5.33331 9.34016 5.03484 9.34016 4.66665C9.34016 4.29846 9.04169 3.99998 8.6735 3.99998H8.66683Z" fill="#155EEF"/>
+<path d="M11.3335 7.49998C11.5629 7.49998 11.7629 7.65613 11.8186 7.87871L12.0196 8.68271C12.1974 9.39402 12.2642 9.63563 12.3859 9.82588C12.5029 10.0087 12.6581 10.1639 12.8409 10.2809C13.0312 10.4026 13.2728 10.4694 13.9841 10.6472L14.7881 10.8482C15.0107 10.9039 15.1668 11.1039 15.1668 11.3333C15.1668 11.5627 15.0107 11.7627 14.7881 11.8184L13.9841 12.0194C13.2728 12.1972 13.0312 12.264 12.8409 12.3857C12.6581 12.5027 12.5029 12.658 12.3859 12.8407C12.2642 13.031 12.1974 13.2726 12.0196 13.9839L11.8186 14.7879C11.7629 15.0105 11.5629 15.1666 11.3335 15.1666C11.1041 15.1666 10.9041 15.0105 10.8484 14.7879L10.6474 13.9839C10.4696 13.2726 10.4028 13.031 10.2811 12.8407C10.1641 12.658 10.0089 12.5027 9.82606 12.3857C9.63581 12.264 9.39421 12.1972 8.68289 12.0194L7.8789 11.8184C7.65631 11.7627 7.50016 11.5627 7.50016 11.3333C7.50016 11.1039 7.65631 10.9039 7.8789 10.8482L8.68289 10.6472C9.39421 10.4694 9.63581 10.4026 9.82606 10.2809C10.0089 10.1639 10.1641 10.0087 10.2811 9.82588C10.4028 9.63563 10.4696 9.39402 10.6474 8.6827L10.8484 7.87871C10.9041 7.65613 11.1041 7.49998 11.3335 7.49998Z" fill="#155EEF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/puzzle-piece-01.svg b/app/components/base/icons/assets/vender/solid/development/puzzle-piece-01.svg
new file mode 100644
index 0000000..c2efc73
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/puzzle-piece-01.svg
@@ -0,0 +1,5 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="puzzle-piece-01">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M4.83333 2.99999C4.83333 1.71133 5.878 0.666656 7.16667 0.666656C8.45533 0.666656 9.5 1.71133 9.5 2.99999V3.33332L9.52285 3.33332C9.96938 3.33332 10.338 3.33331 10.6397 3.3539C10.9525 3.37525 11.2419 3.42093 11.5205 3.53631C12.1739 3.80696 12.693 4.32609 12.9637 4.9795C13.0791 5.25804 13.1247 5.54744 13.1461 5.8603C13.1558 6.0027 13.1609 6.15998 13.1636 6.33332H13.5C14.7887 6.33332 15.8333 7.37799 15.8333 8.66666C15.8333 9.95532 14.7887 11 13.5 11H13.1667V11.4942C13.1667 12.0308 13.1667 12.4737 13.1372 12.8345C13.1066 13.2093 13.0409 13.5537 12.876 13.8773C12.6204 14.3791 12.2124 14.787 11.7106 15.0427C11.3871 15.2075 11.0426 15.2732 10.6679 15.3039C10.3071 15.3333 9.86419 15.3333 9.32755 15.3333H8.83333C8.46514 15.3333 8.16667 15.0348 8.16667 14.6667V13.5C8.16667 13.0398 7.79357 12.6667 7.33333 12.6667C6.8731 12.6667 6.5 13.0398 6.5 13.5V14.6667C6.5 15.0348 6.20152 15.3333 5.83333 15.3333H5.00578C4.46914 15.3333 4.02624 15.3333 3.66545 15.3039C3.29072 15.2732 2.94625 15.2075 2.62269 15.0427C2.12093 14.787 1.71298 14.3791 1.45732 13.8773C1.29246 13.5537 1.22675 13.2093 1.19613 12.8345C1.16665 12.4737 1.16666 12.0308 1.16667 11.4942L1.16667 10.3333C1.16667 9.96513 1.46514 9.66666 1.83333 9.66666H2.83333C3.38562 9.66666 3.83333 9.21894 3.83333 8.66666C3.83333 8.11437 3.38562 7.66666 2.83333 7.66666H1.83333C1.46514 7.66666 1.16667 7.36818 1.16667 6.99999L1.16667 6.97715C1.16666 6.53062 1.16666 6.16204 1.18724 5.8603C1.20859 5.54744 1.25428 5.25804 1.36965 4.9795C1.64031 4.32609 2.15944 3.80696 2.81284 3.53631C3.09139 3.42093 3.38078 3.37525 3.69364 3.3539C3.99538 3.33331 4.36396 3.33332 4.81048 3.33332L4.83333 3.33332L4.83333 2.99999Z" fill="#155EEF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/semantic.svg b/app/components/base/icons/assets/vender/solid/development/semantic.svg
new file mode 100644
index 0000000..9b30e1c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/semantic.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M16.5833 12.945C16.4856 13.3276 16.2038 14.272 15.7382 15.7784H17.4432C17.0038 14.3674 16.7569 13.5692 16.7025 13.3841C16.6493 13.1998 16.609 13.0532 16.5833 12.945Z" fill="#212121"/>
+<path d="M21.1667 9.33333H12C11.5138 9.33333 11.0475 9.52649 10.7036 9.87031C10.3598 10.2141 10.1667 10.6804 10.1667 11.1667V19.4167C10.1667 19.9029 10.3598 20.3692 10.7036 20.713C11.0475 21.0568 11.5138 21.25 12 21.25H17.5L21.1667 24V21.25C21.6529 21.25 22.1192 21.0568 22.463 20.713C22.8068 20.3692 23 19.9029 23 19.4167V11.1667C23 10.6804 22.8068 10.2141 22.463 9.87031C22.1192 9.52649 21.6529 9.33333 21.1667 9.33333ZM18.2507 18.5L17.775 16.9417H15.3917L14.9159 18.5H13.4208L15.7308 11.9293H17.4267L19.7458 18.5H18.2507Z" fill="#212121"/>
+<path d="M12 2H2.83333C2.3471 2 1.88079 2.19315 1.53697 2.53697C1.19315 2.88079 1 3.3471 1 3.83333V12.0833C1 12.5696 1.19315 13.0359 1.53697 13.3797C1.88079 13.7235 2.3471 13.9167 2.83333 13.9167V16.6667L6.5 13.9167H9.25V11.1667C9.25381 11.0459 9.26606 10.9255 9.28667 10.8064C8.64229 10.5527 8.0315 10.2208 7.468 9.81825C6.5802 10.4316 5.59355 10.8877 4.55117 11.1667C4.394 10.6965 4.15573 10.2575 3.84717 9.86958C4.76378 9.70375 5.64426 9.37861 6.44867 8.90892C6.07755 8.50417 5.75993 8.05346 5.50358 7.56783C5.29175 7.16889 5.12217 6.74892 4.99758 6.31475C4.56583 6.31475 4.3165 6.32942 3.94983 6.35875V5.03233C4.30266 5.0703 4.65741 5.08744 5.01225 5.08367H6.63292V4.64367C6.63379 4.48979 6.61904 4.33623 6.58892 4.18533H8.05833C8.02877 4.33229 8.01403 4.48185 8.01433 4.63175V5.07908H9.756C10.1108 5.08303 10.4656 5.06589 10.8184 5.02775V6.35875C10.4958 6.32942 10.2098 6.31475 9.778 6.31475C9.67623 6.80565 9.51074 7.28115 9.28575 7.72917C9.06864 8.16083 8.79489 8.56159 8.47175 8.92083C8.89523 9.17057 9.34617 9.37051 9.81558 9.51667C10.0695 9.17655 10.399 8.90012 10.7781 8.70922C11.1573 8.51831 11.5755 8.41816 12 8.41667H13.8333V3.83333C13.8333 3.3471 13.6402 2.88079 13.2964 2.53697C12.9525 2.19315 12.4862 2 12 2Z" fill="#212121"/>
+<path d="M7.43133 8.0885C7.87722 7.58102 8.19195 6.97201 8.348 6.31475H6.40833C6.59708 6.98164 6.94861 7.59116 7.43133 8.0885Z" fill="#212121"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/terminal-square.svg b/app/components/base/icons/assets/vender/solid/development/terminal-square.svg
new file mode 100644
index 0000000..ccab5f6
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/terminal-square.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="terminal-square">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M8.91927 1H3.08073C2.81716 0.999992 2.58977 0.999984 2.40249 1.01529C2.20481 1.03144 2.00821 1.06709 1.81902 1.16349C1.53677 1.3073 1.3073 1.53677 1.16349 1.81902C1.06709 2.00821 1.03144 2.20481 1.01529 2.40249C0.999984 2.58977 0.999992 2.81714 1 3.08071V8.91927C0.999992 9.18284 0.999984 9.41023 1.01529 9.59752C1.03144 9.79519 1.06709 9.9918 1.16349 10.181C1.3073 10.4632 1.53677 10.6927 1.81902 10.8365C2.00821 10.9329 2.20481 10.9686 2.40249 10.9847C2.58977 11 2.81715 11 3.08072 11H8.91928C9.18285 11 9.41023 11 9.59752 10.9847C9.79519 10.9686 9.9918 10.9329 10.181 10.8365C10.4632 10.6927 10.6927 10.4632 10.8365 10.181C10.9329 9.9918 10.9686 9.79519 10.9847 9.59752C11 9.41023 11 9.18285 11 8.91928V3.08072C11 2.81715 11 2.58977 10.9847 2.40249C10.9686 2.20481 10.9329 2.00821 10.8365 1.81902C10.6927 1.53677 10.4632 1.3073 10.181 1.16349C9.9918 1.06709 9.79519 1.03144 9.59752 1.01529C9.41023 0.999984 9.18284 0.999992 8.91927 1ZM3.85355 4.14645C3.65829 3.95118 3.34171 3.95118 3.14645 4.14645C2.95118 4.34171 2.95118 4.65829 3.14645 4.85355L4.29289 6L3.14645 7.14645C2.95118 7.34171 2.95118 7.65829 3.14645 7.85355C3.34171 8.04882 3.65829 8.04882 3.85355 7.85355L5.35355 6.35355C5.54882 6.15829 5.54882 5.84171 5.35355 5.64645L3.85355 4.14645ZM6.5 7C6.22386 7 6 7.22386 6 7.5C6 7.77614 6.22386 8 6.5 8H8.5C8.77614 8 9 7.77614 9 7.5C9 7.22386 8.77614 7 8.5 7H6.5Z" fill="#B54708"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/development/variable-02.svg b/app/components/base/icons/assets/vender/solid/development/variable-02.svg
new file mode 100644
index 0000000..75ad244
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/development/variable-02.svg
@@ -0,0 +1,9 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="variable-02">
+<g id="Vector">
+<path d="M13.9986 8.76189C14.6132 8.04115 15.5117 7.625 16.459 7.625H16.5486C17.1009 7.625 17.5486 8.07272 17.5486 8.625C17.5486 9.17728 17.1009 9.625 16.5486 9.625H16.459C16.0994 9.625 15.7564 9.78289 15.5205 10.0595L13.1804 12.8039L13.9213 15.4107C13.9372 15.4666 13.9859 15.5 14.0355 15.5H15.4296C15.9819 15.5 16.4296 15.9477 16.4296 16.5C16.4296 17.0523 15.9819 17.5 15.4296 17.5H14.0355C13.0858 17.5 12.2562 16.8674 11.9975 15.9575L11.621 14.6328L10.1457 16.3631C9.5311 17.0839 8.63257 17.5 7.68532 17.5H7.59564C7.04336 17.5 6.59564 17.0523 6.59564 16.5C6.59564 15.9477 7.04336 15.5 7.59564 15.5H7.68532C8.04487 15.5 8.38789 15.3421 8.62379 15.0655L10.964 12.3209L10.2231 9.71433C10.2072 9.65839 10.1586 9.625 10.1089 9.625H8.71484C8.16256 9.625 7.71484 9.17728 7.71484 8.625C7.71484 8.07272 8.16256 7.625 8.71484 7.625H10.1089C11.0586 7.625 11.8883 8.25756 12.1469 9.16754L12.5234 10.4921L13.9986 8.76189Z" fill="black"/>
+<path d="M5.429 3C3.61372 3 2.143 4.47071 2.143 6.286V10.4428L1.29289 11.2929C1.10536 11.4804 1 11.7348 1 12C1 12.2652 1.10536 12.5196 1.29289 12.7071L2.143 13.5572V17.714C2.143 19.5293 3.61372 21 5.429 21C5.98128 21 6.429 20.5523 6.429 20C6.429 19.4477 5.98128 19 5.429 19C4.71828 19 4.143 18.4247 4.143 17.714V13.143C4.143 12.8778 4.03764 12.6234 3.85011 12.4359L3.41421 12L3.85011 11.5641C4.03764 11.3766 4.143 11.1222 4.143 10.857V6.286C4.143 5.57528 4.71828 5 5.429 5C5.98128 5 6.429 4.55228 6.429 4C6.429 3.44772 5.98128 3 5.429 3Z" fill="black"/>
+<path d="M18.5708 3C18.0185 3 17.5708 3.44772 17.5708 4C17.5708 4.55228 18.0185 5 18.5708 5C19.2815 5 19.8568 5.57529 19.8568 6.286V10.857C19.8568 11.1222 19.9622 11.3766 20.1497 11.5641L20.5856 12L20.1497 12.4359C19.9622 12.6234 19.8568 12.8778 19.8568 13.143V17.714C19.8568 18.4244 19.2808 19 18.5708 19C18.0185 19 17.5708 19.4477 17.5708 20C17.5708 20.5523 18.0185 21 18.5708 21C20.3848 21 21.8568 19.5296 21.8568 17.714V13.5572L22.7069 12.7071C23.0974 12.3166 23.0974 11.6834 22.7069 11.2929L21.8568 10.4428V6.286C21.8568 4.47071 20.3861 3 18.5708 3Z" fill="black"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/editor/brush-01.svg b/app/components/base/icons/assets/vender/solid/editor/brush-01.svg
new file mode 100644
index 0000000..c58c071
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/editor/brush-01.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M17.264 2.20765C18.5274 1.0378 20.4895 1.07552 21.707 2.29307C22.9246 3.51061 22.9623 5.47268 21.7924 6.73612L15.4019 13.638C15.008 14.0634 14.811 14.2761 14.579 14.3585C14.3751 14.4309 14.1531 14.4352 13.9465 14.3707C13.7115 14.2973 13.5065 14.0923 13.0965 13.6823L10.3178 10.9036C9.9078 10.4936 9.7028 10.2886 9.62943 10.0536C9.56493 9.84699 9.5692 9.62504 9.6416 9.42107C9.72395 9.18906 9.93667 8.9921 10.3621 8.59817L17.264 2.20765Z" fill="black"/>
+<path d="M8.76212 12.1763C8.35165 11.7659 8.14641 11.5606 7.9013 11.4888C7.7037 11.4308 7.43858 11.4436 7.24747 11.5203C7.01041 11.6154 6.86226 11.7953 6.56595 12.1551C6.46827 12.2737 6.37864 12.398 6.30066 12.53C6.03001 12.9883 5.8908 13.5013 5.88405 14.0163C4.608 13.9077 3.29445 14.3416 2.31799 15.318C1.28682 16.3492 1.34471 17.8002 1.38417 18.7893L1.38921 18.9154C1.43381 20.027 1.46675 20.848 1.11009 21.5439C0.951191 21.8539 0.965076 22.2242 1.14673 22.5215C1.32839 22.8187 1.65165 23 2 23C2.27235 23 2.58299 23.0081 2.91511 23.0167C3.66655 23.0362 4.52805 23.0586 5.30424 22.9968C6.44876 22.9057 7.7418 22.6221 8.68195 21.682C9.65838 20.7056 10.0923 19.3921 9.98366 18.1161C10.4987 18.1093 11.0118 17.9701 11.4701 17.6994C11.6021 17.6215 11.7264 17.5318 11.845 17.4341C12.2048 17.1378 12.3847 16.9897 12.4798 16.7526C12.5565 16.5615 12.5693 16.2964 12.5113 16.0988C12.4395 15.8537 12.2342 15.6484 11.8238 15.238L8.76212 12.1763Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/editor/citations.svg b/app/components/base/icons/assets/vender/solid/editor/citations.svg
new file mode 100644
index 0000000..5405495
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/editor/citations.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="citations">
+<path id="Subtract" d="M0.666992 7.99996C0.666992 3.94987 3.95024 0.666626 8.00033 0.666626C12.0504 0.666626 15.3337 3.94987 15.3337 7.99996C15.3337 12.05 12.0504 15.3333 8.00033 15.3333C3.95024 15.3333 0.666992 12.05 0.666992 7.99996ZM4.66699 7.9801V9.97196H7.35742V7.48922H5.87533C5.85644 7.21231 5.90365 6.94484 6.01693 6.68681C6.2372 6.19592 6.66829 5.84979 7.31022 5.6484V4.66663C6.44803 4.83655 5.79036 5.19527 5.33724 5.7428C4.89041 6.29032 4.66699 7.03609 4.66699 7.9801ZM10.0264 6.70569C10.2466 6.19592 10.6746 5.84349 11.3102 5.6484V4.66663C10.4732 4.83655 9.82183 5.19212 9.35612 5.73336C8.8967 6.27459 8.66699 7.02351 8.66699 7.9801V9.97196H11.3574V7.48922H9.87533C9.85015 7.23748 9.9005 6.9763 10.0264 6.70569Z" fill="#FD853A"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/editor/colors.svg b/app/components/base/icons/assets/vender/solid/editor/colors.svg
new file mode 100644
index 0000000..b01556c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/editor/colors.svg
@@ -0,0 +1,9 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="colors">
+<g id="Solid">
+<path d="M13.4494 13.2298C12.9854 13.3409 12.5002 13.3999 12 13.3999C10.2804 13.3999 8.72326 12.6997 7.59953 11.5677C6.4872 10.4471 5.8 8.90382 5.8 7.20007C5.8 3.77586 8.57584 1 12 1C15.4241 1 18.2 3.77586 18.2 7.20007C18.2 8.44569 17.8327 9.60551 17.2005 10.5771C16.3665 11.8588 15.0715 12.8131 13.5506 13.2047C13.517 13.2133 13.4833 13.2217 13.4494 13.2298Z" fill="black"/>
+<path d="M15.1476 14.7743C16.6646 14.1431 17.9513 13.0695 18.8465 11.7146C19.0004 11.4817 19.0773 11.3652 19.1762 11.3066C19.2615 11.2561 19.3659 11.2312 19.4648 11.2379C19.5795 11.2457 19.6773 11.3015 19.8728 11.4133C21.7413 12.4817 23 14.4946 23 16.7999C23 20.2241 20.2242 23 16.8 23C15.9123 23 15.0689 22.8139 14.3059 22.4782C14.0549 22.3678 13.9294 22.3126 13.8502 22.2049C13.7822 22.1126 13.7468 21.9922 13.7539 21.8777C13.7622 21.7444 13.8565 21.6018 14.045 21.3167C14.8373 20.1184 15.3234 18.6997 15.3917 17.1723C15.3969 17.0566 15.3996 16.9402 15.4 16.8233L15.4 16.7999C15.4 16.1888 15.333 15.5926 15.2057 15.0185C15.1876 14.9366 15.1682 14.8552 15.1476 14.7743Z" fill="black"/>
+<path d="M4.12723 11.4133C4.32273 11.3015 4.42049 11.2457 4.53516 11.2379C4.63414 11.2312 4.73848 11.2561 4.82382 11.3066C4.92269 11.3652 4.99964 11.4817 5.15355 11.7146C6.62074 13.9352 9.13929 15.4001 12 15.4001C12.4146 15.4001 12.822 15.3694 13.2201 15.31L13.2263 15.3357C13.3398 15.8045 13.4 16.2947 13.4 16.7999L13.4 16.8214C13.3997 16.9056 13.3977 16.9895 13.3941 17.0728C13.2513 20.3704 10.5327 23 7.2 23C3.77584 23 1 20.2241 1 16.7999C1 14.4946 2.25869 12.4817 4.12723 11.4133Z" fill="black"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/editor/paragraph.svg b/app/components/base/icons/assets/vender/solid/editor/paragraph.svg
new file mode 100644
index 0000000..be8afce
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/editor/paragraph.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M2 6.5C2 5.67157 2.67157 5 3.5 5H20.5C21.3284 5 22 5.67157 22 6.5C22 7.32843 21.3284 8 20.5 8H3.5C2.67157 8 2 7.32843 2 6.5Z" fill="black"/>
+<path d="M2 12.5C2 11.6716 2.67157 11 3.5 11H20.5C21.3284 11 22 11.6716 22 12.5C22 13.3284 21.3284 14 20.5 14H3.5C2.67157 14 2 13.3284 2 12.5Z" fill="black"/>
+<path d="M2 18.5C2 17.6716 2.67157 17 3.5 17H12.5C13.3284 17 14 17.6716 14 18.5C14 19.3284 13.3284 20 12.5 20H3.5C2.67157 20 2 19.3284 2 18.5Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/editor/type-square.svg b/app/components/base/icons/assets/vender/solid/editor/type-square.svg
new file mode 100644
index 0000000..6e402f8
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/editor/type-square.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.7587 2H16.2413C17.0463 1.99999 17.7106 1.99998 18.2518 2.0442C18.8139 2.09012 19.3306 2.18868 19.816 2.43598C20.5686 2.81947 21.1805 3.43139 21.564 4.18404C21.8113 4.66938 21.9099 5.18608 21.9558 5.74818C22 6.28937 22 6.95372 22 7.75868V16.2413C22 17.0463 22 17.7106 21.9558 18.2518C21.9099 18.8139 21.8113 19.3306 21.564 19.816C21.1805 20.5686 20.5686 21.1805 19.816 21.564C19.3306 21.8113 18.8139 21.9099 18.2518 21.9558C17.7106 22 17.0463 22 16.2413 22H7.75868C6.95372 22 6.28937 22 5.74818 21.9558C5.18608 21.9099 4.66938 21.8113 4.18404 21.564C3.43139 21.1805 2.81947 20.5686 2.43598 19.816C2.18868 19.3306 2.09012 18.8139 2.0442 18.2518C1.99998 17.7106 1.99999 17.0463 2 16.2413V7.75869C1.99999 6.95373 1.99998 6.28936 2.0442 5.74818C2.09012 5.18608 2.18868 4.66938 2.43598 4.18404C2.81947 3.43139 3.43139 2.81947 4.18404 2.43598C4.66938 2.18868 5.18608 2.09012 5.74818 2.0442C6.28936 1.99998 6.95375 1.99999 7.7587 2ZM7 7C7 6.44772 7.44772 6 8 6H16C16.5523 6 17 6.44772 17 7C17 7.55229 16.5523 8 16 8H13V17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V8H8C7.44772 8 7 7.55229 7 7Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/education/beaker-02.svg b/app/components/base/icons/assets/vender/solid/education/beaker-02.svg
new file mode 100644
index 0000000..2809cc8
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/education/beaker-02.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="beaker-02">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M4.13856 0.500003H7.8617C7.92126 0.49998 7.99238 0.499953 8.05504 0.505073C8.12765 0.511005 8.23165 0.526227 8.34062 0.581751C8.48174 0.653656 8.59648 0.768392 8.66838 0.909513C8.72391 1.01849 8.73913 1.12248 8.74506 1.19509C8.75018 1.25775 8.75015 1.32888 8.75013 1.38844V2.61157C8.75015 2.67113 8.75018 2.74226 8.74506 2.80492C8.73913 2.87753 8.72391 2.98153 8.66838 3.0905C8.59648 3.23162 8.48174 3.34636 8.34062 3.41826C8.23165 3.47379 8.12765 3.48901 8.05504 3.49494C8.03725 3.49639 8.01877 3.49743 8.00006 3.49817V5.2506C8.00006 5.55312 8.00408 5.61265 8.01723 5.66153C8.03245 5.71807 8.05747 5.7715 8.09117 5.81939C8.1203 5.86078 8.16346 5.90197 8.39586 6.09564L10.2807 7.66627C10.4566 7.81255 10.6116 7.94145 10.7267 8.10509C10.8278 8.24875 10.9029 8.40904 10.9486 8.57867C11.0005 8.7719 11.0003 8.97351 11.0001 9.2023C11.0001 9.39886 11.0002 9.59542 11.0002 9.79198C11.0003 9.98232 11.0005 10.1463 10.9713 10.2927C10.853 10.8877 10.3878 11.3529 9.7928 11.4712C9.64637 11.5003 9.48246 11.5002 9.29211 11.5001H2.70822C2.51787 11.5002 2.35396 11.5003 2.20753 11.4712C1.98473 11.4269 1.78014 11.334 1.60515 11.2038C1.42854 11.0725 1.28221 10.9034 1.17753 10.7077C1.10892 10.5796 1.05831 10.4401 1.02899 10.2927C0.999862 10.1463 0.999992 9.98233 1.00014 9.79199C1.00014 9.59542 1.00006 9.39886 1.00003 9.20229C0.999794 8.97351 0.999584 8.7719 1.05157 8.57867C1.09721 8.40904 1.17229 8.24875 1.27338 8.10509C1.38855 7.94145 1.54356 7.81255 1.71947 7.66627L3.60427 6.09564C3.83667 5.90197 3.87983 5.86078 3.90896 5.81939C3.94266 5.7715 3.96768 5.71807 3.9829 5.66153C3.99605 5.61265 4.00006 5.55312 4.00006 5.2506V3.49817C3.9814 3.49743 3.96297 3.49639 3.94521 3.49494C3.8726 3.48901 3.76861 3.47379 3.65964 3.41826C3.51851 3.34636 3.40378 3.23162 3.33187 3.0905C3.27635 2.98153 3.26113 2.87753 3.25519 2.80492C3.25008 2.74226 3.2501 2.67113 3.25013 2.61158V1.38844C3.2501 1.32888 3.25008 1.25775 3.25519 1.19509C3.26113 1.12248 3.27635 1.01849 3.33187 0.909513C3.40378 0.768392 3.51851 0.653656 3.65964 0.581751C3.76861 0.526227 3.8726 0.511005 3.94521 0.505073C4.00787 0.499953 4.079 0.49998 4.13856 0.500003ZM9.11909 8.00004H2.88104L4.28066 6.83373C4.45657 6.68745 4.61158 6.55855 4.72675 6.39491C4.82784 6.25125 4.90292 6.09096 4.94856 5.92133C5.00054 5.7281 5.00033 5.52649 5.0001 5.29771L5.00006 3.50001H7.00006L7.00003 5.29771C6.99979 5.52649 6.99958 5.7281 7.05157 5.92133C7.09721 6.09096 7.17229 6.25125 7.27338 6.39491C7.38855 6.55855 7.54356 6.68745 7.71947 6.83373L9.11909 8.00004Z" fill="#0E7090"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/education/bubble-text.svg b/app/components/base/icons/assets/vender/solid/education/bubble-text.svg
new file mode 100644
index 0000000..c97b784
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/education/bubble-text.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="bubble-text">
+<path id="vector" fill-rule="evenodd" clip-rule="evenodd" d="M2 9C2 5.68629 4.68629 3 8 3H16C19.3137 3 22 5.68629 22 9V15C22 18.3137 19.3137 21 16 21H3C2.44772 21 2 20.5523 2 20V9ZM9 9C8.44772 9 8 9.44772 8 10C8 10.5523 8.44772 11 9 11H15C15.5523 11 16 10.5523 16 10C16 9.44772 15.5523 9 15 9H9ZM9 13C8.44772 13 8 13.4477 8 14C8 14.5523 8.44772 15 9 15H12C12.5523 15 13 14.5523 13 14C13 13.4477 12.5523 13 12 13H9Z" fill="black"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/education/heart-02.svg b/app/components/base/icons/assets/vender/solid/education/heart-02.svg
new file mode 100644
index 0000000..d1d4ad1
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/education/heart-02.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.5836 3.8721C12.3615 3.99329 12.1665 4.11496 12 4.22818C11.8335 4.11496 11.6385 3.99329 11.4164 3.8721C10.6185 3.4369 9.45449 3 8 3C6.48169 3 4.96498 3.60857 3.83296 4.81606C2.69616 6.02865 2 7.78592 2 10C2 13.3448 4.37277 16.1023 6.58187 17.9272C7.71336 18.8619 8.86688 19.6065 9.7917 20.1203C10.2539 20.377 10.6687 20.5816 11.004 20.7253C11.1707 20.7967 11.3289 20.858 11.4705 20.9033C11.5784 20.9378 11.7841 21 12 21C12.2159 21 12.4216 20.9378 12.5295 20.9033C12.6711 20.858 12.8293 20.7967 12.996 20.7253C13.3313 20.5816 13.7461 20.377 14.2083 20.1203C15.1331 19.6065 16.2866 18.8619 17.4181 17.9272C19.6272 16.1023 22 13.3448 22 10C22 7.78592 21.3038 6.02865 20.167 4.81606C19.035 3.60857 17.5183 3 16 3C14.5455 3 13.3815 3.4369 12.5836 3.8721Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/education/unblur.svg b/app/components/base/icons/assets/vender/solid/education/unblur.svg
new file mode 100644
index 0000000..498c2a0
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/education/unblur.svg
@@ -0,0 +1,19 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="unblur">
+<g id="vector">
+<path d="M9.5 6.25C9.5 6.80228 9.05228 7.25 8.5 7.25C7.94772 7.25 7.5 6.80228 7.5 6.25C7.5 5.69772 7.94772 5.25 8.5 5.25C9.05228 5.25 9.5 5.69772 9.5 6.25Z" fill="black"/>
+<path d="M6 6.25C6 6.80228 5.55228 7.25 5 7.25C4.44772 7.25 4 6.80228 4 6.25C4 5.69772 4.44772 5.25 5 5.25C5.55228 5.25 6 5.69772 6 6.25Z" fill="black"/>
+<path d="M9.5 17.75C9.5 18.3023 9.05228 18.75 8.5 18.75C7.94772 18.75 7.5 18.3023 7.5 17.75C7.5 17.1977 7.94772 16.75 8.5 16.75C9.05228 16.75 9.5 17.1977 9.5 17.75Z" fill="black"/>
+<path d="M9.25 3.25C9.25 3.66421 8.91421 4 8.5 4C8.08579 4 7.75 3.66421 7.75 3.25C7.75 2.83579 8.08579 2.5 8.5 2.5C8.91421 2.5 9.25 2.83579 9.25 3.25Z" fill="black"/>
+<path d="M3 10C3 10.4142 2.66421 10.75 2.25 10.75C1.83579 10.75 1.5 10.4142 1.5 10C1.5 9.58579 1.83579 9.25 2.25 9.25C2.66421 9.25 3 9.58579 3 10Z" fill="black"/>
+<path d="M3 14C3 14.4142 2.66421 14.75 2.25 14.75C1.83579 14.75 1.5 14.4142 1.5 14C1.5 13.5858 1.83579 13.25 2.25 13.25C2.66421 13.25 3 13.5858 3 14Z" fill="black"/>
+<path d="M9.25 20.75C9.25 21.1642 8.91421 21.5 8.5 21.5C8.08579 21.5 7.75 21.1642 7.75 20.75C7.75 20.3358 8.08579 20 8.5 20C8.91421 20 9.25 20.3358 9.25 20.75Z" fill="black"/>
+<path d="M10 10C10 10.8284 9.32843 11.5 8.5 11.5C7.67157 11.5 7 10.8284 7 10C7 9.17157 7.67157 8.5 8.5 8.5C9.32843 8.5 10 9.17157 10 10Z" fill="black"/>
+<path d="M10 14C10 14.8284 9.32843 15.5 8.5 15.5C7.67157 15.5 7 14.8284 7 14C7 13.1716 7.67157 12.5 8.5 12.5C9.32843 12.5 10 13.1716 10 14Z" fill="black"/>
+<path d="M6 10C6 10.5523 5.55228 11 5 11C4.44772 11 4 10.5523 4 10C4 9.44772 4.44772 9 5 9C5.55228 9 6 9.44772 6 10Z" fill="black"/>
+<path d="M6 14C6 14.5523 5.55228 15 5 15C4.44772 15 4 14.5523 4 14C4 13.4477 4.44772 13 5 13C5.55228 13 6 13.4477 6 14Z" fill="black"/>
+<path d="M6 17.75C6 18.3023 5.55228 18.75 5 18.75C4.44772 18.75 4 18.3023 4 17.75C4 17.1977 4.44772 16.75 5 16.75C5.55228 16.75 6 17.1977 6 17.75Z" fill="black"/>
+<path d="M12 2C11.4477 2 11 2.44772 11 3V21C11 21.5523 11.4477 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2Z" fill="black"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/files/file-05.svg b/app/components/base/icons/assets/vender/solid/files/file-05.svg
new file mode 100644
index 0000000..950b55e
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/files/file-05.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-05">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.66667 1.34356C8.66667 1.32602 8.66667 1.31725 8.66591 1.30135C8.65018 0.972168 8.3607 0.682824 8.03151 0.667251C8.01562 0.666499 8.0104 0.666501 8.00001 0.666504H5.8391C5.30248 0.666497 4.85957 0.666491 4.49878 0.695968C4.12405 0.726585 3.77958 0.792295 3.45603 0.957155C2.95426 1.21282 2.54631 1.62077 2.29065 2.12253C2.12579 2.44609 2.06008 2.79056 2.02946 3.16529C1.99999 3.52608 1.99999 3.96899 2 4.50562V11.494C1.99999 12.0307 1.99999 12.4736 2.02946 12.8344C2.06008 13.2091 2.12579 13.5536 2.29065 13.8771C2.54631 14.3789 2.95426 14.7869 3.45603 15.0425C3.77958 15.2074 4.12405 15.2731 4.49878 15.3037C4.85958 15.3332 5.30248 15.3332 5.83912 15.3332H10.1609C10.6975 15.3332 11.1404 15.3332 11.5012 15.3037C11.8759 15.2731 12.2204 15.2074 12.544 15.0425C13.0457 14.7869 13.4537 14.3789 13.7093 13.8771C13.8742 13.5536 13.9399 13.2091 13.9705 12.8344C14 12.4736 14 12.0307 14 11.4941V6.66646C14 6.65611 14 6.65093 13.9993 6.63505C13.9837 6.30583 13.6943 6.01631 13.3651 6.0006C13.3492 5.99985 13.3405 5.99985 13.323 5.99985L10.3787 5.99985C10.2105 5.99987 10.0466 5.99989 9.90785 5.98855C9.75545 5.9761 9.57563 5.94672 9.39468 5.85452C9.1438 5.72669 8.93983 5.52272 8.81199 5.27183C8.7198 5.09088 8.69042 4.91106 8.67797 4.75867C8.66663 4.61989 8.66665 4.45603 8.66667 4.28778L8.66667 1.34356ZM5.33333 8.6665C4.96514 8.6665 4.66667 8.96498 4.66667 9.33317C4.66667 9.70136 4.96514 9.99984 5.33333 9.99984H10.6667C11.0349 9.99984 11.3333 9.70136 11.3333 9.33317C11.3333 8.96498 11.0349 8.6665 10.6667 8.6665H5.33333ZM5.33333 11.3332C4.96514 11.3332 4.66667 11.6316 4.66667 11.9998C4.66667 12.368 4.96514 12.6665 5.33333 12.6665H9.33333C9.70152 12.6665 10 12.368 10 11.9998C10 11.6316 9.70152 11.3332 9.33333 11.3332H5.33333Z" fill="#6938EF"/>
+<path d="M12.6053 4.6665C12.8011 4.6665 12.8989 4.6665 12.9791 4.61735C13.0923 4.54794 13.16 4.3844 13.129 4.25526C13.107 4.16382 13.0432 4.10006 12.9155 3.97253L10.694 1.75098C10.5664 1.62333 10.5027 1.5595 10.4112 1.53752C10.2821 1.50648 10.1186 1.57417 10.0492 1.6874C10 1.76757 10 1.86545 10 2.0612L10 4.13315C10 4.31982 10 4.41316 10.0363 4.48446C10.0683 4.54718 10.1193 4.59818 10.182 4.63014C10.2533 4.66647 10.3466 4.66647 10.5333 4.66647L12.6053 4.6665Z" fill="#6938EF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/files/file-search-02.svg b/app/components/base/icons/assets/vender/solid/files/file-search-02.svg
new file mode 100644
index 0000000..ceae7dd
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/files/file-search-02.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-search-02">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M10.1609 0.666748H5.83913C5.3025 0.66674 4.85958 0.666734 4.49878 0.696212C4.12405 0.726828 3.77958 0.792538 3.45603 0.957399C2.95426 1.21306 2.54631 1.62101 2.29065 2.12277C2.12579 2.44633 2.06008 2.7908 2.02946 3.16553C1.99999 3.52632 1.99999 3.96924 2 4.50587V11.4943C1.99999 12.0309 1.99999 12.4738 2.02946 12.8346C2.06008 13.2094 2.12579 13.5538 2.29065 13.8774C2.54631 14.3792 2.95426 14.7871 3.45603 15.0428C3.77958 15.2076 4.12405 15.2733 4.49878 15.304C4.85958 15.3334 5.30248 15.3334 5.83912 15.3334H7.75554C8.22798 15.3334 8.4642 15.3334 8.55219 15.2689C8.64172 15.2033 8.67645 15.1421 8.68693 15.0316C8.69724 14.9229 8.55693 14.6879 8.27632 14.2177C7.88913 13.5689 7.66667 12.8105 7.66667 12.0001C7.66667 9.60685 9.60677 7.66675 12 7.66675C12.4106 7.66675 12.8078 7.72385 13.1842 7.83055C13.5061 7.92177 13.667 7.96739 13.7581 7.94138C13.847 7.91602 13.9015 7.87486 13.9501 7.79623C14 7.71563 14 7.56892 14 7.27549V4.50587C14 3.96923 14 3.52633 13.9705 3.16553C13.9399 2.7908 13.8742 2.44633 13.7093 2.12277C13.4537 1.62101 13.0457 1.21306 12.544 0.957399C12.2204 0.792538 11.8759 0.726828 11.5012 0.696212C11.1404 0.666734 10.6975 0.66674 10.1609 0.666748ZM4.66667 3.33342C4.29848 3.33342 4 3.63189 4 4.00008C4 4.36827 4.29848 4.66675 4.66667 4.66675H10.6667C11.0349 4.66675 11.3333 4.36827 11.3333 4.00008C11.3333 3.63189 11.0349 3.33342 10.6667 3.33342H4.66667ZM4 6.66675C4 6.29856 4.29848 6.00008 4.66667 6.00008H8.66667C9.03486 6.00008 9.33333 6.29856 9.33333 6.66675C9.33333 7.03494 9.03486 7.33342 8.66667 7.33342H4.66667C4.29848 7.33342 4 7.03494 4 6.66675ZM4 9.33342C4 8.96523 4.29848 8.66675 4.66667 8.66675H6C6.36819 8.66675 6.66667 8.96523 6.66667 9.33342C6.66667 9.7016 6.36819 10.0001 6 10.0001H4.66667C4.29848 10.0001 4 9.7016 4 9.33342Z" fill="#039855"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9 12.0001C9 10.3432 10.3431 9.00008 12 9.00008C13.6569 9.00008 15 10.3432 15 12.0001C15 12.5871 14.8314 13.1348 14.54 13.5972L15.1381 14.1953C15.3984 14.4557 15.3984 14.8778 15.1381 15.1382C14.8777 15.3985 14.4556 15.3985 14.1953 15.1382L13.5972 14.54C13.1347 14.8315 12.587 15.0001 12 15.0001C10.3431 15.0001 9 13.6569 9 12.0001ZM12 10.3334C11.0795 10.3334 10.3333 11.0796 10.3333 12.0001C10.3333 12.9206 11.0795 13.6667 12 13.6667C12.9205 13.6667 13.6667 12.9206 13.6667 12.0001C13.6667 11.0796 12.9205 10.3334 12 10.3334Z" fill="#039855"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/files/file-zip.svg b/app/components/base/icons/assets/vender/solid/files/file-zip.svg
new file mode 100644
index 0000000..213606a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/files/file-zip.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<path id="Vector" d="M3.99999 1.33325H7.99999V5.33325C7.99999 6.06963 8.59692 6.66659 9.33332 6.66659H13.3333V13.3333C13.3333 14.0697 12.7364 14.6666 12 14.6666H6.66666V13.3333H7.99999V11.9999H6.66666V10.6666H7.99999V9.33325H6.66666V7.99992H5.33332V9.33325H6.66666V10.6666H5.33332V11.9999H6.66666V13.3333H5.33332V14.6666H3.99999C3.26361 14.6666 2.66666 14.0697 2.66666 13.3333V2.66659C2.66666 1.93021 3.26361 1.33325 3.99999 1.33325Z" fill="#676F83"/>
+<path id="Vector_2" opacity="0.5" d="M12.9428 4.99993C13.0415 5.09868 13.1232 5.21133 13.1859 5.33327H9.33334V1.48071C9.45528 1.54338 9.56794 1.62504 9.66668 1.72379L12.9428 4.99993Z" fill="#676F83"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/files/folder.svg b/app/components/base/icons/assets/vender/solid/files/folder.svg
new file mode 100644
index 0000000..8334887
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/files/folder.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M0.666993 4.10794C0.666981 3.75652 0.666972 3.45333 0.687374 3.20362C0.708908 2.94006 0.756452 2.67791 0.884981 2.42566C1.07673 2.04933 1.38269 1.74337 1.75901 1.55163C2.01127 1.4231 2.27341 1.37555 2.53698 1.35402C2.78669 1.33362 3.08986 1.33363 3.4413 1.33364L6.0981 1.33357C6.4938 1.33304 6.84179 1.33258 7.16176 1.44295C7.44201 1.53961 7.69726 1.69737 7.90905 1.9048C8.15086 2.14164 8.30607 2.45309 8.48257 2.80725L9.07895 4.00016H11.4945C12.0312 4.00015 12.4741 4.00015 12.8349 4.02963C13.2096 4.06024 13.5541 4.12595 13.8776 4.29081C14.3794 4.54648 14.7873 4.95442 15.043 5.45619C15.2079 5.77975 15.2736 6.12421 15.3042 6.49895C15.3337 6.85974 15.3337 7.30264 15.3337 7.83928V10.8277C15.3337 11.3644 15.3337 11.8073 15.3042 12.168C15.2736 12.5428 15.2079 12.8872 15.043 13.2108C14.7873 13.7126 14.3794 14.1205 13.8776 14.3762C13.5541 14.541 13.2096 14.6068 12.8349 14.6374C12.4741 14.6668 12.0312 14.6668 11.4945 14.6668H4.50614C3.9695 14.6668 3.52657 14.6668 3.16578 14.6374C2.79104 14.6068 2.44658 14.541 2.12302 14.3762C1.62125 14.1205 1.2133 13.7126 0.957643 13.2108C0.792782 12.8872 0.727073 12.5428 0.696456 12.168C0.666978 11.8073 0.666985 11.3643 0.666993 10.8277V4.10794ZM6.01519 2.66697C6.54213 2.66697 6.64658 2.67567 6.727 2.70341C6.82041 2.73563 6.9055 2.78822 6.97609 2.85736C7.03687 2.91688 7.09136 3.00642 7.32701 3.47773L7.58823 4.00016L2.00038 4.00016C2.00067 3.69017 2.00271 3.47827 2.01628 3.3122C2.03108 3.13109 2.05619 3.06394 2.07299 3.03098C2.13691 2.90554 2.23889 2.80355 2.36433 2.73964C2.3973 2.72284 2.46444 2.69772 2.64555 2.68292C2.83444 2.66749 3.08263 2.66697 3.46699 2.66697H6.01519Z" fill="#444CE7"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/answer-triangle.svg b/app/components/base/icons/assets/vender/solid/general/answer-triangle.svg
new file mode 100644
index 0000000..134856c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/answer-triangle.svg
@@ -0,0 +1,3 @@
+<svg width="8" height="12" viewBox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path id="Rectangle 1" d="M1.03647 1.5547C0.59343 0.890144 1.06982 0 1.86852 0H8V12L1.03647 1.5547Z" fill="#F2F4F7"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/arrow-down-round-fill.svg b/app/components/base/icons/assets/vender/solid/general/arrow-down-round-fill.svg
new file mode 100644
index 0000000..9566fcc
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/arrow-down-round-fill.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="arrow-down-round-fill">
+<path id="Vector" d="M6.02913 6.23572C5.08582 6.23572 4.56482 7.33027 5.15967 8.06239L7.13093 10.4885C7.57922 11.0403 8.42149 11.0403 8.86986 10.4885L10.8411 8.06239C11.4359 7.33027 10.9149 6.23572 9.97158 6.23572H6.02913Z" fill="#101828"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/check-circle.svg b/app/components/base/icons/assets/vender/solid/general/check-circle.svg
new file mode 100644
index 0000000..33d0bec
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/check-circle.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="check-circle">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M8 0.666626C3.94992 0.666626 0.666672 3.94987 0.666672 7.99996C0.666672 12.05 3.94992 15.3333 8 15.3333C12.0501 15.3333 15.3333 12.05 15.3333 7.99996C15.3333 3.94987 12.0501 0.666626 8 0.666626ZM11.4714 6.47136C11.7318 6.21101 11.7318 5.7889 11.4714 5.52855C11.2111 5.26821 10.7889 5.26821 10.5286 5.52855L7 9.05715L5.47141 7.52855C5.21106 7.2682 4.78895 7.2682 4.5286 7.52855C4.26825 7.7889 4.26825 8.21101 4.5286 8.47136L6.5286 10.4714C6.78895 10.7317 7.21106 10.7317 7.47141 10.4714L11.4714 6.47136Z" fill="#039855"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/check-done-01.svg b/app/components/base/icons/assets/vender/solid/general/check-done-01.svg
new file mode 100644
index 0000000..7e3cd54
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/check-done-01.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.8385 7H5.16146C4.63433 6.99998 4.17954 6.99997 3.80497 7.03057C3.40963 7.06287 3.01641 7.13419 2.63803 7.32698C2.07354 7.6146 1.6146 8.07354 1.32698 8.63803C1.13419 9.01641 1.06287 9.40963 1.03057 9.80497C0.999969 10.1795 0.999984 10.6343 1 11.1614V18.8385C0.999984 19.3657 0.999969 19.8205 1.03057 20.195C1.06287 20.5904 1.13419 20.9836 1.32698 21.362C1.6146 21.9265 2.07354 22.3854 2.63803 22.673C3.01641 22.8658 3.40963 22.9371 3.80497 22.9694C4.17952 23 4.63425 23 5.16136 23H12.8385C13.3656 23 13.8205 23 14.195 22.9694C14.5904 22.9371 14.9836 22.8658 15.362 22.673C15.9265 22.3854 16.3854 21.9265 16.673 21.362C16.8658 20.9836 16.9371 20.5904 16.9694 20.195C17 19.8205 17 19.3657 17 18.8385V11.1615C17 10.6343 17 10.1796 16.9694 9.80497C16.9371 9.40963 16.8658 9.01641 16.673 8.63803C16.3854 8.07354 15.9265 7.6146 15.362 7.32698C14.9836 7.13419 14.5904 7.06287 14.195 7.03057C13.8205 6.99997 13.3657 6.99998 12.8385 7ZM13.2071 13.2071C13.5976 12.8166 13.5976 12.1834 13.2071 11.7929C12.8166 11.4024 12.1834 11.4024 11.7929 11.7929L8 15.5858L6.70711 14.2929C6.31658 13.9024 5.68342 13.9024 5.29289 14.2929C4.90237 14.6834 4.90237 15.3166 5.29289 15.7071L7.29289 17.7071C7.68342 18.0976 8.31658 18.0976 8.70711 17.7071L13.2071 13.2071Z" fill="black"/>
+<path d="M18.8385 1H11.1615C10.6343 0.999984 10.1795 0.999969 9.80497 1.03057C9.40963 1.06287 9.01641 1.13419 8.63803 1.32698C8.07354 1.6146 7.6146 2.07354 7.32698 2.63803C7.13419 3.01641 7.06287 3.40963 7.03057 3.80497C7.00314 4.14076 7.00031 4.54098 7.00003 5.00003L12.8809 5.00001C13.3695 4.9999 13.8993 4.99977 14.3579 5.03724C14.8769 5.07964 15.5626 5.1846 16.2699 5.54499C17.2108 6.02436 17.9757 6.78926 18.455 7.73007C18.8154 8.43739 18.9204 9.12311 18.9628 9.64213C19.0003 10.1007 19.0001 10.6305 19 11.1192L19 17C19.459 16.9997 19.8593 16.9969 20.195 16.9694C20.5904 16.9371 20.9836 16.8658 21.362 16.673C21.9265 16.3854 22.3854 15.9265 22.673 15.362C22.8658 14.9836 22.9371 14.5904 22.9694 14.195C23 13.8205 23 13.3658 23 12.8386V5.16148C23 4.63437 23 4.17952 22.9694 3.80497C22.9371 3.40963 22.8658 3.01641 22.673 2.63803C22.3854 2.07354 21.9265 1.6146 21.362 1.32698C20.9836 1.13419 20.5904 1.06287 20.195 1.03057C19.8205 0.999969 19.3657 0.999984 18.8385 1Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/download-02.svg b/app/components/base/icons/assets/vender/solid/general/download-02.svg
new file mode 100644
index 0000000..0ad6d8b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/download-02.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M21 21H3M18 11L12 17M12 17L6 11M12 17V3" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/edit-03.svg b/app/components/base/icons/assets/vender/solid/general/edit-03.svg
new file mode 100644
index 0000000..f547765
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/edit-03.svg
@@ -0,0 +1,8 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="edit-03">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.50004 10.0001C5.50004 9.72398 5.7239 9.50012 6.00004 9.50012H10.5C10.7762 9.50012 11 9.72398 11 10.0001C11 10.2763 10.7762 10.5001 10.5 10.5001H6.00004C5.7239 10.5001 5.50004 10.2763 5.50004 10.0001Z" fill="#98A2B3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.89651 1.39656C8.50599 0.787085 9.49414 0.787084 10.1036 1.39656C10.7131 2.00604 10.7131 2.99419 10.1036 3.60367L3.82225 9.88504C3.81235 9.89494 3.80254 9.90476 3.79281 9.91451C3.64909 10.0585 3.52237 10.1855 3.3696 10.2791C3.23539 10.3613 3.08907 10.4219 2.93602 10.4587C2.7618 10.5005 2.58242 10.5003 2.37897 10.5001C2.3652 10.5001 2.35132 10.5001 2.33732 10.5001H1.50005C1.22391 10.5001 1.00005 10.2763 1.00005 10.0001V9.16286C1.00005 9.14886 1.00004 9.13497 1.00003 9.1212C0.999836 8.91776 0.999669 8.73838 1.0415 8.56416C1.07824 8.4111 1.13885 8.26479 1.22109 8.13058C1.31471 7.97781 1.44166 7.85109 1.58566 7.70736C1.5954 7.69764 1.60523 7.68783 1.61513 7.67793L7.89651 1.39656Z" fill="#98A2B3"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/edit-04.svg b/app/components/base/icons/assets/vender/solid/general/edit-04.svg
new file mode 100644
index 0000000..805e39a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/edit-04.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M21.6747 17.2619C22.0824 17.6345 22.1107 18.2671 21.7381 18.6747L20.738 19.7687C20.0284 20.5448 19.0458 21 18.0002 21C16.9549 21 15.9726 20.5452 15.2631 19.7696C14.9112 19.3863 14.4549 19.1901 14.0002 19.1901C13.5454 19.1901 13.0889 19.3864 12.7369 19.7701C12.3635 20.177 11.7309 20.2043 11.324 19.8309C10.917 19.4575 10.8898 18.8249 11.2632 18.418C11.9735 17.6438 12.9555 17.1901 14.0002 17.1901C15.045 17.1901 16.0269 17.6438 16.7373 18.418L16.7384 18.4192C17.0897 18.8034 17.5458 19 18.0002 19C18.4545 19 18.9106 18.8034 19.2618 18.4193L20.2619 17.3253C20.6346 16.9177 21.2671 16.8893 21.6747 17.2619Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15.793 2.79287C17.0119 1.57393 18.9882 1.57392 20.2072 2.79287C21.4261 4.01183 21.4261 5.98814 20.2072 7.20709L7.64443 19.7698C7.62463 19.7896 7.60502 19.8093 7.58556 19.8288C7.29811 20.1168 7.04467 20.3707 6.73914 20.5579C6.47072 20.7224 6.17809 20.8436 5.87198 20.9171C5.52353 21.0007 5.16478 21.0004 4.75788 21C4.73034 21 4.70258 21 4.67458 21H3.00004C2.44776 21 2.00004 20.5523 2.00004 20V18.3255C2.00004 18.2975 2.00001 18.2697 1.99999 18.2422C1.99961 17.8353 1.99928 17.4765 2.08293 17.1281C2.15642 16.822 2.27763 16.5293 2.44212 16.2609C2.62936 15.9554 2.88327 15.7019 3.17125 15.4145C3.19075 15.395 3.2104 15.3754 3.23019 15.3556L15.793 2.79287Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/eye.svg b/app/components/base/icons/assets/vender/solid/general/eye.svg
new file mode 100644
index 0000000..f75b90a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/eye.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10 12C10 10.8954 10.8954 10 12 10C13.1046 10 14 10.8954 14 12C14 13.1046 13.1046 14 12 14C10.8954 14 10 13.1046 10 12Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 4C9.13833 4 6.80535 5.26472 5.07675 6.70743C3.3505 8.14818 2.16697 9.81429 1.57422 10.7528L1.55014 10.7908C1.43252 10.976 1.27981 11.2164 1.2026 11.5532C1.14027 11.8251 1.14027 12.1749 1.2026 12.4468C1.2798 12.7836 1.43252 13.024 1.55014 13.2092L1.57423 13.2472C2.16697 14.1857 3.3505 15.8518 5.07675 17.2926C6.80535 18.7353 9.13833 20 12 20C14.8617 20 17.1947 18.7353 18.9233 17.2926C20.6495 15.8518 21.833 14.1857 22.4258 13.2472L22.4499 13.2092C22.5675 13.024 22.7202 12.7837 22.7974 12.4468C22.8597 12.1749 22.8597 11.8251 22.7974 11.5532C22.7202 11.2163 22.5675 10.976 22.4499 10.7908L22.4258 10.7528C21.833 9.81429 20.6495 8.14818 18.9233 6.70743C17.1947 5.26472 14.8617 4 12 4ZM12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/github.svg b/app/components/base/icons/assets/vender/solid/general/github.svg
new file mode 100644
index 0000000..c7b203d
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/github.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<path id="Vector" d="M8 1C4.1325 1 1 4.1325 1 8C1 11.0975 3.00375 13.7137 5.78625 14.6413C6.13625 14.7025 6.2675 14.4925 6.2675 14.3088C6.2675 14.1425 6.25875 13.5913 6.25875 13.005C4.5 13.3288 4.045 12.5763 3.905 12.1825C3.82625 11.9812 3.485 11.36 3.1875 11.1937C2.9425 11.0625 2.5925 10.7387 3.17875 10.73C3.73 10.7212 4.12375 11.2375 4.255 11.4475C4.885 12.5062 5.89125 12.2088 6.29375 12.025C6.355 11.57 6.53875 11.2638 6.74 11.0887C5.1825 10.9137 3.555 10.31 3.555 7.6325C3.555 6.87125 3.82625 6.24125 4.2725 5.75125C4.2025 5.57625 3.9575 4.85875 4.3425 3.89625C4.3425 3.89625 4.92875 3.7125 6.2675 4.61375C6.8275 4.45625 7.4225 4.3775 8.0175 4.3775C8.6125 4.3775 9.2075 4.45625 9.7675 4.61375C11.1063 3.70375 11.6925 3.89625 11.6925 3.89625C12.0775 4.85875 11.8325 5.57625 11.7625 5.75125C12.2087 6.24125 12.48 6.8625 12.48 7.6325C12.48 10.3187 10.8438 10.9137 9.28625 11.0887C9.54 11.3075 9.75875 11.7275 9.75875 12.3837C9.75875 13.32 9.75 14.0725 9.75 14.3088C9.75 14.4925 9.88125 14.7113 10.2312 14.6413C11.6209 14.1721 12.8284 13.279 13.6839 12.0877C14.5393 10.8963 14.9996 9.46668 15 8C15 4.1325 11.8675 1 8 1Z" fill="#676F83"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/message-clock-circle.svg b/app/components/base/icons/assets/vender/solid/general/message-clock-circle.svg
new file mode 100644
index 0000000..307e070
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/message-clock-circle.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="message-clock-circle">
+<path id="Solid" d="M1.33301 8.00016C1.33301 4.31826 4.31778 1.3335 7.99967 1.3335C11.6816 1.3335 14.6663 4.31826 14.6663 8.00016C14.6663 11.6821 11.6816 14.6668 7.99967 14.6668C7.11413 14.6668 6.26734 14.4938 5.49248 14.1791C5.42249 14.1507 5.38209 14.1344 5.35225 14.1231L5.34304 14.1197L5.33987 14.1202C5.31527 14.1235 5.28173 14.129 5.21771 14.1397L2.82667 14.5382C2.71958 14.5561 2.59976 14.5761 2.4957 14.5839C2.38225 14.5925 2.20175 14.5955 2.01101 14.5137C1.77521 14.4125 1.5873 14.2246 1.48616 13.9888C1.40435 13.7981 1.40733 13.6176 1.41589 13.5041C1.42375 13.4001 1.44375 13.2803 1.46163 13.1732L1.86015 10.7821C1.87082 10.7181 1.87634 10.6846 1.87967 10.66L1.8801 10.6568L1.87669 10.6476C1.86549 10.6178 1.84914 10.5773 1.82071 10.5074C1.50602 9.7325 1.33301 8.88571 1.33301 8.00016ZM7.99967 5.3335C7.99967 4.96531 7.7012 4.66683 7.33301 4.66683C6.96482 4.66683 6.66634 4.96531 6.66634 5.3335V8.66683C6.66634 9.03502 6.96482 9.3335 7.33301 9.3335H10.6663C11.0345 9.3335 11.333 9.03502 11.333 8.66683C11.333 8.29864 11.0345 8.00016 10.6663 8.00016H7.99967V5.3335Z" fill="#DD2590"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/plus-circle.svg b/app/components/base/icons/assets/vender/solid/general/plus-circle.svg
new file mode 100644
index 0000000..b169bd1
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/plus-circle.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="plus-circle">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1ZM12 7C12.5523 7 13 7.44772 13 8V11H16C16.5523 11 17 11.4477 17 12C17 12.5523 16.5523 13 16 13H13V16C13 16.5523 12.5523 17 12 17C11.4477 17 11 16.5523 11 16V13H8C7.44772 13 7 12.5523 7 12C7 11.4477 7.44772 11 8 11H11V8C11 7.44772 11.4477 7 12 7Z" fill="black"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/question-triangle.svg b/app/components/base/icons/assets/vender/solid/general/question-triangle.svg
new file mode 100644
index 0000000..52039ea
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/question-triangle.svg
@@ -0,0 +1,6 @@
+<svg width="8" height="12" viewBox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Rectangle 2">
+<path d="M6.96353 1.5547C7.40657 0.890144 6.93018 0 6.13148 0H0V12L6.96353 1.5547Z" fill="white"/>
+<path d="M6.96353 1.5547C7.40657 0.890144 6.93018 0 6.13148 0H0V12L6.96353 1.5547Z" fill="#D1E9FF" fill-opacity="0.5"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/search-md.svg b/app/components/base/icons/assets/vender/solid/general/search-md.svg
new file mode 100644
index 0000000..31ce7be
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/search-md.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="search-md">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2ZM4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11Z" fill="black"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/target-04.svg b/app/components/base/icons/assets/vender/solid/general/target-04.svg
new file mode 100644
index 0000000..c43124e
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/target-04.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19.1601 1.01292C19.4774 1.06441 19.7506 1.26529 19.8944 1.5528L20.7453 3.25466L22.4472 4.10558C22.7347 4.24934 22.9355 4.52254 22.987 4.83983C23.0385 5.15712 22.9343 5.47982 22.707 5.70712L19.707 8.70712C19.5195 8.89466 19.2652 9.00001 18.9999 9.00001H16.4142L12.7071 12.7071C12.3166 13.0976 11.6834 13.0976 11.2929 12.7071C10.9024 12.3166 10.9024 11.6834 11.2929 11.2929L14.9999 7.58585V5.00001C14.9999 4.7348 15.1053 4.48044 15.2928 4.29291L18.2928 1.29291C18.5201 1.06561 18.8428 0.961435 19.1601 1.01292Z" fill="black"/>
+<path d="M3 12C3 7.02944 7.02944 3 12 3C12.5523 3 13 2.55228 13 2C13 1.44772 12.5523 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C18.0751 23 23 18.0751 23 12C23 11.4477 22.5523 11 22 11C21.4477 11 21 11.4477 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z" fill="black"/>
+<path d="M8 12C8 9.79086 9.79086 8 12 8C12.5523 8 13 7.55228 13 7C13 6.44772 12.5523 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18C15.3137 18 18 15.3137 18 12C18 11.4477 17.5523 11 17 11C16.4477 11 16 11.4477 16 12C16 14.2091 14.2091 16 12 16C9.79086 16 8 14.2091 8 12Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/tool-03.svg b/app/components/base/icons/assets/vender/solid/general/tool-03.svg
new file mode 100644
index 0000000..96d4686
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/tool-03.svg
@@ -0,0 +1,9 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="tool-03">
+<g id="Vector">
+<path d="M5.10516 6.61092L6.45642 5.41856C6.43816 5.25959 6.43018 5.09961 6.43253 4.93962V4.9285L2.91826 1.41365C2.89245 1.38778 2.86179 1.36725 2.82804 1.35325C2.79429 1.33924 2.75811 1.33203 2.72157 1.33203C2.68503 1.33203 2.64884 1.33924 2.61509 1.35325C2.58134 1.36725 2.55069 1.38778 2.52488 1.41365L1.41365 2.52489C1.38778 2.5507 1.36725 2.58135 1.35325 2.6151C1.33924 2.64885 1.33203 2.68504 1.33203 2.72158C1.33203 2.75812 1.33924 2.7943 1.35325 2.82806C1.36725 2.86181 1.38778 2.89246 1.41365 2.91827L5.10516 6.61092Z" fill="#444CE7"/>
+<path d="M12.5043 9.33348C12.3512 9.3848 12.1956 9.42819 12.0381 9.46349L11.9748 9.47461C11.7112 9.51388 11.4451 9.53375 11.1786 9.53406C10.9848 9.53389 10.7912 9.52314 10.5985 9.50183L8.58942 11.7604L10.8297 14.0007C11.0335 14.2097 11.2767 14.3763 11.5452 14.4907C11.8138 14.6052 12.1024 14.6652 12.3943 14.6674H12.4176C12.8604 14.6643 13.2924 14.5307 13.6596 14.2832C14.0268 14.0356 14.3128 13.6853 14.4818 13.276C14.6508 12.8667 14.6952 12.4167 14.6096 11.9822C14.524 11.5478 14.3122 11.1483 14.0006 10.8337L12.5043 9.33348Z" fill="#444CE7"/>
+<path d="M14.4606 3.79227C14.4443 3.74889 14.4174 3.71027 14.3823 3.67995C14.3472 3.64963 14.3051 3.62857 14.2599 3.61868C14.2146 3.6088 14.1675 3.6104 14.123 3.62335C14.0785 3.6363 14.0379 3.66018 14.005 3.69282L12.4132 5.27745L10.7224 3.5928L12.3132 2.00929C12.3454 1.97739 12.3692 1.93802 12.3825 1.89468C12.3957 1.85134 12.3981 1.80539 12.3893 1.76092C12.3805 1.7159 12.3606 1.67376 12.3315 1.63828C12.3024 1.60279 12.265 1.57506 12.2226 1.55757C11.7685 1.35982 11.2688 1.29063 10.778 1.35754C9.88338 1.43541 9.05173 1.8501 8.45122 2.51777C7.8507 3.18544 7.52615 4.05624 7.54319 4.95408C7.53907 5.24983 7.58317 5.54428 7.67376 5.82584L2.09204 10.7442C1.64427 11.1439 1.3735 11.7051 1.33923 12.3043C1.30495 12.9036 1.50997 13.4919 1.90924 13.9401L1.95703 13.9924C2.35812 14.411 2.90891 14.6533 3.4885 14.6662C4.06809 14.6791 4.62913 14.4616 5.04848 14.0613C5.11213 14.0008 5.17189 13.9364 5.22739 13.8685L10.1801 8.30058C10.7141 8.43272 11.2688 8.45821 11.8126 8.37559C12.4502 8.24485 13.04 7.9423 13.5182 7.50065C13.9964 7.05899 14.3447 6.49503 14.5256 5.86974C14.7321 5.18882 14.7092 4.45895 14.4606 3.79227Z" fill="#444CE7"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/x-circle.svg b/app/components/base/icons/assets/vender/solid/general/x-circle.svg
new file mode 100644
index 0000000..5acbe5f
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/x-circle.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M8.00008 0.666016C3.94999 0.666016 0.666748 3.94926 0.666748 7.99935C0.666748 12.0494 3.94999 15.3327 8.00008 15.3327C12.0502 15.3327 15.3334 12.0494 15.3334 7.99935C15.3334 3.94926 12.0502 0.666016 8.00008 0.666016ZM10.4715 5.52794C10.7318 5.78829 10.7318 6.2104 10.4715 6.47075L8.94289 7.99935L10.4715 9.52794C10.7318 9.78829 10.7318 10.2104 10.4715 10.4708C10.2111 10.7311 9.78903 10.7311 9.52868 10.4708L8.00008 8.94216L6.47149 10.4708C6.21114 10.7311 5.78903 10.7311 5.52868 10.4708C5.26833 10.2104 5.26833 9.78829 5.52868 9.52794L7.05727 7.99935L5.52868 6.47075C5.26833 6.2104 5.26833 5.78829 5.52868 5.52794C5.78903 5.26759 6.21114 5.26759 6.47149 5.52794L8.00008 7.05654L9.52868 5.52794C9.78903 5.26759 10.2111 5.26759 10.4715 5.52794Z" fill="#98A2B3"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/zap-fast.svg b/app/components/base/icons/assets/vender/solid/general/zap-fast.svg
new file mode 100644
index 0000000..d2dc5ec
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/zap-fast.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="zap-fast">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.25 8.75004C1.25 8.4739 1.47386 8.25004 1.75 8.25004H4.5C4.77614 8.25004 5 8.4739 5 8.75004C5 9.02618 4.77614 9.25004 4.5 9.25004H1.75C1.47386 9.25004 1.25 9.02618 1.25 8.75004Z" fill="#3538CD"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M0.5 6.00004C0.5 5.7239 0.723858 5.50004 1 5.50004H3.25C3.52614 5.50004 3.75 5.7239 3.75 6.00004C3.75 6.27618 3.52614 6.50004 3.25 6.50004H1C0.723858 6.50004 0.5 6.27618 0.5 6.00004Z" fill="#3538CD"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 3.25004C1.5 2.9739 1.72386 2.75004 2 2.75004H4.5C4.77614 2.75004 5 2.9739 5 3.25004C5 3.52618 4.77614 3.75004 4.5 3.75004H2C1.72386 3.75004 1.5 3.52618 1.5 3.25004Z" fill="#3538CD"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.68379 1.03505C8.89736 1.11946 9.02596 1.33849 8.99561 1.56612L8.57109 4.75004H10.4727C10.4785 4.75004 10.4842 4.75004 10.49 4.75004C10.6003 4.75002 10.7147 4.74999 10.8092 4.75863C10.9022 4.76713 11.0713 4.78965 11.2224 4.90631C11.3987 5.04237 11.5054 5.24972 11.5137 5.47225C11.5208 5.66306 11.4408 5.81376 11.3937 5.89434C11.3458 5.97625 11.2793 6.06932 11.2151 6.15912C11.2118 6.16381 11.2084 6.16849 11.2051 6.17316L7.90687 10.7907C7.77339 10.9775 7.52978 11.0495 7.31621 10.965C7.10264 10.8806 6.97404 10.6616 7.00439 10.434L7.42891 7.25004H5.52728C5.52154 7.25004 5.51579 7.25004 5.51003 7.25004C5.39966 7.25007 5.28526 7.25009 5.19077 7.24145C5.09782 7.23296 4.92871 7.21044 4.77755 7.09377C4.60127 6.95771 4.49456 6.75036 4.48631 6.52783C4.47924 6.33702 4.5592 6.18632 4.60631 6.10575C4.65421 6.02383 4.72072 5.93076 4.78489 5.84097C4.78824 5.83628 4.79158 5.8316 4.79492 5.82693L8.09313 1.20942C8.22661 1.02255 8.47022 0.950633 8.68379 1.03505Z" fill="#3538CD"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/general/zap-narrow.svg b/app/components/base/icons/assets/vender/solid/general/zap-narrow.svg
new file mode 100644
index 0000000..1d7a8ba
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/general/zap-narrow.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="zap-narrow">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M6.69792 1.03505C6.91148 1.11946 7.04009 1.33849 7.00974 1.56612L6.58522 4.75004H8.48685C8.49259 4.75004 8.49834 4.75004 8.5041 4.75004C8.61447 4.75002 8.72887 4.74999 8.82336 4.75863C8.91631 4.76713 9.08541 4.78965 9.23657 4.90631C9.41286 5.04237 9.51956 5.24972 9.52781 5.47225C9.53489 5.66306 9.45493 5.81376 9.40781 5.89434C9.35992 5.97625 9.29341 6.06932 9.22924 6.15912C9.22589 6.16381 9.22255 6.16849 9.21921 6.17316L5.92099 10.7907C5.78752 10.9775 5.54391 11.0495 5.33034 10.965C5.11677 10.8806 4.98816 10.6616 5.01851 10.434L5.44304 7.25004H3.5414C3.53567 7.25004 3.52992 7.25004 3.52416 7.25004C3.41378 7.25007 3.29939 7.25009 3.2049 7.24145C3.11194 7.23296 2.94284 7.21044 2.79168 7.09377C2.6154 6.95771 2.50869 6.75036 2.50044 6.52783C2.49336 6.33702 2.57333 6.18632 2.62044 6.10575C2.66833 6.02383 2.73484 5.93076 2.79901 5.84097C2.80236 5.83628 2.80571 5.8316 2.80904 5.82693L6.10726 1.20942C6.24074 1.02255 6.48435 0.950633 6.69792 1.03505Z" fill="#3538CD"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/layout/grid-01.svg b/app/components/base/icons/assets/vender/solid/layout/grid-01.svg
new file mode 100644
index 0000000..1ffbf44
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/layout/grid-01.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="grid-01">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.04545 1.33338C3.90407 1.33348 4.76437 1.33348 5.62131 1.33338C5.78956 1.33336 5.95343 1.33334 6.0922 1.34467C6.24459 1.35713 6.42442 1.3865 6.60536 1.4787C6.85625 1.60653 7.06022 1.81051 7.18805 2.06139C7.28025 2.24234 7.30963 2.42216 7.32208 2.57456C7.33342 2.71333 7.3334 2.8772 7.33338 3.04546V5.6213C7.3334 5.78956 7.33342 5.95342 7.32208 6.0922C7.30963 6.24459 7.28025 6.42442 7.18805 6.60536C7.06022 6.85625 6.85625 7.06022 6.60536 7.18805C6.42442 7.28025 6.24459 7.30963 6.0922 7.32208C5.95342 7.33342 5.78956 7.3334 5.6213 7.33338H3.04546C2.8772 7.3334 2.71333 7.33342 2.57456 7.32208C2.42216 7.30963 2.24234 7.28025 2.06139 7.18805C1.81051 7.06022 1.60653 6.85625 1.4787 6.60536C1.3865 6.42442 1.35713 6.24459 1.34467 6.0922C1.33334 5.95343 1.33336 5.78956 1.33338 5.62131C1.33338 5.61423 1.33338 5.60714 1.33338 5.60004V3.06671C1.33338 3.05962 1.33338 3.05253 1.33338 3.04545C1.33336 2.87719 1.33334 2.71333 1.34467 2.57456C1.35713 2.42216 1.3865 2.24234 1.4787 2.06139C1.60653 1.81051 1.81051 1.60653 2.06139 1.4787C2.24234 1.3865 2.42216 1.35713 2.57456 1.34467C2.71333 1.33334 2.87719 1.33336 3.04545 1.33338Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.04545 8.66671C3.90407 8.66682 4.76437 8.66682 5.62131 8.66671C5.78956 8.66669 5.95343 8.66667 6.0922 8.67801C6.24459 8.69046 6.42442 8.71984 6.60536 8.81204C6.85625 8.93987 7.06022 9.14384 7.18805 9.39472C7.28025 9.57567 7.30963 9.7555 7.32208 9.90789C7.33342 10.0467 7.3334 10.2105 7.33338 10.3788V12.9546C7.3334 13.1229 7.33342 13.2868 7.32208 13.4255C7.30963 13.5779 7.28025 13.7577 7.18805 13.9387C7.06022 14.1896 6.85625 14.3936 6.60536 14.5214C6.42442 14.6136 6.24459 14.643 6.0922 14.6554C5.95342 14.6668 5.78956 14.6667 5.6213 14.6667H3.04546C2.8772 14.6667 2.71333 14.6668 2.57456 14.6554C2.42216 14.643 2.24234 14.6136 2.06139 14.5214C1.81051 14.3936 1.60653 14.1896 1.4787 13.9387C1.3865 13.7577 1.35713 13.5779 1.34467 13.4255C1.33334 13.2868 1.33336 13.1229 1.33338 12.9546C1.33338 12.9476 1.33338 12.9405 1.33338 12.9334V10.4C1.33338 10.3929 1.33338 10.3859 1.33338 10.3788C1.33336 10.2105 1.33334 10.0467 1.34467 9.90789C1.35713 9.7555 1.3865 9.57567 1.4787 9.39472C1.60653 9.14384 1.81051 8.93987 2.06139 8.81204C2.24234 8.71984 2.42216 8.69046 2.57456 8.67801C2.71333 8.66667 2.87719 8.66669 3.04545 8.66671Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M10.3788 1.33338C11.2374 1.33348 12.0977 1.33348 12.9546 1.33338C13.1229 1.33336 13.2868 1.33334 13.4255 1.34467C13.5779 1.35713 13.7577 1.3865 13.9387 1.4787C14.1896 1.60653 14.3936 1.81051 14.5214 2.06139C14.6136 2.24234 14.643 2.42216 14.6554 2.57456C14.6668 2.71333 14.6667 2.8772 14.6667 3.04546V5.6213C14.6667 5.78956 14.6668 5.95342 14.6554 6.0922C14.643 6.24459 14.6136 6.42442 14.5214 6.60536C14.3936 6.85625 14.1896 7.06022 13.9387 7.18805C13.7577 7.28025 13.5779 7.30963 13.4255 7.32208C13.2868 7.33342 13.1229 7.3334 12.9546 7.33338H10.3788C10.2105 7.3334 10.0467 7.33342 9.90789 7.32208C9.7555 7.30963 9.57567 7.28025 9.39472 7.18805C9.14384 7.06022 8.93987 6.85625 8.81204 6.60536C8.71984 6.42442 8.69046 6.24459 8.67801 6.0922C8.66667 5.95343 8.66669 5.78956 8.66671 5.62131C8.66671 5.61423 8.66671 5.60714 8.66671 5.60004V3.06671C8.66671 3.05962 8.66671 3.05253 8.66671 3.04545C8.66669 2.87719 8.66667 2.71333 8.67801 2.57456C8.69046 2.42216 8.71984 2.24234 8.81204 2.06139C8.93987 1.81051 9.14384 1.60653 9.39472 1.4787C9.57567 1.3865 9.7555 1.35713 9.90789 1.34467C10.0467 1.33334 10.2105 1.33336 10.3788 1.33338Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M10.3788 8.66671C11.2374 8.66682 12.0977 8.66682 12.9546 8.66671C13.1229 8.66669 13.2868 8.66667 13.4255 8.67801C13.5779 8.69046 13.7577 8.71984 13.9387 8.81204C14.1896 8.93987 14.3936 9.14384 14.5214 9.39472C14.6136 9.57567 14.643 9.7555 14.6554 9.90789C14.6668 10.0467 14.6667 10.2105 14.6667 10.3788V12.9546C14.6667 13.1229 14.6668 13.2868 14.6554 13.4255C14.643 13.5779 14.6136 13.7577 14.5214 13.9387C14.3936 14.1896 14.1896 14.3936 13.9387 14.5214C13.7577 14.6136 13.5779 14.643 13.4255 14.6554C13.2868 14.6668 13.1229 14.6667 12.9546 14.6667H10.3788C10.2105 14.6667 10.0467 14.6668 9.90789 14.6554C9.7555 14.643 9.57567 14.6136 9.39472 14.5214C9.14384 14.3936 8.93987 14.1896 8.81204 13.9387C8.71984 13.7577 8.69046 13.5779 8.67801 13.4255C8.66667 13.2868 8.66669 13.1229 8.66671 12.9546C8.66671 12.9476 8.66671 12.9405 8.66671 12.9334V10.4C8.66671 10.3929 8.66671 10.3859 8.66671 10.3788C8.66669 10.2105 8.66667 10.0467 8.67801 9.90789C8.69046 9.7555 8.71984 9.57567 8.81204 9.39472C8.93987 9.14384 9.14384 8.93987 9.39472 8.81204C9.57567 8.71984 9.7555 8.69046 9.90789 8.67801C10.0467 8.66667 10.2105 8.66669 10.3788 8.66671Z" fill="#155EEF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mapsAndTravel/globe-06.svg b/app/components/base/icons/assets/vender/solid/mapsAndTravel/globe-06.svg
new file mode 100644
index 0000000..45f3778
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mapsAndTravel/globe-06.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.39498 2.71706C6.90587 2.57557 7.44415 2.49996 8.00008 2.49996C9.30806 2.49996 10.5183 2.91849 11.5041 3.62893C10.9796 3.97562 10.5883 4.35208 10.3171 4.75458C9.90275 5.36959 9.79654 6.00558 9.88236 6.58587C9.96571 7.1494 10.2245 7.63066 10.4965 7.98669C10.7602 8.33189 11.0838 8.6206 11.3688 8.76305C12.0863 9.12177 12.9143 9.30141 13.5334 9.39399C14.0933 9.47774 15.2805 9.75802 15.3244 8.86608C15.3304 8.74474 15.3334 8.62267 15.3334 8.49996C15.3334 4.44987 12.0502 1.16663 8.00008 1.16663C3.94999 1.16663 0.666748 4.44987 0.666748 8.49996C0.666748 12.55 3.94999 15.8333 8.00008 15.8333C8.1228 15.8333 8.24486 15.8303 8.3662 15.8243C8.73395 15.8062 9.01738 15.4934 8.99927 15.1256C8.98117 14.7579 8.66837 14.4745 8.30063 14.4926C8.20111 14.4975 8.10091 14.5 8.00008 14.5C5.6605 14.5 3.63367 13.1609 2.6442 11.2074L3.28991 10.8346L5.67171 11.2804C6.28881 11.3959 6.85846 10.9208 6.85566 10.293L6.84632 8.19093L8.06357 6.10697C8.26079 5.76932 8.24312 5.3477 8.01833 5.02774L6.39498 2.71706Z" fill="#1570EF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.29718 8.93736C9.05189 8.84432 8.77484 8.90379 8.58934 9.08929C8.40383 9.27479 8.34437 9.55184 8.43741 9.79713L10.5486 15.363C10.6461 15.6199 10.8912 15.7908 11.166 15.7932C11.4408 15.7956 11.689 15.6292 11.791 15.374L12.6714 13.1714L14.874 12.2909C15.1292 12.1889 15.2957 11.9408 15.2932 11.666C15.2908 11.3912 15.12 11.146 14.863 11.0486L9.29718 8.93736Z" fill="#1570EF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mapsAndTravel/route.svg b/app/components/base/icons/assets/vender/solid/mapsAndTravel/route.svg
new file mode 100644
index 0000000..b647dfc
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mapsAndTravel/route.svg
@@ -0,0 +1,7 @@
+<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="route-sep">
+<path id="Icon" d="M6.08303 2.5H6.30023C7.82386 2.5 8.58567 2.5 8.87485 2.77364C9.12483 3.01018 9.23561 3.35864 9.16812 3.69611C9.09004 4.08651 8.46809 4.52643 7.22418 5.40627L5.19189 6.84373C3.94799 7.72357 3.32603 8.16349 3.24795 8.55389C3.18046 8.89136 3.29124 9.23982 3.54122 9.47636C3.8304 9.75 4.59221 9.75 6.11584 9.75H6.58303" stroke="#F79009" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Icon_2" d="M2.83301 4C3.66143 4 4.33301 3.32843 4.33301 2.5C4.33301 1.67157 3.66143 1 2.83301 1C2.00458 1 1.33301 1.67157 1.33301 2.5C1.33301 3.32843 2.00458 4 2.83301 4Z" fill="#F79009"/>
+<path id="Icon_3" d="M9.83301 11C10.6614 11 11.333 10.3284 11.333 9.5C11.333 8.67157 10.6614 8 9.83301 8C9.00458 8 8.33301 8.67157 8.33301 9.5C8.33301 10.3284 9.00458 11 9.83301 11Z" fill="#F79009"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/audio-support-icon.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/audio-support-icon.svg
new file mode 100644
index 0000000..cad145c
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/audio-support-icon.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
+ <path d="M10.3567 3.56405L10.2334 3.84689C10.1432 4.05396 9.8568 4.05396 9.76655 3.84689L9.6433 3.56405C9.42355 3.05973 9.02775 2.6582 8.53385 2.43854L8.154 2.26961C7.94865 2.17826 7.94865 1.8794 8.154 1.78806L8.5126 1.62857C9.0192 1.40325 9.4221 0.986865 9.63805 0.465414L9.76465 0.159767C9.8529 -0.0532556 10.1471 -0.0532556 10.2353 0.159767L10.3619 0.465414C10.5779 0.986865 10.9808 1.40325 11.4874 1.62857L11.846 1.78806C12.0514 1.8794 12.0514 2.17826 11.846 2.26961L11.4662 2.43854C10.9723 2.6582 10.5764 3.05973 10.3567 3.56405ZM4.25 3H3.25V9H4.25V3ZM2 5H1V7H2V5ZM6.5 1H5.5V11H6.5V1ZM8.75 4H7.75V9H8.75V4ZM11 5H10V7H11V5Z" fill="#676F83"/>
+</svg>
\ No newline at end of file
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/document-support-icon.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/document-support-icon.svg
new file mode 100644
index 0000000..d7c0978
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/document-support-icon.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
+ <path d="M10.5 4V10.4966C10.5 10.7751 10.2776 11 10.0033 11H1.9967C1.72248 11 1.5 10.778 1.5 10.5041V1.4959C1.5 1.22766 1.72435 1 2.00111 1H7.4984L10.5 4ZM9.5 4.5H7V2H2.5V10H9.5V4.5ZM4 3.5H5.5V4.5H4V3.5ZM4 5.5H8V6.5H4V5.5ZM4 7.5H8V8.5H4V7.5Z" fill="#676F83"/>
+</svg>
\ No newline at end of file
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-box.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-box.svg
new file mode 100644
index 0000000..855ac45
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-box.svg
@@ -0,0 +1,9 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="box-sparkle, magic box">
+<g id="Icon">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.76205 2.07424C9.99723 2.21897 10.0706 2.52694 9.92583 2.76212L8.85632 4.50007H9.5C9.77614 4.50007 10 4.72393 10 5.00007V9.00007C10 10.1046 9.10457 11.0001 8 11.0001H4C2.89543 11.0001 2 10.1046 2 9.00007V5.00007C2 4.72393 2.22386 4.50007 2.5 4.50007H7.68214L9.07417 2.23802C9.2189 2.00284 9.52687 1.92952 9.76205 2.07424ZM5 6.50007C4.72386 6.50007 4.5 6.72393 4.5 7.00007C4.5 7.27621 4.72386 7.50007 5 7.50007H7C7.27614 7.50007 7.5 7.27621 7.5 7.00007C7.5 6.72393 7.27614 6.50007 7 6.50007H5Z" fill="#667085"/>
+<path d="M5.92504 1.53733C5.97342 1.51314 6.01265 1.47391 6.03684 1.42553L6.27597 0.947279C6.3681 0.763016 6.63105 0.763017 6.72318 0.947279L6.96231 1.42553C6.9865 1.47391 7.02573 1.51314 7.07411 1.53733L7.55236 1.77646C7.73663 1.86859 7.73663 2.13154 7.55236 2.22367L7.07411 2.4628C7.02573 2.48699 6.9865 2.52622 6.96231 2.5746L6.72318 3.05285C6.63105 3.23711 6.3681 3.23711 6.27597 3.05285L6.03684 2.5746C6.01265 2.52622 5.97342 2.48699 5.92504 2.4628L5.44679 2.22367C5.26253 2.13154 5.26253 1.86859 5.44679 1.77646L5.92504 1.53733Z" fill="#667085"/>
+<path d="M3.25837 2.37067C3.30676 2.34648 3.34599 2.30724 3.37018 2.25886L3.52597 1.94728C3.6181 1.76302 3.88105 1.76302 3.97318 1.94728L4.12898 2.25886C4.15317 2.30724 4.1924 2.34648 4.24078 2.37067L4.55236 2.52646C4.73662 2.61859 4.73663 2.88154 4.55236 2.97367L4.24078 3.12946C4.1924 3.15365 4.15317 3.19289 4.12898 3.24127L3.97318 3.55285C3.88105 3.73711 3.6181 3.73711 3.52597 3.55285L3.37018 3.24127C3.34599 3.19289 3.30676 3.15365 3.25837 3.12946L2.94679 2.97367C2.76253 2.88154 2.76253 2.61859 2.94679 2.52646L3.25837 2.37067Z" fill="#667085"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-eyes.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-eyes.svg
new file mode 100644
index 0000000..d56a375
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-eyes.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="eye-sparkle, magic eyes">
+<path id="Icon" fill-rule="evenodd" clip-rule="evenodd" d="M11.0338 5.05688C9.75366 3.05335 7.90203 1.99999 6.00017 2C4.09831 2.00001 2.24669 3.05341 0.966566 5.05693C0.599687 5.63113 0.599686 6.36892 0.966566 6.94312C2.24669 8.94665 4.09832 10 6.00018 10C7.90204 9.99999 9.75366 8.94659 11.0338 6.94307C11.4007 6.36887 11.4007 5.63108 11.0338 5.05688ZM5.77639 4.44721L5.3706 5.2588C5.34641 5.30718 5.30718 5.34641 5.2588 5.3706L4.44721 5.77639C4.26295 5.86852 4.26295 6.13148 4.44721 6.22361L5.2588 6.6294C5.30718 6.65359 5.34641 6.69282 5.3706 6.7412L5.77639 7.55279C5.86852 7.73705 6.13148 7.73705 6.22361 7.55279L6.6294 6.7412C6.65359 6.69282 6.69282 6.65359 6.7412 6.6294L7.55279 6.22361C7.73705 6.13148 7.73705 5.86852 7.55279 5.77639L6.7412 5.3706C6.69282 5.34641 6.65359 5.30718 6.6294 5.2588L6.22361 4.44721C6.13148 4.26295 5.86852 4.26295 5.77639 4.44721Z" fill="#667085"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-wand.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-wand.svg
new file mode 100644
index 0000000..ea4ccb1
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-wand.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="magic-wand-2, magic stick, star">
+<g id="Icon">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.27056 1.77151C8.811 1.23107 9.68723 1.23107 10.2277 1.77151C10.7681 2.31195 10.7681 3.18818 10.2277 3.72862L3.72767 10.2286C3.18723 10.7691 2.31101 10.7691 1.77056 10.2286C1.23012 9.68818 1.23012 8.81195 1.77056 8.27151L8.27056 1.77151ZM9.52056 2.47862C9.37065 2.3287 9.12759 2.3287 8.97767 2.47862L8.08122 3.37506L8.62412 3.91796L9.52056 3.02151C9.67048 2.87159 9.67048 2.62853 9.52056 2.47862Z" fill="#667085"/>
+<path d="M4.92504 1.03733C4.97342 1.01314 5.01265 0.973911 5.03684 0.92553L5.27597 0.447279C5.3681 0.263016 5.63105 0.263017 5.72318 0.447279L5.96231 0.92553C5.9865 0.973911 6.02573 1.01314 6.07411 1.03733L6.55236 1.27646C6.73663 1.36859 6.73663 1.63154 6.55236 1.72367L6.07411 1.9628C6.02573 1.98699 5.9865 2.02622 5.96231 2.0746L5.72318 2.55285C5.63105 2.73711 5.3681 2.73711 5.27597 2.55285L5.03684 2.0746C5.01265 2.02622 4.97342 1.98699 4.92504 1.9628L4.44679 1.72367C4.26253 1.63154 4.26253 1.36859 4.44679 1.27646L4.92504 1.03733Z" fill="#667085"/>
+<path d="M9.42504 6.53733C9.47342 6.51314 9.51265 6.47391 9.53684 6.42553L9.77597 5.94728C9.8681 5.76302 10.1311 5.76302 10.2232 5.94728L10.4623 6.42553C10.4865 6.47391 10.5257 6.51314 10.5741 6.53733L11.0524 6.77646C11.2366 6.86859 11.2366 7.13154 11.0524 7.22367L10.5741 7.4628C10.5257 7.48699 10.4865 7.52622 10.4623 7.5746L10.2232 8.05285C10.1311 8.23711 9.8681 8.23711 9.77597 8.05285L9.53684 7.5746C9.51265 7.52622 9.47342 7.48699 9.42504 7.4628L8.94679 7.22367C8.76253 7.13154 8.76253 6.86859 8.94679 6.77646L9.42504 6.53733Z" fill="#667085"/>
+<path d="M2.42504 3.53733C2.47342 3.51314 2.51265 3.47391 2.53684 3.42553L2.77597 2.94728C2.8681 2.76302 3.13105 2.76302 3.22318 2.94728L3.46231 3.42553C3.4865 3.47391 3.52573 3.51314 3.57411 3.53733L4.05236 3.77646C4.23663 3.86859 4.23663 4.13154 4.05236 4.22367L3.57411 4.4628C3.52573 4.48699 3.4865 4.52622 3.46231 4.5746L3.22318 5.05285C3.13105 5.23711 2.8681 5.23711 2.77597 5.05285L2.53684 4.5746C2.51265 4.52622 2.47342 4.48699 2.42504 4.4628L1.94679 4.22367C1.76253 4.13154 1.76253 3.86859 1.94679 3.77646L2.42504 3.53733Z" fill="#667085"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/microphone-01.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/microphone-01.svg
new file mode 100644
index 0000000..8727719
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/microphone-01.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="microphone-01">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.00008 0.666016C6.52732 0.666016 5.33341 1.85992 5.33341 3.33268V7.99935C5.33341 9.47211 6.52732 10.666 8.00008 10.666C9.47284 10.666 10.6667 9.47211 10.6667 7.99935V3.33268C10.6667 1.85992 9.47284 0.666016 8.00008 0.666016Z" fill="#155EEF"/>
+<path d="M4.00008 6.66602C4.00008 6.29783 3.7016 5.99935 3.33341 5.99935C2.96522 5.99935 2.66675 6.29783 2.66675 6.66602V7.99935C2.66675 10.7195 4.70319 12.9641 7.33466 13.2916C7.33384 13.3052 7.33341 13.3189 7.33341 13.3327V13.9993H5.33341C4.96522 13.9993 4.66675 14.2978 4.66675 14.666C4.66675 15.0342 4.96522 15.3327 5.33341 15.3327H10.6667C11.0349 15.3327 11.3334 15.0342 11.3334 14.666C11.3334 14.2978 11.0349 13.9993 10.6667 13.9993H8.66675V13.3327C8.66675 13.3189 8.66633 13.3052 8.6655 13.2916C11.297 12.9641 13.3334 10.7195 13.3334 7.99935V6.66602C13.3334 6.29783 13.0349 5.99935 12.6667 5.99935C12.2986 5.99935 12.0001 6.29783 12.0001 6.66602V7.99935C12.0001 10.2085 10.2092 11.9993 8.00008 11.9993C5.79094 11.9993 4.00008 10.2085 4.00008 7.99935V6.66602Z" fill="#155EEF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/play.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/play.svg
new file mode 100644
index 0000000..545e407
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/play.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="play">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M4.00312 1.40109C4.0091 1.40508 4.0151 1.40907 4.02111 1.41309L9.29548 4.92933C9.44809 5.03105 9.58959 5.12537 9.69827 5.21301C9.81168 5.30448 9.94538 5.43132 10.0223 5.61687C10.124 5.86212 10.124 6.13775 10.0223 6.38301C9.94538 6.56856 9.81168 6.6954 9.69827 6.78686C9.5896 6.8745 9.44811 6.96881 9.2955 7.07053L4.00314 10.5988C3.8166 10.7232 3.64886 10.835 3.50652 10.9121C3.36409 10.9893 3.16859 11.0775 2.9404 11.0639C2.64852 11.0465 2.3789 10.9022 2.20249 10.669C2.06458 10.4867 2.02952 10.2751 2.01474 10.1138C1.99997 9.95254 1.99999 9.75094 2 9.52674L2 2.49475C2 2.48752 2 2.48031 2 2.47313C1.99999 2.24893 1.99997 2.04733 2.01474 1.88612C2.02952 1.72479 2.06458 1.5132 2.20249 1.33089C2.3789 1.0977 2.64852 0.953401 2.9404 0.935973C3.16859 0.922349 3.36409 1.01055 3.50652 1.08774C3.64885 1.16488 3.81659 1.27672 4.00312 1.40109Z" fill="#155EEF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/robot.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/robot.svg
new file mode 100644
index 0000000..72d8ddf
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/robot.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="robot, bot">
+<path id="Icon" fill-rule="evenodd" clip-rule="evenodd" d="M6 0.5C6.27614 0.5 6.5 0.723858 6.5 1V1.5H8.5C9.32843 1.5 10 2.17157 10 3V5.5C10 5.94425 9.80688 6.34339 9.5 6.61805V7.29289L10.3536 8.14645C10.5488 8.34171 10.5488 8.65829 10.3536 8.85355C10.1583 9.04882 9.84171 9.04882 9.64645 8.85355L9.34052 8.54762C8.89526 9.96884 7.56805 11 6 11C4.43195 11 3.10474 9.96884 2.65948 8.54762L2.35355 8.85355C2.15829 9.04882 1.84171 9.04882 1.64645 8.85355C1.45118 8.65829 1.45118 8.34171 1.64645 8.14645L2.5 7.29289V6.61805C2.19313 6.34339 2 5.94425 2 5.5V3C2 2.17157 2.67157 1.5 3.5 1.5H5.5V1C5.5 0.723858 5.72386 0.5 6 0.5ZM3.5 2.5C3.22386 2.5 3 2.72386 3 3V5.5C3 5.77614 3.22386 6 3.5 6H8.5C8.77614 6 9 5.77614 9 5.5V3C9 2.72386 8.77614 2.5 8.5 2.5H3.5ZM4.5 3.5C4.77614 3.5 5 3.72386 5 4V4.5C5 4.77614 4.77614 5 4.5 5C4.22386 5 4 4.77614 4 4.5V4C4 3.72386 4.22386 3.5 4.5 3.5ZM7.5 3.5C7.77614 3.5 8 3.72386 8 4V4.5C8 4.77614 7.77614 5 7.5 5C7.22386 5 7 4.77614 7 4.5V4C7 3.72386 7.22386 3.5 7.5 3.5Z" fill="#667085"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/sliders-02.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/sliders-02.svg
new file mode 100644
index 0000000..42ff057
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/sliders-02.svg
@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5 2C5.55228 2 6 2.44772 6 3V7C6 7.55228 5.55228 8 5 8C4.44772 8 4 7.55228 4 7V3C4 2.44772 4.44772 2 5 2Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6 15.8293C7.16519 15.4175 8 14.3062 8 13C8 11.3431 6.65685 10 5 10C3.34315 10 2 11.3431 2 13C2 14.3062 2.83481 15.4175 4 15.8293L4 21C4 21.5523 4.44772 22 5 22C5.55229 22 6 21.5523 6 21L6 15.8293Z" fill="black"/>
+<path d="M13 15C13 14.4477 12.5523 14 12 14C11.4477 14 11 14.4477 11 15V21C11 21.5523 11.4477 22 12 22C12.5523 22 13 21.5523 13 21V15Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C12.5523 2 13 2.44772 13 3V6.17071C14.1652 6.58254 15 7.69378 15 9C15 10.6569 13.6569 12 12 12C10.3431 12 9 10.6569 9 9C9 7.69378 9.83481 6.58254 11 6.17071V3C11 2.44772 11.4477 2 12 2Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M22 15C22 16.3062 21.1652 17.4175 20 17.8293V21C20 21.5523 19.5523 22 19 22C18.4477 22 18 21.5523 18 21V17.8293C16.8348 17.4175 16 16.3062 16 15C16 13.3431 17.3431 12 19 12C20.6569 12 22 13.3431 22 15Z" fill="black"/>
+<path d="M19 2C19.5523 2 20 2.44772 20 3V9C20 9.55228 19.5523 10 19 10C18.4477 10 18 9.55228 18 9V3C18 2.44772 18.4477 2 19 2Z" fill="black"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/speaker.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/speaker.svg
new file mode 100644
index 0000000..f769c7e
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/speaker.svg
@@ -0,0 +1,15 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_109_6694)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.86666C0 2.05664 0.656649 1.39999 1.46667 1.39999H5.86667C6.67668 1.39999 7.33333 2.05664 7.33333 2.86666C7.33333 3.27167 7.00501 3.59999 6.6 3.59999C6.19499 3.59999 5.86667 3.27167 5.86667 2.86666H4.4V7.99999C4.80501 7.99999 5.13333 8.32831 5.13333 8.73332C5.13333 9.13833 4.80501 9.46666 4.4 9.46666H2.93333C2.52832 9.46666 2.2 9.13833 2.2 8.73332C2.2 8.32831 2.52832 7.99999 2.93333 7.99999V2.86666H1.46667C1.46667 3.27167 1.13834 3.59999 0.733333 3.59999C0.328324 3.59999 0 3.27167 0 2.86666Z" fill="#444CE7"/>
+<path d="M13.8205 0.782296C13.7434 0.62811 13.5233 0.62811 13.4462 0.782296C12.9664 1.74206 12.8754 1.83302 11.9156 2.3129C11.7615 2.39 11.7615 2.61003 11.9156 2.68712C12.8754 3.167 12.9664 3.25797 13.4462 4.21773C13.5233 4.37191 13.7434 4.37191 13.8205 4.21773C14.3003 3.25797 14.3913 3.167 15.3511 2.68712C15.5053 2.61003 15.5053 2.39 15.3511 2.3129C14.3913 1.83302 14.3003 1.74206 13.8205 0.782296Z" fill="#444CE7"/>
+<path d="M9.79394 2.25319C9.71404 2.09337 9.48596 2.09337 9.40605 2.25319C9.04994 2.96543 8.96544 3.04993 8.2532 3.40605C8.09338 3.48595 8.09338 3.71402 8.2532 3.79393C8.96544 4.15005 9.04994 4.23455 9.40606 4.94679C9.48596 5.10661 9.71404 5.10661 9.79394 4.94679C10.1501 4.23455 10.2346 4.15005 10.9468 3.79393C11.1066 3.71402 11.1066 3.48595 10.9468 3.40605C10.2346 3.04993 10.1501 2.96543 9.79394 2.25319Z" fill="#444CE7"/>
+<path d="M2.75377 11.049C2.67668 10.8948 2.45665 10.8948 2.37956 11.049C1.89969 12.0087 1.80872 12.0997 0.848971 12.5796C0.694788 12.6566 0.694787 12.8767 0.848971 12.9538C1.80872 13.4336 1.89969 13.5246 2.37956 14.4844C2.45665 14.6385 2.67668 14.6385 2.75377 14.4844C3.23365 13.5246 3.32461 13.4336 4.28436 12.9538C4.43855 12.8767 4.43855 12.6566 4.28436 12.5796C3.32461 12.0997 3.23365 12.0087 2.75377 11.049Z" fill="#444CE7"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14.6741 8.65106C14.8886 8.50146 15.1837 8.55405 15.3333 8.76853C15.7614 9.38226 16.0125 10.1292 16.0125 10.9333C16.0125 11.7375 15.7614 12.4844 15.3333 13.0981C15.1837 13.3126 14.8886 13.3652 14.6741 13.2156C14.4596 13.066 14.407 12.7708 14.5567 12.5564C14.8775 12.0964 15.0656 11.5375 15.0656 10.9333C15.0656 10.3291 14.8775 9.77025 14.5567 9.31028C14.407 9.09581 14.4596 8.80066 14.6741 8.65106Z" fill="#444CE7"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.5674 6.53771C12.794 6.51987 13.0155 6.61161 13.1632 6.78449C13.2954 6.93929 13.3164 7.12549 13.3244 7.21587C13.3334 7.31718 13.3334 7.44301 13.3333 7.57103C13.3333 7.57691 13.3333 7.58278 13.3333 7.58866L13.3333 14.3C13.3334 14.428 13.3334 14.5539 13.3244 14.6552C13.3164 14.7455 13.2954 14.9317 13.1632 15.0865C13.0155 15.2594 12.794 15.3512 12.5674 15.3333C12.3644 15.3173 12.2179 15.2005 12.1484 15.1423C12.0704 15.077 11.9814 14.988 11.8909 14.8975L10.3795 13.3861C10.3357 13.3423 10.3137 13.3205 10.2971 13.3053L10.2958 13.3041L10.2941 13.3041C10.2716 13.303 10.2407 13.3029 10.1787 13.3029L9.34101 13.3029C9.22151 13.3029 9.10513 13.3029 9.00657 13.2949C8.89833 13.286 8.77062 13.2652 8.6421 13.1997C8.46392 13.1089 8.31906 12.964 8.22827 12.7859C8.16279 12.6574 8.14192 12.5296 8.13308 12.4214C8.12503 12.3228 8.12504 12.2065 8.12505 12.087V9.79916C8.12505 9.79413 8.12505 9.78909 8.12505 9.78406C8.12504 9.66456 8.12503 9.54819 8.13308 9.44963C8.14192 9.34139 8.16279 9.21368 8.22827 9.08517C8.31906 8.90699 8.46392 8.76212 8.6421 8.67133C8.77062 8.60585 8.89833 8.58498 9.00657 8.57614C9.10512 8.56809 9.2215 8.5681 9.341 8.56812C9.34603 8.56812 9.35106 8.56812 9.3561 8.56812H10.1787C10.2407 8.56812 10.2716 8.56801 10.2941 8.56698L10.2958 8.5669L10.2971 8.56575C10.3137 8.55058 10.3357 8.52877 10.3795 8.48491L11.8784 6.98602C11.8826 6.98186 11.8867 6.97771 11.8909 6.97355C11.9814 6.88302 12.0704 6.79403 12.1484 6.72874C12.2179 6.67049 12.3644 6.55368 12.5674 6.53771Z" fill="#444CE7"/>
+</g>
+<defs>
+<clipPath id="clip0_109_6694">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/stop-circle.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/stop-circle.svg
new file mode 100644
index 0000000..3009a52
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/stop-circle.svg
@@ -0,0 +1,5 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="stop-circle">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M9.99992 0.833984C4.93731 0.833984 0.833252 4.93804 0.833252 10.0007C0.833252 15.0633 4.93731 19.1673 9.99992 19.1673C15.0625 19.1673 19.1666 15.0633 19.1666 10.0007C19.1666 4.93804 15.0625 0.833984 9.99992 0.833984ZM6.75741 7.12232C6.66658 7.30058 6.66658 7.53394 6.66658 8.00065V12.0006C6.66658 12.4674 6.66658 12.7007 6.75741 12.879C6.83731 13.0358 6.96479 13.1633 7.12159 13.2432C7.29985 13.334 7.53321 13.334 7.99992 13.334H11.9999C12.4666 13.334 12.7 13.334 12.8782 13.2432C13.035 13.1633 13.1625 13.0358 13.2424 12.879C13.3333 12.7007 13.3333 12.4674 13.3333 12.0006V8.00065C13.3333 7.53394 13.3333 7.30058 13.2424 7.12232C13.1625 6.96552 13.035 6.83804 12.8782 6.75814C12.7 6.66732 12.4666 6.66732 11.9999 6.66732H7.99992C7.53321 6.66732 7.29985 6.66732 7.12159 6.75814C6.96479 6.83804 6.83731 6.96552 6.75741 7.12232Z" fill="#155EEF"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/mediaAndDevices/video-support-icon.svg b/app/components/base/icons/assets/vender/solid/mediaAndDevices/video-support-icon.svg
new file mode 100644
index 0000000..f87aa02
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/mediaAndDevices/video-support-icon.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
+ <path d="M10.2334 4.3469L10.3567 4.06406C10.5764 3.55974 10.9723 3.15821 11.4662 2.93854L11.846 2.76961C12.0514 2.67827 12.0514 2.37941 11.846 2.28806L11.4874 2.12857C10.9808 1.90326 10.5779 1.48687 10.3619 0.965415L10.2353 0.659765C10.1471 0.446745 9.8529 0.446745 9.76465 0.659765L9.63805 0.965415C9.4221 1.48687 9.0192 1.90326 8.5126 2.12857L8.154 2.28806C7.94865 2.37941 7.94865 2.67827 8.154 2.76961L8.53385 2.93854C9.02775 3.15821 9.42355 3.55974 9.6433 4.06406L9.76655 4.3469C9.8568 4.55396 10.1432 4.55396 10.2334 4.3469ZM1.4959 1.5H7V2.5H4V9.5H8V4.5H9V5.5H10H11V10.0033C11 10.2776 10.7723 10.5 10.5041 10.5H1.4959C1.22203 10.5 1 10.2775 1 10.0033V1.9967C1 1.72238 1.22766 1.5 1.4959 1.5ZM2 2.5V3.5H3V2.5H2ZM2 4.5V5.5H3V4.5H2ZM2 6.5V7.5H3V6.5H2ZM9 6.5V7.5H10V6.5H9ZM2 8.5V9.5H3V8.5H2ZM9 8.5V9.5H10V8.5H9Z" fill="#676F83"/>
+</svg>
\ No newline at end of file
diff --git a/app/components/base/icons/assets/vender/solid/security/lock-01.svg b/app/components/base/icons/assets/vender/solid/security/lock-01.svg
new file mode 100644
index 0000000..9ca6d8e
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/security/lock-01.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="lock-01">
+<path id="Solid" fill-rule="evenodd" clip-rule="evenodd" d="M3 4C3 2.34315 4.34315 1 6 1C7.65685 1 9 2.34315 9 4V4.57516C9.1413 4.60613 9.27693 4.65121 9.40798 4.71799C9.78431 4.90973 10.0903 5.2157 10.282 5.59202C10.4057 5.83469 10.4549 6.09304 10.4779 6.37409C10.5 6.64468 10.5 6.97686 10.5 7.37934V8.12066C10.5 8.52314 10.5 8.85532 10.4779 9.12591C10.4549 9.40696 10.4057 9.66531 10.282 9.90798C10.0903 10.2843 9.78431 10.5903 9.40798 10.782C9.16531 10.9057 8.90696 10.9549 8.62591 10.9779C8.35531 11 8.02313 11 7.62064 11H4.37936C3.97687 11 3.64469 11 3.37409 10.9779C3.09304 10.9549 2.83469 10.9057 2.59202 10.782C2.2157 10.5903 1.90973 10.2843 1.71799 9.90798C1.59434 9.66531 1.54506 9.40696 1.5221 9.12591C1.49999 8.85532 1.49999 8.52314 1.5 8.12066V7.37934C1.49999 6.97687 1.49999 6.64468 1.5221 6.37409C1.54506 6.09304 1.59434 5.83469 1.71799 5.59202C1.90973 5.2157 2.2157 4.90973 2.59202 4.71799C2.72307 4.65121 2.8587 4.60613 3 4.57516V4ZM8 4V4.50081H4V4C4 2.89543 4.89543 2 6 2C7.10457 2 8 2.89543 8 4ZM6.5 7.25C6.5 6.97386 6.27614 6.75 6 6.75C5.72386 6.75 5.5 6.97386 5.5 7.25V8.25C5.5 8.52614 5.72386 8.75 6 8.75C6.27614 8.75 6.5 8.52614 6.5 8.25V7.25Z" fill="#667085"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/shapes/corner.svg b/app/components/base/icons/assets/vender/solid/shapes/corner.svg
new file mode 100644
index 0000000..9b360e4
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/shapes/corner.svg
@@ -0,0 +1,3 @@
+<svg width="13" height="20" viewBox="0 0 13 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path id="Shape" d="M0 0H13V20C9.98017 20 7.26458 18.1615 6.14305 15.3576L0 0Z" fill="#F9FAFB"/>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/shapes/star-04.svg b/app/components/base/icons/assets/vender/solid/shapes/star-04.svg
new file mode 100644
index 0000000..5dc88ab
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/shapes/star-04.svg
@@ -0,0 +1,5 @@
+<svg width="11" height="10" viewBox="0 0 11 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="star-04">
+<path id="Solid" d="M5.88897 0.683596C5.82708 0.522683 5.67249 0.416504 5.50008 0.416504C5.32768 0.416504 5.17308 0.522683 5.11119 0.683596L4.27287 2.86321C4.1477 3.18865 4.10837 3.28243 4.05457 3.35809C4.00059 3.43401 3.93426 3.50034 3.85834 3.55433C3.78267 3.60813 3.68889 3.64746 3.36346 3.77263L1.18384 4.61094C1.02293 4.67283 0.916748 4.82743 0.916748 4.99984C0.916748 5.17224 1.02293 5.32684 1.18384 5.38873L3.36346 6.22705C3.68889 6.35221 3.78267 6.39155 3.85834 6.44535C3.93426 6.49933 4.00059 6.56566 4.05457 6.64158C4.10837 6.71724 4.1477 6.81102 4.27287 7.13646L5.11119 9.31608C5.17308 9.47699 5.32768 9.58317 5.50008 9.58317C5.67249 9.58317 5.82709 9.47699 5.88898 9.31608L6.72729 7.13646C6.85246 6.81102 6.89179 6.71724 6.94559 6.64158C6.99957 6.56566 7.06591 6.49933 7.14183 6.44535C7.21749 6.39155 7.31127 6.35221 7.6367 6.22705L9.81632 5.38873C9.97723 5.32684 10.0834 5.17224 10.0834 4.99984C10.0834 4.82743 9.97723 4.67283 9.81632 4.61094L7.6367 3.77263C7.31127 3.64746 7.21749 3.60813 7.14183 3.55433C7.06591 3.50034 6.99957 3.43401 6.94559 3.35809C6.89179 3.28243 6.85246 3.18865 6.72729 2.86321L5.88897 0.683596Z" fill="#667085"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/shapes/star-06.svg b/app/components/base/icons/assets/vender/solid/shapes/star-06.svg
new file mode 100644
index 0000000..be9a77b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/shapes/star-06.svg
@@ -0,0 +1,9 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="star-06">
+<g id="Solid">
+<path d="M3.66675 1.33268C3.66675 0.964492 3.36827 0.666016 3.00008 0.666016C2.63189 0.666016 2.33341 0.964492 2.33341 1.33268V2.33268H1.33341C0.965225 2.33268 0.666748 2.63116 0.666748 2.99935C0.666748 3.36754 0.965225 3.66602 1.33341 3.66602H2.33341V4.66602C2.33341 5.0342 2.63189 5.33268 3.00008 5.33268C3.36827 5.33268 3.66675 5.0342 3.66675 4.66602V3.66602H4.66675C5.03494 3.66602 5.33341 3.36754 5.33341 2.99935C5.33341 2.63116 5.03494 2.33268 4.66675 2.33268H3.66675V1.33268Z" fill="#444CE7"/>
+<path d="M3.66675 11.3327C3.66675 10.9645 3.36827 10.666 3.00008 10.666C2.63189 10.666 2.33341 10.9645 2.33341 11.3327V12.3327H1.33341C0.965225 12.3327 0.666748 12.6312 0.666748 12.9993C0.666748 13.3675 0.965225 13.666 1.33341 13.666H2.33341V14.666C2.33341 15.0342 2.63189 15.3327 3.00008 15.3327C3.36827 15.3327 3.66675 15.0342 3.66675 14.666V13.666H4.66675C5.03494 13.666 5.33341 13.3675 5.33341 12.9993C5.33341 12.6312 5.03494 12.3327 4.66675 12.3327H3.66675V11.3327Z" fill="#444CE7"/>
+<path d="M9.28898 1.76003C9.18995 1.50257 8.94259 1.33268 8.66675 1.33268C8.3909 1.33268 8.14354 1.50257 8.04452 1.76003L6.8884 4.76594C6.68813 5.28663 6.6252 5.43668 6.53912 5.55774C6.45274 5.67921 6.34661 5.78534 6.22514 5.87172C6.10408 5.9578 5.95403 6.02073 5.43334 6.221L2.42743 7.37712C2.16997 7.47614 2.00008 7.7235 2.00008 7.99935C2.00008 8.2752 2.16997 8.52256 2.42743 8.62158L5.43334 9.7777C5.95403 9.97797 6.10408 10.0409 6.22514 10.127C6.34661 10.2134 6.45274 10.3195 6.53912 10.441C6.6252 10.562 6.68813 10.7121 6.8884 11.2328L8.04452 14.2387C8.14354 14.4961 8.3909 14.666 8.66675 14.666C8.9426 14.666 9.18995 14.4961 9.28898 14.2387L10.4451 11.2328C10.6454 10.7121 10.7083 10.562 10.7944 10.441C10.8808 10.3195 10.9869 10.2134 11.1084 10.127C11.2294 10.0409 11.3795 9.97797 11.9002 9.7777L14.9061 8.62158C15.1635 8.52256 15.3334 8.2752 15.3334 7.99935C15.3334 7.7235 15.1635 7.47614 14.9061 7.37712L11.9002 6.221C11.3795 6.02073 11.2294 5.9578 11.1084 5.87172C10.9869 5.78534 10.8808 5.67921 10.7944 5.55774C10.7083 5.43668 10.6454 5.28663 10.4451 4.76594L9.28898 1.76003Z" fill="#444CE7"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/users/user-01.svg b/app/components/base/icons/assets/vender/solid/users/user-01.svg
new file mode 100644
index 0000000..139e1cc
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/users/user-01.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="user-01">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.85731 9.66669C7.28575 9.66701 8.71419 9.66701 10.1426 9.66669C10.6271 9.66659 10.9572 9.66652 11.2455 9.71735C12.6255 9.96068 13.706 11.0412 13.9493 12.4212C14.0002 12.7095 14.0001 13.0396 14 13.524C14 13.6296 14.0032 13.7359 13.9848 13.8404C13.9118 14.2544 13.5876 14.5785 13.1736 14.6515C13.0828 14.6675 12.9872 14.667 12.9396 14.6668C9.64686 14.6491 6.35308 14.6491 3.06031 14.6668C3.01274 14.667 2.9171 14.6675 2.82632 14.6515C2.41231 14.5785 2.08816 14.2544 2.01516 13.8404C1.99675 13.7359 1.99998 13.6296 1.99996 13.524C1.99985 13.0396 1.99978 12.7095 2.05061 12.4212C2.29395 11.0412 3.37444 9.96068 4.75447 9.71735C5.04275 9.66652 5.37286 9.66659 5.85731 9.66669Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4.3333 5.00004C4.3333 2.975 5.97493 1.33337 7.99997 1.33337C10.025 1.33337 11.6666 2.975 11.6666 5.00004C11.6666 7.02508 10.025 8.66671 7.99997 8.66671C5.97493 8.66671 4.3333 7.02508 4.3333 5.00004Z" fill="#155EEF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/users/user-edit-02.svg b/app/components/base/icons/assets/vender/solid/users/user-edit-02.svg
new file mode 100644
index 0000000..02a89f2
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/users/user-edit-02.svg
@@ -0,0 +1,14 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="user-edit 2" clip-path="url(#clip0_10419_49994)">
+<g id="Group">
+<path id="Vector" d="M5.83333 6.41667C7.60525 6.41667 9.04167 4.98025 9.04167 3.20833C9.04167 1.43642 7.60525 0 5.83333 0C4.06142 0 2.625 1.43642 2.625 3.20833C2.625 4.98025 4.06142 6.41667 5.83333 6.41667Z" fill="#FD853A"/>
+<path id="Vector_2" d="M5.90917 13.2465L6.78417 10.6221C6.85533 10.4086 6.97725 10.2114 7.1365 10.0522L8.79083 8.39783C7.92225 7.88391 6.91308 7.5835 5.83333 7.5835C2.61683 7.5835 0 10.2003 0 13.4168C0 13.7394 0.261333 14.0002 0.583333 14.0002H5.86717C5.817 13.7546 5.82575 13.4962 5.90917 13.2465Z" fill="#FD853A"/>
+<path id="Vector_3" d="M13.5524 7.44766C12.9562 6.85208 11.9856 6.85208 11.39 7.44766L7.96057 10.8771C7.92849 10.9092 7.90457 10.9482 7.88999 10.9908L7.01499 13.6158C6.97999 13.7208 7.0074 13.8363 7.08557 13.9145C7.14099 13.9705 7.21565 13.9997 7.29207 13.9997C7.32299 13.9997 7.3539 13.9944 7.38424 13.9851L10.0092 13.1101C10.0524 13.0961 10.0915 13.0716 10.123 13.0395L13.5524 9.61008C14.148 9.0145 14.148 8.04383 13.5524 7.44766Z" fill="#FD853A"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_10419_49994">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/users/users-01.svg b/app/components/base/icons/assets/vender/solid/users/users-01.svg
new file mode 100644
index 0000000..0028619
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/users/users-01.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="users-01">
+<g id="Solid">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0211 9.91782C12.1128 9.56125 12.4763 9.34659 12.8329 9.43837C14.2704 9.80837 15.3334 11.1125 15.3334 12.6666V14C15.3334 14.3682 15.0349 14.6666 14.6667 14.6666C14.2985 14.6666 14 14.3682 14 14V12.6666C14 11.7356 13.3633 10.9517 12.5005 10.7296C12.1439 10.6378 11.9293 10.2744 12.0211 9.91782Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.7154 1.94368C9.85355 1.60239 10.2422 1.43771 10.5835 1.57586C11.8039 2.06985 12.6667 3.26669 12.6667 4.66665C12.6667 6.0666 11.8039 7.26344 10.5835 7.75743C10.2422 7.89558 9.85355 7.73091 9.7154 7.38962C9.57725 7.04833 9.74193 6.65967 10.0832 6.52152C10.8174 6.22432 11.3334 5.50494 11.3334 4.66665C11.3334 3.82835 10.8174 3.10897 10.0832 2.81178C9.74193 2.67363 9.57725 2.28496 9.7154 1.94368Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4.78598 9.33329C5.81757 9.33363 6.84915 9.33363 7.88073 9.33329C8.60781 9.33305 9.10395 9.33289 9.52942 9.44689C10.6797 9.75512 11.5782 10.6536 11.8864 11.8039C12.0399 12.3768 11.9955 12.989 12.0001 13.576C12.0007 13.6473 12.0019 13.7915 11.966 13.9255C11.8735 14.2706 11.6039 14.5401 11.2588 14.6326C11.1248 14.6685 10.9807 14.6673 10.9094 14.6668C7.85941 14.6424 4.80731 14.6424 1.7573 14.6668C1.68602 14.6673 1.54188 14.6685 1.40787 14.6326C1.06278 14.5401 0.793233 14.2706 0.700765 13.9255C0.664858 13.7915 0.666007 13.6473 0.666575 13.576C0.671243 12.9905 0.627014 12.3759 0.780272 11.8039C1.0885 10.6536 1.98699 9.75512 3.13729 9.44689C3.56277 9.33289 4.05891 9.33305 4.78598 9.33329Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.00002 4.66665C3.00002 2.8257 4.49241 1.33331 6.33336 1.33331C8.17431 1.33331 9.66669 2.8257 9.66669 4.66665C9.66669 6.5076 8.17431 7.99998 6.33336 7.99998C4.49241 7.99998 3.00002 6.5076 3.00002 4.66665Z" fill="#155EEF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/solid/users/users-plus.svg b/app/components/base/icons/assets/vender/solid/users/users-plus.svg
new file mode 100644
index 0000000..36c82d1
--- /dev/null
+++ b/app/components/base/icons/assets/vender/solid/users/users-plus.svg
@@ -0,0 +1,10 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="users-plus">
+<g id="Solid">
+<path d="M20 15C20 14.4477 19.5523 14 19 14C18.4477 14 18 14.4477 18 15V17H16C15.4477 17 15 17.4477 15 18C15 18.5523 15.4477 19 16 19H18V21C18 21.5523 18.4477 22 19 22C19.5523 22 20 21.5523 20 21V19H22C22.5523 19 23 18.5523 23 18C23 17.4477 22.5523 17 22 17H20V15Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.181 14.1635C12.4632 14.3073 12.6927 14.5368 12.8365 14.819C12.9896 15.1194 13.0001 15.4476 13 15.7769C13 15.7847 13 15.7924 13 15.8C13 17.2744 12.9995 18.7488 13 20.2231C13.0001 20.3422 13.0001 20.4845 12.9899 20.6098C12.978 20.755 12.9476 20.963 12.8365 21.181C12.6927 21.4632 12.4632 21.6927 12.181 21.8365C11.963 21.9476 11.7551 21.978 11.6098 21.9899C11.4845 22.0001 11.3423 22.0001 11.2231 22C8.4077 21.999 5.59226 21.999 2.77682 22C2.65755 22.0001 2.51498 22.0001 2.38936 21.9898C2.24364 21.9778 2.03523 21.9472 1.81695 21.8356C1.53435 21.6911 1.30428 21.46 1.16109 21.1767C1.05079 20.9585 1.02087 20.7506 1.0095 20.6046C0.999737 20.4791 1.00044 20.3369 1.00103 20.2185C1.00619 19.1792 0.975203 18.0653 1.38061 17.0866C1.88808 15.8614 2.86145 14.8881 4.08659 14.3806C4.59629 14.1695 5.13457 14.0819 5.74331 14.0404C6.33532 14 7.06273 14 7.96449 14C9.05071 14 10.1369 14.0004 11.2231 14C11.5524 13.9999 11.8806 14.0104 12.181 14.1635Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14.5731 2.91554C14.7803 2.40361 15.3633 2.1566 15.8752 2.36382C17.7058 3.10481 19 4.90006 19 7C19 9.09994 17.7058 10.8952 15.8752 11.6362C15.3633 11.8434 14.7803 11.5964 14.5731 11.0845C14.3658 10.5725 14.6129 9.98953 15.1248 9.7823C16.2261 9.33652 17 8.25744 17 7C17 5.74256 16.2261 4.66348 15.1248 4.2177C14.6129 4.01047 14.3658 3.42748 14.5731 2.91554Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4.50001 7C4.50001 4.23858 6.73858 2 9.50001 2C12.2614 2 14.5 4.23858 14.5 7C14.5 9.76142 12.2614 12 9.50001 12C6.73858 12 4.50001 9.76142 4.50001 7Z" fill="black"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/agent.svg b/app/components/base/icons/assets/vender/workflow/agent.svg
new file mode 100644
index 0000000..f30c0b4
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/agent.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="agent">
+<g id="Vector">
+<path d="M14.7401 5.80454C14.5765 4.77996 14.1638 3.79808 13.5306 2.97273C12.8973 2.14738 12.0648 1.48568 11.1185 1.06589C10.1722 0.646098 9.12632 0.461106 8.08751 0.546487C7.05582 0.624753 6.04548 0.966277 5.17744 1.53548C4.3094 2.09758 3.58366 2.88024 3.09272 3.79808C2.59466 4.70881 2.33852 5.7405 2.33852 6.7793V7.22756L1.25703 9.3692C1.04357 9.80322 1.22145 10.3368 1.65547 10.5574L2.3314 10.8989V12.3006C2.3314 12.82 2.53063 13.3038 2.90061 13.6738C3.2706 14.0367 3.75442 14.243 4.27382 14.243H6.01702V14.7624C6.01702 15.1538 6.3372 15.4739 6.72853 15.4739C7.11986 15.4739 7.44004 15.1538 7.44004 14.7624V13.7094C7.44004 13.2185 7.04159 12.82 6.55065 12.82H4.27382C4.13864 12.82 4.00345 12.7631 3.91095 12.6706C3.81846 12.5781 3.76154 12.4429 3.76154 12.3077V10.5716C3.76154 10.2301 3.56943 9.92417 3.2706 9.77476L2.77254 9.52573L3.66904 7.73984C3.72596 7.61889 3.76154 7.4837 3.76154 7.34851V6.77219C3.76154 5.96818 3.96076 5.17129 4.34498 4.4669C4.72919 3.76251 5.28417 3.15772 5.9601 2.7237C6.63603 2.28968 7.41158 2.02643 8.20847 1.96239C9.00536 1.89835 9.81648 2.04066 10.5493 2.36795C11.2822 2.69524 11.9225 3.20042 12.4135 3.84077C12.8973 4.47402 13.2246 5.23533 13.3456 6.02511C13.4665 6.81488 13.3954 7.63312 13.125 8.38731C12.8617 9.12017 12.4206 9.78187 11.8585 10.3084C11.6735 10.4792 11.5668 10.7139 11.5668 10.9701V14.7624C11.5668 15.1538 11.887 15.4739 12.2783 15.4739C12.6696 15.4739 12.9898 15.1538 12.9898 14.7624V11.1978C13.6515 10.5432 14.1567 9.73918 14.4697 8.87114C14.8184 7.89637 14.918 6.83623 14.7615 5.81165L14.7401 5.80454Z" fill="white"/>
+<path d="M10.8055 7.99599C10.8909 7.83234 10.962 7.66158 11.0189 7.4837H11.6522C12.0435 7.4837 12.3637 7.16352 12.3637 6.77219C12.3637 6.38086 12.0435 6.06068 11.6522 6.06068H11.0189C10.9691 5.8828 10.898 5.71204 10.8055 5.54839L11.2537 5.10014C11.5312 4.82266 11.5312 4.3744 11.2537 4.09692C10.9762 3.81943 10.528 3.81943 10.2505 4.09692L9.80225 4.54517C9.6386 4.45267 9.46784 4.38863 9.28996 4.33171V3.69847C9.28996 3.30714 8.96978 2.98696 8.57845 2.98696C8.18712 2.98696 7.86694 3.30714 7.86694 3.69847V4.33171C7.68907 4.38152 7.5183 4.45267 7.35466 4.54517L6.90641 4.09692C6.62892 3.81943 6.18067 3.81943 5.90318 4.09692C5.62569 4.3744 5.62569 4.82266 5.90318 5.10014L6.35143 5.54839C6.26605 5.71204 6.1949 5.8828 6.13798 6.06068H5.50473C5.1134 6.06068 4.79323 6.38086 4.79323 6.77219C4.79323 7.16352 5.1134 7.4837 5.50473 7.4837H6.13798C6.18778 7.66158 6.25893 7.83234 6.35143 7.99599L5.90318 8.44424C5.62569 8.72172 5.62569 9.16997 5.90318 9.44746C6.04548 9.58976 6.22336 9.6538 6.40835 9.6538C6.59334 9.6538 6.77122 9.58265 6.91352 9.44746L7.36177 8.99921C7.52542 9.08459 7.69618 9.15574 7.87406 9.21267V9.84591C7.87406 10.2372 8.19424 10.5574 8.58557 10.5574C8.9769 10.5574 9.29708 10.2372 9.29708 9.84591V9.21267C9.47496 9.16286 9.64572 9.09171 9.80936 8.99921L10.2576 9.44746C10.3999 9.58976 10.5778 9.6538 10.7628 9.6538C10.9478 9.6538 11.1257 9.58265 11.268 9.44746C11.5454 9.16997 11.5454 8.72172 11.268 8.44424L10.8197 7.99599H10.8055ZM7.44004 6.77219C7.44004 6.14606 7.94521 5.64089 8.57134 5.64089C9.19747 5.64089 9.70264 6.14606 9.70264 6.77219C9.70264 7.39832 9.19747 7.90349 8.57134 7.90349C7.94521 7.90349 7.44004 7.39832 7.44004 6.77219Z" fill="white"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/answer.svg b/app/components/base/icons/assets/vender/workflow/answer.svg
new file mode 100644
index 0000000..7767ce1
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/answer.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/answer">
+<path id="Vector (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M3.50114 1.67701L10.5011 1.677C11.5079 1.677 12.3241 2.49311 12.3241 3.49992V9.35414C12.3241 10.3609 11.5079 11.177 10.5012 11.1771H8.9954L7.41734 12.4845C7.17339 12.6866 6.81987 12.6856 6.57708 12.4821L5.02026 11.1771H3.50114C2.49436 11.1771 1.67822 10.3608 1.67822 9.35414V3.49993C1.67822 2.49316 2.49437 1.67701 3.50114 1.67701ZM10.5011 2.9895L3.50114 2.98951C3.21924 2.98951 2.99072 3.21803 2.99072 3.49993V9.35414C2.99072 9.63601 3.21926 9.86455 3.50114 9.86455H5.04675C5.33794 9.86455 5.61984 9.96705 5.84302 10.1541L7.00112 11.1249L8.17831 10.1496C8.40069 9.96537 8.68041 9.86455 8.96916 9.86455H10.5011C10.5011 9.86455 10.5011 9.86455 10.5011 9.86455C10.783 9.8645 11.0116 9.63592 11.0116 9.35414V3.49992C11.0116 3.21806 10.7831 2.9895 10.5011 2.9895ZM9.06809 4.93171C9.32437 5.18799 9.32437 5.60351 9.06809 5.85979L7.02642 7.90146C6.77014 8.15774 6.35464 8.15774 6.09835 7.90146L5.22333 7.02646C4.96704 6.77019 4.96704 6.35467 5.22332 6.09839C5.4796 5.8421 5.89511 5.8421 6.15139 6.09837L6.56238 6.50935L8.14001 4.93171C8.3963 4.67543 8.81181 4.67543 9.06809 4.93171Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/assigner.svg b/app/components/base/icons/assets/vender/workflow/assigner.svg
new file mode 100644
index 0000000..b37fbce
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/assigner.svg
@@ -0,0 +1,9 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="variable assigner">
+<g id="Vector">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.71438 4.42875C1.71438 3.22516 2.68954 2.25 3.89313 2.25C4.30734 2.25 4.64313 2.58579 4.64313 3C4.64313 3.41421 4.30734 3.75 3.89313 3.75C3.51796 3.75 3.21438 4.05359 3.21438 4.42875V7.28563C3.21438 7.48454 3.13536 7.6753 2.9947 7.81596L2.81066 8L2.9947 8.18404C3.13536 8.3247 3.21438 8.51546 3.21438 8.71437V11.5713C3.21438 11.9464 3.51796 12.25 3.89313 12.25C4.30734 12.25 4.64313 12.5858 4.64313 13C4.64313 13.4142 4.30734 13.75 3.89313 13.75C2.68954 13.75 1.71438 12.7748 1.71438 11.5713V9.02503L1.21967 8.53033C1.07902 8.38968 1 8.19891 1 8C1 7.80109 1.07902 7.61032 1.21967 7.46967L1.71438 6.97497V4.42875ZM11.3568 3C11.3568 2.58579 11.6925 2.25 12.1068 2.25C13.3103 2.25 14.2855 3.22516 14.2855 4.42875V6.97497L14.7802 7.46967C14.9209 7.61032 14.9999 7.80109 14.9999 8C14.9999 8.19891 14.9209 8.38968 14.7802 8.53033L14.2855 9.02503V11.5713C14.2855 12.7751 13.3095 13.75 12.1068 13.75C11.6925 13.75 11.3568 13.4142 11.3568 13C11.3568 12.5858 11.6925 12.25 12.1068 12.25C12.4815 12.25 12.7855 11.9462 12.7855 11.5713V8.71437C12.7855 8.51546 12.8645 8.3247 13.0052 8.18404L13.1892 8L13.0052 7.81596C12.8645 7.6753 12.7855 7.48454 12.7855 7.28563V4.42875C12.7855 4.05359 12.4819 3.75 12.1068 3.75C11.6925 3.75 11.3568 3.41421 11.3568 3Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.25 6C5.25 5.58579 5.58579 5.25 6 5.25H10C10.4142 5.25 10.75 5.58579 10.75 6C10.75 6.41421 10.4142 6.75 10 6.75H6C5.58579 6.75 5.25 6.41421 5.25 6Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.25 10C5.25 9.58579 5.58579 9.25 6 9.25H10C10.4142 9.25 10.75 9.58579 10.75 10C10.75 10.4142 10.4142 10.75 10 10.75H6C5.58579 10.75 5.25 10.4142 5.25 10Z" fill="white"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/code.svg b/app/components/base/icons/assets/vender/workflow/code.svg
new file mode 100644
index 0000000..4d4b6cb
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/code.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/code">
+<path id="Vector (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M8.32593 1.69675C8.67754 1.78466 8.89132 2.14096 8.80342 2.49257L6.47009 11.8259C6.38218 12.1775 6.02588 12.3913 5.67427 12.3034C5.32265 12.2155 5.10887 11.8592 5.19678 11.5076L7.53011 2.17424C7.61801 1.82263 7.97431 1.60885 8.32593 1.69675ZM3.96414 4.20273C4.22042 4.45901 4.22042 4.87453 3.96413 5.13081L2.45578 6.63914C2.45577 6.63915 2.45578 6.63914 2.45578 6.63914C2.25645 6.83851 2.25643 7.16168 2.45575 7.36103C2.45574 7.36103 2.45576 7.36104 2.45575 7.36103L3.96413 8.86936C4.22041 9.12564 4.22042 9.54115 3.96414 9.79744C3.70787 10.0537 3.29235 10.0537 3.03607 9.79745L1.52769 8.28913C0.815811 7.57721 0.815803 6.42302 1.52766 5.7111L3.03606 4.20272C3.29234 3.94644 3.70786 3.94644 3.96414 4.20273ZM10.0361 4.20273C10.2923 3.94644 10.7078 3.94644 10.9641 4.20272L12.4725 5.71108C13.1843 6.423 13.1844 7.57717 12.4725 8.28909L10.9641 9.79745C10.7078 10.0537 10.2923 10.0537 10.036 9.79744C9.77977 9.54115 9.77978 9.12564 10.0361 8.86936L11.5444 7.36107C11.7437 7.16172 11.7438 6.83854 11.5444 6.63917C11.5444 6.63915 11.5445 6.63918 11.5444 6.63917L10.0361 5.13081C9.77978 4.87453 9.77978 4.45901 10.0361 4.20273Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/docs-extractor.svg b/app/components/base/icons/assets/vender/workflow/docs-extractor.svg
new file mode 100644
index 0000000..5b85003
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/docs-extractor.svg
@@ -0,0 +1,9 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="docs-extractor">
+<g id="Vector">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M2.66663 3.33325C2.66663 2.22869 3.56206 1.33325 4.66663 1.33325H12.6666C13.0348 1.33325 13.3333 1.63173 13.3333 1.99992V13.9999C13.3333 14.3681 13.0348 14.6666 12.6666 14.6666H4.66663C3.56206 14.6666 2.66663 13.7712 2.66663 12.6666V3.33325ZM3.99996 10.7804V3.33325C3.99996 2.96507 4.29844 2.66659 4.66663 2.66659H12V10.6666H4.66663C4.43287 10.6666 4.20848 10.7067 3.99996 10.7804ZM12 11.9999H4.66663C4.29844 11.9999 3.99996 12.2984 3.99996 12.6666C3.99996 13.0348 4.29844 13.3333 4.66663 13.3333H12V11.9999Z" fill="white"/>
+<path d="M8.12296 4.9385C8.18749 4.90624 8.23983 4.85394 8.27203 4.78942L8.70203 3.92954C8.82483 3.68385 9.17543 3.68385 9.29829 3.92954L9.72823 4.78942C9.76049 4.85394 9.81276 4.90624 9.87729 4.9385L10.7372 5.36844C10.9829 5.49128 10.9829 5.84189 10.7372 5.96473L9.87729 6.39467C9.81276 6.42692 9.76049 6.47923 9.72823 6.54375L9.29829 7.40365C9.17543 7.64932 8.82483 7.64932 8.70203 7.40365L8.27203 6.54375C8.23983 6.47923 8.18749 6.42692 8.12296 6.39467L7.26309 5.96473C7.01743 5.84189 7.01743 5.49128 7.26309 5.36844L8.12296 4.9385Z" fill="white"/>
+<path d="M5.71829 7.80752C5.757 7.78819 5.78838 7.75678 5.80773 7.71805L6.15459 7.02438C6.22829 6.87692 6.43865 6.87692 6.51236 7.02438L6.85923 7.71805C6.87856 7.75678 6.90996 7.78819 6.94863 7.80752L7.64236 8.15439C7.78976 8.22805 7.78976 8.43845 7.64236 8.51212L6.94863 8.85898C6.90996 8.87832 6.87856 8.90972 6.85923 8.94845L6.51236 9.64212C6.43865 9.78959 6.22829 9.78959 6.15459 9.64212L5.80773 8.94845C5.78838 8.90972 5.757 8.87832 5.71829 8.85898L5.02458 8.51212C4.87717 8.43845 4.87717 8.22805 5.02458 8.15439L5.71829 7.80752Z" fill="white"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/end.svg b/app/components/base/icons/assets/vender/workflow/end.svg
new file mode 100644
index 0000000..388803a
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/end.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/end">
+<path id="Vector (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M6.67315 1.18094C6.87691 1.0639 7.12769 1.06475 7.33067 1.18315L10.8307 3.22481C11.0323 3.34242 11.1562 3.55826 11.1562 3.79167C11.1562 4.02507 11.0323 4.24091 10.8307 4.35852L7.65625 6.21026V9.91667C7.65625 10.2791 7.36244 10.5729 7 10.5729C6.63756 10.5729 6.34375 10.2791 6.34375 9.91667V5.84577C6.34361 5.83788 6.34361 5.83 6.34375 5.82213V1.75C6.34375 1.51502 6.46939 1.29797 6.67315 1.18094ZM7.65625 4.69078L9.19758 3.79167L7.65625 2.89256V4.69078ZM5.31099 8.25466C5.37977 8.61051 5.14704 8.95473 4.79119 9.0235C3.97285 9.18165 3.32667 9.41764 2.90374 9.67762C2.45323 9.95454 2.40625 10.1564 2.40625 10.2086C2.40625 10.2448 2.42254 10.3508 2.60674 10.5202C2.79151 10.6901 3.09509 10.8732 3.52555 11.0406C4.38229 11.3738 5.61047 11.594 7 11.594C8.38954 11.594 9.61773 11.3738 10.4745 11.0406C10.9049 10.8732 11.2085 10.6901 11.3933 10.5202C11.5775 10.3508 11.5938 10.2448 11.5938 10.2086C11.5938 10.1564 11.5468 9.95454 11.0963 9.67762C10.6733 9.41764 10.0271 9.18165 9.20881 9.0235C8.85296 8.95473 8.62023 8.61051 8.68901 8.25465C8.75778 7.8988 9.102 7.66608 9.45786 7.73485C10.3682 7.91077 11.1803 8.18867 11.7836 8.55947C12.3592 8.91331 12.9062 9.45912 12.9062 10.2086C12.9062 10.7361 12.6287 11.1672 12.2816 11.4864C11.935 11.805 11.4698 12.0618 10.9502 12.2639C9.90679 12.6696 8.50997 12.9065 7 12.9065C5.49004 12.9065 4.09322 12.6696 3.04983 12.2639C2.53023 12.0618 2.06497 11.805 1.7184 11.4864C1.37128 11.1672 1.09375 10.7361 1.09375 10.2086C1.09375 9.45913 1.64077 8.91332 2.21642 8.55947C2.81966 8.18867 3.63181 7.91077 4.54215 7.73485C4.898 7.66608 5.24222 7.8988 5.31099 8.25466Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/home.svg b/app/components/base/icons/assets/vender/workflow/home.svg
new file mode 100644
index 0000000..f7c6988
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/home.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/home">
+<path id="Icon (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M6.99999 2.44562C6.97241 2.46663 6.94086 2.49116 6.90151 2.52177L3.43971 5.21428C3.17896 5.41708 3.15115 5.44593 3.13396 5.46918C3.10759 5.50483 3.08794 5.545 3.07599 5.58771C3.0682 5.61555 3.0625 5.65522 3.0625 5.98554V9.67837C3.0625 9.97506 3.06301 10.1581 3.07422 10.2954C3.08463 10.4228 3.10101 10.4541 3.10219 10.4563C3.13714 10.5249 3.19296 10.5808 3.26156 10.6157C3.2638 10.6169 3.29514 10.6333 3.42254 10.6437C3.55984 10.6549 3.74289 10.6555 4.03958 10.6555H4.8125V7.53462C4.8125 7.52831 4.81249 7.52199 4.81249 7.51565C4.81247 7.38933 4.81245 7.25834 4.82163 7.14594C4.8319 7.02025 4.85685 6.86124 4.93966 6.69872C5.05151 6.4792 5.22998 6.30072 5.44951 6.18886C5.61203 6.10605 5.77104 6.08111 5.89673 6.07084C6.00913 6.06166 6.14012 6.06168 6.26644 6.0617C6.27278 6.0617 6.2791 6.06171 6.28541 6.06171H7.71458C7.72089 6.06171 7.72721 6.0617 7.73355 6.0617C7.85987 6.06168 7.99086 6.06166 8.10326 6.07084C8.22896 6.08111 8.38796 6.10605 8.55049 6.18886C8.77001 6.30072 8.94849 6.4792 9.06034 6.69872C9.14315 6.86124 9.16809 7.02025 9.17836 7.14594C9.18755 7.25834 9.18752 7.38933 9.1875 7.51565C9.1875 7.52199 9.1875 7.52831 9.1875 7.53462V10.6555H9.96041C10.2571 10.6555 10.4402 10.6549 10.5775 10.6437C10.7049 10.6333 10.7361 10.6169 10.7383 10.6158C10.8069 10.5808 10.8628 10.525 10.8978 10.4564C10.8989 10.4541 10.9154 10.4228 10.9258 10.2954C10.937 10.1581 10.9375 9.97506 10.9375 9.67837V5.98554C10.9375 5.65522 10.9318 5.61555 10.924 5.58771C10.912 5.545 10.8924 5.50483 10.866 5.46918C10.8488 5.44593 10.821 5.41708 10.5603 5.21428L7.09848 2.52177C7.05913 2.49116 7.02757 2.46663 6.99999 2.44562ZM9.98433 11.968C10.2497 11.968 10.4871 11.968 10.6843 11.9519C10.8951 11.9346 11.1172 11.8958 11.3343 11.7852C11.6499 11.6244 11.9064 11.3678 12.0672 11.0523C12.1778 10.8351 12.2167 10.6131 12.2339 10.4023C12.25 10.205 12.25 9.96764 12.25 9.70225L12.25 5.98554C12.25 5.9671 12.25 5.94866 12.2501 5.93025C12.2504 5.69307 12.2508 5.45861 12.1879 5.23392C12.1329 5.03748 12.0426 4.85272 11.9213 4.68871C11.7825 4.50112 11.5972 4.35747 11.4098 4.21216C11.3952 4.20087 11.3806 4.18958 11.3661 4.17826L7.90428 1.48574C7.89214 1.4763 7.87933 1.46621 7.86587 1.4556C7.73357 1.35131 7.53852 1.19755 7.3049 1.1343C7.10523 1.08023 6.89477 1.08023 6.69509 1.1343C6.46148 1.19755 6.26642 1.35131 6.13412 1.4556C6.12066 1.46621 6.10785 1.4763 6.09571 1.48574L2.63391 4.17826C2.61935 4.18958 2.60478 4.20088 2.59022 4.21216C2.40278 4.35747 2.21747 4.50112 2.07873 4.68871C1.95742 4.85271 1.86706 5.03748 1.81207 5.23392C1.74918 5.4586 1.74956 5.69307 1.74994 5.93024C1.74997 5.94866 1.75 5.96709 1.75 5.98554L1.75 9.70227C1.74998 9.96765 1.74997 10.205 1.76608 10.4023C1.78331 10.6131 1.82216 10.8351 1.93279 11.0523C2.09357 11.3678 2.35014 11.6244 2.6657 11.7852C2.88282 11.8958 3.10485 11.9346 3.31566 11.9519C3.5129 11.968 3.75029 11.968 4.01566 11.968H9.98433ZM7.875 10.6555V7.53462C7.875 7.47093 7.87498 7.41945 7.87447 7.37473C7.82975 7.37422 7.77828 7.37421 7.71458 7.37421H6.28541C6.22172 7.37421 6.17024 7.37422 6.12553 7.37473C6.12501 7.41945 6.125 7.47093 6.125 7.53462V10.6555H7.875Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/http.svg b/app/components/base/icons/assets/vender/workflow/http.svg
new file mode 100644
index 0000000..de832d9
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/http.svg
@@ -0,0 +1,10 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/http">
+<g id="Vector">
+<path d="M13.0968 4.66675H10.8387V9.18288H11.7419V7.82804H13.0968C13.3362 7.82772 13.5658 7.73245 13.7351 7.56313C13.9044 7.39382 13.9997 7.16426 14 6.92481V5.56997C13.9997 5.33051 13.9045 5.10093 13.7351 4.9316C13.5658 4.76227 13.3362 4.66702 13.0968 4.66675ZM11.7419 6.92481V5.56997H13.0968L13.0972 6.92481H11.7419Z" fill="white"/>
+<path d="M4.06452 5.56997H4.96774V9.18288H5.87097V5.56997H6.77419V4.66675H4.06452V5.56997Z" fill="white"/>
+<path d="M9.93548 4.66675H7.22581V5.56997H8.12903V9.18288H9.03226V5.56997H9.93548V4.66675Z" fill="white"/>
+<path d="M2.25806 4.66675V6.4732H0.903226V4.66675H0V9.18288H0.903226V7.37643H2.25806V9.18288H3.16129V4.66675H2.25806Z" fill="white"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/if-else.svg b/app/components/base/icons/assets/vender/workflow/if-else.svg
new file mode 100644
index 0000000..2343da8
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/if-else.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/if-else">
+<path id="Vector (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M8.16667 2.98975C7.80423 2.98975 7.51042 2.69593 7.51042 2.3335C7.51042 1.97106 7.80423 1.67725 8.16667 1.67725H11.0833C11.4458 1.67725 11.7396 1.97106 11.7396 2.3335V5.25016C11.7396 5.6126 11.4458 5.90641 11.0833 5.90641C10.7209 5.90641 10.4271 5.6126 10.4271 5.25016V3.91782L7.34474 7.00016L10.4271 10.0825V8.75016C10.4271 8.38773 10.7209 8.09391 11.0833 8.09391C11.4458 8.09391 11.7396 8.38773 11.7396 8.75016V11.6668C11.7396 12.0293 11.4458 12.3231 11.0833 12.3231H8.16667C7.80423 12.3231 7.51042 12.0293 7.51042 11.6668C7.51042 11.3044 7.80423 11.0106 8.16667 11.0106H9.49901L6.14484 7.65641H1.75C1.38756 7.65641 1.09375 7.3626 1.09375 7.00016C1.09375 6.63773 1.38756 6.34391 1.75 6.34391H6.14484L9.49901 2.98975H8.16667Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/iteration-start.svg b/app/components/base/icons/assets/vender/workflow/iteration-start.svg
new file mode 100644
index 0000000..a1cc763
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/iteration-start.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/block-start">
+<path id="Vector" d="M6.8498 1.72732C6.3379 1.3754 5.6621 1.3754 5.1502 1.72732L2.1502 3.78982C1.74317 4.06965 1.5 4.53193 1.5 5.02588V8.99983C1.5 9.82828 2.17158 10.4998 3 10.4998H4.25C4.52614 10.4998 4.75 10.276 4.75 9.99983V8.24983C4.75 7.55948 5.30965 6.99983 6 6.99983C6.69035 6.99983 7.25 7.55948 7.25 8.24983V9.99983C7.25 10.276 7.47385 10.4998 7.75 10.4998H9C9.82845 10.4998 10.5 9.82828 10.5 8.99983V5.02588C10.5 4.53193 10.2568 4.06965 9.8498 3.78982L6.8498 1.72732Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/iteration.svg b/app/components/base/icons/assets/vender/workflow/iteration.svg
new file mode 100644
index 0000000..2a74fac
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/iteration.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/iteration">
+<path id="Vector" d="M6.82849 0.754349C6.6007 0.526545 6.23133 0.526545 6.00354 0.754349C5.77573 0.982158 5.77573 1.3515 6.00354 1.57931L6.82849 0.754349ZM8.16602 2.91683L8.57849 3.32931C8.80628 3.1015 8.80628 2.73216 8.57849 2.50435L8.16602 2.91683ZM6.00354 4.25435C5.77573 4.48216 5.77573 4.8515 6.00354 5.07931C6.23133 5.30711 6.6007 5.30711 6.82849 5.07931L6.00354 4.25435ZM7.99516 9.74597C8.22295 9.51818 8.22295 9.14881 7.99516 8.92102C7.76737 8.69323 7.398 8.69323 7.17021 8.92102L7.99516 9.74597ZM5.83268 11.0835L5.4202 10.671C5.1924 10.8988 5.1924 11.2682 5.4202 11.496L5.83268 11.0835ZM7.17021 13.246C7.398 13.4738 7.76737 13.4738 7.99516 13.246C8.22295 13.0182 8.22295 12.6488 7.99516 12.421L7.17021 13.246ZM11.4993 3.73414C11.2738 3.50404 10.9045 3.5003 10.6744 3.72578C10.4443 3.95127 10.4405 4.32059 10.6661 4.55069L11.4993 3.73414ZM7.58268 3.50016C7.90486 3.50016 8.16602 3.23899 8.16602 2.91683C8.16602 2.59467 7.90486 2.3335 7.58268 2.3335L7.58268 3.50016ZM2.49938 10.2662C2.72486 10.4963 3.09419 10.5 3.32429 10.2745C3.55439 10.0491 3.55814 9.6797 3.33266 9.44964L2.49938 10.2662ZM6.00354 1.57931L7.75354 3.32931L8.57849 2.50435L6.82849 0.754349L6.00354 1.57931ZM7.75354 2.50435L6.00354 4.25435L6.82849 5.07931L8.57849 3.32931L7.75354 2.50435ZM7.17021 8.92102L5.4202 10.671L6.24516 11.496L7.99516 9.74597L7.17021 8.92102ZM5.4202 11.496L7.17021 13.246L7.99516 12.421L6.24516 10.671L5.4202 11.496ZM8.16602 10.5002L6.41602 10.5002V11.6668L8.16602 11.6668V10.5002ZM11.666 7.00016C11.666 8.93316 10.099 10.5002 8.16602 10.5002V11.6668C10.7434 11.6668 12.8327 9.57751 12.8327 7.00016H11.666ZM12.8327 7.00016C12.8327 5.72882 12.3235 4.57524 11.4993 3.73414L10.6661 4.55069C11.2852 5.18256 11.666 6.0463 11.666 7.00016H12.8327ZM5.83268 3.50016H7.58268L7.58268 2.3335H5.83268L5.83268 3.50016ZM2.33268 7.00016C2.33268 5.06717 3.89968 3.50016 5.83268 3.50016L5.83268 2.3335C3.25535 2.3335 1.16602 4.42283 1.16602 7.00016H2.33268ZM1.16602 7.00016C1.16602 8.27148 1.67517 9.42508 2.49938 10.2662L3.33266 9.44964C2.71348 8.81777 2.33268 7.95403 2.33268 7.00016H1.16602Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/jinja.svg b/app/components/base/icons/assets/vender/workflow/jinja.svg
new file mode 100644
index 0000000..5b40f30
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/jinja.svg
@@ -0,0 +1,13 @@
+<svg width="24" height="12" viewBox="0 0 24 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Jinja Icon">
+<g id="Vector">
+<path d="M7.46013 5.99982C7.46013 4.87982 7.48013 3.92982 7.53013 3.16982V3.06982L6.13013 3.23982L6.15013 3.32982C6.29013 4.03982 6.36013 4.93982 6.36013 5.99982C6.36013 6.93982 6.33013 7.78982 6.28013 8.51982V8.60982H7.55013V8.51982C7.49013 7.72982 7.46013 6.87982 7.46013 5.99982Z" fill="#667085"/>
+<path d="M3.33016 1.31998C3.38016 2.31998 3.38016 5.13998 3.38016 7.00998V7.77998C3.38016 8.21998 3.35016 8.58998 3.28016 8.85998C3.22016 9.12998 3.11016 9.34998 2.96016 9.52998C2.82016 9.70998 2.62016 9.83998 2.37016 9.92998C2.12016 10.01 1.82016 10.06 1.49016 10.06C1.19016 10.06 0.900156 9.99998 0.620156 9.87998L0.520156 9.83998L0.410156 10.83L0.480156 10.85C0.800156 10.93 1.16016 10.97 1.56016 10.97C2.08016 10.97 2.53016 10.9 2.90016 10.77C3.28016 10.64 3.59016 10.43 3.83016 10.15C4.07016 9.87998 4.25016 9.52998 4.36016 9.13998C4.47016 8.74998 4.53016 8.23998 4.53016 7.64998C4.53016 6.78998 4.59016 3.54998 4.59016 3.17998C4.61016 2.47998 4.63016 1.86998 4.66016 1.31998V1.22998H3.33016V1.31998Z" fill="#667085"/>
+<path d="M7.08021 0.919922C6.82022 0.919922 6.60021 0.999922 6.45021 1.14992C6.30021 1.29992 6.22021 1.47992 6.22021 1.68992C6.22021 1.87992 6.28021 2.04992 6.41021 2.18992C6.54022 2.31992 6.73022 2.38992 6.96022 2.38992C7.23022 2.38992 7.44021 2.30992 7.59021 2.15992C7.74021 1.99992 7.81021 1.81992 7.81021 1.60992C7.81021 1.42992 7.74021 1.25992 7.61021 1.12992C7.48021 0.989922 7.30021 0.919922 7.08021 0.919922Z" fill="#667085"/>
+<path d="M15.6102 3.30981C15.7702 4.07981 15.8502 5.25981 15.8502 6.81981C15.8502 8.26981 15.7902 9.23981 15.6702 9.67981C15.5902 9.96981 15.3802 10.2598 15.0302 10.5198L14.9702 10.5698L15.3502 11.0998H15.4002C16.4302 10.8198 16.9602 10.0598 16.9602 8.83981C16.9602 8.64981 16.9502 8.30981 16.9202 7.80981C16.9002 7.31981 16.8902 6.90981 16.8902 6.59981C16.8902 5.44981 16.9202 4.28981 16.9902 3.15981V3.05981L15.5802 3.21981L15.6002 3.30981H15.6102Z" fill="#667085"/>
+<path d="M14.2901 5.77C14.2901 5.7 14.2901 5.56 14.3001 5.36C14.3001 5.15 14.3101 5.01 14.3101 4.94C14.3101 4.22 14.1101 3.71 13.7201 3.43C13.3401 3.15 12.8001 3 12.1101 3C11.4201 3 10.7901 3.24 10.2001 3.71L10.0901 3.06L8.8501 3.22L8.8701 3.31C9.0501 4.11 9.1401 4.95 9.1401 5.8C9.1401 6.36 9.1101 7.27 9.0401 8.52V8.61H10.3101V8.53C10.2901 7.07 10.2801 5.71 10.2801 4.49C10.7401 4.14 11.2501 3.96 11.7901 3.96C12.2401 3.96 12.5801 4.06 12.8201 4.26C13.0501 4.45 13.1701 4.82 13.1701 5.36C13.1701 6.5 13.1301 7.56 13.0401 8.53V8.62H14.3101V8.54C14.2901 7.35 14.2801 6.42 14.2801 5.79L14.2901 5.77Z" fill="#667085"/>
+<path d="M16.5302 0.919922C16.2702 0.919922 16.0502 0.999922 15.9002 1.14992C15.7502 1.29992 15.6702 1.47992 15.6702 1.68992C15.6702 1.87992 15.7302 2.04992 15.8602 2.18992C15.9902 2.31992 16.1802 2.38992 16.4102 2.38992C16.6702 2.38992 16.8902 2.30992 17.0302 2.15992C17.1802 1.99992 17.2502 1.81992 17.2502 1.60992C17.2502 1.42992 17.1802 1.25992 17.0502 1.12992C16.9202 0.989922 16.7402 0.919922 16.5202 0.919922H16.5302Z" fill="#667085"/>
+<path d="M23.1802 8.51001C23.0702 8.00001 23.0202 7.40001 23.0202 6.73001C23.0202 6.57001 23.0202 6.26001 23.0402 5.83001C23.0602 5.38001 23.0702 5.06001 23.0702 4.88001C23.0702 4.20001 22.8602 3.71001 22.4502 3.43001C22.0402 3.15001 21.4702 3.01001 20.7302 3.01001C19.9402 3.01001 19.2302 3.09001 18.6102 3.25001H18.5602L18.4302 4.20001L18.5502 4.17001C19.1602 4.03001 19.7802 3.96001 20.4102 3.96001C20.9302 3.96001 21.3202 4.03001 21.5702 4.18001C21.8102 4.31001 21.9302 4.59001 21.9302 5.01001C21.9302 5.09001 21.9302 5.16001 21.9302 5.23001C20.5102 5.25001 19.5602 5.44001 19.0302 5.79001C18.4802 6.15001 18.2002 6.63001 18.2002 7.23001C18.2002 7.72001 18.3802 8.10001 18.7402 8.36001C19.0902 8.62001 19.5102 8.75001 19.9902 8.75001C20.8202 8.75001 21.5002 8.55001 22.0102 8.17001C22.0102 8.30001 22.0402 8.44001 22.0802 8.58001L22.1002 8.64001L23.2202 8.60001L23.2002 8.50001L23.1802 8.51001ZM20.2802 6.18001C20.6502 6.08001 21.2002 6.03001 21.9102 6.03001C21.9102 6.45001 21.9202 6.92001 21.9402 7.42001C21.5602 7.69001 21.0502 7.83001 20.4302 7.83001C19.7002 7.83001 19.3502 7.61001 19.3502 7.16001C19.3502 6.68001 19.6602 6.36001 20.2802 6.18001Z" fill="#667085"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/knowledge-retrieval.svg b/app/components/base/icons/assets/vender/workflow/knowledge-retrieval.svg
new file mode 100644
index 0000000..e721f9d
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/knowledge-retrieval.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/knowledge-retrieval">
+<path id="Vector (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M3.78528 2.62834C3.78527 2.62834 3.78528 2.62834 3.78528 2.62834L8 3.56494L12.2147 2.62834C13.5158 2.33921 14.75 3.32924 14.75 4.66206V11.2637C14.75 12.2401 14.0718 13.0855 13.1187 13.2974L8.1627 14.3987C8.05554 14.4225 7.94446 14.4225 7.8373 14.3987L2.88139 13.2974C1.92824 13.0855 1.25 12.2401 1.25 11.2637V4.66206C1.25 3.32925 2.4842 2.33921 3.78528 2.62834ZM7.25 4.93487L3.45988 4.09262C3.09558 4.01166 2.75 4.28887 2.75 4.66206V11.2637C2.75 11.537 2.93986 11.7738 3.20679 11.8331C3.20678 11.8331 3.20681 11.8331 3.20679 11.8331L7.25 12.7316V4.93487ZM8.75 12.7316L12.7932 11.8331C13.0601 11.7738 13.25 11.537 13.25 11.2637V4.66206C13.25 4.28887 12.9044 4.01165 12.5401 4.09262L8.75 4.93487V12.7316Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/list-filter.svg b/app/components/base/icons/assets/vender/workflow/list-filter.svg
new file mode 100644
index 0000000..8b91e48
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/list-filter.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="filter">
+<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M2 4C2 2.89543 2.89543 2 4 2L12 2C13.1046 2 14 2.89544 14 4V4.78105C14 5.31148 13.7893 5.82019 13.4142 6.19528L10.1953 9.4142C10.0702 9.53925 10 9.70881 10 9.8856V12.8713C10 13.427 9.65528 13.9246 9.13482 14.1198C9.13479 14.1198 9.13476 14.1198 9.13473 14.1198L7.80153 14.6197C6.92984 14.9467 6 14.3022 6 13.3713L6 9.8856C6 9.70883 5.92978 9.53926 5.80474 9.4142C5.80473 9.4142 5.80473 9.4142 5.80472 9.41419L2.58579 6.19526L3.05004 5.73102L2.58579 6.19526C2.21071 5.82019 2 5.31148 2 4.78105V4ZM4 3.33333C3.63181 3.33333 3.33333 3.63181 3.33333 4L3.33333 4.78105C3.33333 4.95786 3.40357 5.12743 3.5286 5.25246L6.74754 8.47139L6.74756 8.47141C7.12262 8.84649 7.33333 9.35518 7.33333 9.8856L7.33333 13.3713L8.66665 12.8713L8.66667 12.8713L8.66667 9.8856C8.66667 9.35518 8.87737 8.84648 9.25246 8.4714L12.4714 5.25246L12.4714 5.25244C12.5964 5.12742 12.6667 4.95787 12.6667 4.78105V4C12.6667 3.6318 12.3682 3.33333 12 3.33333L4 3.33333Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/llm.svg b/app/components/base/icons/assets/vender/workflow/llm.svg
new file mode 100644
index 0000000..8a115cc
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/llm.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/llm">
+<path id="Vector (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M5.83333 2.40625C5.04971 2.40625 4.39011 2.94431 4.20689 3.67206C4.13982 3.93846 3.91391 4.1349 3.64078 4.16432C2.94692 4.23906 2.40625 4.82766 2.40625 5.54167C2.40625 5.92943 2.56471 6.27904 2.82212 6.53129C2.94807 6.65472 3.01905 6.82365 3.01905 7C3.01905 7.17635 2.94807 7.34528 2.82212 7.46871C2.56471 7.72096 2.40625 8.07057 2.40625 8.45833C2.40625 9.03652 2.76061 9.53347 3.26651 9.74092C3.45247 9.81717 3.59324 9.97444 3.64849 10.1677C3.8841 10.9917 4.64342 11.5938 5.54167 11.5938C5.82802 11.5938 6.09916 11.533 6.34375 11.4237V9.91667C6.34375 9.31258 5.85409 8.82292 5.25 8.82292C4.88756 8.82292 4.59375 8.5291 4.59375 8.16667C4.59375 7.80423 4.88756 7.51042 5.25 7.51042C5.64385 7.51042 6.0156 7.60503 6.34375 7.77278V2.48514C6.18319 2.43393 6.01183 2.40625 5.83333 2.40625ZM7.65625 2.48514V4.08333C7.65625 4.6874 8.14592 5.17708 8.75 5.17708C9.11244 5.17708 9.40625 5.4709 9.40625 5.83333C9.40625 6.19577 9.11244 6.48958 8.75 6.48958C8.35615 6.48958 7.9844 6.39496 7.65625 6.22722V11.4237C7.90087 11.533 8.17199 11.5938 8.45833 11.5938C9.35657 11.5938 10.1159 10.9917 10.3515 10.1677C10.4068 9.97444 10.5475 9.81717 10.7335 9.74092C11.2394 9.53347 11.5938 9.03652 11.5938 8.45833C11.5938 8.07056 11.4353 7.72096 11.1779 7.46871C11.0519 7.34528 10.981 7.17635 10.981 7C10.981 6.82365 11.0519 6.65472 11.1779 6.53129C11.4353 6.27904 11.5938 5.92944 11.5938 5.54167C11.5938 4.82766 11.0531 4.23906 10.3592 4.16432C10.0861 4.1349 9.86022 3.93847 9.79315 3.67208C9.6099 2.94432 8.95027 2.40625 8.16667 2.40625C7.98817 2.40625 7.81681 2.43393 7.65625 2.48514ZM7.00001 12.565C6.56031 12.7835 6.06472 12.9062 5.54167 12.9062C4.14996 12.9062 2.96198 12.0403 2.48457 10.8188C1.65595 10.3591 1.09375 9.47501 1.09375 8.45833C1.09375 7.9213 1.2511 7.42042 1.52161 7C1.2511 6.57958 1.09375 6.0787 1.09375 5.54167C1.09375 4.30153 1.93005 3.25742 3.06973 2.94157C3.51828 1.85715 4.586 1.09375 5.83333 1.09375C6.24643 1.09375 6.64104 1.17788 7 1.33013C7.35896 1.17788 7.75357 1.09375 8.16667 1.09375C9.41399 1.09375 10.4817 1.85716 10.9303 2.94157C12.0699 3.25742 12.9062 4.30153 12.9062 5.54167C12.9062 6.07869 12.7489 6.57958 12.4784 7C12.7489 7.42043 12.9062 7.92131 12.9062 8.45833C12.9062 9.47502 12.344 10.3591 11.5154 10.8188C11.038 12.0403 9.85003 12.9062 8.45833 12.9062C7.93526 12.9062 7.4397 12.7834 7.00001 12.565Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/loop-end.svg b/app/components/base/icons/assets/vender/workflow/loop-end.svg
new file mode 100644
index 0000000..cedacb9
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/loop-end.svg
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="ongoing">
+<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M8 2.75C5.10051 2.75 2.75 5.10051 2.75 8C2.75 10.8995 5.1005 13.25 8 13.25C8.41421 13.25 8.75 13.5858 8.75 14C8.75 14.4142 8.41421 14.75 8 14.75C4.27208 14.75 1.25 11.7279 1.25 8C1.25 4.27208 4.27208 1.25 8 1.25C8.41421 1.25 8.75 1.58579 8.75 2C8.75 2.41421 8.41421 2.75 8 2.75ZM10.3508 2.42715C10.5582 2.06861 11.017 1.94608 11.3755 2.15349C11.9971 2.51301 12.5556 2.96859 13.0311 3.49984C13.3073 3.8085 13.281 4.28264 12.9724 4.55887C12.6637 4.8351 12.1896 4.80882 11.9133 4.50016C11.5429 4.08625 11.1079 3.73153 10.6245 3.4519C10.2659 3.2445 10.1434 2.7857 10.3508 2.42715ZM8.13634 5.46967C8.42923 5.17678 8.9041 5.17678 9.197 5.46967L11.197 7.46967C11.4899 7.76256 11.4899 8.23744 11.197 8.53033L9.197 10.5303C8.9041 10.8232 8.42923 10.8232 8.13634 10.5303C7.84344 10.2374 7.84344 9.76256 8.13634 9.46967L8.85601 8.75H5.33333C4.91912 8.75 4.58333 8.41421 4.58333 8C4.58333 7.58579 4.91912 7.25 5.33333 7.25H8.85601L8.13634 6.53033C7.84344 6.23744 7.84344 5.76256 8.13634 5.46967ZM13.7414 6.09691C14.1478 6.01676 14.5422 6.28123 14.6224 6.68762C14.7062 7.1128 14.75 7.55166 14.75 8C14.75 8.44834 14.7062 8.88721 14.6224 9.31234C14.5422 9.71872 14.1478 9.98318 13.7414 9.90302C13.335 9.82287 13.0706 9.42845 13.1507 9.02206C13.2158 8.69213 13.25 8.35046 13.25 8C13.25 7.64954 13.2158 7.30787 13.1507 6.97785C13.0706 6.57146 13.335 6.17705 13.7414 6.09691ZM12.9723 11.4411C13.281 11.7173 13.3073 12.1915 13.0311 12.5002C12.5556 13.0314 11.9971 13.487 11.3756 13.8465C11.017 14.0539 10.5582 13.9314 10.3508 13.5729C10.1434 13.2143 10.2659 12.7556 10.6244 12.5481C11.1079 12.2685 11.5429 11.9138 11.9133 11.4999C12.1895 11.1912 12.6637 11.1649 12.9723 11.4411Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/loop.svg b/app/components/base/icons/assets/vender/workflow/loop.svg
new file mode 100644
index 0000000..6692c4d
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/loop.svg
@@ -0,0 +1,5 @@
+<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="loop">
+<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M2.02915 5.34506C3.50752 3.88498 5.9006 3.88498 7.37896 5.34506L8.99983 6.94588L10.6207 5.34506C12.0991 3.88499 14.4921 3.88498 15.9705 5.34506C17.454 6.81027 17.454 9.18971 15.9705 10.6549C14.4921 12.115 12.0991 12.115 10.6207 10.655L8.99983 9.05413L7.37896 10.655C5.9006 12.115 3.50753 12.115 2.02916 10.655C0.545627 9.18974 0.545611 6.81028 2.02915 5.34506ZM7.93251 8L6.32492 6.4123C5.4308 5.52924 3.97732 5.52923 3.08319 6.4123C2.19426 7.29026 2.19426 8.70975 3.0832 9.58772C3.97733 10.4708 5.4308 10.4707 6.32492 9.58771C6.32492 9.58772 6.32492 9.58771 6.32492 9.58771L7.93251 8ZM10.0671 8L11.6747 9.5877C11.6747 9.58769 11.6747 9.58771 11.6747 9.5877C12.5688 10.4707 14.0223 10.4707 14.9165 9.58773C15.8054 8.70975 15.8054 7.29024 14.9165 6.41229C14.0223 5.52923 12.5689 5.52924 11.6747 6.4123C11.6747 6.4123 11.6747 6.41229 11.6747 6.4123L10.0671 8Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/parameter-extractor.svg b/app/components/base/icons/assets/vender/workflow/parameter-extractor.svg
new file mode 100644
index 0000000..dc9418b
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/parameter-extractor.svg
@@ -0,0 +1,28 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/parma-extractor">
+<path id="Vector" d="M7.58398 10.3543C7.58398 10.0322 7.84514 9.771 8.16732 9.771C8.48949 9.771 8.75065 10.0322 8.75065 10.3543C8.75065 10.6765 8.48949 10.9377 8.16732 10.9377C7.84514 10.9377 7.58398 10.6765 7.58398 10.3543Z" fill="white"/>
+<path id="Vector_2" d="M9.625 10.3543C9.625 10.0322 9.88616 9.771 10.2083 9.771C10.5305 9.771 10.7917 10.0322 10.7917 10.3543C10.7917 10.6765 10.5305 10.9377 10.2083 10.9377C9.88616 10.9377 9.625 10.6765 9.625 10.3543Z" fill="white"/>
+<path id="Vector_3" d="M7.58398 3.64583C7.58398 3.32366 7.84514 3.0625 8.16732 3.0625C8.48949 3.0625 8.75065 3.32366 8.75065 3.64583C8.75065 3.968 8.48949 4.22917 8.16732 4.22917C7.84514 4.22917 7.58398 3.968 7.58398 3.64583Z" fill="white"/>
+<path id="Vector_4" d="M7.72852 12.104C7.72852 11.8624 7.9244 11.6665 8.16602 11.6665C8.40763 11.6665 8.60352 11.8624 8.60352 12.104C8.60352 12.3456 8.40763 12.5415 8.16602 12.5415C7.9244 12.5415 7.72852 12.3456 7.72852 12.104Z" fill="white"/>
+<path id="Vector_5" d="M11.375 8.1665C11.375 7.92489 11.5709 7.729 11.8125 7.729C12.0541 7.729 12.25 7.92489 12.25 8.1665C12.25 8.40812 12.0541 8.604 11.8125 8.604C11.5709 8.604 11.375 8.40812 11.375 8.1665Z" fill="white"/>
+<path id="Vector_6" d="M11.375 5.8335C11.375 5.59187 11.5709 5.396 11.8125 5.396C12.0541 5.396 12.25 5.59187 12.25 5.8335C12.25 6.07511 12.0541 6.271 11.8125 6.271C11.5709 6.271 11.375 6.07511 11.375 5.8335Z" fill="white"/>
+<path id="Vector_7" d="M7.72852 1.896C7.72852 1.65437 7.9244 1.4585 8.16602 1.4585C8.40763 1.4585 8.60352 1.65437 8.60352 1.896C8.60352 2.13762 8.40763 2.3335 8.16602 2.3335C7.9244 2.3335 7.72852 2.13762 7.72852 1.896Z" fill="white"/>
+<path id="Vector_8" d="M7.29102 8.1665C7.29102 7.68327 7.68278 7.2915 8.16602 7.2915C8.64925 7.2915 9.04102 7.68327 9.04102 8.1665C9.04102 8.64974 8.64925 9.0415 8.16602 9.0415C7.68278 9.0415 7.29102 8.64974 7.29102 8.1665Z" fill="white"/>
+<path id="Vector_9" d="M7.29102 5.8335C7.29102 5.35025 7.68278 4.9585 8.16602 4.9585C8.64925 4.9585 9.04102 5.35025 9.04102 5.8335C9.04102 6.31673 8.64925 6.7085 8.16602 6.7085C7.68278 6.7085 7.29102 6.31673 7.29102 5.8335Z" fill="white"/>
+<path id="Vector_10" d="M9.625 8.16683C9.625 7.84465 9.88616 7.5835 10.2083 7.5835C10.5305 7.5835 10.7917 7.84465 10.7917 8.16683C10.7917 8.489 10.5305 8.75016 10.2083 8.75016C9.88616 8.75016 9.625 8.489 9.625 8.16683Z" fill="white"/>
+<path id="Vector_11" d="M9.625 5.83333C9.625 5.51116 9.88616 5.25 10.2083 5.25C10.5305 5.25 10.7917 5.51116 10.7917 5.83333C10.7917 6.15551 10.5305 6.41667 10.2083 6.41667C9.88616 6.41667 9.625 6.15551 9.625 5.83333Z" fill="white"/>
+<path id="Vector_12" d="M9.625 3.64583C9.625 3.32366 9.88616 3.0625 10.2083 3.0625C10.5305 3.0625 10.7917 3.32366 10.7917 3.64583C10.7917 3.968 10.5305 4.22917 10.2083 4.22917C9.88616 4.22917 9.625 3.968 9.625 3.64583Z" fill="white"/>
+<path id="Vector_13" d="M6.41667 3.64583C6.41667 3.968 6.15551 4.22917 5.83333 4.22917C5.51117 4.22917 5.25 3.968 5.25 3.64583C5.25 3.32367 5.51117 3.0625 5.83333 3.0625C6.15551 3.0625 6.41667 3.32367 6.41667 3.64583Z" fill="white"/>
+<path id="Vector_14" d="M4.37565 3.64583C4.37565 3.968 4.11448 4.22917 3.79232 4.22917C3.47015 4.22917 3.20898 3.968 3.20898 3.64583C3.20898 3.32367 3.47015 3.0625 3.79232 3.0625C4.11448 3.0625 4.37565 3.32367 4.37565 3.64583Z" fill="white"/>
+<path id="Vector_15" d="M6.41667 10.3543C6.41667 10.6765 6.15551 10.9377 5.83333 10.9377C5.51117 10.9377 5.25 10.6765 5.25 10.3543C5.25 10.0322 5.51117 9.771 5.83333 9.771C6.15551 9.771 6.41667 10.0322 6.41667 10.3543Z" fill="white"/>
+<path id="Vector_16" d="M6.27148 1.896C6.27148 2.13762 6.0756 2.3335 5.83398 2.3335C5.59236 2.3335 5.39648 2.13762 5.39648 1.896C5.39648 1.65437 5.59236 1.4585 5.83398 1.4585C6.0756 1.4585 6.27148 1.65437 6.27148 1.896Z" fill="white"/>
+<path id="Vector_17" d="M2.625 5.8335C2.625 6.07511 2.42912 6.271 2.1875 6.271C1.94588 6.271 1.75 6.07511 1.75 5.8335C1.75 5.59187 1.94588 5.396 2.1875 5.396C2.42912 5.396 2.625 5.59187 2.625 5.8335Z" fill="white"/>
+<path id="Vector_18" d="M2.625 8.1665C2.625 8.40812 2.42912 8.604 2.1875 8.604C1.94588 8.604 1.75 8.40812 1.75 8.1665C1.75 7.92489 1.94588 7.729 2.1875 7.729C2.42912 7.729 2.625 7.92489 2.625 8.1665Z" fill="white"/>
+<path id="Vector_19" d="M6.27148 12.104C6.27148 12.3456 6.0756 12.5415 5.83398 12.5415C5.59236 12.5415 5.39648 12.3456 5.39648 12.104C5.39648 11.8624 5.59236 11.6665 5.83398 11.6665C6.0756 11.6665 6.27148 11.8624 6.27148 12.104Z" fill="white"/>
+<path id="Vector_20" d="M6.70898 5.8335C6.70898 6.31673 6.31722 6.7085 5.83398 6.7085C5.35073 6.7085 4.95898 6.31673 4.95898 5.8335C4.95898 5.35025 5.35073 4.9585 5.83398 4.9585C6.31722 4.9585 6.70898 5.35025 6.70898 5.8335Z" fill="white"/>
+<path id="Vector_21" d="M6.70898 8.1665C6.70898 8.64974 6.31722 9.0415 5.83398 9.0415C5.35073 9.0415 4.95898 8.64974 4.95898 8.1665C4.95898 7.68327 5.35073 7.2915 5.83398 7.2915C6.31722 7.2915 6.70898 7.68327 6.70898 8.1665Z" fill="white"/>
+<path id="Vector_22" d="M4.37565 5.83333C4.37565 6.15551 4.11448 6.41667 3.79232 6.41667C3.47015 6.41667 3.20898 6.15551 3.20898 5.83333C3.20898 5.51117 3.47015 5.25 3.79232 5.25C4.11448 5.25 4.37565 5.51117 4.37565 5.83333Z" fill="white"/>
+<path id="Vector_23" d="M4.37565 8.16683C4.37565 8.489 4.11448 8.75016 3.79232 8.75016C3.47015 8.75016 3.20898 8.489 3.20898 8.16683C3.20898 7.84465 3.47015 7.5835 3.79232 7.5835C4.11448 7.5835 4.37565 7.84465 4.37565 8.16683Z" fill="white"/>
+<path id="Vector_24" d="M4.37565 10.3543C4.37565 10.6765 4.11448 10.9377 3.79232 10.9377C3.47015 10.9377 3.20898 10.6765 3.20898 10.3543C3.20898 10.0322 3.47015 9.771 3.79232 9.771C4.11448 9.771 4.37565 10.0322 4.37565 10.3543Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/question-classifier.svg b/app/components/base/icons/assets/vender/workflow/question-classifier.svg
new file mode 100644
index 0000000..6289cb9
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/question-classifier.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/question-classifier">
+<path id="Vector (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M6.34379 3.53597C6.34379 2.35003 7.45832 1.47985 8.60885 1.76749L10.9422 2.35082C11.7537 2.55369 12.323 3.28283 12.323 4.1193V9.88081C12.323 10.7173 11.7537 11.4464 10.9422 11.6493L8.60886 12.2326C7.45832 12.5203 6.34379 11.6501 6.34379 10.4641V3.53597ZM8.29052 3.0408C7.96836 2.96026 7.65629 3.20392 7.65629 3.53597V10.4641C7.65629 10.7962 7.96836 11.0399 8.29051 10.9593L10.6238 10.376C10.6238 10.376 10.6238 10.376 10.6238 10.376C10.8511 10.3192 11.0105 10.115 11.0105 9.88081V4.1193C11.0105 3.88509 10.851 3.68093 10.6239 3.62413L8.29052 3.0408ZM4.66671 2.26048C5.02914 2.26048 5.32296 2.5543 5.32296 2.91673V11.0834C5.32296 11.4458 5.02914 11.7397 4.66671 11.7397C4.30427 11.7397 4.01046 11.4458 4.01046 11.0834V2.91673C4.01046 2.5543 4.30427 2.26048 4.66671 2.26048ZM2.33337 2.84382C2.69581 2.84382 2.98962 3.13763 2.98962 3.50007V10.5001C2.98962 10.8625 2.69581 11.1563 2.33337 11.1563C1.97094 11.1563 1.67712 10.8625 1.67712 10.5001V3.50007C1.67712 3.13763 1.97094 2.84382 2.33337 2.84382Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/templating-transform.svg b/app/components/base/icons/assets/vender/workflow/templating-transform.svg
new file mode 100644
index 0000000..a7d88d6
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/templating-transform.svg
@@ -0,0 +1,19 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/templating-transform">
+<g id="Vector">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.34375 1.75C6.34375 1.38756 6.63756 1.09375 7 1.09375C10.262 1.09375 12.9062 3.73807 12.9062 7C12.9062 10.262 10.262 12.9062 7 12.9062C6.63756 12.9062 6.34375 12.6124 6.34375 12.25V1.75Z" fill="white"/>
+<path d="M5.54167 3.64583C5.54167 3.968 5.2805 4.22917 4.95833 4.22917C4.63617 4.22917 4.375 3.968 4.375 3.64583C4.375 3.32367 4.63617 3.0625 4.95833 3.0625C5.2805 3.0625 5.54167 3.32367 5.54167 3.64583Z" fill="white"/>
+<path d="M3.5 3.64583C3.5 3.968 3.23883 4.22917 2.91667 4.22917C2.5945 4.22917 2.33333 3.968 2.33333 3.64583C2.33333 3.32367 2.5945 3.0625 2.91667 3.0625C3.23883 3.0625 3.5 3.32367 3.5 3.64583Z" fill="white"/>
+<path d="M5.54167 10.3542C5.54167 10.6763 5.2805 10.9375 4.95833 10.9375C4.63617 10.9375 4.375 10.6763 4.375 10.3542C4.375 10.032 4.63617 9.77083 4.95833 9.77083C5.2805 9.77083 5.54167 10.032 5.54167 10.3542Z" fill="white"/>
+<path d="M5.39583 1.89583C5.39583 2.13746 5.19996 2.33333 4.95833 2.33333C4.71671 2.33333 4.52083 2.13746 4.52083 1.89583C4.52083 1.65421 4.71671 1.45833 4.95833 1.45833C5.19996 1.45833 5.39583 1.65421 5.39583 1.89583Z" fill="white"/>
+<path d="M1.75 5.83333C1.75 6.07495 1.55412 6.27083 1.3125 6.27083C1.07088 6.27083 0.875 6.07495 0.875 5.83333C0.875 5.59171 1.07088 5.39583 1.3125 5.39583C1.55412 5.39583 1.75 5.59171 1.75 5.83333Z" fill="white"/>
+<path d="M1.75 8.16667C1.75 8.40828 1.55412 8.60417 1.3125 8.60417C1.07088 8.60417 0.875 8.40828 0.875 8.16667C0.875 7.92505 1.07088 7.72917 1.3125 7.72917C1.55412 7.72917 1.75 7.92505 1.75 8.16667Z" fill="white"/>
+<path d="M5.39583 12.1042C5.39583 12.3458 5.19996 12.5417 4.95833 12.5417C4.71671 12.5417 4.52083 12.3458 4.52083 12.1042C4.52083 11.8625 4.71671 11.6667 4.95833 11.6667C5.19996 11.6667 5.39583 11.8625 5.39583 12.1042Z" fill="white"/>
+<path d="M5.83333 5.83333C5.83333 6.31657 5.44158 6.70833 4.95833 6.70833C4.47508 6.70833 4.08333 6.31657 4.08333 5.83333C4.08333 5.35008 4.47508 4.95833 4.95833 4.95833C5.44158 4.95833 5.83333 5.35008 5.83333 5.83333Z" fill="white"/>
+<path d="M5.83333 8.16667C5.83333 8.6499 5.44158 9.04167 4.95833 9.04167C4.47508 9.04167 4.08333 8.6499 4.08333 8.16667C4.08333 7.68343 4.47508 7.29167 4.95833 7.29167C5.44158 7.29167 5.83333 7.68343 5.83333 8.16667Z" fill="white"/>
+<path d="M3.5 5.83333C3.5 6.15551 3.23883 6.41667 2.91667 6.41667C2.5945 6.41667 2.33333 6.15551 2.33333 5.83333C2.33333 5.51117 2.5945 5.25 2.91667 5.25C3.23883 5.25 3.5 5.51117 3.5 5.83333Z" fill="white"/>
+<path d="M3.5 8.16667C3.5 8.48884 3.23883 8.75 2.91667 8.75C2.5945 8.75 2.33333 8.48884 2.33333 8.16667C2.33333 7.84449 2.5945 7.58333 2.91667 7.58333C3.23883 7.58333 3.5 7.84449 3.5 8.16667Z" fill="white"/>
+<path d="M3.5 10.3542C3.5 10.6763 3.23883 10.9375 2.91667 10.9375C2.5945 10.9375 2.33333 10.6763 2.33333 10.3542C2.33333 10.032 2.5945 9.77083 2.91667 9.77083C3.23883 9.77083 3.5 10.032 3.5 10.3542Z" fill="white"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/base/icons/assets/vender/workflow/variable-x.svg b/app/components/base/icons/assets/vender/workflow/variable-x.svg
new file mode 100644
index 0000000..d87ea61
--- /dev/null
+++ b/app/components/base/icons/assets/vender/workflow/variable-x.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="icons/variable-x">
+<path id="Icon (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M0.714375 3.42875C0.714375 2.22516 1.68954 1.25 2.89313 1.25C3.30734 1.25 3.64313 1.58579 3.64313 2C3.64313 2.41421 3.30734 2.75 2.89313 2.75C2.51796 2.75 2.21438 3.05359 2.21438 3.42875V6.28563C2.21438 6.48454 2.13536 6.6753 1.9947 6.81596L1.81066 7L1.9947 7.18404C2.13536 7.3247 2.21438 7.51546 2.21438 7.71437V10.5713C2.21438 10.9464 2.51796 11.25 2.89313 11.25C3.30734 11.25 3.64313 11.5858 3.64313 12C3.64313 12.4142 3.30734 12.75 2.89313 12.75C1.68954 12.75 0.714375 11.7748 0.714375 10.5713V8.02503L0.21967 7.53033C0.0790176 7.38968 0 7.19891 0 7C0 6.80109 0.0790176 6.61032 0.21967 6.46967L0.714375 5.97497V3.42875ZM10.3568 2C10.3568 1.58579 10.6925 1.25 11.1068 1.25C12.3103 1.25 13.2855 2.22516 13.2855 3.42875V5.97497L13.7802 6.46967C13.9209 6.61032 13.9999 6.80109 13.9999 7C13.9999 7.19891 13.9209 7.38968 13.7802 7.53033L13.2855 8.02503V10.5713C13.2855 11.7751 12.3095 12.75 11.1068 12.75C10.6925 12.75 10.3568 12.4142 10.3568 12C10.3568 11.5858 10.6925 11.25 11.1068 11.25C11.4815 11.25 11.7855 10.9462 11.7855 10.5713V7.71437C11.7855 7.51546 11.8645 7.3247 12.0052 7.18404L12.1892 7L12.0052 6.81596C11.8645 6.6753 11.7855 6.48454 11.7855 6.28563V3.42875C11.7855 3.05359 11.4819 2.75 11.1068 2.75C10.6925 2.75 10.3568 2.41421 10.3568 2ZM4.59467 4.59467C4.88756 4.30178 5.36244 4.30178 5.65533 4.59467L7 5.93934L8.34467 4.59467C8.63756 4.30178 9.11244 4.30178 9.40533 4.59467C9.69822 4.88756 9.69822 5.36244 9.40533 5.65533L8.06066 7L9.40533 8.34467C9.69822 8.63756 9.69822 9.11244 9.40533 9.40533C9.11244 9.69822 8.63756 9.69822 8.34467 9.40533L7 8.06066L5.65533 9.40533C5.36244 9.69822 4.88756 9.69822 4.59467 9.40533C4.30178 9.11244 4.30178 8.63756 4.59467 8.34467L5.93934 7L4.59467 5.65533C4.30178 5.36244 4.30178 4.88756 4.59467 4.59467Z" fill="white"/>
+</g>
+</svg>
diff --git a/app/components/base/icons/script.mjs b/app/components/base/icons/script.mjs
new file mode 100644
index 0000000..7f9d7b7
--- /dev/null
+++ b/app/components/base/icons/script.mjs
@@ -0,0 +1,174 @@
+import path from 'node:path'
+import { access, appendFile, mkdir, open, readdir, rm, writeFile } from 'node:fs/promises'
+import { fileURLToPath } from 'node:url'
+import { parseXml } from '@rgrove/parse-xml'
+import { camelCase, template } from 'lodash-es'
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url))
+
+const generateDir = async (currentPath) => {
+ try {
+ await mkdir(currentPath, { recursive: true })
+ }
+ catch (err) {
+ console.error(err.message)
+ }
+}
+const processSvgStructure = (svgStructure, replaceFillOrStrokeColor) => {
+ if (svgStructure?.children.length) {
+ svgStructure.children = svgStructure.children.filter(c => c.type !== 'text')
+
+ svgStructure.children.forEach((child) => {
+ if (child?.name === 'path' && replaceFillOrStrokeColor) {
+ if (child?.attributes?.stroke)
+ child.attributes.stroke = 'currentColor'
+
+ if (child?.attributes.fill)
+ child.attributes.fill = 'currentColor'
+ }
+ if (child?.children.length)
+ processSvgStructure(child, replaceFillOrStrokeColor)
+ })
+ }
+}
+const generateSvgComponent = async (fileHandle, entry, pathList, replaceFillOrStrokeColor) => {
+ const currentPath = path.resolve(__dirname, 'src', ...pathList.slice(2))
+
+ try {
+ await access(currentPath)
+ }
+ catch {
+ await generateDir(currentPath)
+ }
+
+ const svgString = await fileHandle.readFile({ encoding: 'utf8' })
+ const svgJson = parseXml(svgString).toJSON()
+ const svgStructure = svgJson.children[0]
+ processSvgStructure(svgStructure, replaceFillOrStrokeColor)
+ const prefixFileName = camelCase(entry.split('.')[0])
+ const fileName = prefixFileName.charAt(0).toUpperCase() + prefixFileName.slice(1)
+ const svgData = {
+ icon: svgStructure,
+ name: fileName,
+ }
+
+ const componentRender = template(`
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './<%= svgName %>.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = '<%= svgName %>'
+
+export default Icon
+`.trim())
+
+ await writeFile(path.resolve(currentPath, `${fileName}.json`), JSON.stringify(svgData, '', '\t'))
+ await writeFile(path.resolve(currentPath, `${fileName}.tsx`), `${componentRender({ svgName: fileName })}\n`)
+
+ const indexingRender = template(`
+export { default as <%= svgName %> } from './<%= svgName %>'
+`.trim())
+
+ await appendFile(path.resolve(currentPath, 'index.ts'), `${indexingRender({ svgName: fileName })}\n`)
+}
+
+const generateImageComponent = async (entry, pathList) => {
+ const currentPath = path.resolve(__dirname, 'src', ...pathList.slice(2))
+
+ try {
+ await access(currentPath)
+ }
+ catch {
+ await generateDir(currentPath)
+ }
+
+ const prefixFileName = camelCase(entry.split('.')[0])
+ const fileName = prefixFileName.charAt(0).toUpperCase() + prefixFileName.slice(1)
+
+ const componentCSSRender = template(`
+.wrapper {
+ display: inline-flex;
+ background: url(<%= assetPath %>) center center no-repeat;
+ background-size: contain;
+}
+`.trim())
+
+ await writeFile(path.resolve(currentPath, `${fileName}.module.css`), `${componentCSSRender({ assetPath: path.posix.join('~@/app/components/base/icons/assets', ...pathList.slice(2), entry) })}\n`)
+
+ const componentRender = template(`
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './<%= fileName %>.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = '<%= fileName %>'
+
+export default Icon
+`.trim())
+
+ await writeFile(path.resolve(currentPath, `${fileName}.tsx`), `${componentRender({ fileName })}\n`)
+
+ const indexingRender = template(`
+export { default as <%= fileName %> } from './<%= fileName %>'
+`.trim())
+
+ await appendFile(path.resolve(currentPath, 'index.ts'), `${indexingRender({ fileName })}\n`)
+}
+
+const walk = async (entry, pathList, replaceFillOrStrokeColor) => {
+ const currentPath = path.resolve(...pathList, entry)
+ let fileHandle
+
+ try {
+ fileHandle = await open(currentPath)
+ const stat = await fileHandle.stat()
+
+ if (stat.isDirectory()) {
+ const files = await readdir(currentPath)
+
+ for (const file of files)
+ await walk(file, [...pathList, entry], replaceFillOrStrokeColor)
+ }
+
+ if (stat.isFile() && /.+\.svg$/g.test(entry))
+ await generateSvgComponent(fileHandle, entry, pathList, replaceFillOrStrokeColor)
+
+ if (stat.isFile() && /.+\.png$/g.test(entry))
+ await generateImageComponent(entry, pathList)
+ }
+ finally {
+ fileHandle?.close()
+ }
+}
+
+(async () => {
+ await rm(path.resolve(__dirname, 'src'), { recursive: true, force: true })
+ await walk('public', [__dirname, 'assets'])
+ await walk('vender', [__dirname, 'assets'], true)
+ await walk('image', [__dirname, 'assets'])
+})()
diff --git a/app/components/base/icons/src/image/llm/BaichuanTextCn.module.css b/app/components/base/icons/src/image/llm/BaichuanTextCn.module.css
new file mode 100644
index 0000000..97ab9b2
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/BaichuanTextCn.module.css
@@ -0,0 +1,5 @@
+.wrapper {
+ display: inline-flex;
+ background: url(~@/app/components/base/icons/assets/image/llm/baichuan-text-cn.png) center center no-repeat;
+ background-size: contain;
+}
diff --git a/app/components/base/icons/src/image/llm/BaichuanTextCn.tsx b/app/components/base/icons/src/image/llm/BaichuanTextCn.tsx
new file mode 100644
index 0000000..be9a407
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/BaichuanTextCn.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './BaichuanTextCn.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = 'BaichuanTextCn'
+
+export default Icon
diff --git a/app/components/base/icons/src/image/llm/Minimax.module.css b/app/components/base/icons/src/image/llm/Minimax.module.css
new file mode 100644
index 0000000..551ecc3
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/Minimax.module.css
@@ -0,0 +1,5 @@
+.wrapper {
+ display: inline-flex;
+ background: url(~@/app/components/base/icons/assets/image/llm/minimax.png) center center no-repeat;
+ background-size: contain;
+}
diff --git a/app/components/base/icons/src/image/llm/Minimax.tsx b/app/components/base/icons/src/image/llm/Minimax.tsx
new file mode 100644
index 0000000..7df7e3f
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/Minimax.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './Minimax.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = 'Minimax'
+
+export default Icon
diff --git a/app/components/base/icons/src/image/llm/MinimaxText.module.css b/app/components/base/icons/src/image/llm/MinimaxText.module.css
new file mode 100644
index 0000000..a63be49
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/MinimaxText.module.css
@@ -0,0 +1,5 @@
+.wrapper {
+ display: inline-flex;
+ background: url(~@/app/components/base/icons/assets/image/llm/minimax-text.png) center center no-repeat;
+ background-size: contain;
+}
diff --git a/app/components/base/icons/src/image/llm/MinimaxText.tsx b/app/components/base/icons/src/image/llm/MinimaxText.tsx
new file mode 100644
index 0000000..840e8cb
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/MinimaxText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './MinimaxText.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = 'MinimaxText'
+
+export default Icon
diff --git a/app/components/base/icons/src/image/llm/Tongyi.module.css b/app/components/base/icons/src/image/llm/Tongyi.module.css
new file mode 100644
index 0000000..3ca4407
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/Tongyi.module.css
@@ -0,0 +1,5 @@
+.wrapper {
+ display: inline-flex;
+ background: url(~@/app/components/base/icons/assets/image/llm/tongyi.png) center center no-repeat;
+ background-size: contain;
+}
diff --git a/app/components/base/icons/src/image/llm/Tongyi.tsx b/app/components/base/icons/src/image/llm/Tongyi.tsx
new file mode 100644
index 0000000..2f62f1a
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/Tongyi.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './Tongyi.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = 'Tongyi'
+
+export default Icon
diff --git a/app/components/base/icons/src/image/llm/TongyiText.module.css b/app/components/base/icons/src/image/llm/TongyiText.module.css
new file mode 100644
index 0000000..f713671
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/TongyiText.module.css
@@ -0,0 +1,5 @@
+.wrapper {
+ display: inline-flex;
+ background: url(~@/app/components/base/icons/assets/image/llm/tongyi-text.png) center center no-repeat;
+ background-size: contain;
+}
diff --git a/app/components/base/icons/src/image/llm/TongyiText.tsx b/app/components/base/icons/src/image/llm/TongyiText.tsx
new file mode 100644
index 0000000..a52f63c
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/TongyiText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './TongyiText.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = 'TongyiText'
+
+export default Icon
diff --git a/app/components/base/icons/src/image/llm/TongyiTextCn.module.css b/app/components/base/icons/src/image/llm/TongyiTextCn.module.css
new file mode 100644
index 0000000..d07e6e8
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/TongyiTextCn.module.css
@@ -0,0 +1,5 @@
+.wrapper {
+ display: inline-flex;
+ background: url(~@/app/components/base/icons/assets/image/llm/tongyi-text-cn.png) center center no-repeat;
+ background-size: contain;
+}
diff --git a/app/components/base/icons/src/image/llm/TongyiTextCn.tsx b/app/components/base/icons/src/image/llm/TongyiTextCn.tsx
new file mode 100644
index 0000000..c982c73
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/TongyiTextCn.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './TongyiTextCn.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = 'TongyiTextCn'
+
+export default Icon
diff --git a/app/components/base/icons/src/image/llm/Wxyy.module.css b/app/components/base/icons/src/image/llm/Wxyy.module.css
new file mode 100644
index 0000000..44344a4
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/Wxyy.module.css
@@ -0,0 +1,5 @@
+.wrapper {
+ display: inline-flex;
+ background: url(~@/app/components/base/icons/assets/image/llm/wxyy.png) center center no-repeat;
+ background-size: contain;
+}
diff --git a/app/components/base/icons/src/image/llm/Wxyy.tsx b/app/components/base/icons/src/image/llm/Wxyy.tsx
new file mode 100644
index 0000000..a3c4948
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/Wxyy.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './Wxyy.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = 'Wxyy'
+
+export default Icon
diff --git a/app/components/base/icons/src/image/llm/WxyyText.module.css b/app/components/base/icons/src/image/llm/WxyyText.module.css
new file mode 100644
index 0000000..58a0c62
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/WxyyText.module.css
@@ -0,0 +1,5 @@
+.wrapper {
+ display: inline-flex;
+ background: url(~@/app/components/base/icons/assets/image/llm/wxyy-text.png) center center no-repeat;
+ background-size: contain;
+}
diff --git a/app/components/base/icons/src/image/llm/WxyyText.tsx b/app/components/base/icons/src/image/llm/WxyyText.tsx
new file mode 100644
index 0000000..e5dd6e8
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/WxyyText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './WxyyText.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = 'WxyyText'
+
+export default Icon
diff --git a/app/components/base/icons/src/image/llm/WxyyTextCn.module.css b/app/components/base/icons/src/image/llm/WxyyTextCn.module.css
new file mode 100644
index 0000000..fb5839a
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/WxyyTextCn.module.css
@@ -0,0 +1,5 @@
+.wrapper {
+ display: inline-flex;
+ background: url(~@/app/components/base/icons/assets/image/llm/wxyy-text-cn.png) center center no-repeat;
+ background-size: contain;
+}
diff --git a/app/components/base/icons/src/image/llm/WxyyTextCn.tsx b/app/components/base/icons/src/image/llm/WxyyTextCn.tsx
new file mode 100644
index 0000000..32108ad
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/WxyyTextCn.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import cn from '@/utils/classnames'
+import s from './WxyyTextCn.module.css'
+
+const Icon = (
+ {
+ ref,
+ className,
+ ...restProps
+ }: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
+ ref?: React.RefObject<HTMLSpanElement>;
+ },
+) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
+
+Icon.displayName = 'WxyyTextCn'
+
+export default Icon
diff --git a/app/components/base/icons/src/image/llm/index.ts b/app/components/base/icons/src/image/llm/index.ts
new file mode 100644
index 0000000..3a4e64a
--- /dev/null
+++ b/app/components/base/icons/src/image/llm/index.ts
@@ -0,0 +1,9 @@
+export { default as BaichuanTextCn } from './BaichuanTextCn'
+export { default as MinimaxText } from './MinimaxText'
+export { default as Minimax } from './Minimax'
+export { default as TongyiTextCn } from './TongyiTextCn'
+export { default as TongyiText } from './TongyiText'
+export { default as Tongyi } from './Tongyi'
+export { default as WxyyTextCn } from './WxyyTextCn'
+export { default as WxyyText } from './WxyyText'
+export { default as Wxyy } from './Wxyy'
diff --git a/app/components/base/icons/src/public/avatar/Robot.json b/app/components/base/icons/src/public/avatar/Robot.json
new file mode 100644
index 0000000..8969a2a
--- /dev/null
+++ b/app/components/base/icons/src/public/avatar/Robot.json
@@ -0,0 +1,92 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg",
+ "xmlns:xlink": "http://www.w3.org/1999/xlink"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "12",
+ "fill": "#D5F5F6"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "0.25",
+ "y": "0.25",
+ "width": "23.5",
+ "height": "23.5",
+ "rx": "11.75",
+ "stroke": "black",
+ "stroke-opacity": "0.05",
+ "stroke-width": "0.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 20.12H20V4.12H4V20.12Z",
+ "fill": "url(#pattern0)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "pattern",
+ "attributes": {
+ "id": "pattern0",
+ "patternContentUnits": "objectBoundingBox",
+ "width": "1",
+ "height": "1"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "use",
+ "attributes": {
+ "xlink:href": "#image0_13843_72627",
+ "transform": "scale(0.00625)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "image",
+ "attributes": {
+ "id": "image0_13843_72627",
+ "width": "160",
+ "height": "160",
+ "xlink:href": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAACgCAYAAACLz2ctAABqnElEQVR4nO39d7xkx3nfCX+rTujcN6fJg8EAGAwIEJEACRJiDqKYJYqUlSjZsiR7bVm2LMm7tvfVem0v9ZHXkkxJq8gokRQlkWIQM0iARAaIHAZhcrh3bux8zqmq9486qfveO9MDDgmSwjOfntt9YoVfPameekoYY3ienqfniuRzXYDn6R83ucNe+M/f+7vn/HClNVtmJ9kxN4nWisWVJqO1CpHSHJ1fZHykysRIlXY3YKXRZsvkKFprGp0eY7UyjVYHYwzVSolSsUDBc9E9wYNPPMnxxdN4rsvbLhnl1RfVMaE+5/JtSNLFNI6ij30DnDGELMLK457pNd5A7+TbRbh0PVFrJ0b7CANowAFjwCku4lTvxal+Grf+cWOiE4xtgZFdyC0vguIY6Oj8FNMRrLQjfv/OBZ6ab+IVily+7xJ275imsbyIMoJWL7BtWfJYanTAQLno0QlCokiBhLVGh2q5SKVUoNHustZoUS2X8XwXYQQV13/WZfwXb3/zWa8ZGoD/+EhYMPZWXyIWH/4NwhOvE1HooOwpJODEfyNtcRg0J5DNV+OKV+PW34Mz8sfIXX+IdNRzWZPvZXoegBuREOCWYPGBX2Lp4f9Id3FGAMIDpkDMbYPxi6A6A64P7WVYPQKnHsPMdzAtA9HqFUKu/j7LlWtMaeJ/x/GPPdfV+l6k73sAOkKAdCxozgdJF5wCYvXQr3LilvdijBAOiDkHsf+1sOvNMHYNyFmgimWDHWAV2k8gTn4J8+jfYQ48jWkDpx/9GXS0gx0vfSfFydPQPU/lFLiOQZ6naj9X9H0OQEE3UhC2QRk4Hwa9EHD64bdx/Nb/C2OE8EFcdQXi6n8BIy/Fgi4A0wDW0nIgBJQvhQv2I3a+GXHhX2Ju/TP0iQCxdOAV5uEP/D9i39v+OVE3wJwHiewaji5XWetJnO9jFH5fA9B1JN860eT60hOM+x2M/naMemNlrOpuNU98/L8RBkVRAfHilyOu+3cgpkEfBhNhuV6iAMb3ooDYwJBVuPjnEKNzyC/8v+jDy/DMzT9L0f+i2PHSvwQB5tswmqQgDEO+flDT6NVxxPkZe88FfV8D0JeGoy3JXacdXrstxOA++54QgNSYE/f+HGvze4UL8vLL4LqfB9oQ3AvCxYIutkKEABLOq+1ho0Eds6J85jrED/0U8tP/C70QYeYf+VWx+7Wfxy0vocNnXW/hQqPtc6gb4knF+bGrnxv6vgagABxhuHNtlhsKk9SLIUTPUhxJF6L2tFo99E9QILaX4QVvhKgB6hn7Mg0WgCZ+e55i5IsYkEZANA+z+xEvuA5x6zcxSyeuNsfveIOY2v8hos6zq7O0j//cgRprvRpFV/DsnvS9Qd/XAAQoOHCq4/D3B3q8e28TIb0YKOdIbhGz9NS1NOb3CB/EBfuhWIDWI+BqEPHHEGMt5n55MAoTc0UBWlqpLNZgx+WI6fsxh1qwevzlbH3xh3BKnDu7FiAjvnXS5a7FIhKNWDcQvr/o+x6AAK5Q3HW6xP4JwwtnGmCk5UDn0jfCYBpHbqQbSTHjwtgUNJ8GuWZbSUbgJI5nyPQ4gxXHZJzPyBiAEqKTIGuImTnEkSdh5eD1FKoTFMcXUcE51VN4gkYz4lMHTxMpRcH5/gYf/KAAUEKo4a+eLOCs3M8LigcwpoRJUTEESQ+WD+wEoFyEaBlWT4PXA1eBE8Xqn7GflPtpUr3QxPJRCdACtAuhC6oGRQcKYDrLsxz64gyF+uK5zIpIGdKJJH9z6nJO98oU3YAfhGn8HwgAAhSkpqlcPjJ/JT8xKbis/DRCuRgzLJcwvgnFuO3UHqw9Bl4EhQgcZbmfNJnhgcHE30UKhNgqVvFHSwgdCAvQU3bGLtRFGQRTyN7Q03JCRHQp87EjO7lzxaHoRXAug+t7mH5gAGiAklS0qPHh5et4N5oX1OdBucNxCteTCNcxCkw3hOVlhA8UiEVw7gOp6y99OYBRGVPUWBAGQNjGNEAriNU2Z1j1QDiGrirw0WPbubO5hbIfgNE/ANCz9AMDQIhBKAJayudDKzfyE85dXF55BqE99NkMEyN7oJeNBtUEdwV0AYQfT8E5WCmb98CI7L3oTDIbE9srEZgARAC6AaoLjm96hM1FhDkrBxSeodtx+KuFq7mruYWy7CIwPzDggx8wAELCCSPakeTDJ/cR7J7lyi0OjnQw+gxsxy8Z02qf5JlnUB1wGkAPjA/GzbkAE3UvAWDOGDY57qcTv3RoQahaYDpAub7KjpecpjDKhr7ARMpLzVJL8alHDXcsVagUe9YB9IOEPn4AAQiZOO6oCn/6ZIXr2pp37Vqg6PYw0WbTBgJK43cjHGPaSigXpG+BZ1yyyY+YEya3pN8TgzgWvUYDEYgw5oQdIARRmXoA9Cl6K2w0JSeEAUdx/6lRPnqgzkrHUPYN8geK72X0AwlAsFjwhCJUEd88JHB7Pm+8UDBWESBjEBoDkbZcxZGIqT3fEKXyaRqNKe2BVNawxQGTn33Lc7/8C3MAJAag0VbS6g5IDWJy561CuhG9tr1PGmvgxLMo3Z7HLSdK3HxMcrLVY6QokTjfnUZ7DugHFoAJudJQcCX3rI5z5DHBGy/x2F6XCC3wPIfKRGwPaAeEOCi23f0lcd/N76IAWtuZh7wBImId0OQBmDCnPBfMfbQCOiCqtZOiVPqkWTyI0AG4ESryeeRElUNLLqXJIkfEGPcu1nBERNXrfZ+7mc9OP/AABMvwXKk43ZF85O4G3ccPUfPrjNTHeOWNO7hwm6FaCBD1snKveNXv6sdue4tu90q6bO/Nc70EeGIDDpjqgJCC0cTGiIzA37bng5T8x4kWCMNR7j+ym0ePS+54KqKrIqoXTuBO1ag4IcqY7+s53mHpHwUAwWKl6Aq63YiTC02Cik+z0+S2+0MeftxjetRhcqLBhXMzt9evuO63eeCWX8fgZXPAGVNjQI1M/IAJJhO8pgcNMD1+d2Pi4t+bX9zKQqNOI9rCt46NsrB4DG1OUi1C2TMIx5zdYv8Bon80AEzIkYKC7+B7kqIvcR1o9QRPHivy4AHF7fWQcfni398ZHHvN5OqRFxU8Rd3T+B54DnhJLEIfyuizhHsaghC6IawGDoFbaz2iXvjeB782c2RiZh8qmqLk+5S8JYpeREf+YBoYw9A/OgAOkuNIHNcBVxAFaufxw903332i8iNl/z0XlUUXEbXxTQPfrFJimZpYpSbbFEQPR+p0SrinPdq6RENXWdOjdBkhEnVCymiv7C91xa+Xy/Il9TE+Xi30vlHwpGmrH3QN7+z0jxaAQghc10EpVe102i8OWuoNKhBvGHFn905fUAanQGQkShuCCIJIsRSFzEchSgVEUYjW1o0iXIHjuDiOj+t4uK6H77pUXYnngBTGu4DwShUFV0bN4D2dQH1eVKO/1drc4rjOYSn/8a6O/UcHQGMMQggwZuvS6ZWfWDzZfJNjiteMVCcLE2NTFEtFDAKtI3yse6TkxbMhwokdg2Ub6JBEYaUhWYnlYTAmRBuDMQajDRqDkAJHe9Wg03t7ozH/9nZ37clmZ/nmkN5HqnXnq/8Y+eH3HwANaK2JlEYpDTEQsmgoawoYDFoblNJIBFLE10lJt9fb/sRTT/2179euKxerjNY9EIog6FgjwnERQiBxECKe/Eomfk3yn45Dr+LDIgZeEqhgDFpr+9cotFZordEoIhXQ6bRYWVm6cHlt6cK15so7R8adf7V7x/ifozVKa1Su7CDif2B0DGrsYMIIlFIYob8vZ0m+JwGYcA6lDcbo+Dc1wBdSjBUKXrFaLjiloq8HASgHAOi6UriOYzzXQQiMVy1HpW2jNz1692PX7Zzbi6gYwqhHu91AIAijACkdpJCI9CMQSKS0f4HY5BUxtwMLOo1Oy6wt8JRCafvRWqGNIowCOt0m3aCDwHB6/mStUyq9Zd/UyG3CcV3lOChjhJC27I7jIKQwAjDGiDwAHSlMZJDG8YXriB6Y08agjKGhjYmUNmhj2+J7kcN+zwBQa9tIBiq+60y4jnPVxEjlSinE9oLvFj3H3SUEVVE0k/sv2u7v01ulkLEDJB8hvwkXEABSGIHQM1M1d23ptH7m68/IHfICVDlCafspFSo4rocUlvsJIS0YEQiZ8CHRtwrUJCBMgactt8sB0MSADKOAbq9Du9skDHscPXwQxhSvf8+PvHLv3ku+LgzS2GgX0e/rIQbg+rUAxkbfCtd1It1tnSoVvEgbDnuuWC757oonxcPNTviQ0fpJpfWCijnz90I09XMOwJi7OQXfvapS8l9X9JxXSyl3uo7cKqVwwLo2DFaXMmgKBQ8pxDqRk3PZZdO1on8CXwjB3NQsr/2xH+YTSx/l4H1PsmPXBYRRSBSGhOWAgl/CdT0caSd+BZYLImL4DaxBNomuh8FoCz5lYtBpqxdatSGgG3TpdJqEUY/5UydZkYv82M+/i0svvaziCqeScLek7KmIz9VpkJLiKKXQWk95jgR4YcFzqJd8tIFKsdDQWh/uBOGtq83O36+1Ol+LlG7q51huP2cAtHqOlr7jvGFsovRznitf7rrOSKJjaW2I1EaNI1BKp0B7Ns0npWTr3Dbe8vNv5wP/z5/y9FNPsGvXHlQUEamQcrGK7xfxPD/WA2MxnOd6+YDQBHymXwznj4VRQBB0aPfaRGHAwsJJjq0d5B3/6l1ce8P1mMgQacW5ZisbDEsVQqBMVq4k3MGRouY57v5iwds/Wim9pxOGd5xebX682w0/Gil96lk043mh5wSAWhsqxcJLdsyM/cpoufRmKaWrjFW6B0d6voEH/b6D5zf6vfH7NUIIduzYxbv/zU/z4d/5C5448CgX7LgQYwxhFFAqVCgUSniOj+O4MQjzpUhKmoCPNFA04dTaGLSKCKOAXtAlCLtEUcjxE4dZCI7z5l96Bze9+hWYyKR6b54GtYqN6rrR9Ru1mzGGyBgbtyjwygX/xh3T4zeOVSs/ubTW/J+dIPorpc13ffbvuwpArQ1hFHmzkyO/vn1m5FdKBX8sjBRRFMWK/no6Vw53LmA0yrD3wkv4p//hl/jw+97Po7ffz9aJXUxMTqOUIgh7+H4R3y3gOC5SxnphTge0DDszChKOp7RCqZAg7BGEPaIopNlY4+DRJ3EmNT/5Kz/Li1/2cqIgRBud6gl50J2t7hsNzPzvXKjiuhvDUCEE1EqFa0arpQ8uN9pvOayi/7C8Gj1+lteeV/quAVBpQ7Hg7p4cqfzX0UrxnZFS9IIwFm1ZE+ZBY31oOtWvsnMDfHLQCFmnpvcfix0aVlxFii1btvHL/+Ff87m/+RRf/5uvsnDgJFumtjM6NmG5l+PhuT6u4yIdN7WQ+1mySQ0PpSKiKCRSIZGKaLeanDh1lJVggYtecjFv/5kf54I9e+m02qjcxO/5inXO5qFFXNZMf00BGV8UKUWkFKPV0tuL/sw+Felf7wbR37tmc53zfJIYVuf4dvIDbp0ZxxFi33i99MGS710dRBsEYhJ715RV3gGk4+D5BRzp4LiWA0np4Dh2IlbGwDUGEFYMCgFSyMxdl4NsouBbxTsRnRqjDb7vIz3JvXfeyVc+9Xke/cbDmIZmYmSa0dEJisVyygUd6cTWsS15ouslvj6lFGHUo9lcY3FpnpZpsnX/dl7ywzfx8te9hkq5SrvRiqNqZGpdJy6kRBqkYyqul/VJZipEYmCZ2GTWWsfuHo2KrFUfhQFRFGF07AgfSOSUB6XvOghoHzq19GunVpr/y5cuVe/7PD+gNgbXcfZNj5Q/7Djyyjz4ksoLEVtwSuEXitTqo5TLNYrFEl6hiCsdpOPEok+kYrCPCRozoKP1j2ANsSPYEBmFMgplbEdprYjCEK0Ue/dfQXl0jD1XPsgD37ibg/c/yfGDh6m4VerVMaqVGgW/iHRdHOHYuWATgy4MaLebNFprtDoNtK+YvHCWq1/8Yi6/9ip279lLuTqGdF1GZ6pI18N1LKAdHBzh4AgLxEQqiBjgiYKSSoIYlQkDsWC0xpuOrXGlFFEY0Ot16XabNNZW6bSb1n/oevHzsrYKowhXOuWdsxO/I4RkYbnxv85kfZ8PGhqA51oIA0RK40i5Z3q08iFHcmUYqj6ncUJBEFAoFJmc28no2ASFQintAK1U6oLRxJkJRNYsKYgHSpm3WJNOTMSdQWPiJWrEHDDR3TzXY6Q2ymWXv5Adu3Zz9KWHefLBRzn46JPMHz/B0aMHMUrjGR+ZE8MKBR54RY/KbI3dOy5m9/697LpoD5OT01QqVXyvEHNcjTFO/G5hA19FDCKsM11KkTNKcrXMz4JACs716/AFruvheT6VSh3ENOFMSLOxyuLCcdbWVnCkREo3J/oFkdZI8LdPj/4OhqDTCv7Y+Q7OVQ8NwHPxFyWSr1wsFHfNjf+O78qrukE0oIeRiqvxiWnmtuykVKrYURudJXHPgGgVCGL7MwWb9eTGYmpAt5JITCyyHSkQQiGEIALKlQrFcokoCGm1mmzZso39l1/ByvISCydPceroMRaOn6K90kTF3NxxHcq1CuOzk0xv3cLk7DQjY2PUanUqpQrlaoVCqRR3uMR1XRzPclCBBZwjZOp5trNA621+Y5JUHP01SurbX8tkhobUFSOlZGxsknp9jNOnT3Dy+GGiKMT13L77tdIIhL9lsv7eQ8HSY1FkbnGd7wwIhwbgWjh8GgmlNb7j8rLL9/zKlqnRN3V7/YBKRrDSETNz29mybTcYQxD0Nn1mXgQNUv7Y4PeNxo3tdCfWB7UFgisQ+AgREakI1/Ooj4xSq9WJooi5uS1cuPdioiii0+3Q63ZjXcw+0/N8qzJ4Hp7n4fu+dWa71nKWUuI4Dq7nWX0WGbu4ZQy+/vbZbGL32zFU7IDv4TgOs7PbKZUqHHrmcQtC18sscWGNRtcRI1MTtd+eX2y9wRizOOiAPx80NAAnapWhHxpGisnR2hVbp0b/fRgpK1bIjVBjiKKQua072bplN5EKUUptag3HNw39/mFIAE6cakqj7cIfVyKkRCqJjq1Do+0UnOu7FLUFdF1rayiZzPARUmbzxTLTVaWU1nBxrSHlSKcvwMCR8rxMiaWc/wznk4prrQmCHiMj41yw51KefuoRoijCdZw+t02kDPVK4bpOEP3qwun2b7pynZz/tmloAE7Wa0NdZ60y4+y7YO5XPUeOdHpRqtskFEUhE5MzzM3tJFJRatVtRFnnrG/eYZzOm1GiMzoyBqExNshZOkgp0I6LVNl0WuIS0okeOeg0jssvRQxiKWILV8YgjH+TWfDJHPP5oLNxxo3OB0GPam2E7Tv3cvDpR20/DOh7kdLUK4Vf7HXUR40290shzisrGBqAnucNdZ3Smnql9PKRavmdYaSRsp+rRVFEuVpj6/YLUtfFmfjd+c8DkL0r9gam+ldq5ODgSBMbArYUWmd6WBb9kpU0daSn03bZBwEyt5JdComTWPKcYY6X883311MQ9Bgbm6Q9s42TJw7jOf1LQI2BgueMjtYLv7Cy0vulhOOfLxoagHMTo0Ndp7QRY/XizwqJH0X9oRtJMOjs3A481ycMg5xud3YxMkiZ7fbsE1aknDAGhDaaOHwUgRNfYJAuOUV943dtBCeRY/8SmbpYzga+zd/y7dJ6bTqKIqZnt9FsrNBuNXG9/nw6RkOh4P5YSPv3w1A9cj51waEB6DhnXxxtDBR858JyqfAKa0n1e+XDKGRsfIqRkYnU0u33cT07OjfwDYjO3FFhwJESbSw/zDpBxCvfkjflLNa+52zQMYmOSBZVk/MifUcoX6eNCjR4XGuF5/lMzWzl8DOPx3qtiEO2bL/6rjMxViu9vtEKHpHPBQDb7bMnglVaM1qvvNaRYjbU1r2QNzxc12Vicjb+uVHzbHQsLzI35nRn4oB5HStx4ibPNOm3RH+zz0mDWsX6MiXF7n9Cdt0gd8g4nciOiLwKsHmZBx3Q51LvwYFxNgNFRRH1+jjV+hjNtRVc110na8tF703dtnofnL+swEMDcKV15v0t7IyHdLeUC68CUt0nyVobhhH1kTGq1Tp6wOKFfqD0H88AcubrNj9ucgDuh3P2juxvOlOc8WWTzdgMxbnW43LAwj+b7tc/+7F57c7cbsNclxXZ4DkeY+NTtBorVm9N+HysRfi+e430uCIM1O3iPLkFhwbg2YScNgYp5TbPc65FgEiMj5iLCCmoj44jpbMhAM/05o0aLw8qs8k1CQ1eM+hzS3CV55DpNSaZZcixvuTG7AXrfieH0npmD+wr65laISv3xleerd5ZMYeLftZGU63WKZRKhEGAcGTfRhSe65S1UVeeXl273TlPjumhATg1cmY3jNKaerV0ecFzZpTWfdXVxk72Vysj6RwmZLzmbAJpI+rvxDM37pn4jej7nueFJh39/fcngBooa4ozkev0jd4z3MBbL7o3v2aDYpxdN92AjFEUCkUqlRrLvQWEcPpmSIwxjNYrVyEd4cjzs5p+aABWyuUzntcGSiX3CoNxcr2GwE7tlMtVPK+Q+tFg/YTSd4rO/clnGhLD+9vO1u1n0u+eLX07TzLxiCuVq6wsnybpxxTUxlAseC8s9VRNa7O2+ZOGp6EBWKuXznyBAccx25JQqrTgcYvYcCZn03neDaTYeYXks33ed9BYfdb0nQBuSibuK9duQSuSVHaC+D+zRcFUZFg7H070oQHY7ZxhLtiAEZSqZfdCx5Fx4ELGAqWU+IUzA3iwKc/UtPmI5PzRJC5vmOef2Xd4vuG/MT0bACU4yDyJ/VOcG+0MMFjXM9VdG43nFXBdnygKBwJvDY4jKlMTIyPna2gODUApN58JMQakZExKsSNzM2TN40gH/9sIbEwoAV4+FjDfCbZhc40bF2MjUJ6587/z4DsXSuorIac/Z1rmIBC/vYVuBimdGIBRbERlzhygGqlouzHcez4wODQAC5XC5ieFQBgjBcGAbwzriI2jQOylz67Ugv5F57nH91HfNfGrhs12NoxV+d2i1ORJ26ufb21org2G3fc9T5zxd54cx8V1bWa6xKhKIKi1djzHnXGdb2NfvhwN74aJzrJgSphxLfWoNc7j4gphY9ikg5DZTMq5OJTTSf6kHGdxqCZCKC+I8qH7Q0WMfJu0ef3Orlrklf7+c8ML7DwQkwDWcyEpbRSP1gbpJGueiS1iTRjpiVCfHykxNADDMwWJGhDC1KVH0chEOIh4qaHGxWGY6Zu8Qwb6ueXZBGbeobOpZpdDwHdbyOYF52bnz3TNsymvBJsrx2Q+zjNxxix+UoCIpyN1vHYmKZ+BngpGgjA6L8N1aAD6Z/Q7CoDdxuhqsjNRWmFtYt1N5jp/gzUOqX6XcE5yhoatfhaGLtKwdVdKHMdG2Nk8KFlin8wBm/M9bsANz3Ux+Nlo46DZVIdaR3KgbNlNIhanBkfKNKLakTaoS2lDpO1CeGVsJE8yEJP1MUl7JovnBf3R7evVDnuvlDJdZpq5s8FojYvY4zuu5NltC9lHw4fkn/GsAWOawi5sdtPqCAtAIMsytfHdSJF1QGrxkynbBpDSoei7lACBzTbQDSKWOm3rayyVKboOZd/F8wqEQEdperH6kG9m613I9BvzLETVuVLeu2izb62Xt/n6Oo5D2XMoAAZFp9ulpzSrnTZRGFKtVKgUChQ8Fyl9AqATKUKl+p6Yt5wN8RRbujJw/YBJDDo0dpcAk0HQGNDadIxzfvIID78o6SxTL8YYR0eRrWausjrnSe+7Pnc0HaXpuYw0IIRkxHfxUCysLHL7k0e49bFjHFlsstiOONWySb1HCg4jnmR6pMCL9s5x5Z45Ltg2x2ShTENpemHUv6CcBOyxAPwubIElYvBtZIxZ7mSXo456DpiQIydO8OgzJ7j1saM8fXKNNS1Y7ipCDWNFh+mKx0TV45pd07zoku3s2jLLSKHEmjL0whApTH9dk+oi0Ilit2FBrQol4/jHBIBaa4yQSMfZeL3DOdLQAAxUhCPlGYwRU8MYR2iNSfKoGOtXSvSKrMnzQQHYvmcgbD/+Xin41IFHDh3kw1/+Fl97aokH16DnVqE6CqUSjBfsQ8IAOh14usn7H3mKaedRrpsr8e6XXcxrrtlHrVhlOVRx+H9/6e2qNJlk6BqsGxuZBptrdP3Xi4Evm3kCNIJ60aNIxP2PP8YHvnw/X3xiiUOBS1QYgeoMVCowUQTXiRNRd2CxxZ89dpQdX32a66Z93nrdHl7/osupF0sshxFK6TQqvd9tlblykjbA2LhFDGgMymDFdyzCbQYwxkwYOjCQyN8YpOsipESp9Wu/N6LhI6JPL9NwBKJeR4TBOmeTEMIUXTdO1Bgfi2ua6LVIgTAyMzby3hpjYm6X6EOSCd9lfmmBP/3Kt/jT2w/zZK8CO/bB/i0wUYdyAXw33ktB2I09AgWdHqw2mT+1wKcPH+UfPvwgr/vmk/zTV+zjFVe9gJbj0wmD2K+Wb0C7Sk5nMiep3abtMgiu/I80dCsHvDxok+lkq15IJj2Xp44e4k8+eycffeA0J80o7LgctszCxAhUSra+brxhiTagtM2G3mhzeH6Rw0eO8rcfe4y33HWIX3jFpdxwxT5ajkcnDDPwJepGss1xvq75DRk1IM2ALigIw1CHUW9d/4mCj2o1Uc0mfrG4aZvlaXgj5MQ8p+64g+nrrsbZdwk6DPtKLmXcb9pk1qYU5Jbu24KKROsQ6/osOeM5DtOuy+2PPs6vvf+b3NEowCVXwYU7YaIGFQ+KZDtZ5od1CIQl6I7Crlm4eDfRkZN8+rEn+fr/dyf/9jXz/MsfeTFeoUojCHK3xjwhKft5MPE2M/z7dGQDnusy6Ui+fM89/NqH7uShZhX2XQ0X7ICpUagWoCyy+ibbhRniHTkL0KvCjkm4aBfqxGk+8dgBvvzHd/ArLz3Gv37bjfiFCqu9nm3jXDVtORIjLztuud3ABxLrTfepzMZAuYxZW+Op93+QsBtw1cteCq8+exsNb4QIQW9+Hv/v/p7i1t1E27fD2lrcZxKlOoVIhzb1gzEYYZA6s6Ty/zL7t687AIMrXcZch0/cche//rEHODy2C17zAtgyDiMuVIEStjM8+rdLMNhRG2K3Se24MDYK4zWYm2LtsWf4j196jAMnPsdvvfvl1MYmWe31cp2xicJ6niiJMIbEMgXPcak7mj/+9Ff5T598jMXJPXD9Ptg6A+NFqMX1LQI+/XvVQf+2sB0JIyUY3Q4zE6wc2Mp/+ua3OLb8Bf7jj7+M2ugEK90eUqw3KjPHfTalmf41FnG2bTRGG9cYIwGFAeX7lNYalP78A7S+fitcfhmit/kS2zwNn5pDCKhW8R5/nG1/+D6c3/xNnH0XQaeLIx1OzB+fOblwgoLvQ2zhaZGlHdNJvrw+4NmxlvBCKawY+sgXb+fffPRhGpdeDlfug6kqjAH1uDPypVbG6kKGTDx5QBmoYAFbdqA8AZUyjFT54F3fQn3k6/zeP30NJa9COwj6rG7IcLieGW7EHgfU/MGH5M6mzzUGKSTjruQvv3obv/LXjxPuvQJeeDHMTcC4tPUtY4GXikUDYWRFr+daXdDFDshyXN8qUC5D5UIYq/H/3XYXp/74y/zBL76GWmWUtaDbxwT6yoXdGDFNri5NnDnCGmhxNNNMyfdLBhMq12VCGWZ/9/dp3nsf1OtI34chsymcW24YIcB1EV/6IuZ1r8Xduwc8B9fmMJZJmt3U5afj/M7agk/n4JdVP/GPSaZ9n6/e9xD//hOP0rjsSrj6Upguwji2M5LZwGYHjh6Hg4dhcQkvXtwUeC6MjsLO7bB9G4xULBj9+OOWwL0AHMlH7n2ACz5zJ//uLS+l5zhEWmFdr+TKl5RSpOVMjq03MfodGplDKTti6PdDjvsetzz0ML/5N48R7r3c1nfruK3vKHawSaAXwolT8MxhODWP0+3iGUPXcaFWsXXdtR0mxiwIC/HHd8CdA/d6PnnLHWz52Df5rz/9KnzXpRdmg26Q6RsR91WcawaTMBJiA85xXdd1lCOpeT67Tp2mfP8DrLru0MBL6NyTEwmBqVQwCIKjxzAz05hCER0pk+RHRtugACmlHUVJPhMBet2Ys8fGCwUeP3iYf/P+u1jaeTFctQ9mijCFBZ+DVbYfehRxx91c2+nw8tlpLhgbYbZSRgrBfLvD0UaTW77yNb6GJLzqCnjhC6BazOlOPugd0A347a89xEWzD/KmG65ioRf18eeBLsn9P8jvNri+T5L3w1jEzuW6X+LYwkl+9SP3cLK2A154iQXfFBZ8RSyXO3AIbr2Di+YXeNXUOPumJpmdGqfie5xudzjRanHHnXfzpZtvYe3SS+BF11iDJWkzKYBpCK/iD2+9nV2fuYN/9qYXs6BEn+9zUKqbmJlIaRlIKsm0QaJ0TzhmpNFktmZ3FIiKRQiGz56R0LPPjlUsEFUrlO+4E3/3blTBF1GkcB27FljFIz5ZzK2NHVU6140Jl3AdF6l6/M7f3cMTTMJVl8J0CSbJGnJxFT75Wa49cpRfu/YKbnzh5cxsmU31cEO2ne/S0jLfvO9B/ui22/n0Aw/Bm38Ytk5bfUoDqgh7d9FdXON3v3aI6/dvp1Qbox0Em6iAg5Bbr72ul7uCVNMSImeH2VkNX4R88CsP8OBaGV56McyNwwQwggVfpwdf/Bp77r2PX7l4L69/+xvZtms7nusSkbmtXKDRbHH/g4/w4Xvu5w8feBh+5PWwb69VQQC0gHAOs7if9958Hy99wWEu2L2TxW47mydP62U9uMrY7SJQOnalWQAqpYl8n/H5U2b3/Q/Qe+OPEJXLeM8yyGRofum4Lsr3CTzPV0JMOIuLs87yytz4X/7lzOgnPkGvUgu1UnFyoXivi/i3Upow/qtVfFzbbFWR1tRdj2888DR/d6ADV+2HmZFM53OA4/PwZx/iJ48f5xM/9WO84w2vobxllnlgHlgEloAF4CQgx8d4wytfxl+955/wm1rh/OkH4anDtrfqWA4zWYVLLuDu1QKfuO1JfKHR8VJEbbTtgL6PiVO6qTgTftZJ9nwu5Vv62+6XYDtQpwOw5Hk8dPAIH7z7NOzdA9tmMp2vBDTa8LG/44Zbb+Ov3/R6fvldb2Pmwt2suC6ncvU9Hdc3rFa47oZr+f1/9tO8b8cWJt7/EbjrPqsvVuL6jjlw0U5OV2f54NefxDEhwpFpgsp0bxKt02PpFhO5flRaEUohLnroAbXj9tvr5vTpLc6pU7Na66nQdWtdx4n3ahmOhuaAjV6vMnrgwC/vP3To5VNra9vK731vyfmDPxD+woKRBw68r/hDN4VBoYgTRQihrfiVAhNXKKlMPiQfbMaFbtji/V95ks7YLOyag1FhO8MFVprwkb/mPd0u7/s3v4iulDlBNnLyVU0Eey8GZmVijP/yS+/B/6MP8J8//DH4hZ+BmUnLCbvAzDjMbuHD9xzmddecZmR8kk43yhJY9rHDfu0vncQzpL5PkfqfrH9FSIEx+akwO8shTcjf3PYUx0wddm+FsUJmcPQi+MwXuOH+h/jLf/0LbNuxjVNkHG/QWQ/W6F8CPN/jF9/9DsZrNd7zV5+gXanA/ossCEeAdhkuuoCPPXQf73jyOBft3cpiL2AQLkIIdGRBKIXAKJ22SU8bykovzT3+5KtLt93263sffGgaY1SwuBi5pdLSVWtrjz2xa+f/KzzvgSFgNTwHfPTv/u5fvviWW/77ZYcOvW6m07msdurUnvJTT13grq3tkY8++mv+kcPXhr6vdJRlCVVKESlNFClUpGzWzni06XhHoLLv8Pgzp/jK4TZcuANGS5nrITLw+a9w7eGj/NYvvQdTKbPCek9EQoP+1BawJiX//j3v5keNgU9+zuqRRWyn1H3YOsNjHY9HDi1REHZzHGtMWW6dfFfxzkw6GUwpJ1fxdTpOsmnSOiqV1dOqIRrXkSyvrXLbwTbMzsLkqLVaK3Gh7/kWs1/7Jv/jZ97Fjh3bmB/oqM28RAILxEXgnT/yWv7tJRfBx//Oqi4O9h11YOs0i94IX3jwOF6sIqR1jeunVGS5otK233Qm2SJjENpo58mnf5ql5evKhw/vKh85sme03b541+LiDe9aWPjZLY889icLy8uTw+BqaADK++77iYsG5/7iCQg67RkOH3lLZIxMWbpSKfCiGHg67gijkoQ/4ArF3Y/Ps+rVYG7SdkSy/umZQ5Ruu4v/88ffwtzEWAq+jTphI8eIANqALPj8x5/8UbY/fgAeeczWOnHTTIwQlUe5/Zk1VNSNN5lRKJWAUKVAyjopr16oGHjJtRkgtUp2R9KxaNN40nDgyDKPNCTMTUHVt+XwgKU1+OJX+dUbr+NFl1/KPP3Ay9d7owGYgLAB/Mo/eQc3RSHcersVxYW4viMlmJnmjkNNVpstHCHSwaF1PHAiyzSiKLKf3ICLEOiV1RvE4sKrNipIEdjy9FPXLhw8+MoNiriOhgbgyNLSzjJYsVgDJjyYLMBMGRxDcOSYr5QSeT0vihRhXIEwrYRO9QmJodlsc+vjp2Fs3LpNEr+XMvCNO3j5aJ2brr+G5VxdN5qDNQPn899XgP0X7OLte3bBLbdbMedjuWy1AKMj3Hm0zeJKE2mMHfXr9J9sYPXpRIO/k2258hwk/milQQXcceA0DYowXs+czBJ44CH2LK/yjte8nNZZ6rQZGAWW849WyvzUDdfCHXdlXLAIlATMTPCtZcXjhxcoOGTgUjrXRxZ8tuxZPbUQ9JaXa+HycoVRH2ZKMOnDqEzdZJPGEBw9esUwuBoagONKlyTYif+5WZjdBrM7YNsFUK4QNJvohF1Hec4Qd0YUZaNKxVszYFhYWuOpxRDGR6Ho2ko4wPIKztMHeceLrqIkJedu4GeksbPmb7nhWuoLp+HkKfsOHyg4UKtyKhCcXuuCUSRbR6hYD7JcXPVzhYHvYfI9tJ8wUkQqSu+zuag1vW7A08s9qFShUsxmdIIQHn6Mt116MdunJmixflbwbJM0eYA2gVe86GoukRIOPGVP+Nj3jVRYMT5PH28gTNIfKu2XpNzrBllk9eOw3SEKQ5idgy27LBbmtsJMHQrWmFenF2eH6ZuhjZByGLoUJEzOwugM+D44DpRLcOI0Pa2zESOytGxGacIw6zCtVJyDzqCVZLXZoyHdeKJd2EYCOH6S0V7AVfsuIj+pc6ZO2KyzElG878LdXOI43HnoCOzcajveA0pFVnFZbvWYGo0Io3DdJL1JnXtn0sLs+f5FU9l31xg6StEIDJSLdubGw/bCYgPnxCmuf9VNQBwHsEldNuL+g9d1gC1TE1w3Mc5jTx+EG6627/GxfVcostyJCIOQKLSOnWS2TWpDGEaEoULbHersOa1RYUQQKULfhektUK5ArwdRBOU6dJ+hPN9m7dChiU0aqo+GBqACKHgwPg3jU7YSnge1Kqb6FEEY2EJHESDihIzCAi6MCKIIJ4owWiNiS1grRaMZ0BQFqNb79b9Wm22+x8TYKAHDxwZsBo8IKJVKbKuUuTNJtFSJP7UqDYosNQJ0FBJFKt0CwT40s4jzPsDEh5bMEuRBZ0MMcwEXMQ5bQZelFlCNgyqqWKSFIWVgZmK8L8ZpM7AN0iAwNRbb2ybHbYiawPZ2FeuYL9VZ6jYIApudNr8Dp5SSKIoIwyg+RpwX0TITwpDA92Bm1gKw04EwhFYJlpeI5tsUJyeHCoc5BwAacD0YGYWJCfALFoBjY+hiiSAWv5GyABQmA6CMIrsRoOdl0TIIQm0IooDK0hM4j3UodCYQYz7Cc1j81n1sLRao+B4qCJED7ptBGuyYdeJLCMq+z9TYCM7dDzEjyphAoZcDgpMruCfmEeqFBHY3JwsuYwGXhuybDH4CwyqSnoAJrXGx/l6Sme0kJjI5Iow1BhD4rWNUTh6lKg4hDhSRVY+1I0cYjxRTE6OYSCFzwbP94Rrrj7HBMW1AFAtsmxrH/8ptjHz6FjzXRzdC1EKb9qFDRBOz9PR2okjl5noNQkqrUugQE3v5E/9opCNQEZF0YHLKDqRmwwKwUIBSxc6kRNH5BWBkjAXdyJg1GIpFywXHxtGFAkHOyDDCZgQVwm6m7CirEzlhzAHjiOB2N6Ba8dnOAguPHWXk9AROoYJ0PXonDtPcWicMQkqOQZ1lVV7/3Oz6mQpHCCIh6PQCSk8eZWvXRQUBqtOkubpCxXOola6mE1oLMI0kA8DEa1tiESXgdKRp33wzpaNHOfTGN7JtahIZW/aDAExAGQlNpVxgi9/gwDOPM9U5jFOs4hbKeGvLRKZNOwhxlEF0e1nW1Q3reWZyDFAssBxGiJOLbPvG/bjCIey2CNsNVhaX2FqbJVCCIIxzNcazHUI6sU6rMPHEfhoVExuUIQJGx+ynULDTcJ5nw7KAzunTZ0mlYWn4iGgA14X6iJ3wLxbti0dHCB1JLzY+ImX3AtHkABhZ0exEKgWgFIJOp0e5WKRWr3OkuUylWMKUS3YDl1qdw40Wq+0OI+PjdJUauvE36ibHcWiHIceXVvArZcJKGe1KFIpeo81YqYjveXS7PeuvpD9yJZGxQkDLcTn04EO89cMfYM/yMn8WRRz+mZ9hBybbqTIFYH9ZSsqjXK6gHJ/QL6FLRUypiCvrNI6d5sTSEpdv30Ycoj10jde1gLQh9YfmT6P8AqZeJdSGSGh6QQ+3WGZ8dIQwDAjDMBW1YBCOSY0r4l2nTLzoSSnbh6FWNrpoYtwGIAQ9+7dYppu02RA0tBXcAQLHtSHh9RH7GRmFkVECx6WnNVrFjuacHynvjgmjiDAMCcOQIIroBQGOIxmtli2H0wajbPb5SrnCSqPD0/PzeJ7zba1cMwZ8z2NhdZVDK2uUy1Ub4aHspjFREFIrFygWXHpBYEe4ylm+sQsmip3Oz7TabPvrv+YS36f44pfwoi98npOPPEYTgVY6syoHPmFoLc7JkRpohVERaLv0seQX6GjBEyfmkc6zB15CnnRodLocPLVArVhGCJnqcVEYUil4lEs+nV5AGJctjPW+1GhUeWvf1sHOkGg6WtuQr9ExGInxUKtBoUALGz86DA0NwAAIHMdyvWIxjjerQKVCz5H0VN6Bmeu0pPChit0TGRB7QUioFXt3ziK1QoUhRtltHarlMu3Q8Jl77gdhU+c+ezIUCy6fu+9BDi81GanVMVpbEEQROozYu3MWz3PodoOcHzCbxYkijY4Uy0LQuec+brrnbuTei+jsvoAXRAHbP/UpjvSCbPYn9zfxIYZRRLcXcMGOaWrFAkE3sPXVCs/18EoVPnPvg6x1uhSGTAq/EWljqJWK3PXU09z9zDHGRset/qoUaEW33WX79DhjI1UazQ6R0haEUZS6oKJk5iPvD4zrFKqIjsbioFqzWCiXoFgCx6PD2V1GCZ0TAFtAvGjUfhy78V2oNAGknvRIq5z3PP6tY0dnbrI7UopWu8PFF2xhsl6h22pjtMIohSNdxsen+ft7H+LAiZOMlEvntFtTQsYYyoUCK602n7jjW5Sqo/iej1ERJoqIeiEFV3LxBVvo9cLYf5fz+SV1iWdxjrTaXPSpT7K77NPZtRtVreLvu4Qbb7mZxqOP0ZQSk0xnJRIg8YlqTaPZZmZylG3TY3SabVCWExpjmJ6Y4vanj/K1hx6hXimmmfnPlTzHAQkf/cadtLVDrVKzwRBKocMIHURccclOHEfQ6wUWZKkjXVvgpVNwOj2eTEVG2tDV8Y4CrmOxICRIQYShzXcIgGta21GklPX7KAW9Hu0gIIR4BsROtZl4cXhScDXgmA0jW7m1RoexkQp7t03TXGtCDAwwTE9Mcqqt+O2/+SwaQ9HzzkkUGyznrJR83ve5L3HPkQW2TM/aANkowihFq9FibmKErTPjNFqdlOslXFwpO4WmlWLZcdD33MdL77oN84LL0SOjiGKR7iWXclHUY+dnPsPRMIrbIQ5dUhmgldJ0gxDPc9l3wRbCbhcdhpgwwmhFrVLDKdX575/8B+ZX1qg/i0FnjGGsVuZTd97D3979EFvmttk0G8py+26zzWjJ5+Jdc6w12ilnTpzqycyViqce453ts76MQ+vaSmO6PRudnWBBKZr6OwjAVWVoBiG614NuFzpdaLVoRBE9QzzHa9LMBNkEvk6DEqIoCVCwlQ3CiHanx/VX7KUA9FptKxaVwnFctm3dxYfueIDf+/Q/UK8UKQwJQmMMjhCM1yv8/Z338N7PfY3Jma0UPB8dRegwRAc9gk6HG668iGLBo9XpxuXvHzjJXPCxZod9n/ok232H7t6LkZ6HcFzUxBTOJZdww9e/QuuxAzSlzHTBWDVJ5oKV0qw2Wlz3wr1M1Su01hqYKESHlgtum9vOXUeW+D8+8te4rqBeKg21aD5pk6nRGg8cPMRvfORvEZVxRmojVqqEIUQhjZVVrtu/m7HRCiuNFkprwnBAX+2bNjX2k87j22CNpjFE7TZ02tDtYrpder0eK1GUTiMOQ+cEwIZSLHU6LLdaNJpNus0GqtmkpRShMevmTZNprJS15xR0FQPSYDi9ssaeXTNcf+kuVhaWMFGADgOM1tSqNaa37OK3/v6rvPdvP03ZdxmvVuwa5WTBU+wuSb5LIamXy4xVy3z0lm/yr97/NxRHZ5gcnbBiKAggDFldXGXX7ATXv/BCFlfWYq6dlE+lHMyoiGXpYO67n5fc8U3Yvx9drdmIZaUQQtK75FIubq2x+3Of5WikUnVEx/PDScdqbQE4Plrlxqsuprm0ig566CBARxGe57Fr14X85d2P8Kt/+iFa3TZTIzV8x4kdwlmyoKS+IKgUi0yOVLn90cf5ufd9gOOBy9a5bTaTQRhiwpDmyhqTlSKvuOEyltcaub5IfLiDc+A6jWDSCRCVjeVsA+1Oh6jRoNVqsdpqsdRqsxoEsQ44nBEyvB8QWFWKxWaT7loDt9DDCwIKpRLN2G2RbJiczFoJITKOkkSGxH7C1EFsINKKpdU1Xvniy/jWE4dZW1qhPjmBlhLwmRybQEiH//OTN/PE8Xl+4TU3cem2rYxVymluFDDpllhRFPH0qRO8/2u38Yc33015dJq5ySk7lxn00GGPsN0maLV49RtuwHEEzXYX33HRxi6oTkL7DNaHeKLTZf/nPsM2E9LddYFdyZisq4hC1OgYhd27uPErX+TPXvs6mnt240chaRy0AYOO/dGG08tr3HDVxdx27+MsLSwxOueiHbuPSKVUZsuOvfzJ7Y/w6PwS/+6Nr+JFe/cwVa8QJYuFtLE5cYRAYjixvMyffeVe/sdnv8YKRXbt2IVEoMIAHQSobpe1hSXe9LobqFQKHD4+j+95hJHK4hgTf7sQ6Rww8bSpwe5vYmJm0gWWWi1ay8t0V1dRQUC32WS517NumCEN+XMC4FoUcbrZpLW6guv7uIUChW6XtTAiIl6wojWpM9hkoNQqU2ITiqcZEcDySpOtsxO87ZXX8Bef/iaFYiFdg4TnMzE6SrlQ5OOPHOWLT3yAl164k5v2X8S2sTozI3UcIZlvNDixssbtB57hq488xfGOYmpuF/VKBR0pdNBDdXuYbo/FE6f5oav3ceX+nZyYXwIBkdY20DTN32HHccsvED34CC+5/Rtw4R5MtY5QIaJnq2qUAiFQF+7l4ocfZffnP8+xX/hnbFfazkjE/sBsmSOsNdtMT4zwzje+hPd9+At0VtYoj8l0a9VyscQFey7mvvlT/OQff4zrd83x6hdcws7JcaZH6pR9j8Vmi/m1BvcfOsYXHnyMA4staqNT7BodswuIogAddDFBj4Xj81x78U6uv+pCjp86jRC2vwbn8OysjYijerRd7J8E6xswWqGNoaM1pxtruEtL9FZXUWFI0Gqx0uue0yYi5wxAv9GgUCji+D6O7+O326z1emk4u4q5UVIpnYZ6Jx+dq7BJ+hkDHDlxmhfu38kPL67xyVvuZ2rHHB7YZYG+R6lYYPe2nay1mnz2wEk+8+ghKq6kULKbR3c6PXqhJnJ86tVRdk3WkQJUGKKCHqZnwTd/5ASXbJ/mba+7jtNLK0RRhOM4KFS/89gYHCk4EYRc/KUvcEF7hWDXyzBCYILAKt5C2E5SEd3xSSpbZrjh5i/xF699Hd3tW3FVlH9cGtQggJPzS1y8Z463v/o6PvzpW3EcSaFeR5k4rZ3rsWNuG81Om28eW+Hrz3ydsgN+wU9dRkGo6CCplmts2zaN73loFcXWbs+C7+hJdo3VeOcbb2BpdZVON8B1HDT57TJsX0ghQcusr2KJRtIs8U6hXWM4tbqKW64SNtZQYUjUbtPo9vqCR84bABXQVArZbOJ5Po7nIT0f13dZ7XUxxCNK6XRxiwVg5lNLzHqT9EZS9VinUVpz8NgpfuiGfTRbHb5y3xOMzU1TrFVRWmFipX+0WmO0Vk/9VkEUEhlDZXycMcexu/xgbHhYFFl9MgiIOh1OHzvFrslRfvptN9Fud1hrdvBc1y4VEHbVGmSpzpquT/DEk7z0a1/GbNtKc2Tc+hDD0G60aCxvE0ohXB95wR4uu/lWtt7ydU7++I+zTauYq/XLJK11POgWuPFFl7DWaPOZr99HPVKUx0Zs53sK43tUikWq5S2pxRpEEaHWFEdcaq6L77rpvHsU9DCxzqd6PU4fO8WWSpGfedtNdIIui8tNu7BJrd8eF2GlkkniGeNFSX1sUtnpxq6BhZVVnEIR1Wqho4io06XTSwB4nnVABbSVQrWaeK6HcF2k6+K4Ls0wQGEDG9G2udNpLJUp4qklxcAkP8RJgQydXsSRU6f54VdeyWitzKdvfYBuq0N9csxyHMfBuC7CcXCExPFcSr7Nz2GMAa1RYWDdLMknDGivNFhdWOLafbt455teQhAFLC038DwXbXS2qWAWAoMDnFCK3V/5CnuXl1m76gUErhe7NEK0so0sASKFMIZoao7p8Tov+dLn+dDLbmJidgo3ikjyH+bbBgFBGHH4xDyve+ULGR+t8rHP3Uan1WF0ehKKESLyUK6LdGydC45D0Y3raydp0bFLKfFtmiik22ixfHKBK3bN8aM/cgOhjlhYWMNzHUIdpdvFJsgTicokwNEiZRhoaVEpjF1Sqm3kTM9oltbWkAUf1e5goggVBAS9HuHw+Du3/IBtpQhabRzpIlwH4bh2jjVS8VpSHYvgjIxOVobZj0pCsUgsuGy9aeLzanV6PHX0JNddcyHTE3U+9ZV7OHnwKOWxOuVaFXwPpJM6P0XSm7HoMtpyYh0G9Fod1pZWqDmSt738Kl56w6UsNxqsrLXxPReldbzwZn1kcdf1aB86wo23fBWmRmiOTxIlHCJKEqLH2UGUstHUxRKru3bywrsf5Iu3f5NTb34LW5RG5eOyYgmRrELu9kKePnKCK6/YzfhohU996W4OHT5OoV6hMlrH8T2M49kUeVLGYV4ZAE2sq5koIuh0aCyuUjSa1193KS+/8TJOr62xvNrEd13CyFbUEQId4y9LQy0QaISRts+UQQodFzlO2qStEdQDVlsthO+jul1QygZ39KxPeFhHzDkBsKc1vW4XKV2EIxGO/RtEEcpYDpiGTcVSWGuNk1vyp0y2+NumfEhSdxCvS7CbBQah4sChE8zOjPHz73w5Dz56mDsefJr5w8cRBZ9SpYRX9Ek2hbbqiXWUR0FIp9VGdQMqnsNNL9jDDVdfxNhYhSOnFuj1QlzXteqAsWuYM2zEG7UKOCkNu772NS47dZLFa68gKBTjjtEYVJpFQQBCa6TROEKyOj3H1vJjXP/lL/HxF9/I+EgdGcWxdZBy27wUCCPNgUPHmZ0c5Z/+xKu5/6Fn+OY9j3Pi6AnwPArlEn6pgBNnHxBxG2utUWFIt9Uh6gUUBVx74TZefPVFjI5XOHhynm4vwHNcgtjiTffxi3VAka7cMwhh9T8dr4lJd71KEowqhdGG0ECj00a4LiYIbNuHASYKOXPc0rMEoIkBaHpdpHQQjp2CEY60FqaxBbY6Qw646eKcbJVY4sNKwpzSzAmxe0ElXiQBh48vUC75vOCynVyydyvPPH2KZ44vcOjEEmsrayCTRIsxEIyh7Hvsnh1n1/ZpLtw1y/h4laW1Jk8cPJ65alRkwatzG3TFUahCQOC6NE6c5K1fvxmn6tOYnEYJSRSD3KaTE9l7MQitcTCocpWV7Vu55vHH+OLd97DwqlcwGanUws1HueR9mQBHTy7iFzz279/BJRdu5emDp3jm6AKHT55m6fQyPeLMBdhMpxJDwXPZOzXK9tkJdm6bYnK6zmq7zRMHj9u0vo4gTKKJhN2gW8dLSWUcdSNiLiexEesq3ilepBIt7q84WEQZQ6fbRTiu1Tm1xkQhRIqI4cPGzokDRgZ0ECJk12a9dyz3IVa0VRxd0nefyi1LjLlgYoSYPBcwWTZVbTIuKoSg1e7xROME5XKBrbun2LN3jnarR7vbo9cLaXcCtDaUyj7lYoFyyadWKxMZRbPd5cCh4/G0pWPBrkwc7WTZdD7w02CXiyy4HjN33sUVRw6yeMkuwmLZupriiBKTM+aTvYSljhefuy4r07Nsf/Ig1978FT5zzTXUC16cIyeVaGnYf+pgxmCEoNMNeOrwSUpFn7nt41xwwSzdbkCj0aHbC2m3uyitKRR9KkWfgu9RqRZRaNZaHZ46dgpjDK7jxMahLWnM+NDxhtyY2BUmkp0FBEZaqz6ZTsQxaSiaZRg2oj3CYHo9iAGI0favspLBPd9GiIkBaMLAcgrHseATAqEUykCkNI7SffBXSiOVIVJWRCVumETfN0nah9RPRsrRkjg8AwgpabV7rLU6SCGplH0KRY9yqcTIZBUpbBi5NoaWClg40cAojYiTewsZG0mxzmgjtpOd0ZOesKZvJB2Wlpb5oVu+StGBhckZQsdNMx0YpTGDe/UZg9QGoW1ddHWElZkJrnn4fr78yMMsXX019SDMkh/Fzl+TdLxOkjcRc2FBu9uj0bLzCoWCT9H3KRUL1MZKSCnsfLrWtKOQ06cahEpbDidtvKXSOk1xnGY/FdiF9MJmQjXJ3sUi2eZHgDLpTBZKpuqUiR3RQluViTDA9BxMGNl+igJEwmCGpHNOUm5UBKHARNLuIyYkMm48bXQ2Woz1wNrjyeJuO52TT5CNSdZU5LPGZKIp05XsMRlHCbeaPRqm2wd2KRKlOs6cH4dwaZ24Vaw3PxFFOW9R+mIJrBQ8Kg8+xAsff5SV2Ql65RpKEBtRBmMUNoN95kNLZjhEnIZOej5L07PMHV9k/623ctu+SyljcnmZ4xmSpNMhzcya6sgmNjYEdLoBrVY3lhD9XZykF0423Lb5obJrpCTdt1mbWOQCJtEBE31HgDQSRKxSGTKjMscUhImziAWhjZiOolQ/RPdnGDsbnVNyIgMYZYDIKqWx/pA0SqQ1TlxAg9XHVM4KNjpLcmPSxs7pg/m69s3zZteKHKfoS4WRtFAsZ7Q25HcmR0iE0NbPZwuX3pktQDJoIVhstXnxbd9kVGtOTU4RJNxPK1C23ibuSBJAxzMGIp4rlQJ0rUarWuDKb93NNw++lubuXRRUaIHVt92rSf9PxLImlc2J9pXWN9M8TQ4Y/Zwnq1taOTbeKSThFfYOnRtMymhEHuyx0ZP0r4kiKzi0AXTqI/yOcMCkUtZHazGe92vpWASTm2oD4jUhKnXD6EFgxS2Qcrn4gdnvzFLMKpf/P/fbJNEV2dRRauCmu3hmLZTNemTl6Hoe5tAz7H/wWzTLHo1yNdZv7aJs21syHny5QsQDD60QkcJRmsgtMD85wdaDx9ly372c2LGDORVnCMvpnWkNkmel2NpkUBJzIpG9u+9paR2tWNXxt+QFwmSZ+kXuXmkMiCyULkrngrNCaqWRStlXKgMijmTPlf87AsC+hyY2QqY2WXatNCLWQ5K+z+dVScJ6+sKLdL6h7dHMlRiDMHFbJI21Sbi33Z0pE259S3pSLmDSazMtzB6TwHKkmXzwASZaDU7NTdCUrg3fCuxMA9JJk6KbAfSI2BEulUJGCmkgKFfwBFxw/708eePLCOr1bDDkytfPm/p1g3S4mYyLCUSs7RjSgvQ9JJEEJFZSOuCEsCBEZE2ZYFYIW4ckeLjfCrYA7NtjRG3M8oYF4fAA7Fsou/4tSf4ToU1WYUh9fwn4Eh0wEaHJVlAkDZqDhMiJX8hen+IweXkejwKMTqTj5vIgL9YTioSgudpg52MPcQpoSYew07bulp6LcR1MEv1L4kvLuFMCQLRGqAjR6+FEEQ1XUDj4DOLgMzQufyHVDbaCyNSwTDfsK2+/JMzUCJ2VIeFmiYhP74lnMmSM61QymP5Bmmw2kEweKG3SNdwJ2QSkuQHybYAPzhGAYhCAMdm6mDT5UB4QSbaoSMduithKzrbdShpXZ4XvE8+kLTz49n4+wbrrsweS2kX0HTbp9QJhG73bYa3d5kEgOjaPWFhEJFkgpGNnI9IVazm4xFzBLqyy0cEmiqAXgIY2EardIYwdubqPadlCJO6cPmDn6tivX2V+IDN4Thj6VEzsNFrawnlOmHuLxq4JFtrkEizFrqO4QFplOuDGGuW50bPPkDpA1n0S5xTu0w2te0LHSR513oFGHoDZkUGOmOgz6f+i//58OFu/VDR94joTHDlKDXYLnnqxyKlXv4G1xx9BBQHCaAqx4xmgoDWhsHPjeW4lAc9AJAWhkPgGAimJHAcpJeHcFtxduymqCCVk+s4+bparS16NSd1w63S+fgCk9Teg08vz/RGLbxNrhibbny9VTWI/XxIVLpL+NBasyhgwen07Pks6NxFMX9/3kTLW15fslJQ0UqIXKmMtZDXARTM+mPD/5MhgI8ecIZ422mj0JZ4V+p6QiKX+tw7q7YmqU/M9OlddTe+qq9PR3zM5Dtf/RgyZVWrVMVuXdtKzsbLvSsmYViR7G6TA6itG/951CQhzxcx+GCtZ00EaV16va7fktMmVNXfC9D87Tc+b9KejY24qABugINSGsictmgL8Wm2ofFLD+wGlxBmwcPNksDqeHARgfMzqgPGujulNtpNsdbKsAiatCvR1eo7vpyM8vUHkQJJDojFpR6Uj3SQT+TnmmjOMClpRFAKTcKgECAmLMrnCpNkLNigvMaQMCGXngjUWXMlWqiK9zt6bJDFPn5W8xuQ5bvyWPvWs37WVvd9SNl3Zbxf3XZQ+3GRGiErcWbb1tIp13TNwQAN4lcpQcalDA9A5S2YCY6zTUqbcwlJyzOZTVgPRMiYdXTkNMKWN32cy0MRAy3O6jVT4pL3yrh3ynWWS67KGNX03ZwCm74oYeolOlZzPsedUPRB9SkQsUUxqEAiTGDXJATI9LsVh8v8GnZ8bQOt1XXKGX3KmP3I9T0LbhJVKaYSrY/DnGIrZfMWHwSbgahw7NlRc6vAi2HU1QSA3erGAbK53wLhQWiG03fQuiYpO7skaJGuEvmMkIzYn5tbxSNGPDkTaWCmccrIo8zVuokgn6cgwmJx7Q+Sfl74n//zcDECfaM0pxHndNW81xCIyr5OlojHRv5JZDjaBYFyGpN1zNe4rU1+tc32VH1xCG6L4I7S2rR77aZTBRjydwSDtAlt37lzd8IIBGhqAo47TOw0lf5PzBmHXVKiEl9nOtsfiFVaJd33QikiLTm5WglRYZGdNCrbMykvZF/1w6neOZl8NyUbQmTDK3xWXI8VHwmXXN3gCyLxt0Bfhnh8bSb0SF5UZfJbVsdAxaHNNlM5mpPcnN2fqQN4na8iV1+S1hqQQg1w+exwkjEJbz4XS8aCwJyOlLGg2yVSRpoUbqZ/a8IIBGhqAN5SKpz/e6WwvwLquEI5DbXqKk8QBp0lCGyznc4yNIlHK6hCZnzBr5WRqyoIv15qJ/GIDkZx6T+PfA/PJ6y7PnbPdvV5W5Xf7JAf/DKR5Vk2uzFhdMccZRIwKHddhsPx5o8m6NpJ6ZgEbg8aHSMZgTuybPiT1KyGCAcd+rgrZ1/iAjl+g7fYZ1hixz0j2OY7CkEK1RnF0jKDZ6KuPBNaAPULwes9/jCFoaADetH//Fz93y63vWcAmW8/v6Fny/U5t67aHVbt3pcQ42eaEpP4/legVJtN77LhPhXGGuaRB+hlBrt2y68FgdGperB8c+fvzRkp6dmD4Dz6hv4fp61oTi0NDyrr7QWb67jqTDp1/nRCC/jcOnM/9EBtelX3XG1Svr4Yxi051Y0OsswvC+LskmT2BIAopzcw8XN8yJ44fPXxpkjTeEGfPAK4fGVm8aM/urw9R3eEBuPM1r/6/f+bIkem/PXXqJb1IVUIpfY01uacvuuiTp+a2PtN+6OGrKyYd8zafcDx5bSOe473kkkl8kRcVcbfmLMOssTbiZyY9nwjqbGqq/w5tQLoOXrGE6zrIAeNho2cnvGjT9+feseljUlrPwTeCtJ1I0fR6ASrskYZH5Z4j0nKTTaf1PX2jtsqVdwN1wo7L7KidBbFcUGqNFHHwqxREYUQHcWJyz54vL95/3/8eIiqOEHjGqCp0bqrXD73+xpe8l127zi8HpFh66qaL9r79mosv2vfk4aNzJ2dna72g57ajSPH6N958sDbyy6rTEapQSF0NOq6MVWg1brruw6TSdV3nyGyU5zs4Ex3Z0XTqLqdTZ96/eF+zQoFqpYIXdAkWT9JrNuitraHCAAeySOH4++D7TDowBhrOceLwJ0uRtjMc+ZJnvDa3IMnYfDVS2o27nTim0khJsVrDrdYojYwh6yM0A7vWVsYFSACZL0s6KTNAG7df3vE9ILozTQelDVHcb44xaCOQwiDjSa751cb0ca/0wesvufieqUp12q3Xo9FOp3OR0YtzE5NPulu3nuIsCUXTdhzqKoAoIjAmGKnV7p8qFO4PKxUiFbI6OsXiC69BHz5eNipCGWumqBiAkbZ+I2VEagmLXIP2NZoA1AYNuk4ZynO5zKmcrIk3WqOAUr1Ood1g4evf4NB993L68EF0FNkMCDqi07GeAmMM0pFUK2Wb8iP2/vepVmRlEECr3SEMQ2zePUOlUrJrcgfcTMkdiTtGCGh3enSDwALYGHzfwy/4hPFC9trEOHMX72PbdS+msuNCGs0WRAFSyvQZ2fMSQK5T7FLumLSPyf/on5AiMRoFAhIr2BicOLTMGDAy1oq1ch8r1Zr7R8a/uN2BsFplTAimjEZ4HlEQDA2scwvHMoYgigiMRrWadIslFt74NtT2XYgDT5tQG/xYzCbcL4iTTiar3hImIWKrdf3gNalPLKH81vZ5fmlywzbdwtsYlBBUqjXU04/zjY9/mBOHDzE5MsLendsZHx1lpF7l1Pwid93/MK7jEClFpVzi+muuoFws2LCyjUjEC7cx3H7Pg5w6vYTn2cVNl+/fz9zMFL14x8g8B8pVDd9zuf/RJ3jq0DH8gke3FzIzO8Pl+/bS7nRpNlscO3mKB778RR679etc+cNvYvaHXkdDSFTQQ8gsqDbBk8ib3wNsL8/xEikRd+aAVpo5dwQQGk0Qi2AHkFLgaEGkDToM9erkpPuNPfvYefBxRns9ekrRM7HI3rj1NqRntV2r7HToFcscfONbWL38SqqdNr0oEoE2+FqjjE0Pq7B55LLN/5Jo3iwUqk+hjtsxnU6O8TU4wDF2lkKkDZmJXq0NhfoI7Ufv49Y/fR8O8JqX38TOHVvtmhCt8X2fTmRj3ZLJd9d1GRkbpVIu2Tg4M1CwmJ0kycs937Nra6Wd163Wa4xNjtOJd2DfUNkHCn6BYrGEENjFXSKkWCwxPTtjU5sIwaX797G8usbd936LW//m41y5tMSut76blvJAR6n5nAn63AjdgCxni6/WeS9idkP+m9aGMM4BKLXBESA1OMK61QKlBVpz39gUIor4qeYiY53O0Plg8nTOG1bLbgdTLLL49ncRXXEV9U6bSsHHdT3d0xo/jliOjOWAvTh8JzJZQEKfaEobL9vUL2ndvMTIOF+isK/nMcaALBaJFo5z+4f+gnKxwI/96NuZnBij3emitQ2kLJeKlCrl3LMs8qv1OtValTBO2m0x1z9UnDhmyfXddPGUEZpStUJtbAy30xkoU1ZGARSKBdyCH+uLVl1wfZfq6Ai9IIh3ERDsHB9l1+6dfPWWb3DXzV/Gn5hm8qbX0ms2cqpLzukeszqR/D/oKO7jfP0nBhQhpDGEyhDE63hcBI4BV2AzMoDxEJSV5t6JWbzRMX754Xsom82najejc9IB3eUlot176P7mLzB748vY1u0hRqrUKmXuqFW7QaToxuI3MiZdQ6tTJ3S83QP0uWLoA1naLvZPngPm56Y2Et5C4DqSp7/0Obqry/zkP/95Lt53ESsrq4yUS/YebahUy5xcXLL3GIMxdnfPkclxRkbqBL1gQBHN3udIm5HKKxQsiOIiVUfrjE9P0mq2+6Vh3nASgmKxQKFYSFcPam3wi0XGp6bo9nr2uACjDYVCgbe85Y0snV7k4c9/hhftvwLq46heJ7ccYbBtcu8bbMu4FtnYNemYzt8hY2aBNnYDIgROHFARKY0QIvJ9T8tI4Qm4pzLOn87u5L825hlX0bqAkzPR8AAcGSV61WtZ+JG3YK68holWE+G5IGCkWqHg+xBGdLQmDaM32BGXuGHIxKtVZk1ubdAmYsQMNHR2ou+8ESB9n9b8PIfvvYcXXnk5L3rpDXTabSYLhZyXwlCtVhk7NY+U1pK2WxNIxiYnGB8fp9vrptqpIe+uMUjp4DiSYqmYbuQMgpGxUSZnZyg0GnGoe1L9jJULIShXyhSKhXRZu0ZTKpWYmJ2m2+5YFSWustaasdFRXv361/DHf/RnzD/yEFM3vhzVS3TorFyDTXQmadg3r537niA0SbWHseH5EYZICELAKIUwxjiuYww2fUldhXxz525+O5zlXxw8wBZXnrkAORoagB+95kaiao2oXMZ56pm+51cbHY63Wm0Ecfq1BDRW6zVx0kMD6axA1hr970kEXr9fK9N21gneNFjA4EiXtdMLdDtNLot3VF9ZXul7l8FQr9cZHR+zXETbtcx+wWdyZpqx8TG6nV7Ov9avHzmOixQCx3XjgaaRjmRsapLJmSn8Yv/+LInwTuyEar3G6MS4bQljMGjK1QqTM9O0m62+FW/Wuq6w77L91As+S4cOMXqDXQKbOr3zs0E59K0z7wYNlXzlcghMjBut48jn3BRgUrZGGAXHlte0jvMACQNKCP5cCG4e3cKrtaG42OI3ODsNDcDf/NjfIoxGbuDfkY5DY22tK4tJYu3kY0VekqLNLvMDIeKpptzE7yCwNpt7HTyQqTZW3CebrlRqNcbGJ7KAAnsRGsPo2CjFcsUGy2LDzAulIpNTU1TrNYqlXgbs5F5h31HwfXq9Hr1eQBIeIAXUanXGxidAOPSnPBPpuwFGRkYYn5pIo38MgBSMjo3h+YW+/InaGKq1Kq1WG1c69IIevTj/Nrk5dZGKFDKbaYP2y4y5HFJT9ScH5DiwxIotG7hq48csICMIusokaX7SugoMj7tFHjQGE5jzC8BwdXXzk0LgKB1JDVpksbhWjoDQpFaxVdyTTtG5ud/kjtziwbhBTHYy/8d+z3vwo8huG4Dk+OGjjI6PZSlDEmvZaEZGR6nUqjlnjkFKQbVeoz4yQrfQpS/iJAG6MfiFAl6nk0anJNzCLxaoj43aGLpBKzUdaIL62Ciu62YDB3Bcl/roCE6crya5U2nN9PQUjz70KKudDlOT0zY7hVK5cHrRp/7JXBsNjgORA1ufcZe7X2DFu4mULbPKPVAKiBSjfjHYNT2poiGdzWeioQE4Nz626TnpOHRbrfDUEbuzTp+CEYtgrTM9cDAMaIDX5CbP00tzv/NXZ9apAQh6uFOz1HddyDdv/jrHjxznksv2MT8/b/OhxCJzdGyUer1mQRSHlwshqI3UGR0fpd3u0Kfjm6wTCqUi7ZaP4yQBF/ZTKpcZHRu1YM+rIOQDFKyu6LhOX538gh8fd23qNyyoC4UC9foIX/j05wiA6t5LsmwHJvEFZgqLEPlQ/Bx361Py+j0K/eFuseg2xBm3klEUc0EDhIpawY92TE6YIPh2NtG1NDQAZ84AQNd1aTpOV2pj2Z3MsS1jMFpnCYhMNhQz7S77Yhj4m6I0B7xYjTRpgpX4uFI4hRIzr3gtB/7s9/hv//m/8Bd/9WG2b9vB4tLpdJf2YrFEoVBEiCyxkQEKhQLlciVVD9YJUgPFUjG2VPtFe9EvUK3W6MZ7vPXdmQJBUKvX4sX9mZ7m+wVqtToY4vR1xvoGJ6b5g999H//w2c8zfeX1FHZcgO710inHTATHv3LSMh9xZFW43HAfWERj+mqaRG1bI4R0kVl8sYoo+V5nfKQe9nrnkgt1YxoagEfWmpuek45Lr91tKUdqlJLo/GJmG+OWjGxDvPI+uyA5Gv/MR/bGHCRurJTb5eY0Bzmk6LQoX7SfXa97K5//h7/lF37qZ/nP//3/5sK9FxLpkEhF1It1CoU4A3UOR6VymUq1kkajbGTIlcqlLLdyjgp+kVqxRrfWzQEwLRUkXLZYT58sZAJAn9HaKJ7nIRB4vken1eF//Y/f47d+4z9Q276b6Te81Q7keDfSZFot41w5hTg+koawmsymz4w8G2CwfgsIyzCsMz5mEal+aUA6nOyFzXuOz+so8Zd+GzQ0APdsndv8Ia5LY63RefohR4W9nsT1+liYjjeoMfTnNenX5RKnLuTb0sQNYJsiieDL3CeQuUlS663XZezlr8XxPT712b/jgfvu401veTPXXX8901tn2DK3jVNHT4DRyFiUqV6P+eMn0GFIp93J6W39VCyVWF1dIWh3kcQ+MwxLCwscP36EpZWl9QA0iQol6I20aa6sWkDEufd6zSZPP3mAxdOLLM0v8ugjj/DFz36Wr91yG/V9l7Ptre9GVGtE7VbaLjquf94AsSFTyeDRGfBEjlvGBRKI1CebtaEFpd3KIsr8Zslo1EAYsWVyvPeii/bQ63Y3BsQ5kBh256H/9MkvbHrO9zwWl5Zv+pP3f/izjUazLApeGholNJhQc8G1VzE+N0fY62EDN+29fePP5MVyFt+XcylihEl1oFT3wYo3Gf8VGKTjIoslesePsHDHLTSePkApCig5klqtShgpVhdO2zdpjev7TG2dw3GdbJZig7pKIVFacfrYccJegIh9iZNbZilVK6hIrXcVJY2NQDqSpfl5miurSOlgtKZcq1IdG6PdbNIJAppGIscnmbnmBuqXXQlCoLsdjEiSPSXt0a9LI+w2uUmSJrCh9On3+JpECmflTFYaGqTjoJTiyTvupL26gvR8y0QQCMdg1lq89Uff+nvvftPr/7dWq70pJgB++rorzngezoEDPrG0uRXsui6tVruBFCEqBC1jj7OxUbZJSD4i5eZ93I/+QQYWbDp3XT5DRF53zItKg7UCbcLuCNFu4sxsYfqt72ai1aS3tEjUatIMArRWjBR8EghrrVnodnJi39KAey19Y+XaIhVHpifXul2WksTfgxP9SX7l+P7i5QXGPS8dfKFSrEYK6dl0c2Oj4zgjozZzf7djM5LF4Eu3ke0ft5lKgnUkJzlyUmMl5oKZJZzALvM6mPhYpLEbj6sIpBNLJ0GShmGh3Vv82tNHz8oBzysAf/RFV296ruB5zK+urd7x+S+0GidPjph41GT6W0TY661rqJyUTsGWB8CASpN+kYPnYtIQZ3dKhrdBdNoW1I6LP7uFgnSsS2Ig6higSD+Yk9duBMDBewubao39BsNGz/aTRoA4s0KE6nbj9TOkoE7aKOVkuacOct28iy6REhgb3ZzcJMkcz8mVUkqiKEAHdhMUnc7vGkygcR2HdtBbfPSpZ/iu6oCPP31w84c4knYYLfuFwhJCbkl9Arkm6bZbhFrHbqVknUR/Q2Wj8MxqwdmUhsRo6btWRemulOdCm4nT7yiJbKFCXtQm5cnTMGVL1BcgbXdMYi3HojenIwa9HioKIUlDksBeaJxCEd/zllWn3ec0f7Y0NAA/+60HNz9pDIViMXA8r2HBZwZaxhAEXcLUFdO/JDLPOzbmIWenMwGl79wmQQbPFQ1y3GGuz7ddQs9mkOjcjYl5ZwwEQRjv/pSXNQa0xnUcdfGOrWujo6NZ1NC3QUMD8MJdO894vlgsdRaPHTuVeZvpGz1Rt5eOmLyRkfNU5Z7Wf2Zzyu7rF5PrO2RYTpa5Kfqfu/F164/1l2oYbt1/x0b3iXV3nK1dBsu5eXvmmUDy9LDbsXOmnpNrWAFK45XL7bHJyVPjtRpB9F0E4MsuvfiM5yuVslo+dvTpb92c5BROHLACHIew2STqdPArFVQYki7+yFM+zx2Z2FgXo28gi+cSuUbKujP/INN3Prk+ESu5l6Wel/zx/KP6YZ5PzZfv5lwhB94Vf0/fwTrqr3NSn5xLSMjchWeBuYA0k+sgpJNyZQpleqq7shIXWZJzV9hQtpHRBeW4Rxu9kEh/F0Xw0cXFM54vNhu45dIBt1ImCgLIbzkvHVSnQ6/VpDgykjpTM+oH3vrfGSXYHmy0/Jd1t4n+H9ZGERtfk3t29q4NH9SHocH1a2lZRHYutTnPVMDN3jc4CMVg+5mBAicpTPo9gP1N1X9MSIkKw9y8/3pgj0xMHFzqdBeD8+ADhHOZCVlePeN5z3NxSuXDhVpNRfPzDn7OGS0ERIruygojW7eRr7gZ4Cp5OpOYO9t1G1+zHqDZvRu/f1jKrMm8wDs3cbxZPYZTKwaBvcFCeNbxwdxvg3RdeivL9FotcJ08O7bfpWR6eurQhdOTvU7nXPbE3JyGBuB0vXbmB0mHaqH4+Mj4+KnWiRNb1mlljqR18gTRBXuQrrsBFzwb9euJ+cYbzhJMN2Toe8b5p7zoPDfKg+Hs+u+56aeb3Z+/VkhJ8+QJTLcLxWL/U6IQUS4zPjH+oAlDxHkQv3AOABwreGc8L4CZkZGDl++7+PbjDz/8tmyj3LgSnkewvMza8eOMX3ghqh2dYWG4pX6wDK94b1y+9e8Z1igZ5tr+675daK83O57dnf206XOMwfF8gmaLtcOHbTbYPmQCYcj0rt2Nyy/YcUu94BI652f4Dg3AK+emznjeALVySS1dednXvviFL71NtdtQKOSUZ6sMrzzzNPVt23B9HxUMrr0YjgbbBjZq3OG4yNlo0D7fjLuc6T3DcqRhn/fs71vvdkr0ROl7rD7xOFGjYblfMv8JJHGB+y/e+60d46MPhUGAds5l8eXmNPRTksXQm32kgCgMuHz3jq/v3rWjSXcgVMcY8H2C5WUWHnkY4ThIJ69nnJnMJt/T8g1x//no1LN38JlJDPwdPPedUQvOQMbgFUusHT/O8oHHwY0lXX6EBwGiUuHKfXtvrniy6wkoOuKsn2HovAHQ2hmK6Xrl4Ve++LrP4kg7lzjYqr7P6pMHWHj8MZxi8ZxAmLRHngzrwZWYGufiK/t2rhFnuWozQ2qzunznaOCNBtxymfbqMqfuvRsdReC6uULEalSnw2X7L164+tKL/tqVkkqpSLl49s8wNHyGVO/MOmBcXIQU4Tte+0P/47bb737DA3fdU2V8LBfUiJ3e8TwWH34YR0rG9+5FKGdocTyoOG92zbnQsAr7MOfOpjM+G4Cd2Xo9E60XuQA2FYmDWyjSXl7kxF13EbXbmejN/DLQC/CqVX72nW/+8xfs3v7AWqt1Xrn08BHRU2NDP3RnpXr7L/70j330X9z/4M+pTheKOV1QG3BcIGL+W9+iu7LC9Asutw7qXi9bVbdhLfM59DZ33/Q3+8adcN4pduzm14pkUNmI17HB8c1pI5fKcM+Kj+d0ca9QxAhYfvpJTj/8EFGvl4FvkJZXeO2Pvfngu1550x9KKRirlYcu8zA0dDzgcTVc+LUBm/xHsf8XfuO3Pv3JT3xqF7PT/UotWG5nNHR7FMbGmNy3j+rMLE6hgApDKw7OVPDc+/K/B49t1j3DGg0bvWczV87mnHAzEK73S54JrhuV7Uzlyv+WQiB9H4Od6Vh64nHWDh+ymU59P+ufPPdbXWN8bIS//pP/+Us/dPHeP1jj3GhkiGuG5oDrw8w3uQ6IjKLq+A//3M/++LseePjRP3nm6UP7GR8Dk6wZhnSdaqlIb22VY7ffRmlikpGdu6hu2YJXKpGuJ4lsFIsABrcvyNOZQJP/vTklcOnnX/nvg8/Inx/s9DO/rx98wz53s+dv9C6ZGHpSolVEc36e1UMHaRw/jgl64BcsANOltCL+I6DXoyxF+G9/5Z//p+sv3vvHrb5Snz8aGoCdc1gBJYQgRFMeqd3+qje/7mc//Icf+GS70ZyjVolzqMVkfQB2BGpNZ/E0ndML+E+NUZ6epjQ+TnF0DL9SsXn0ktvixeTJfsJAFp6ff/TA9+zcBtw4uVD035fuDJl/wAZmR3LrxkDdvNs2GiTDyKS8D1VIgRDSJluK62KMIer1aC8t0VleorMwT/v0aUwyTZq6WvLLaOOvWsPCIpe85of+y0tufNF/7WGB8p1QZIYWwZ949PFzezBxwkfX4a5v3Pmjf/xHf/Hna5Gq9OmD624S9ly88zbSwamUKY6OUqyN4FXKeOUybqGILBZwXM9mtxJx14vs3fDstb9z19CePZ1ZOJ/pRo0xAm00OgrRYUjU6xG2WkTdLkGjQWd5mbDZsDuZgwXe2bwOWiMaTV75ypv+4t0/8aO/cMW+vcFMrUqSivdcaE46Z73mO8IBE5JC4OPw8le+7OPPzJ92P/WxT743CoKteD4bVifRQzzPfoxBdTq0mk1aHAUhrP/QL+AUfZxCEddxEZ6L9HyE54Hr4mIXe5s4fRoGjJSWmzkSobU9LyU62SwxWWGWpqOwK6Gcgh/vPp4E0W7wicGfSK8s83WyMm1jV42NpIlzZsei0KgIHNdOdRmDEQIVRTZgVCu7pgbQvR4qCNBGE8XfVS+wojXv/HddOyGQb+N17Y515CoF7S57L9//+7/27//lb1y/bVtwWqs438+zGJDnE4DOJmn5z0ZRpAiCgLG52b+sbp071F1a+sNut/sCfJ9sfeqA1Ztftu+69gO2gzCoXhfVaecac5PmyeutCXdNjyXvTMqQ6xiT+xJzWBNbuZkyNrjBQ/w9eWYfGzUZOjeiBAAJoDdakbfZ72R1kYi3kU3cZQPrltP6DuIvuazXQzpOWJie/v9N7tn9X1zfN2vYVYaCZwG+Iem8bVZ4JjLGEAYBUspvTu3c/mPt1cZ/X5pfeJMxxoKrb5HHIBByv5POdZwYlInivIlJcjaZkQLyDOBN1s3mdC5L+QG5Uc+eC53FTEpBPTCAzvTOdW2StEfuPiEgjEBrRkdHnpjdtfP/Wmi0Phj2Apvm5LtA3xUAJqSUwi8WH6vW6u/wfe/Hu43mv1xeW7uWUIPnWjGUM8jOSH3cbyMaUAg3vGRj42PDa85K54NHnOUZ65YTPMtXGCCKIFIUy6XFUrXy/t17Lvij2sT4EycfOTdd/9ul7yoAwVqwSkVheaT+wW3btnzh8MHDP9taWfmZdi+8WIeBBaET6w4btvGgY2QjkyN3TV5U9XEBNr7PbPAMTB9HzI7n78+9p4/7DJZzg/rkkhdlCbFz7zW569KimQ2qm3vOYDXB6rcqBG0oV0rNsdHRz8xu2/I/V5qt2zQQhd8drpen7zoAE7IZnsSpSr3233Zunf3w0aPHX9npdN/UDcKbOp3OuJ0xcTLxs26Xuo044AZiJ/06eN0ACDdSAfK/zZlAtMk7Ny3n4CW5awbLYQbrMOAn2qwMxlh3SrKgWmmk4wQTY2N3V2qVL1y4Z9eX3FLxG2vNFnp1Lc3Y+t2m5wyAYHVDpRSe6x7xCoW/qE+MfyCIoit6rc6rVBhev7y6donWeotRajTLVQJp9EPyWwrStRJKZedTGtCXBJvojRtfnivx2b8PMuj8j0GbZdPrN6EkKZKM12okDmSt7WBVNvE6SuE4Do7ntT1HLviFwjOzM9MPtLrdfxipVW+p1+vNYrFo0yhH5yew9NnScwrAhOxOmxqttRZS3jc9M3WflFIGh46MTU6M7+y023sbrdbFjuPsMUE40Q2jySDo1VzHHddGlyKtizYRg6YocCKBG/V16KAFuUlBzmILrLt2I6m/0TvSfL0bXJ88Z0CSD5LEUBRChRAFAFIKz5WhEKJTdJ3lQKnGSKm4pIRYrNVrx7TmsUqtcsCFp1q9cPGCvXvaTz19kCiKiKIIpRRmw71Pv7v0PQHAPBlj4jRqRgtYLBQLi5FS95aEoF6tTumgV19qtkdEx6lMjI9PVgr++OGl1enW0pIpSMl1l+0rHFltjJ9YXvG1ihJ/XKpJ2Zesty3MwI/+RXE53TDv2Rm8N40kESmg+q7JqXTCZIuGUubYt3rNZI+UDvVyKXzR3t3LTx853n344BFDrSZ3bJlpSGPmXc89feLEqcbM3HQjDMLVibmZ06cXVwK/WMRVirVOjyiK0PGeH99LNPRMyPP0PH0n6PzEVT9Pz9OzpOcB+Dw9p/Q8AJ+n55SeB+Dz9JzS8wB8np5Teh6Az9NzSs8D8Hl6Tul5AD5Pzyn9/wEFaPppgwjxcAAAAABJRU5ErkJggg=="
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Robot"
+}
diff --git a/app/components/base/icons/src/public/avatar/Robot.tsx b/app/components/base/icons/src/public/avatar/Robot.tsx
new file mode 100644
index 0000000..8bee6e2
--- /dev/null
+++ b/app/components/base/icons/src/public/avatar/Robot.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Robot.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Robot'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/avatar/User.json b/app/components/base/icons/src/public/avatar/User.json
new file mode 100644
index 0000000..4b9ad76
--- /dev/null
+++ b/app/components/base/icons/src/public/avatar/User.json
@@ -0,0 +1,89 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "512",
+ "height": "512",
+ "viewBox": "0 0 512 512",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_5968_39205)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "512",
+ "height": "512",
+ "rx": "256",
+ "fill": "#B2DDFF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "circle",
+ "attributes": {
+ "opacity": "0.68",
+ "cx": "256",
+ "cy": "196",
+ "r": "84",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "ellipse",
+ "attributes": {
+ "opacity": "0.68",
+ "cx": "256",
+ "cy": "583.5",
+ "rx": "266",
+ "ry": "274.5",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_5968_39205"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "512",
+ "height": "512",
+ "rx": "256",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "User"
+}
diff --git a/app/components/base/icons/src/public/avatar/User.tsx b/app/components/base/icons/src/public/avatar/User.tsx
new file mode 100644
index 0000000..c7af428
--- /dev/null
+++ b/app/components/base/icons/src/public/avatar/User.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './User.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'User'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/avatar/index.ts b/app/components/base/icons/src/public/avatar/index.ts
new file mode 100644
index 0000000..7355b6b
--- /dev/null
+++ b/app/components/base/icons/src/public/avatar/index.ts
@@ -0,0 +1,2 @@
+export { default as Robot } from './Robot'
+export { default as User } from './User'
diff --git a/app/components/base/icons/src/public/billing/ArCube1.json b/app/components/base/icons/src/public/billing/ArCube1.json
new file mode 100644
index 0000000..89d9786
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/ArCube1.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "28",
+ "height": "28",
+ "viewBox": "0 0 28 28",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.0002 14V23.9166M14.0002 14L5.25 9.07806M14.0002 14L22.4731 9.2338M23.625 9.95052V18.0493C23.625 18.8924 23.1703 19.6697 22.4356 20.0831L15.1439 24.1846C14.4336 24.5842 13.5663 24.5842 12.8561 24.1846L5.56439 20.0831C4.82967 19.6697 4.375 18.8924 4.375 18.0493V9.95052C4.375 9.10756 4.82967 8.33012 5.56439 7.91684L12.8561 3.81529C13.5663 3.41574 14.4336 3.41574 15.1439 3.81529L22.4356 7.91684C23.1703 8.33012 23.625 9.10756 23.625 9.95052Z",
+ "stroke": "#101828",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ArCube1"
+}
diff --git a/app/components/base/icons/src/public/billing/ArCube1.tsx b/app/components/base/icons/src/public/billing/ArCube1.tsx
new file mode 100644
index 0000000..dfd3c41
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/ArCube1.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ArCube1.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ArCube1'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/Asterisk.json b/app/components/base/icons/src/public/billing/Asterisk.json
new file mode 100644
index 0000000..d4a2e91
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Asterisk.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "28",
+ "height": "28",
+ "viewBox": "0 0 28 28",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "asterisk"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M14.0033 3.20837V24.7917M4.65747 8.60421L23.3492 19.3959M4.6586 19.3959L23.3503 8.60421",
+ "stroke": "#101828",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Asterisk"
+}
diff --git a/app/components/base/icons/src/public/billing/Asterisk.tsx b/app/components/base/icons/src/public/billing/Asterisk.tsx
new file mode 100644
index 0000000..71b778b
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Asterisk.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Asterisk.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Asterisk'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/AwsMarketplace.json b/app/components/base/icons/src/public/billing/AwsMarketplace.json
new file mode 100644
index 0000000..8aeb93f
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/AwsMarketplace.json
@@ -0,0 +1,179 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "126",
+ "height": "24",
+ "viewBox": "0 0 126 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_394_42756)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M47.3963 14.5593V8.71609C47.3963 8.14631 47.2869 7.73413 47.0682 7.45531C46.8494 7.1886 46.5091 7.04313 46.0473 7.04313C45.2209 7.04313 44.3824 7.29771 43.5438 7.80687C43.556 7.89173 43.556 7.97659 43.556 8.06145C43.556 8.14631 43.556 8.2433 43.556 8.32816V14.5351H41.8667V8.69184C41.8667 8.12207 41.7573 7.70989 41.5386 7.43106C41.3198 7.16436 40.9795 7.01888 40.5177 7.01888C39.6549 7.01888 38.8284 7.27346 38.0385 7.7705V14.523H36.3492V5.9157H37.759L37.9291 6.77642C39.0229 6.0248 40.0802 5.66112 41.1132 5.66112C42.1705 5.66112 42.8875 6.06117 43.2521 6.86128C44.3702 6.06117 45.5004 5.66112 46.6185 5.66112C47.3963 5.66112 48.004 5.87933 48.4172 6.32788C48.8425 6.7643 49.0491 7.39469 49.0491 8.20693V14.523H47.3963V14.5593Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M56.0492 14.5593L55.9156 13.6744C55.5023 14.0259 55.0527 14.2926 54.5666 14.4866C54.0683 14.6806 53.5822 14.7775 53.0961 14.7775C52.294 14.7775 51.6498 14.5472 51.1637 14.0865C50.6776 13.6259 50.4346 13.0197 50.4346 12.2439C50.4346 11.4195 50.7262 10.7527 51.3217 10.2678C51.9172 9.77078 52.7072 9.52832 53.7037 9.52832C54.36 9.52832 55.077 9.62531 55.8426 9.81927V8.70397C55.8426 8.09782 55.709 7.6614 55.4294 7.41894C55.1499 7.16436 54.6759 7.04313 54.0075 7.04313C53.0474 7.04313 52.0509 7.21285 51.0179 7.56441V6.37637C51.4311 6.15816 51.9294 6.00056 52.5127 5.87933C53.1082 5.7581 53.7037 5.69749 54.2992 5.69749C55.3808 5.69749 56.1708 5.9157 56.6812 6.36425C57.1916 6.81279 57.4468 7.49168 57.4468 8.41302V14.5593H56.0492ZM53.4971 13.5046C54.2627 13.5046 55.0527 13.2137 55.8426 12.6439V10.9103C55.2471 10.7649 54.6516 10.6921 54.044 10.6921C52.7679 10.6921 52.1238 11.1892 52.1238 12.1711C52.1238 12.5954 52.2453 12.9349 52.4763 13.1652C52.7193 13.3834 53.0596 13.5046 53.4971 13.5046Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M59.3792 14.5593V5.95207H60.7889L60.9712 7.22497C61.2872 6.88553 61.5788 6.61883 61.8584 6.43698C62.1379 6.25514 62.4053 6.10966 62.6969 6.0248C62.9764 5.93994 63.2924 5.89145 63.6206 5.89145C63.8393 5.89145 64.0702 5.90357 64.3133 5.93994V7.46743C63.9487 7.41894 63.6449 7.39469 63.3896 7.39469C62.4782 7.39469 61.7004 7.6614 61.0563 8.20693V14.5593H59.3792Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M65.3584 14.5593V2H67.0477V9.71017L70.7057 5.96419H72.7596L68.6762 10.0496L73.027 14.5593H70.9002L67.0355 10.486V14.5593H65.3584Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M74.5704 10.6194C74.5947 11.5892 74.8378 12.3166 75.2996 12.7773C75.7614 13.2379 76.4663 13.4683 77.4385 13.4683C78.3378 13.4683 79.2493 13.2985 80.1729 12.947V14.1472C79.3587 14.5836 78.3621 14.8139 77.1833 14.8139C75.7857 14.8139 74.7284 14.426 74.0235 13.6622C73.3065 12.8985 72.954 11.7589 72.954 10.2557C72.954 8.81307 73.3065 7.69776 74.0235 6.90978C74.7405 6.12179 75.7371 5.70961 77.0131 5.70961C78.0948 5.70961 78.9212 6.01268 79.4924 6.61883C80.0757 7.22497 80.3552 8.0857 80.3552 9.18888C80.3552 9.72229 80.3066 10.2072 80.2215 10.6315H74.5704V10.6194ZM76.9159 6.97039C76.1989 6.97039 75.6399 7.1886 75.251 7.60078C74.8499 8.02508 74.6312 8.65547 74.5704 9.49195H78.8118C78.824 9.40709 78.824 9.2495 78.824 9.05553C78.824 8.36452 78.666 7.84324 78.3379 7.49168C78.0219 7.15223 77.5479 6.97039 76.9159 6.97039Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M86.9421 14.3532C86.3831 14.5715 85.7511 14.6806 85.0584 14.6806C83.4421 14.6806 82.64 13.8804 82.64 12.2681V7.27346H81.0722V6.1824L82.6886 5.97631L82.9438 3.52749H84.3171V5.93994H86.8692V7.26134H84.3171V12.1832C84.3171 12.6075 84.4143 12.8985 84.5966 13.0682C84.7789 13.2379 85.107 13.3228 85.5567 13.3228C86.0185 13.3228 86.4803 13.2622 86.93 13.1531V14.3532H86.9421Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M88.0967 5.95207H89.5064L89.6644 6.83704C90.5273 6.0733 91.4874 5.69749 92.5447 5.69749C93.6506 5.69749 94.5135 6.09754 95.1454 6.89765C95.7774 7.69776 96.0933 8.7767 96.0933 10.1466C96.0933 11.5407 95.7531 12.656 95.0846 13.4925C94.4162 14.329 93.5291 14.7533 92.411 14.7533C91.3901 14.7533 90.5151 14.4139 89.7738 13.7471V18.0628H88.0967V5.95207ZM92.0585 7.05525C91.2564 7.05525 90.4908 7.30983 89.7738 7.83112V12.5712C90.5151 13.1167 91.2564 13.3834 92.0221 13.3834C93.5898 13.3834 94.3676 12.3287 94.3676 10.2315C94.3676 9.15251 94.1732 8.36453 93.7964 7.84324C93.4318 7.32196 92.8485 7.05525 92.0585 7.05525Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M100.711 14.4381C100.335 14.5715 99.9337 14.6442 99.484 14.6442C98.8885 14.6442 98.4267 14.4745 98.1107 14.1229C97.7948 13.7835 97.6368 13.2864 97.6368 12.6439V2H99.326V12.5348C99.326 12.7894 99.3746 12.9834 99.484 13.1046C99.5934 13.2258 99.7757 13.2864 100.019 13.2864C100.25 13.2864 100.481 13.2743 100.711 13.2379V14.4381Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M107.225 14.5593L107.092 13.6744C106.679 14.0259 106.229 14.2926 105.743 14.4866C105.245 14.6806 104.758 14.7775 104.272 14.7775C103.47 14.7775 102.826 14.5472 102.34 14.0865C101.854 13.6259 101.611 13.0197 101.611 12.2439C101.611 11.4195 101.902 10.7527 102.498 10.2678C103.093 9.77078 103.883 9.52832 104.88 9.52832C105.536 9.52832 106.253 9.62531 107.019 9.81927V8.70397C107.019 8.09782 106.885 7.6614 106.606 7.41894C106.326 7.16436 105.852 7.04313 105.184 7.04313C104.224 7.04313 103.227 7.21285 102.194 7.56441V6.37637C102.607 6.15816 103.106 6.00056 103.689 5.87933C104.284 5.7581 104.88 5.69749 105.475 5.69749C106.557 5.69749 107.347 5.9157 107.857 6.36425C108.368 6.81279 108.623 7.49168 108.623 8.41302V14.5593H107.225ZM104.673 13.5046C105.439 13.5046 106.229 13.2137 107.019 12.6439V10.9103C106.423 10.7649 105.828 10.6921 105.22 10.6921C103.944 10.6921 103.3 11.1892 103.3 12.1711C103.3 12.5954 103.422 12.9349 103.652 13.1652C103.896 13.3834 104.236 13.5046 104.673 13.5046Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M116.571 14.232C115.915 14.5715 115.149 14.7412 114.286 14.7412C112.95 14.7412 111.929 14.3532 111.212 13.5895C110.507 12.8258 110.142 11.7226 110.142 10.2678C110.142 8.82519 110.507 7.72201 111.236 6.93402C111.965 6.14603 112.998 5.7581 114.335 5.7581C115.101 5.7581 115.805 5.9157 116.474 6.23089V7.43106C115.83 7.22497 115.198 7.12799 114.566 7.12799C113.618 7.12799 112.925 7.37045 112.512 7.85536C112.087 8.34028 111.88 9.10402 111.88 10.1587V10.3769C111.88 11.4074 112.099 12.159 112.512 12.6439C112.937 13.1288 113.606 13.3713 114.529 13.3713C115.137 13.3713 115.805 13.2622 116.535 13.0318V14.232H116.571Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M118.965 10.6194C118.99 11.5892 119.233 12.3166 119.694 12.7773C120.156 13.2379 120.861 13.4683 121.833 13.4683C122.733 13.4683 123.644 13.2985 124.568 12.947V14.1472C123.754 14.5836 122.757 14.8139 121.578 14.8139C120.181 14.8139 119.123 14.426 118.418 13.6622C117.701 12.8985 117.349 11.7589 117.349 10.2557C117.349 8.81307 117.701 7.69776 118.418 6.90978C119.135 6.12179 120.132 5.70961 121.408 5.70961C122.49 5.70961 123.316 6.01268 123.887 6.61883C124.471 7.22497 124.75 8.0857 124.75 9.18888C124.75 9.72229 124.701 10.2072 124.616 10.6315H118.965V10.6194ZM121.311 6.97039C120.594 6.97039 120.035 7.1886 119.646 7.60078C119.245 8.02508 119.026 8.65547 118.965 9.49195H123.207C123.219 9.40709 123.219 9.2495 123.219 9.05553C123.219 8.36452 123.061 7.84324 122.733 7.49168C122.405 7.15223 121.931 6.97039 121.311 6.97039Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M27.0036 14.8139C26.4567 14.8139 25.922 14.7533 25.3994 14.6321C24.8768 14.5108 24.4758 14.3775 24.1962 14.2199C24.0261 14.1229 23.9167 14.0259 23.8803 13.9289C23.8317 13.832 23.8195 13.735 23.8195 13.638V13.1167C23.8195 12.8985 23.8924 12.7894 24.0504 12.7894C24.1112 12.7894 24.1719 12.8015 24.2449 12.8258C24.3056 12.85 24.4029 12.8864 24.5122 12.9349C24.8647 13.0925 25.2414 13.2137 25.6546 13.2985C26.0678 13.3834 26.481 13.4198 26.8942 13.4198C27.5505 13.4198 28.0487 13.3107 28.4133 13.0803C28.7658 12.85 28.9481 12.5227 28.9481 12.0984C28.9481 11.8074 28.8508 11.565 28.6686 11.371C28.4862 11.177 28.1338 10.9952 27.6234 10.8255L26.1164 10.3527C25.3508 10.1102 24.8039 9.75866 24.4515 9.29799C24.1112 8.83732 23.9289 8.34028 23.9289 7.79475C23.9289 7.35832 24.0261 6.97039 24.2084 6.64307C24.3907 6.31575 24.6459 6.0248 24.9497 5.79447C25.2536 5.56413 25.6182 5.38229 26.0313 5.26106C26.4446 5.13983 26.8821 5.07922 27.3439 5.07922C27.5748 5.07922 27.8057 5.09134 28.0487 5.12771C28.2797 5.16408 28.5106 5.20045 28.7172 5.24894C28.9238 5.29743 29.1304 5.34592 29.3127 5.40654C29.495 5.46715 29.6408 5.52777 29.7502 5.58838C29.896 5.67324 29.9932 5.7581 30.054 5.84296C30.1148 5.92782 30.1391 6.03693 30.1391 6.1824V6.66732C30.1391 6.88553 30.0661 6.99464 29.9082 6.99464C29.8231 6.99464 29.6894 6.95827 29.5071 6.87341C28.9116 6.6067 28.2432 6.47335 27.514 6.47335C26.9185 6.47335 26.4567 6.57033 26.1286 6.7643C25.8004 6.95827 25.6425 7.26134 25.6425 7.68564C25.6425 7.97659 25.7397 8.21905 25.9463 8.42514C26.1529 8.61911 26.5296 8.81307 27.0887 8.99492L28.5592 9.46771C29.3127 9.71017 29.8474 10.0375 30.1634 10.4618C30.4793 10.8861 30.6495 11.371 30.6495 11.9165C30.6495 12.3651 30.5644 12.7651 30.3821 13.1167C30.1998 13.4683 29.9446 13.7835 29.6286 14.038C29.3127 14.2926 28.9238 14.4866 28.4741 14.6199C28.0244 14.7412 27.5383 14.8139 27.0036 14.8139ZM13.6718 14.5351C13.4895 14.5351 13.3558 14.4987 13.2707 14.4381C13.1856 14.3775 13.1127 14.232 13.052 14.0259L10.6214 6.01268C10.5606 5.80659 10.5363 5.67324 10.5363 5.6005C10.5363 5.43078 10.6214 5.34592 10.7915 5.34592H11.8124C12.0068 5.34592 12.1405 5.38229 12.2256 5.4429C12.2985 5.50352 12.3714 5.64899 12.4322 5.85508L14.1822 12.7045L15.7742 5.85508C15.8228 5.64899 15.8836 5.51564 15.9687 5.4429C16.0538 5.38229 16.1874 5.34592 16.3819 5.34592H17.2204C17.4149 5.34592 17.5486 5.38229 17.6336 5.4429C17.7187 5.50352 17.7795 5.64899 17.8281 5.85508L19.4687 12.8015L21.2674 5.85508C21.3281 5.64899 21.4011 5.51564 21.474 5.4429C21.5469 5.38229 21.6927 5.34592 21.8872 5.34592H22.8473C23.0174 5.34592 23.1025 5.43078 23.1025 5.6005C23.1025 5.64899 23.0903 5.69749 23.0903 5.7581C23.0781 5.81871 23.0538 5.90357 23.0174 6.01268L20.5138 14.0259C20.4531 14.232 20.3802 14.3654 20.2951 14.4381C20.21 14.4987 20.0763 14.5351 19.894 14.5351H19.0069C18.8124 14.5351 18.6787 14.4987 18.5937 14.426C18.5086 14.3532 18.4478 14.2199 18.3992 14.0138L16.7829 7.3462L15.1787 14.0138C15.1301 14.2199 15.0693 14.3532 14.9842 14.426C14.8992 14.4987 14.7655 14.5351 14.571 14.5351H13.6718ZM5.32267 13.4077C5.66296 13.4077 6.0154 13.347 6.39214 13.2137C6.76888 13.0925 7.09701 12.8621 7.37653 12.5469C7.54667 12.353 7.6682 12.1347 7.72897 11.8802C7.78973 11.6377 7.82619 11.3346 7.82619 10.9831V10.5466C7.52237 10.4739 7.20639 10.4133 6.86611 10.3769C6.53797 10.3406 6.20984 10.3163 5.89387 10.3163C5.20114 10.3163 4.69072 10.4497 4.35044 10.7285C4.01015 11.0073 3.84001 11.4074 3.84001 11.9287C3.84001 12.4136 3.96154 12.7773 4.21675 13.0197C4.49627 13.2864 4.84871 13.4077 5.32267 13.4077ZM9.53976 11.8317C9.53976 12.2196 9.57622 12.5227 9.66129 12.753C9.73421 12.9834 9.85574 13.2258 10.0016 13.4925C10.0502 13.5774 10.0745 13.6501 10.0745 13.7228C10.0745 13.832 10.0137 13.9289 9.88005 14.0259L9.21163 14.4866C9.11441 14.5472 9.02934 14.5715 8.94427 14.5715C8.83489 14.5715 8.73767 14.523 8.64044 14.426C8.49461 14.2805 8.37308 14.1229 8.2637 13.9411C8.16647 13.7713 8.0571 13.5653 7.94772 13.3349C7.13347 14.2926 6.11262 14.7654 4.89732 14.7654C4.0223 14.7654 3.32959 14.523 2.83131 14.0259C2.32089 13.5289 2.06567 12.8621 2.06567 12.0378C2.06567 11.1528 2.38165 10.4497 3.01361 9.90413C3.64556 9.37073 4.49627 9.0919 5.55358 9.0919C5.90602 9.0919 6.27061 9.11614 6.64735 9.17676C7.02409 9.22525 7.42514 9.31011 7.83834 9.40709V8.64335C7.83834 7.85536 7.68036 7.30983 7.35222 6.98251C7.02409 6.66732 6.46506 6.4976 5.66296 6.4976C5.29837 6.4976 4.92163 6.54609 4.54488 6.63095C4.16814 6.71581 3.7914 6.83704 3.42681 6.98251C3.25667 7.05525 3.13514 7.10374 3.06222 7.11587C2.9893 7.12799 2.94069 7.14011 2.90423 7.14011C2.75839 7.14011 2.68548 7.031 2.68548 6.81279V6.30363C2.68548 6.13391 2.70978 6.01268 2.75839 5.93994C2.80701 5.86721 2.90423 5.79447 3.05007 5.72173C3.41466 5.53989 3.85216 5.38229 4.36259 5.24894C4.87301 5.11559 5.40775 5.05497 5.97894 5.05497C7.21854 5.05497 8.11786 5.3338 8.70121 5.90357C9.2724 6.46123 9.56407 7.30983 9.56407 8.44938V11.8317H9.53976Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M28.9723 19.8449C25.5573 22.3665 20.5989 23.7 16.3332 23.7C10.3539 23.7 4.97014 21.4936 0.886731 17.8204C0.570753 17.5294 0.850272 17.1415 1.23917 17.3597C5.63855 19.9177 11.0709 21.4451 16.6978 21.4451C20.4895 21.4451 24.658 20.6572 28.4862 19.0448C29.0573 18.8023 29.5313 19.4327 28.9723 19.8449Z",
+ "fill": "#FF9900"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M30.3942 18.2205C29.9567 17.6628 27.5018 17.9537 26.3958 18.0871C26.0677 18.1235 26.0069 17.8325 26.3108 17.6264C28.2674 16.2565 31.4758 16.6566 31.8525 17.1051C32.2293 17.5658 31.7553 20.7784 29.9202 22.3059C29.6407 22.5362 29.3733 22.415 29.4949 22.0998C29.9081 21.0815 30.8317 18.7902 30.3942 18.2205Z",
+ "fill": "#FF9900"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_394_42756"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "124.5",
+ "height": "24",
+ "fill": "white",
+ "transform": "translate(0.75)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AwsMarketplace"
+}
diff --git a/app/components/base/icons/src/public/billing/AwsMarketplace.tsx b/app/components/base/icons/src/public/billing/AwsMarketplace.tsx
new file mode 100644
index 0000000..7ea4e14
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/AwsMarketplace.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AwsMarketplace.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AwsMarketplace'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/Azure.json b/app/components/base/icons/src/public/billing/Azure.json
new file mode 100644
index 0000000..fb6a9b9
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Azure.json
@@ -0,0 +1,193 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "21",
+ "height": "20",
+ "viewBox": "0 0 21 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group 5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M7.08403 0.812966H12.8543L6.86419 18.5609C6.80263 18.7433 6.68542 18.9018 6.52907 19.0141C6.37271 19.1263 6.18509 19.1867 5.99261 19.1868H1.50193C1.35609 19.1868 1.21234 19.1521 1.08258 19.0855C0.952814 19.019 0.840765 18.9225 0.755699 18.804C0.670633 18.6855 0.614995 18.5485 0.593389 18.4043C0.571782 18.2601 0.584829 18.1128 0.631448 17.9746L6.21222 1.43879C6.27376 1.25634 6.39099 1.09779 6.54739 0.985482C6.70379 0.873171 6.89148 0.812976 7.08403 0.812966Z",
+ "fill": "url(#paint0_linear_644_3772)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M15.469 12.7173H6.31874C6.23367 12.7173 6.15054 12.7428 6.08019 12.7906C6.00984 12.8384 5.95552 12.9063 5.92431 12.9855C5.8931 13.0646 5.88644 13.1513 5.90521 13.2343C5.92398 13.3173 5.96731 13.3927 6.02954 13.4506L11.9093 18.9386C12.0805 19.0983 12.3059 19.187 12.54 19.187H17.7212L15.469 12.7173Z",
+ "fill": "#0078D4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M7.08432 0.813056C6.88967 0.812309 6.69988 0.873821 6.54267 0.988606C6.38547 1.10339 6.26908 1.26543 6.21052 1.45107L0.638609 17.9596C0.588854 18.0983 0.573233 18.2469 0.593069 18.3929C0.612904 18.5389 0.667613 18.678 0.752567 18.7984C0.83752 18.9188 0.950219 19.0169 1.08113 19.0845C1.21204 19.1522 1.35731 19.1873 1.50466 19.1869H6.11124C6.28281 19.1562 6.44316 19.0806 6.57593 18.9676C6.7087 18.8547 6.80911 18.7086 6.86692 18.5442L7.97807 15.2695L11.9471 18.9715C12.1134 19.109 12.3221 19.1851 12.5379 19.1869H17.6998L15.4359 12.7172L8.83614 12.7188L12.8754 0.813056H7.08432Z",
+ "fill": "url(#paint1_linear_644_3772)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M14.4539 1.43799C14.3925 1.25583 14.2754 1.09755 14.1193 0.985434C13.9631 0.87332 13.7757 0.813027 13.5835 0.813049H7.15259C7.34482 0.81306 7.53221 0.873366 7.68837 0.985475C7.84453 1.09758 7.96159 1.25585 8.02307 1.43799L13.6041 17.9744C13.6507 18.1126 13.6638 18.26 13.6422 18.4042C13.6206 18.5485 13.565 18.6856 13.4799 18.8041C13.3949 18.9226 13.2828 19.0191 13.153 19.0857C13.0232 19.1523 12.8795 19.1871 12.7336 19.1871H19.1647C19.3105 19.187 19.4543 19.1523 19.584 19.0856C19.7138 19.019 19.8258 18.9225 19.9109 18.804C19.9959 18.6855 20.0515 18.5484 20.0731 18.4042C20.0947 18.2599 20.0816 18.1126 20.0349 17.9744L14.4539 1.43799Z",
+ "fill": "url(#paint2_linear_644_3772)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_644_3772",
+ "x1": "9.1871",
+ "y1": "2.17453",
+ "x2": "3.19457",
+ "y2": "19.878",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#114A8B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#0669BC"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_644_3772",
+ "x1": "11.0593",
+ "y1": "10.4249",
+ "x2": "9.67315",
+ "y2": "10.8936",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-opacity": "0.3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.071",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.321",
+ "stop-opacity": "0.1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.623",
+ "stop-opacity": "0.05"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-opacity": "0"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint2_linear_644_3772",
+ "x1": "10.2966",
+ "y1": "1.65827",
+ "x2": "16.8746",
+ "y2": "19.1833",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#3CCBF4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#2892DF"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Azure"
+}
diff --git a/app/components/base/icons/src/public/billing/Azure.tsx b/app/components/base/icons/src/public/billing/Azure.tsx
new file mode 100644
index 0000000..fe47611
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Azure.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Azure.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Azure'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/Buildings.json b/app/components/base/icons/src/public/billing/Buildings.json
new file mode 100644
index 0000000..62d22f9
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Buildings.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "29",
+ "height": "28",
+ "viewBox": "0 0 29 28",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "buildings"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M5.04134 22.4583H17.2913M5.04134 22.4583V6.70833C5.04134 5.41967 6.08601 4.375 7.37467 4.375H14.958C16.2467 4.375 17.2913 5.41967 17.2913 6.70833V9.33333M5.04134 22.4583H2.70801M17.2913 22.4583V9.33333M17.2913 22.4583H24.2913M17.2913 9.33333H21.958C23.2467 9.33333 24.2913 10.378 24.2913 11.6667V22.4583M24.2913 22.4583H26.6247M12.6247 10.2083H9.70801M9.70801 14.875H12.6247",
+ "stroke": "white",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Buildings"
+}
diff --git a/app/components/base/icons/src/public/billing/Buildings.tsx b/app/components/base/icons/src/public/billing/Buildings.tsx
new file mode 100644
index 0000000..eaed4e8
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Buildings.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Buildings.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Buildings'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/Diamond.json b/app/components/base/icons/src/public/billing/Diamond.json
new file mode 100644
index 0000000..6717026
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Diamond.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "29",
+ "height": "28",
+ "viewBox": "0 0 29 28",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "diamond"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M10.2499 9.04167L7.62486 11.6667L10.2499 14.2917M15.9831 22.8501L25.4978 13.3353C26.4164 12.4168 26.408 10.925 25.4791 10.017L20.3883 5.03988C19.9523 4.61365 19.3668 4.375 18.7571 4.375H9.90929C9.29958 4.375 8.71408 4.61365 8.27811 5.03988L3.18727 10.017C2.25844 10.925 2.25002 12.4168 3.16852 13.3353L12.6833 22.8501C13.5945 23.7613 15.0719 23.7613 15.9831 22.8501Z",
+ "stroke": "#DC6803",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Diamond"
+}
diff --git a/app/components/base/icons/src/public/billing/Diamond.tsx b/app/components/base/icons/src/public/billing/Diamond.tsx
new file mode 100644
index 0000000..18226e3
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Diamond.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Diamond.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Diamond'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/GoogleCloud.json b/app/components/base/icons/src/public/billing/GoogleCloud.json
new file mode 100644
index 0000000..0c55bda
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/GoogleCloud.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "22",
+ "height": "18",
+ "viewBox": "0 0 22 18",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group 4"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M14.1587 5.40399H14.7992L16.6247 3.57855L16.7143 2.80353C15.6686 1.88054 14.4049 1.23936 13.0424 0.94058C11.68 0.641797 10.2639 0.695269 8.92788 1.09594C7.59187 1.49662 6.38006 2.23127 5.40691 3.2305C4.43376 4.22973 3.73142 5.46055 3.36621 6.80669C3.56957 6.72334 3.79485 6.70982 4.00672 6.76826L7.6576 6.16619C7.6576 6.16619 7.84334 5.85874 7.93942 5.87796C8.72169 5.01883 9.80276 4.4912 10.9613 4.40309C12.1199 4.31497 13.2683 4.67304 14.1715 5.40399H14.1587Z",
+ "fill": "#EA4335"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M19.225 6.80663C18.8055 5.2615 17.944 3.87244 16.7463 2.80988L14.1843 5.3719C14.7182 5.80819 15.1461 6.36003 15.4357 6.9858C15.7253 7.61158 15.869 8.29494 15.856 8.98435V9.43911C16.1554 9.43911 16.4519 9.49809 16.7286 9.61268C17.0052 9.72727 17.2566 9.89523 17.4683 10.107C17.6801 10.3187 17.848 10.5701 17.9626 10.8467C18.0772 11.1234 18.1362 11.4199 18.1362 11.7193C18.1362 12.0187 18.0772 12.3153 17.9626 12.5919C17.848 12.8685 17.6801 13.1199 17.4683 13.3316C17.2566 13.5434 17.0052 13.7113 16.7286 13.8259C16.4519 13.9405 16.1554 13.9995 15.856 13.9995H11.2956L10.8408 14.4607V17.1956L11.2956 17.6504H15.856C17.1295 17.6603 18.3723 17.2601 19.4007 16.5089C20.429 15.7577 21.1883 14.6954 21.5662 13.4792C21.944 12.2631 21.9204 10.9576 21.4988 9.75589C21.0771 8.55419 20.2799 7.52012 19.225 6.80663Z",
+ "fill": "#4285F4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M6.72886 17.625H11.2893V13.9741H6.72886C6.40396 13.9741 6.08286 13.9042 5.78732 13.7692L5.14681 13.9677L3.30856 15.7932L3.14844 16.4337C4.17929 17.2121 5.43714 17.6306 6.72886 17.625Z",
+ "fill": "#34A853"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M6.7289 5.78196C5.49325 5.78934 4.29076 6.18247 3.28939 6.90643C2.28801 7.6304 1.53775 8.64904 1.1434 9.8201C0.749049 10.9912 0.730302 12.2561 1.08978 13.4384C1.44925 14.6206 2.16899 15.661 3.14848 16.4143L5.79377 13.7691C5.4576 13.6172 5.16331 13.386 4.93613 13.0954C4.70895 12.8048 4.55567 12.4634 4.48944 12.1005C4.42321 11.7376 4.446 11.3641 4.55587 11.0119C4.66574 10.6598 4.8594 10.3396 5.12024 10.0788C5.38107 9.81792 5.7013 9.62426 6.05343 9.51439C6.40557 9.40452 6.7791 9.38172 7.14198 9.44795C7.50487 9.51418 7.84626 9.66747 8.13688 9.89465C8.4275 10.1218 8.65867 10.4161 8.81055 10.7523L11.4558 8.10699C10.9006 7.38115 10.185 6.79357 9.36499 6.39023C8.54496 5.98688 7.64275 5.7787 6.7289 5.78196Z",
+ "fill": "#FBBC05"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "GoogleCloud"
+}
diff --git a/app/components/base/icons/src/public/billing/GoogleCloud.tsx b/app/components/base/icons/src/public/billing/GoogleCloud.tsx
new file mode 100644
index 0000000..6750a7c
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/GoogleCloud.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './GoogleCloud.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'GoogleCloud'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/Group2.json b/app/components/base/icons/src/public/billing/Group2.json
new file mode 100644
index 0000000..8cc0896
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Group2.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "29",
+ "height": "28",
+ "viewBox": "0 0 29 28",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.4942 15.3771C21.1508 13.8584 25.694 15.7846 27.1017 21.1559C27.4448 22.465 26.348 23.625 24.9948 23.625H19.6233M13.2066 8.16667C13.2066 10.2608 11.509 11.9583 9.41493 11.9583C7.32086 11.9583 5.62326 10.2608 5.62326 8.16667C5.62326 6.07258 7.32086 4.375 9.41493 4.375C11.509 4.375 13.2066 6.07258 13.2066 8.16667ZM23.7066 8.16667C23.7066 10.2608 22.009 11.9583 19.9149 11.9583C17.8209 11.9583 16.1232 10.2608 16.1232 8.16667C16.1232 6.07258 17.8209 4.375 19.9149 4.375C22.009 4.375 23.7066 6.07258 23.7066 8.16667ZM14.328 23.625H4.3352C2.98193 23.625 1.88599 22.4589 2.22976 21.15C4.42721 12.7833 14.2359 12.7833 16.4335 21.15C16.7772 22.4589 15.6813 23.625 14.328 23.625Z",
+ "stroke": "#444CE7",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Group2"
+}
diff --git a/app/components/base/icons/src/public/billing/Group2.tsx b/app/components/base/icons/src/public/billing/Group2.tsx
new file mode 100644
index 0000000..792b454
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Group2.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Group2.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Group2'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/Keyframe.json b/app/components/base/icons/src/public/billing/Keyframe.json
new file mode 100644
index 0000000..ed0dcb4
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Keyframe.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "29",
+ "height": "28",
+ "viewBox": "0 0 29 28",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.9831 3.98321C15.072 3.072 13.5945 3.072 12.6833 3.98321L4.31648 12.35C3.40526 13.2612 3.40524 14.7386 4.31647 15.6499L12.6833 24.0167C13.5945 24.9279 15.072 24.9279 15.9831 24.0167L24.35 15.6499C25.2612 14.7386 25.2612 13.2612 24.35 12.35L15.9831 3.98321Z",
+ "stroke": "#155AEF",
+ "stroke-width": "1.5",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Keyframe"
+}
diff --git a/app/components/base/icons/src/public/billing/Keyframe.tsx b/app/components/base/icons/src/public/billing/Keyframe.tsx
new file mode 100644
index 0000000..a82aad9
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Keyframe.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Keyframe.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Keyframe'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/Sparkles.json b/app/components/base/icons/src/public/billing/Sparkles.json
new file mode 100644
index 0000000..5317b50
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Sparkles.json
@@ -0,0 +1,95 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "600",
+ "height": "600",
+ "viewBox": "0 0 600 600",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg",
+ "xmlns:xlink": "http://www.w3.org/1999/xlink"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_1_382)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "600",
+ "height": "600",
+ "fill": "url(#pattern999)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "pattern",
+ "attributes": {
+ "id": "pattern999",
+ "patternContentUnits": "objectBoundingBox",
+ "width": "1",
+ "height": "1"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "use",
+ "attributes": {
+ "xlink:href": "#image0_1_382",
+ "transform": "scale(0.000976562)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_1_382"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "600",
+ "height": "600",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "image",
+ "attributes": {
+ "id": "image0_1_382",
+ "width": "1024",
+ "height": "1024",
+ "xlink:href": "data:image/png;base64,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fAkQAMjX8WZvEUAAAQQQQGAaBfav3Va5+vLVF91w5YXXrzm15sZZI+3L0janXjw2vhMAt5ACBGmVfFs/rOzbPLX272rbdefa7XvWPdz30v+uuOFDI/YaJQIIIIBA/gQIAOTvmLPHCCCAAAIIIJABAQsGXLFq2TWXllf+9qr5yy9pFhCY6uaqwv/KWwd276zu2/rq4aPbt+/Zv5PW/qnqsRwCCCAw8wUIAMz8Y8weIoAAAggggEALCCggsOzs7s7fWL5w5col3ef2zJ69oFQsLzx/UVdn59GFC8NdGFzQ3//y4YHBWr3a/+bQ0NF9vzy+98jAO2/2vXzodVr5QynGEUAAAQRCAQIAoQbjCCCAAAIIIIAAAggggAACCMxQgeB5MzN0D9ktBBBAAAEEEEAAAQQQQAABBBAoEADgS4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCBAA4DuAAAIIIIAAAggggAACCCCAQA4ECADk4CCziwgggAACCCCAAAIIIIAAAggQAOA7gAACCOgv+e0AAABaSURBVCCAAAIIIIAAAggggEAOBAgA5OAgs4sIIIAAAggggAACCCCAAAIIEADgO4AAAggggAACCCCAAAIIIIBADgQIAOTgILOLCCCAAAIIIIAAAggggAACCPwfNaPiwKKqjBIAAAAASUVORK5CYII="
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Sparkles"
+}
diff --git a/app/components/base/icons/src/public/billing/Sparkles.tsx b/app/components/base/icons/src/public/billing/Sparkles.tsx
new file mode 100644
index 0000000..09fb779
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/Sparkles.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Sparkles.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Sparkles'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/SparklesSoft.json b/app/components/base/icons/src/public/billing/SparklesSoft.json
new file mode 100644
index 0000000..b6a5a6d
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/SparklesSoft.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "13",
+ "height": "13",
+ "viewBox": "0 0 13 13",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M9.75878 1.67256C9.74813 1.57435 9.6684 1.5001 9.5735 1.5C9.47861 1.4999 9.39874 1.57397 9.38789 1.67217C9.33725 2.12931 9.20693 2.44292 9.00273 2.65564C8.79849 2.86835 8.49744 3.00411 8.05857 3.05683C7.9643 3.06816 7.89321 3.15136 7.89331 3.2502C7.89341 3.34905 7.96469 3.43208 8.05896 3.44321C8.49038 3.49411 8.79835 3.62984 9.00773 3.84402C9.216 4.05703 9.34877 4.3702 9.38736 4.82276C9.39595 4.92317 9.47673 5.00011 9.5735 5C9.67027 4.99988 9.75096 4.92276 9.75926 4.82232C9.79627 4.37742 9.92894 4.05719 10.1386 3.83882C10.3482 3.62045 10.6556 3.48223 11.0827 3.44372C11.1792 3.43503 11.2532 3.35103 11.2533 3.25022C11.2534 3.14942 11.1795 3.06524 11.0832 3.05632C10.6487 3.01612 10.3481 2.87779 10.1436 2.66085C9.93797 2.44273 9.80765 2.12197 9.75878 1.67256Z",
+ "fill": "#FCFCFD"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.45025 2.94373C6.42279 2.69117 6.21783 2.50026 5.9738 2.5C5.72982 2.49974 5.52443 2.69021 5.49649 2.94271C5.36631 4.11822 5.0312 4.92465 4.50609 5.47164C3.98098 6.0186 3.20681 6.3677 2.07832 6.5033C1.83592 6.5324 1.65307 6.74635 1.65332 7.0005C1.65357 7.2547 1.83684 7.4682 2.0793 7.4968C3.1887 7.6277 3.9805 7.97675 4.51896 8.5275C5.05449 9.07525 5.39598 9.8805 5.49519 11.0442C5.51722 11.3024 5.72502 11.5003 5.97385 11.5C6.22273 11.4997 6.43009 11.3014 6.45154 11.0431C6.54658 9.89905 6.88782 9.07565 7.42686 8.5141C7.96595 7.9526 8.75641 7.59715 9.8547 7.49815C10.1026 7.4758 10.293 7.2598 10.2933 7.00055C10.2936 6.74135 10.1037 6.5249 9.8558 6.50195C8.7386 6.3986 7.96556 6.0429 7.43972 5.48504C6.911 4.92415 6.57591 4.09936 6.45025 2.94373Z",
+ "fill": "#FCFCFD"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "SparklesSoft"
+}
diff --git a/app/components/base/icons/src/public/billing/SparklesSoft.tsx b/app/components/base/icons/src/public/billing/SparklesSoft.tsx
new file mode 100644
index 0000000..b3f94d0
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/SparklesSoft.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './SparklesSoft.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'SparklesSoft'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/billing/index.ts b/app/components/base/icons/src/public/billing/index.ts
new file mode 100644
index 0000000..9460acf
--- /dev/null
+++ b/app/components/base/icons/src/public/billing/index.ts
@@ -0,0 +1,11 @@
+export { default as ArCube1 } from './ArCube1'
+export { default as Asterisk } from './Asterisk'
+export { default as AwsMarketplace } from './AwsMarketplace'
+export { default as Azure } from './Azure'
+export { default as Buildings } from './Buildings'
+export { default as Diamond } from './Diamond'
+export { default as GoogleCloud } from './GoogleCloud'
+export { default as Group2 } from './Group2'
+export { default as Keyframe } from './Keyframe'
+export { default as SparklesSoft } from './SparklesSoft'
+export { default as Sparkles } from './Sparkles'
diff --git a/app/components/base/icons/src/public/common/D.json b/app/components/base/icons/src/public/common/D.json
new file mode 100644
index 0000000..ab4ed79
--- /dev/null
+++ b/app/components/base/icons/src/public/common/D.json
@@ -0,0 +1,125 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2 1H7.94339C11.8094 1 14.9434 4.13401 14.9434 8C14.9434 11.866 11.8094 15 7.9434 15H2V1Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2 1H7.94339C11.8094 1 14.9434 4.13401 14.9434 8C14.9434 11.866 11.8094 15 7.9434 15H2V1Z",
+ "fill": "url(#paint0_angular_19344_240446)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.94336 8H8.20751V15H7.94336V8Z",
+ "fill": "url(#paint1_linear_19344_240446)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "radialGradient",
+ "attributes": {
+ "id": "paint0_angular_19344_240446",
+ "cx": "0",
+ "cy": "0",
+ "r": "1",
+ "gradientUnits": "userSpaceOnUse",
+ "gradientTransform": "translate(7.9434 8) rotate(90) scale(8.75 8.75)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#001FC2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.711334",
+ "stop-color": "#0667F8",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#155EEF",
+ "stop-opacity": "0"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_19344_240446",
+ "x1": "8.06244",
+ "y1": "8.43754",
+ "x2": "7.93744",
+ "y2": "9.20317",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "D"
+}
diff --git a/app/components/base/icons/src/public/common/D.tsx b/app/components/base/icons/src/public/common/D.tsx
new file mode 100644
index 0000000..87aca80
--- /dev/null
+++ b/app/components/base/icons/src/public/common/D.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './D.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'D'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/DiagonalDividingLine.json b/app/components/base/icons/src/public/common/DiagonalDividingLine.json
new file mode 100644
index 0000000..a9e7cd7
--- /dev/null
+++ b/app/components/base/icons/src/public/common/DiagonalDividingLine.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "7",
+ "height": "20",
+ "viewBox": "0 0 7 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Line 3",
+ "d": "M1 19.3544L5.94174 0.645657",
+ "stroke": "#EAECF0",
+ "stroke-linecap": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "DiagonalDividingLine"
+}
diff --git a/app/components/base/icons/src/public/common/DiagonalDividingLine.tsx b/app/components/base/icons/src/public/common/DiagonalDividingLine.tsx
new file mode 100644
index 0000000..ce95c2f
--- /dev/null
+++ b/app/components/base/icons/src/public/common/DiagonalDividingLine.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './DiagonalDividingLine.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'DiagonalDividingLine'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/Dify.json b/app/components/base/icons/src/public/common/Dify.json
new file mode 100644
index 0000000..a954b66
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Dify.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "50",
+ "height": "26",
+ "viewBox": "0 0 50 26",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Dify"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.61784 2.064C8.37784 2.064 9.92184 2.408 11.2498 3.096C12.5938 3.784 13.6258 4.768 14.3458 6.048C15.0818 7.312 15.4498 8.784 15.4498 10.464C15.4498 12.144 15.0818 13.616 14.3458 14.88C13.6258 16.128 12.5938 17.096 11.2498 17.784C9.92184 18.472 8.37784 18.816 6.61784 18.816H0.761841V2.064H6.61784ZM6.49784 15.96C8.25784 15.96 9.61784 15.48 10.5778 14.52C11.5378 13.56 12.0178 12.208 12.0178 10.464C12.0178 8.72 11.5378 7.36 10.5778 6.384C9.61784 5.392 8.25784 4.896 6.49784 4.896H4.12184V15.96H6.49784Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.869 3.936C20.277 3.936 19.781 3.752 19.381 3.384C18.997 3 18.805 2.528 18.805 1.968C18.805 1.408 18.997 0.944 19.381 0.576C19.781 0.192 20.277 0 20.869 0C21.461 0 21.949 0.192 22.333 0.576C22.733 0.944 22.933 1.408 22.933 1.968C22.933 2.528 22.733 3 22.333 3.384C21.949 3.752 21.461 3.936 20.869 3.936ZM22.525 5.52V18.816H19.165V5.52H22.525Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M33.1407 8.28H30.8127V18.816H27.4047V8.28H25.8927V5.52H27.4047V4.848C27.4047 3.216 27.8687 2.016 28.7967 1.248C29.7247 0.48 31.1247 0.12 32.9967 0.168001V3C32.1807 2.984 31.6127 3.12 31.2927 3.408C30.9727 3.696 30.8127 4.216 30.8127 4.968V5.52H33.1407V8.28Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M49.2381 5.52L41.0061 25.104H37.4301L40.3101 18.48L34.9821 5.52H38.7501L42.1821 14.808L45.6621 5.52H49.2381Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Dify"
+}
diff --git a/app/components/base/icons/src/public/common/Dify.tsx b/app/components/base/icons/src/public/common/Dify.tsx
new file mode 100644
index 0000000..f53f47f
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Dify.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Dify.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Dify'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/Gdpr.json b/app/components/base/icons/src/public/common/Gdpr.json
new file mode 100644
index 0000000..1e030b5
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Gdpr.json
@@ -0,0 +1,340 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "23",
+ "height": "28",
+ "viewBox": "0 0 23 28",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M11.0371 28L10.7001 27.8596C8.90271 27.1013 0 23.001 0 16.8786V4.32497L11.0371 0L22.0742 4.32497V16.8786C22.0742 23.001 13.1434 27.1013 11.3741 27.8596L11.0371 28ZM1.71314 5.47643V16.8786C1.71314 18.9569 3.11735 21.0632 5.86961 23.1414C7.89167 24.658 10.0822 25.7252 11.0652 26.1464C12.0481 25.6971 14.2387 24.658 16.2608 23.1414C19.013 21.0632 20.4173 18.9569 20.4173 16.8786V5.47643L11.0652 1.82548L1.71314 5.47643Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_3"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_4"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M11.0371 0.898682V27.0732C12.666 26.3711 21.2317 22.4674 21.2317 16.8786C21.2317 10.672 21.2317 4.88664 21.2317 4.88664L11.0371 0.898682Z",
+ "fill": "#1611D3"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M11.0371 0.898682V27.0732C9.40823 26.3711 0.842529 22.4674 0.842529 16.8786C0.842529 10.672 0.842529 4.88664 0.842529 4.88664L11.0371 0.898682Z",
+ "fill": "#0D00A0"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_6"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M7.1333 15.5306C7.04905 15.5867 6.93671 15.6429 6.82437 15.671C6.71204 15.7272 6.5997 15.7552 6.48736 15.7833C6.37503 15.8114 6.23461 15.8395 6.0661 15.8676C5.92568 15.8957 5.72909 15.8957 5.56058 15.8957C5.33591 15.8957 5.1674 15.8676 4.97081 15.8114C4.80231 15.7552 4.6338 15.671 4.52147 15.5867C4.40913 15.5025 4.26871 15.3621 4.18445 15.2216C4.07212 15.0812 4.01595 14.9408 3.9317 14.7723C3.84745 14.6038 3.81936 14.4353 3.79128 14.2668C3.76319 14.0983 3.73511 13.9017 3.73511 13.7332C3.73511 13.5366 3.76319 13.34 3.79128 13.1715C3.81936 12.9749 3.87553 12.8064 3.95978 12.6379C4.04403 12.4694 4.12829 12.329 4.24062 12.1885C4.35296 12.0481 4.4653 11.9358 4.60572 11.8235C4.74614 11.7111 4.91465 11.6549 5.08315 11.5988C5.25166 11.5426 5.44825 11.5145 5.64484 11.5145C5.75717 11.5145 5.84143 11.5145 5.92568 11.5145C6.00993 11.5145 6.09418 11.5426 6.15035 11.5426C6.2346 11.5426 6.29077 11.5707 6.34694 11.5988C6.40311 11.6269 6.48736 11.6549 6.54353 11.683C6.5997 11.7111 6.68395 11.7673 6.74012 11.8235C6.79629 11.8796 6.88054 11.9358 6.9648 11.992L6.57162 12.5256C6.48736 12.4413 6.40311 12.3571 6.31886 12.3009C6.23461 12.2447 6.15035 12.1885 6.09418 12.1605C6.00993 12.1324 5.92568 12.1043 5.84143 12.1043C5.75717 12.1043 5.67292 12.0762 5.56058 12.0762C5.39208 12.0762 5.22357 12.1043 5.08315 12.1885C4.94273 12.2728 4.83039 12.3851 4.74614 12.5256C4.66189 12.666 4.57764 12.8345 4.52147 13.003C4.4653 13.1715 4.43721 13.3962 4.43721 13.6208C4.43721 13.8455 4.4653 14.0702 4.49338 14.2668C4.52147 14.4634 4.60572 14.66 4.68997 14.8004C4.77422 14.9408 4.88656 15.0812 5.05507 15.1655C5.19549 15.2497 5.36399 15.3059 5.58867 15.3059C5.64484 15.3059 5.70101 15.3059 5.75717 15.3059C5.81334 15.3059 5.89759 15.3059 5.95376 15.2778C6.00993 15.2778 6.09418 15.2497 6.15035 15.2497C6.20652 15.2497 6.26269 15.2216 6.31886 15.2216V13.7894H7.04905V15.5306H7.1333Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M8.93074 11.5707C9.32391 11.5707 9.66093 11.6268 9.91368 11.7392C10.1945 11.8515 10.3911 11.9919 10.5877 12.1885C10.7562 12.3851 10.8685 12.5817 10.9528 12.8345C11.0371 13.0872 11.0651 13.34 11.0651 13.6208C11.0651 13.8174 11.0371 14.014 11.009 14.1825C10.9809 14.351 10.9247 14.5476 10.8685 14.7161C10.7843 14.8846 10.7 15.025 10.5877 15.1655C10.4754 15.3059 10.3349 15.4182 10.1664 15.5025C9.99794 15.5867 9.82943 15.671 9.60476 15.7271C9.38008 15.7833 9.15541 15.8114 8.87457 15.8114H7.83545V11.5988H8.93074V11.5707ZM8.62181 12.1324V15.2497H8.84648C9.04307 15.2497 9.23966 15.2216 9.43625 15.1374C9.60476 15.0812 9.77326 14.9689 9.8856 14.8285C10.026 14.688 10.1103 14.5195 10.1945 14.3229C10.2788 14.1263 10.3069 13.8736 10.3069 13.5927C10.3069 13.3962 10.2788 13.2276 10.2226 13.0311C10.1664 12.8626 10.0822 12.694 9.96985 12.5536C9.85752 12.4132 9.7171 12.3009 9.54859 12.2166C9.38008 12.1324 9.15541 12.0762 8.90265 12.0762H8.62181V12.1324Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M12.5537 14.1825V15.8114H11.8235V11.5988H13.0311C13.312 11.5988 13.5366 11.6268 13.7332 11.683C13.9298 11.7392 14.0983 11.8234 14.2106 11.9358C14.3511 12.0481 14.4353 12.1885 14.4915 12.3289C14.5477 12.4694 14.5757 12.6379 14.5757 12.8345C14.5757 12.8906 14.5757 12.9749 14.5477 13.0872C14.5196 13.1715 14.4915 13.2838 14.4634 13.3681C14.4072 13.4804 14.3511 13.5647 14.2668 13.6489C14.1826 13.7332 14.0983 13.8174 13.9579 13.9017C13.8175 13.9859 13.677 14.0421 13.5085 14.0983C13.34 14.1544 13.1434 14.1544 12.8907 14.1544H12.5537V14.1825ZM12.5537 13.6208H12.9188C13.0592 13.6208 13.1715 13.5927 13.2839 13.5647C13.3962 13.5366 13.4805 13.4804 13.5647 13.4242C13.649 13.3681 13.7051 13.2838 13.7613 13.1715C13.8175 13.0872 13.8175 12.9749 13.8175 12.8345C13.8175 12.7221 13.7894 12.6379 13.7613 12.5536C13.7332 12.4694 13.677 12.3851 13.6209 12.3289C13.5647 12.2728 13.4524 12.2166 13.34 12.1604C13.2277 12.1324 13.0873 12.1043 12.9188 12.1043H12.5537V13.6208Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M15.9519 15.8114H15.2217V11.5988H16.4293C16.7101 11.5988 16.9348 11.6268 17.1314 11.683C17.328 11.7392 17.4965 11.8234 17.6088 11.9077C17.7493 12.02 17.8335 12.1324 17.8897 12.2728C17.9459 12.4132 17.9739 12.5817 17.9739 12.7502C17.9739 12.8625 17.9459 13.003 17.9178 13.1153C17.8897 13.2276 17.8335 13.3681 17.7493 13.4804C17.665 13.5927 17.5808 13.7051 17.4403 13.7893C17.2999 13.8736 17.1595 13.9578 16.9629 14.014L18.2548 15.8114H17.4123L16.2889 14.0983C16.2327 14.0983 16.2046 14.0983 16.1485 14.0983C16.0923 14.0983 16.0361 14.0983 15.9519 14.0702V15.8114ZM15.9519 13.5085C16.008 13.5085 16.0642 13.5085 16.1204 13.5085C16.1765 13.5085 16.2327 13.5085 16.2889 13.5085C16.4293 13.5085 16.5697 13.4804 16.6821 13.4523C16.7944 13.4242 16.9067 13.3681 16.991 13.3119C17.0752 13.2557 17.1314 13.1715 17.1876 13.0872C17.2437 13.003 17.2437 12.8906 17.2437 12.7783C17.2437 12.666 17.2157 12.5536 17.1876 12.4694C17.1595 12.3851 17.1033 12.3289 17.0472 12.2728C16.991 12.2166 16.8787 12.1885 16.7663 12.1604C16.654 12.1324 16.4855 12.1324 16.317 12.1324H15.98V13.5085H15.9519Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_7"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_8"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M11.0372 4.63391L11.3461 5.56069H12.301L11.5427 6.12238L11.8236 7.02107L11.0372 6.45939L10.2789 7.02107L10.5598 6.12238L9.80151 5.56069H10.7564L11.0372 4.63391Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_9"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "d": "M14.3231 5.53259L14.632 6.43129H15.5869L14.8005 6.99297L15.1095 7.91975L14.3231 7.35807L13.5648 7.91975L13.8457 6.99297L13.0593 6.43129H14.0423L14.3231 5.53259Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_10"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_10",
+ "d": "M17.0472 7.9198L17.3281 8.81849H18.2829L17.5247 9.38018L17.8055 10.307L17.0472 9.74528L16.2609 10.307L16.5698 9.38018L15.7834 8.81849H16.7383L17.0472 7.9198Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_11",
+ "d": "M11.0372 19.7714L11.3461 20.6981H12.301L11.5427 21.2598L11.8236 22.1585L11.0372 21.5968L10.2789 22.1585L10.5598 21.2598L9.80151 20.6981H10.7564L11.0372 19.7714Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_12"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_12",
+ "d": "M14.3231 18.985L14.632 19.8837H15.5869L14.8005 20.4454L15.1095 21.3721L14.3231 20.8105L13.5648 21.3721L13.8457 20.4454L13.0593 19.8837H14.0423L14.3231 18.985Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_13"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_13",
+ "d": "M17.0472 17.019L17.3281 17.9458H18.2829L17.5247 18.5075L17.8055 19.4062L17.0472 18.8445L16.2609 19.4062L16.5698 18.5075L15.7834 17.9458H16.7383L17.0472 17.019Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_14"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_14",
+ "d": "M7.77942 5.53259L7.47049 6.43129H6.51562L7.30199 6.99297L6.99306 7.91975L7.77942 7.35807L8.53769 7.91975L8.25685 6.99297L9.01512 6.43129H8.06026L7.77942 5.53259Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_15"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_15",
+ "d": "M5.05529 7.9198L4.77444 8.81849H3.81958L4.57785 9.38018L4.29701 10.307L5.05529 9.74528L5.84165 10.307L5.53272 9.38018L6.31908 8.81849H5.36421L5.05529 7.9198Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_16"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_16",
+ "d": "M7.77942 18.985L7.47049 19.8837H6.51562L7.30199 20.4454L6.99306 21.3721L7.77942 20.8105L8.53769 21.3721L8.25685 20.4454L9.01512 19.8837H8.06026L7.77942 18.985Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_17"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_17",
+ "d": "M5.05529 17.019L4.77444 17.9458H3.81958L4.57785 18.5075L4.29701 19.4062L5.05529 18.8445L5.84165 19.4062L5.53272 18.5075L6.31908 17.9458H5.36421L5.05529 17.019Z",
+ "fill": "#F7BC37"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Gdpr"
+}
diff --git a/app/components/base/icons/src/public/common/Gdpr.tsx b/app/components/base/icons/src/public/common/Gdpr.tsx
new file mode 100644
index 0000000..5141b57
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Gdpr.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Gdpr.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Gdpr'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/Github.json b/app/components/base/icons/src/public/common/Github.json
new file mode 100644
index 0000000..523bcd5
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Github.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "18",
+ "height": "18",
+ "viewBox": "0 0 18 18",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "github"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M9 1.125C4.64906 1.125 1.125 4.64906 1.125 9C1.125 12.4847 3.37922 15.428 6.50953 16.4714C6.90328 16.5403 7.05094 16.3041 7.05094 16.0973C7.05094 15.9103 7.04109 15.2902 7.04109 14.6306C5.0625 14.9948 4.55062 14.1483 4.39312 13.7053C4.30453 13.4789 3.92063 12.78 3.58594 12.593C3.31031 12.4453 2.91656 12.0811 3.57609 12.0712C4.19625 12.0614 4.63922 12.6422 4.78688 12.8784C5.49563 14.0695 6.62766 13.7348 7.08047 13.5281C7.14938 13.0163 7.35609 12.6717 7.5825 12.4748C5.83031 12.278 3.99938 11.5987 3.99938 8.58656C3.99938 7.73016 4.30453 7.02141 4.80656 6.47016C4.72781 6.27328 4.45219 5.46609 4.88531 4.38328C4.88531 4.38328 5.54484 4.17656 7.05094 5.19047C7.68094 5.01328 8.35031 4.92469 9.01969 4.92469C9.68906 4.92469 10.3584 5.01328 10.9884 5.19047C12.4945 4.16672 13.1541 4.38328 13.1541 4.38328C13.5872 5.46609 13.3116 6.27328 13.2328 6.47016C13.7348 7.02141 14.04 7.72031 14.04 8.58656C14.04 11.6086 12.1992 12.278 10.447 12.4748C10.7325 12.7209 10.9786 13.1934 10.9786 13.9317C10.9786 14.985 10.9688 15.8316 10.9688 16.0973C10.9688 16.3041 11.1164 16.5502 11.5102 16.4714C13.0735 15.9436 14.432 14.9389 15.3943 13.5986C16.3567 12.2583 16.8746 10.65 16.875 9C16.875 4.64906 13.3509 1.125 9 1.125Z",
+ "fill": "#24292F"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Github"
+}
diff --git a/app/components/base/icons/src/public/common/Github.tsx b/app/components/base/icons/src/public/common/Github.tsx
new file mode 100644
index 0000000..9c6f418
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Github.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Github.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Github'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/Highlight.json b/app/components/base/icons/src/public/common/Highlight.json
new file mode 100644
index 0000000..055d9f7
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Highlight.json
@@ -0,0 +1,67 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "xmlns": "http://www.w3.org/2000/svg",
+ "width": "46",
+ "height": "24",
+ "viewBox": "0 0 46 24",
+ "fill": "none"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M-6.5 8C-6.5 3.58172 -2.91828 0 1.5 0H45.5L33.0248 24H1.49999C-2.91829 24 -6.5 20.4183 -6.5 16V8Z",
+ "fill": "url(#paint0_linear_6333_42118)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_6333_42118",
+ "x1": "1.81679",
+ "y1": "5.47784e-07",
+ "x2": "101.257",
+ "y2": "30.3866",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.12"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white",
+ "stop-opacity": "0.3"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Highlight"
+}
diff --git a/app/components/base/icons/src/public/common/Highlight.tsx b/app/components/base/icons/src/public/common/Highlight.tsx
new file mode 100644
index 0000000..261b589
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Highlight.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Highlight.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Highlight'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/Iso.json b/app/components/base/icons/src/public/common/Iso.json
new file mode 100644
index 0000000..50f0267
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Iso.json
@@ -0,0 +1,121 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "fill": "none",
+ "height": "64",
+ "viewBox": "0 0 64 64",
+ "width": "64",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m8 9.82143c0-2.6628 2.2386-4.82143 5-4.82143h38c2.7614 0 5 2.15863 5 4.82143v44.35717c0 2.6628-2.2386 4.8214-5 4.8214h-38c-2.7614 0-5-2.1586-5-4.8214z",
+ "fill": "#2a3e92"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "fill": "#fff"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m43.4424 46.9899v-1.84h3.08v7.31h-2.05v-5.47z"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m36.5801 48.7c0-1.1467.2333-2.05.7-2.71.4666-.66 1.2-.99 2.2-.99s1.7333.33 2.2.99c.4733.66.71 1.5633.71 2.71 0 1.16-.2334 2.07-.7 2.73-.4667.66-1.2034.99-2.21.99-1.0067 0-1.7434-.33-2.21-.99-.46-.66-.69-1.57-.69-2.73zm3.87 0c0-.6-.0634-1.0567-.19-1.37-.1267-.32-.3867-.48-.78-.48-.3934 0-.6534.16-.78.48-.1267.3133-.19.77-.19 1.37 0 .6133.06 1.08.18 1.4.1266.3133.39.47.79.47s.66-.1567.78-.47c.1266-.32.19-.7867.19-1.4z"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m29.5078 48.7c0-1.1467.2333-2.05.7-2.71s1.2-.99 2.2-.99 1.7333.33 2.2.99c.4733.66.71 1.5633.71 2.71 0 1.16-.2333 2.07-.7 2.73s-1.2033.99-2.21.99-1.7433-.33-2.21-.99c-.46-.66-.69-1.57-.69-2.73zm3.87 0c0-.6-.0633-1.0567-.19-1.37-.1267-.32-.3867-.48-.78-.48s-.6533.16-.78.48c-.1267.3133-.19.77-.19 1.37 0 .6133.06 1.08.18 1.4.1267.3133.39.47.79.47s.66-.1567.78-.47c.1267-.32.19-.7867.19-1.4z"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m28.4533 46.6099-2.4 5.85h-2.01l2.42-5.62h-2.85v-1.68h4.84z"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m17.52 50.89c.6467-.5067 1.1767-.9433 1.59-1.31s.76-.7433 1.04-1.13c.28-.3933.42-.7667.42-1.12 0-.2133-.05-.38-.15-.5-.0933-.12-.2333-.18-.42-.18-.1933 0-.3433.0833-.45.25-.1067.16-.1567.3967-.15.71h-1.9c.02-.5933.15-1.0833.39-1.47.24-.3933.5533-.68.94-.86.3867-.1867.8167-.28 1.29-.28.82 0 1.43.2033 1.83.61s.6.9333.6 1.58c0 .6933-.2333 1.3433-.7 1.95-.46.6067-1.0367 1.15-1.73 1.63h2.5v1.59h-5.1z"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "clip-rule": "evenodd",
+ "d": "m32.5672 11.0281c1.0059.0357 2.2045.2319 3.2746.5387 3.289.9417 6.1071 2.9857 8.1332 5.8894.1106.1605.2033.3103.2033.3317 0 .0286-.1605.0393-.5136.0393h-.5137l-.1641-.2319c-.453-.6278-1.3377-1.6123-1.9191-2.1296l-.2497-.2212-.61.1534c-1.0916.2676-2.2937.4852-3.4923.6314-.2711.0357-.4923.0749-.4923.0856 0 .0143.05.1855.1106.3782.1391.4601.3532 1.2306.3532 1.2877 0 .0357-.1106.0464-.4459.0464h-.4424l-.0606-.2069c-.0144-.0559-.0371-.1365-.0606-.22-.0229-.0816-.0466-.1661-.0643-.233-.1141-.3924-.2889-.9239-.3174-.956-.0143-.0179-.2497-.0143-.5208.0071-.2676.0214-1.0274.0571-1.6838.082-1.2592.0428-3.0321.0036-4.2164-.0963-.3032-.0249-.5636-.0357-.5778-.0214-.0286.0286-.2854.8312-.4067 1.2842l-.0963.3603h-.4388c-.4031 0-.4423-.0071-.4423-.0642 0-.0785.2033-.8347.3567-1.3234.0607-.1855.0963-.3496.0785-.3639-.0143-.0107-.1926-.0428-.3995-.0642-.9739-.1106-2.3865-.371-3.4673-.635l-.6671-.1641-.1891.1606c-.5743.4922-1.4982 1.5053-1.9726 2.1581l-.214.2961h-.5244c-.2925 0-.528-.0107-.528-.0214 0-.0464.5708-.8383.8918-1.245 1.3698-1.7158 3.0464-3.0642 5.0298-4.0451 1.5124-.7492 2.9893-1.1879 4.7265-1.4126.4387-.0571 1.6016-.1178 1.8727-.0999.0678.0035.3675.0178.66.0249zm-1.2702.8884c-.824.2818-1.6088 1.1736-2.3293 2.6468-.1641.3318-.3068.635-.3175.6671-.0179.0499.0107.0642.1641.0821.8846.0963 3.2033.1462 4.4661.0927 1.516-.0642 1.6587-.0749 1.6587-.1427 0-.0892-.5351-1.1629-.7634-1.5267-.4637-.7491-.9239-1.27-1.3947-1.5803-.4959-.321-.9988-.4031-1.484-.239zm-1.9937.139c-1.912.4031-3.4745 1.0487-5.1082 2.1189-.3996.2604-.528.371-.4281.371.0123 0 .1824.0368.3973.0833l.1093.0237c.8632.1962 2.6646.4922 3.2925.5422l.1355.0107.1498-.3567c.4352-1.0167 1.113-2.1261 1.6623-2.704.1213-.1284.1213-.1319.0393-.1284-.05.0036-.1605.0179-.2497.0393zm5.6573 1.2843c-.2069-.3318-.6135-.8918-.8597-1.1772l-.0035-.004c-.0584-.0664-.0945-.1073-.0853-.126.0148-.0301.1474-.0021.4938.0711l.0088.0018c1.673.3532 3.3567 1.0666 4.8764 2.069.2782.1819.5065.346.5065.3639 0 .0891-2.6576.5564-3.7812.667l-.2319.0214-.1248-.3103c-.1641-.4174-.5458-1.1665-.7991-1.5767z",
+ "fill-rule": "evenodd"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m30.8906 19.1863c.5565.0678.8704.082 2.365.0927l1.7194.0143v3.849h-3.0642l-.0214-.8383-.214-.0856c-.6136-.2426-1.4376-.3746-2.3544-.3781-.9025 0-1.3091.0784-1.6979.3388-.3996.2605-.4566.792-.1249 1.1201.346.3496.7705.4602 2.6611.6956 1.6338.2069 2.2652.3389 3.0571.6493.3817.1498.8633.4316 1.1629.6849.4423.3674.8062.9738.9738 1.6159.1249.478.1606 1.3983.0714 1.887-.1534.8348-.4673 1.434-1.0416 1.9798-.6207.5922-1.4198.981-2.522 1.2271-1.2164.2747-2.9394.3175-4.6659.1213-.5922-.0642-.9346-.0785-2.3579-.0892l-1.6694-.0142v-3.8133h3.0677v.7847l.1391.0714c.4531.2283 1.3841.3959 2.3651.4173 1.6908.0428 2.4506-.2568 2.4542-.9702 0-.2783-.0785-.4281-.3139-.5922-.3425-.2426-.824-.3531-2.3615-.5493-1.8478-.239-2.579-.4067-3.3817-.7848-1.2806-.6064-1.912-1.5303-2.0404-2.9857-.0713-.7706.0535-1.4911.3567-2.1189.6814-1.4091 2.2402-2.2188 4.6552-2.4186.4851-.0392 2.1617.0143 2.7824.0892z"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "clip-rule": "evenodd",
+ "d": "m48.2307 20.9806c-.981-.9774-2.2474-1.5767-3.8383-1.8157-.3924-.0607-1.8371-.1035-2.1938-.0678-1.0631.1106-1.9228.3353-2.7182.7099-1.9049.9025-3.0892 2.579-3.3817 4.7907-.0607.4673-.0714 1.5945-.0179 2.0404.1356 1.1166.4745 2.0726 1.0238 2.9073.4531.6849 1.2913 1.4375 2.0797 1.8656 1.1665.635 2.7967.9524 4.3983.8597 3.0571-.1819 5.2295-1.6873 6.0678-4.2057.2461-.742.3496-1.4483.3496-2.39.0035-1.9655-.5743-3.4994-1.7693-4.6944zm-7.7841 3.6847c.214-1.5268.906-2.3722 2.0939-2.5541.2961-.0464.9132-.0179 1.2093.0499.5279.1284 1.0023.4566 1.2949.9025.4209.635.5957 1.4019.5957 2.6112-.0036 1.4732-.2533 2.3258-.874 2.9429-.4459.4495-.8561.6136-1.6088.6492-1.4447.0678-2.3187-.6635-2.6575-2.2259-.1071-.4994-.1356-1.78-.0535-2.3757z",
+ "fill-rule": "evenodd"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m22.2402 22.5002h-2.069v6.4209h2.069v3.1748l-8.2224-.0178-.0107-1.5803-.0071-1.5767h2.069v-6.4209l-1.0238-.0071-1.0274-.0107-.0107-1.5803-.0071-1.5767h8.2402z"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "clip-rule": "evenodd",
+ "d": "m22.5684 35.9913c-.5601-.4852-1.5518-1.5874-2.0048-2.2295l-.1177-.1677h-.5315c-.4174 0-.528.0107-.5066.0428.4495.767 1.4769 2.0012 2.2973 2.7646 2.3865 2.2188 5.1367 3.503 8.4007 3.9239.6278.0785 2.547.0892 3.2105.0178 4.0202-.4459 7.6551-2.472 10.1165-5.6432.2747-.3532.7455-1.031.7455-1.0773 0-.0143-.2318-.0286-.5136-.0286h-.5101l-.3104.4067c-.1676.2247-.4816.6064-.6956.8525-.371.4174-1.1415 1.1843-1.3127 1.2985-.0713.0464-.132.0392-.6421-.0928-.9845-.2497-2.283-.4958-3.3282-.6278-.2461-.0285-.4958-.0642-.56-.0749l-.1142-.0178.0892-.2569c.0963-.2782.4067-1.3912.4067-1.4518 0-.025-.1499-.0357-.4495-.0285l-.4495.0107-.1177.428c-.0642.2355-.1712.5957-.239.8026l-.1213.3746h-.2318c-.1249 0-.5886-.025-1.0309-.0535-1.4091-.0928-4.4126-.0607-5.5648.0571l-.1998.0214-.1498-.4745-.0158-.053c-.0769-.2586-.1768-.5945-.2268-.7746l-.0963-.346h-.4388c-.3995 0-.4423.0072-.4423.0642 0 .0785.2105.8419.3567 1.3021.0607.1962.107.3567.0999.3602-.0071.0036-.2997.0428-.6528.0857-1.1415.1391-2.2473.3424-3.3639.6171l-.5814.1427zm7.698.0141c-.9631.0535-1.623.0927-1.6337.1034-.0286.0286.4209.9525.6563 1.3591.5066.8704 1.006 1.4554 1.5196 1.7907.3354.2176.5387.289.8704.3175.3246.025.5601-.0285.9239-.214.4103-.2105 1.0024-.8062 1.4055-1.4162.2675-.4031.931-1.6694.931-1.7764 0-.0571-.0749-.0678-.7669-.1142-.585-.0392-3.4352-.0749-3.9061-.0499zm-3.7032.3211c.3603-.0499.7027-.0963.7598-.1035.0606-.0107.1676-.0142.2425-.0107l.1356.0036.1712.3924c.4424 1.0166.9881 1.9156 1.566 2.5755.107.1249.1748.2247.1534.2247s-.264-.0463-.5386-.107c-1.327-.2782-2.654-.7812-3.874-1.4625-.4709-.2604-1.409-.8633-1.4732-.9418-.0286-.0356.0998-.0749.5778-.1783.7527-.1605 1.4233-.2747 2.2795-.3924zm9.2354.0962c-.132.3353-.5743 1.2129-.8062 1.5946-.2497.4137-.5529.8347-.8169 1.1379-.1105.1284-.1926.2354-.1855.2461.0393.0393 1.2521-.2532 1.9014-.4601 1.1664-.371 2.6361-1.0987 3.6991-1.83l.3139-.2176-.189-.0428c-.956-.2212-2.1011-.4281-3.0107-.5458-.3139-.0392-.6279-.0785-.6956-.0892-.0483-.0055-.0779-.0089-.101.0018-.0367.017-.057.0694-.1095.2051z",
+ "fill-rule": "evenodd"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Iso"
+}
diff --git a/app/components/base/icons/src/public/common/Iso.tsx b/app/components/base/icons/src/public/common/Iso.tsx
new file mode 100644
index 0000000..db4b515
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Iso.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Iso.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Iso'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/Line3.json b/app/components/base/icons/src/public/common/Line3.json
new file mode 100644
index 0000000..2beb66a
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Line3.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "5",
+ "height": "12",
+ "viewBox": "0 0 5 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Line 3",
+ "d": "M1 11.3545L3.94174 0.645781",
+ "stroke": "#D0D5DD",
+ "stroke-linecap": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Line3"
+}
diff --git a/app/components/base/icons/src/public/common/Line3.tsx b/app/components/base/icons/src/public/common/Line3.tsx
new file mode 100644
index 0000000..a1fb899
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Line3.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Line3.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Line3'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/Lock.json b/app/components/base/icons/src/public/common/Lock.json
new file mode 100644
index 0000000..a5a1f4b
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Lock.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "lock"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8 1.75C6.27411 1.75 4.875 3.14911 4.875 4.875V6.125C3.83947 6.125 3 6.96444 3 8V12.375C3 13.4106 3.83947 14.25 4.875 14.25H11.125C12.1606 14.25 13 13.4106 13 12.375V8C13 6.96444 12.1606 6.125 11.125 6.125V4.875C11.125 3.14911 9.72587 1.75 8 1.75ZM9.875 6.125V4.875C9.875 3.83947 9.03556 3 8 3C6.96444 3 6.125 3.83947 6.125 4.875V6.125H9.875ZM8 8.625C8.34519 8.625 8.625 8.90481 8.625 9.25V11.125C8.625 11.4702 8.34519 11.75 8 11.75C7.65481 11.75 7.375 11.4702 7.375 11.125V9.25C7.375 8.90481 7.65481 8.625 8 8.625Z",
+ "fill": "#155AEF"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Lock"
+}
diff --git a/app/components/base/icons/src/public/common/Lock.tsx b/app/components/base/icons/src/public/common/Lock.tsx
new file mode 100644
index 0000000..1fce8bb
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Lock.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Lock.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Lock'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/MessageChatSquare.json b/app/components/base/icons/src/public/common/MessageChatSquare.json
new file mode 100644
index 0000000..71cf6d0
--- /dev/null
+++ b/app/components/base/icons/src/public/common/MessageChatSquare.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.77438 6.6665H12.5591C12.9105 6.66649 13.2137 6.66648 13.4634 6.68688C13.727 6.70842 13.9891 6.75596 14.2414 6.88449C14.6177 7.07624 14.9237 7.3822 15.1154 7.75852C15.244 8.01078 15.2915 8.27292 15.313 8.53649C15.3334 8.7862 15.3334 9.08938 15.3334 9.44082V11.2974C15.3334 11.5898 15.3334 11.8421 15.3192 12.0509C15.3042 12.2708 15.2712 12.4908 15.1812 12.7081C14.9782 13.1981 14.5888 13.5875 14.0988 13.7905C13.8815 13.8805 13.6616 13.9135 13.4417 13.9285C13.4068 13.9308 13.3707 13.9328 13.3334 13.9345V14.6665C13.3334 14.9147 13.1955 15.1424 12.9756 15.2573C12.7556 15.3723 12.49 15.3556 12.2862 15.2139L10.8353 14.2051C10.6118 14.0498 10.5666 14.0214 10.5238 14.0021C10.4746 13.9798 10.4228 13.9635 10.3696 13.9537C10.3235 13.9452 10.2702 13.9427 9.99803 13.9427H8.7744C8.42296 13.9427 8.11978 13.9427 7.87006 13.9223C7.6065 13.9008 7.34435 13.8532 7.0921 13.7247C6.71578 13.533 6.40981 13.227 6.21807 12.8507C6.08954 12.5984 6.04199 12.3363 6.02046 12.0727C6.00006 11.823 6.00007 11.5198 6.00008 11.1684V9.44081C6.00007 9.08938 6.00006 8.7862 6.02046 8.53649C6.04199 8.27292 6.08954 8.01078 6.21807 7.75852C6.40981 7.3822 6.71578 7.07624 7.0921 6.88449C7.34435 6.75596 7.6065 6.70842 7.87006 6.68688C8.11978 6.66648 8.42295 6.66649 8.77438 6.6665Z",
+ "fill": "#444CE7"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.4943 0.666504H4.5059C3.96926 0.666496 3.52635 0.666489 3.16555 0.695967C2.79082 0.726584 2.44635 0.792293 2.12279 0.957154C1.62103 1.21282 1.21308 1.62076 0.957417 2.12253C0.792557 2.44609 0.726847 2.79056 0.69623 3.16529C0.666752 3.52608 0.666759 3.96899 0.666768 4.50564L0.666758 7.6804C0.666669 7.97482 0.666603 8.19298 0.694924 8.38632C0.86568 9.55207 1.78121 10.4676 2.94695 10.6383C2.99461 10.6453 3.02432 10.6632 3.03714 10.6739L3.03714 11.7257C3.03711 11.9075 3.03708 12.0858 3.04976 12.2291C3.06103 12.3565 3.09053 12.6202 3.27795 12.8388C3.48686 13.0825 3.80005 13.2111 4.11993 13.1845C4.40689 13.1607 4.61323 12.9938 4.71072 12.9111C4.73849 12.8875 4.76726 12.8618 4.7968 12.8344C4.73509 12.594 4.70707 12.3709 4.69157 12.1813C4.66659 11.8756 4.66668 11.5224 4.66676 11.1966V9.41261C4.66668 9.08685 4.66659 8.73364 4.69157 8.42793C4.71984 8.08191 4.78981 7.62476 5.03008 7.15322C5.34965 6.52601 5.85959 6.01608 6.4868 5.6965C6.95834 5.45624 7.41549 5.38627 7.7615 5.358C8.06722 5.33302 8.42041 5.3331 8.74617 5.33318H12.5873C12.8311 5.33312 13.0903 5.33306 13.3334 5.3435V4.50562C13.3334 3.96898 13.3334 3.52608 13.304 3.16529C13.2734 2.79056 13.2076 2.44609 13.0428 2.12253C12.7871 1.62076 12.3792 1.21282 11.8774 0.957154C11.5539 0.792293 11.2094 0.726584 10.8347 0.695967C10.4739 0.666489 10.0309 0.666496 9.4943 0.666504Z",
+ "fill": "#444CE7"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "MessageChatSquare"
+}
diff --git a/app/components/base/icons/src/public/common/MessageChatSquare.tsx b/app/components/base/icons/src/public/common/MessageChatSquare.tsx
new file mode 100644
index 0000000..85ccc0b
--- /dev/null
+++ b/app/components/base/icons/src/public/common/MessageChatSquare.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MessageChatSquare.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MessageChatSquare'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/MultiPathRetrieval.json b/app/components/base/icons/src/public/common/MultiPathRetrieval.json
new file mode 100644
index 0000000..9d64eda
--- /dev/null
+++ b/app/components/base/icons/src/public/common/MultiPathRetrieval.json
@@ -0,0 +1,153 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "36",
+ "height": "36",
+ "viewBox": "0 0 36 36",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_13429_43710)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "36",
+ "height": "36",
+ "rx": "8",
+ "fill": "#FFF6ED"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.7",
+ "d": "M22.25 28C22.25 29.7949 20.7949 31.25 19 31.25C17.2051 31.25 15.75 29.7949 15.75 28C15.75 26.2051 17.2051 24.75 19 24.75C20.7949 24.75 22.25 26.2051 22.25 28Z",
+ "stroke": "#FB6514",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19 12C21.2091 12 23 10.2091 23 8C23 5.79086 21.2091 4 19 4C16.7909 4 15 5.79086 15 8C15 10.2091 16.7909 12 19 12Z",
+ "fill": "#FB6514"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15 22C17.2091 22 19 20.2091 19 18C19 15.7909 17.2091 14 15 14C12.7909 14 11 15.7909 11 18C11 20.2091 12.7909 22 15 22Z",
+ "fill": "#FB6514"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M36 23C38.7614 23 41 20.7614 41 18C41 15.2386 38.7614 13 36 13C33.2386 13 31 15.2386 31 18C31 20.7614 33.2386 23 36 23Z",
+ "fill": "#FB6514"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 18H10",
+ "stroke": "#FB6514",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20 18L30 18",
+ "stroke": "#FB6514",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0.00112438 15C0.00112438 15 -5.64364 15 0.851673 15C7.34699 15 7.84654 8 14 8",
+ "stroke": "#FB6514",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M23.75 9.28125C26.5688 10.1847 27.699 13.2045 30.625 15.0312",
+ "stroke": "#FB6514",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.7",
+ "d": "M-0.000543833 21C-0.000543833 21 -5.57819 21 0.893635 21C7.36546 21 7.8688 28 14 28",
+ "stroke": "#FB6514",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_13429_43710"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "36",
+ "height": "36",
+ "rx": "8",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "MultiPathRetrieval"
+}
diff --git a/app/components/base/icons/src/public/common/MultiPathRetrieval.tsx b/app/components/base/icons/src/public/common/MultiPathRetrieval.tsx
new file mode 100644
index 0000000..a325900
--- /dev/null
+++ b/app/components/base/icons/src/public/common/MultiPathRetrieval.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MultiPathRetrieval.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MultiPathRetrieval'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/NTo1Retrieval.json b/app/components/base/icons/src/public/common/NTo1Retrieval.json
new file mode 100644
index 0000000..74ca345
--- /dev/null
+++ b/app/components/base/icons/src/public/common/NTo1Retrieval.json
@@ -0,0 +1,146 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "36",
+ "height": "36",
+ "viewBox": "0 0 36 36",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_13429_43700)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "36",
+ "height": "36",
+ "rx": "8",
+ "fill": "#EEF4FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.7",
+ "d": "M23.25 28C23.25 29.7949 21.7949 31.25 20 31.25C18.2051 31.25 16.75 29.7949 16.75 28C16.75 26.2051 18.2051 24.75 20 24.75C21.7949 24.75 23.25 26.2051 23.25 28Z",
+ "stroke": "#444CE7",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.7",
+ "d": "M23.25 8C23.25 9.79493 21.7949 11.25 20 11.25C18.2051 11.25 16.75 9.79493 16.75 8C16.75 6.20507 18.2051 4.75 20 4.75C21.7949 4.75 23.25 6.20507 23.25 8Z",
+ "stroke": "#444CE7",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M16 22C18.2091 22 20 20.2091 20 18C20 15.7909 18.2091 14 16 14C13.7909 14 12 15.7909 12 18C12 20.2091 13.7909 22 16 22Z",
+ "fill": "#444CE7"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M36 23C38.7614 23 41 20.7614 41 18C41 15.2386 38.7614 13 36 13C33.2386 13 31 15.2386 31 18C31 20.7614 33.2386 23 36 23Z",
+ "fill": "#444CE7"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 18L11 18",
+ "stroke": "#444CE7",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21 18L30 18",
+ "stroke": "#444CE7",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.7",
+ "d": "M-0.00160408 15C-0.00160408 15 -6.00089 15 1.12411 15C8.24911 15 8.24908 8.25 14.9991 8.25",
+ "stroke": "#444CE7",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.7",
+ "d": "M0.000488281 21C0.000488281 21 -5.92692 21 1.17228 21C8.27148 21 8.27423 27.75 14.9998 27.75",
+ "stroke": "#444CE7",
+ "stroke-width": "1.5"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_13429_43700"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "36",
+ "height": "36",
+ "rx": "8",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "NTo1Retrieval"
+}
diff --git a/app/components/base/icons/src/public/common/NTo1Retrieval.tsx b/app/components/base/icons/src/public/common/NTo1Retrieval.tsx
new file mode 100644
index 0000000..1afa979
--- /dev/null
+++ b/app/components/base/icons/src/public/common/NTo1Retrieval.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './NTo1Retrieval.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'NTo1Retrieval'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/Notion.json b/app/components/base/icons/src/public/common/Notion.json
new file mode 100644
index 0000000..d27aeb8
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Notion.json
@@ -0,0 +1,83 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "viewBox": "0 0 20 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_5364_42310)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3.5725 18.2611L1.4229 15.5832C0.905706 14.9389 0.625 14.1466 0.625 13.3312V3.63437C0.625 2.4129 1.60224 1.39936 2.86295 1.31328L12.8326 0.632614C13.5569 0.583164 14.2768 0.775682 14.8717 1.17794L18.3745 3.5462C19.0015 3.97012 19.375 4.66312 19.375 5.40266V16.427C19.375 17.6223 18.4141 18.6121 17.1798 18.688L6.11458 19.3692C5.12958 19.4298 4.17749 19.0148 3.5725 18.2611Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.03006 8.48663V8.35968C7.03006 8.03787 7.28779 7.77098 7.61997 7.7488L10.0396 7.58726L13.3857 12.5146V8.19003L12.5244 8.07522V8.01492C12.5244 7.68933 12.788 7.42068 13.1244 7.40344L15.326 7.29066V7.60749C15.326 7.75622 15.2154 7.88343 15.0638 7.90907L14.534 7.99868V15.0022L13.8691 15.2309C13.3136 15.4219 12.6952 15.2174 12.3772 14.7376L9.12879 9.83568V14.5143L10.1287 14.7056L10.1147 14.7984C10.0711 15.0889 9.82028 15.3086 9.51687 15.3221L7.03006 15.4328C6.99718 15.1204 7.23132 14.8409 7.55431 14.807L7.88143 14.7726V8.53447L7.03006 8.48663Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12.9218 1.85418L2.95217 2.53485C2.35499 2.57562 1.89209 3.05572 1.89209 3.63431V13.3311C1.89209 13.8748 2.07923 14.4029 2.42402 14.8325L4.57362 17.5104C4.92117 17.9433 5.46812 18.1817 6.03397 18.1469L17.0991 17.4658C17.6663 17.4309 18.1078 16.9761 18.1078 16.4269V5.4026C18.1078 5.06281 17.9362 4.74441 17.6481 4.54963L14.1453 2.18137C13.7883 1.94002 13.3564 1.82451 12.9218 1.85418ZM3.44654 3.78556C3.30788 3.6829 3.37387 3.46903 3.54806 3.45654L12.9889 2.77938C13.2897 2.75781 13.5886 2.84064 13.8318 3.01299L15.7261 4.35502C15.798 4.40597 15.7642 4.51596 15.6752 4.5208L5.67742 5.06454C5.37485 5.081 5.0762 4.99211 4.83563 4.814L3.44654 3.78556ZM5.20848 6.76913C5.20848 6.44433 5.47088 6.17604 5.80642 6.15777L16.3769 5.5821C16.7039 5.56429 16.9792 5.81577 16.9792 6.13232V15.6782C16.9792 16.0024 16.7177 16.2705 16.3829 16.2895L5.8793 16.8871C5.51537 16.9079 5.20848 16.6282 5.20848 16.2759V6.76913Z",
+ "fill": "black"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_5364_42310"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Notion"
+}
diff --git a/app/components/base/icons/src/public/common/Notion.tsx b/app/components/base/icons/src/public/common/Notion.tsx
new file mode 100644
index 0000000..33b7c31
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Notion.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Notion.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Notion'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/Soc2.json b/app/components/base/icons/src/public/common/Soc2.json
new file mode 100644
index 0000000..38b9c5e
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Soc2.json
@@ -0,0 +1,938 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "28",
+ "height": "28",
+ "viewBox": "0 0 28 28",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group 7"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M14 28C21.732 28 28 21.732 28 14C28 6.26801 21.732 0 14 0C6.26801 0 0 6.26801 0 14C0 21.732 6.26801 28 14 28Z",
+ "fill": "url(#paint0_linear_6186_11887)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M13.9999 24.8636C19.9997 24.8636 24.8636 19.9997 24.8636 13.9999C24.8636 8.00006 19.9997 3.13623 13.9999 3.13623C8.00006 3.13623 3.13623 8.00006 3.13623 13.9999C3.13623 19.9997 8.00006 24.8636 13.9999 24.8636Z",
+ "fill": "url(#paint1_linear_6186_11887)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M5.43048 23.2492C5.46819 23.2107 5.48424 23.1666 5.47862 23.1177C5.473 23.0687 5.44412 22.9997 5.39197 22.909C5.33901 22.8192 5.30772 22.7462 5.29809 22.69C5.28365 22.6106 5.30291 22.5432 5.35586 22.4878C5.40721 22.4341 5.4714 22.4124 5.54762 22.4212C5.62384 22.43 5.69605 22.4678 5.76425 22.5344C5.81079 22.5793 5.84368 22.6282 5.86294 22.6812C5.8822 22.7341 5.88621 22.7871 5.87578 22.8384C5.86535 22.8898 5.84048 22.9355 5.80277 22.9748L5.74339 22.9171C5.78993 22.8689 5.80999 22.8152 5.80597 22.755C5.80116 22.6948 5.77147 22.6379 5.71692 22.5841C5.66316 22.5327 5.6094 22.5031 5.55484 22.4966C5.50028 22.4902 5.45455 22.5055 5.41684 22.544C5.38234 22.5793 5.3687 22.6226 5.37512 22.6724C5.38154 22.7221 5.40802 22.7863 5.45455 22.8641C5.50028 22.9419 5.53077 23.0053 5.54521 23.0551C5.55966 23.1048 5.56287 23.1497 5.55404 23.1915C5.54522 23.2332 5.52435 23.2709 5.49066 23.3054C5.4377 23.3608 5.37271 23.3832 5.29649 23.3736C5.22027 23.364 5.14645 23.3247 5.07424 23.2557C5.0253 23.2083 4.98839 23.1554 4.96432 23.0984C4.94025 23.0414 4.93303 22.9861 4.94186 22.9339C4.95148 22.8818 4.97555 22.8352 5.01487 22.7943L5.07424 22.8513C5.0269 22.9002 5.00765 22.9572 5.01647 23.0214C5.0261 23.0856 5.0606 23.1465 5.12158 23.2059C5.17614 23.2581 5.2315 23.2885 5.28686 23.2966C5.34303 23.3046 5.39036 23.2885 5.42888 23.2492H5.43048Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M6.31617 23.7556C6.2584 23.8238 6.19662 23.8744 6.12923 23.9065C6.06183 23.9386 5.99524 23.9498 5.92784 23.941C5.86044 23.9321 5.79786 23.9033 5.74009 23.8551C5.65344 23.7821 5.60931 23.6922 5.60771 23.5855C5.6061 23.4788 5.65023 23.3721 5.73849 23.267L5.80268 23.19C5.85964 23.1226 5.92223 23.072 5.98962 23.0399C6.05702 23.0078 6.12522 22.9958 6.19261 23.0046C6.26001 23.0135 6.32259 23.0415 6.37956 23.0897C6.43652 23.1378 6.47584 23.194 6.4967 23.2582C6.51756 23.3224 6.51836 23.3898 6.49991 23.4604C6.48145 23.531 6.44455 23.6 6.38999 23.6666L6.31537 23.7556H6.31617ZM6.32099 23.6224C6.39641 23.5326 6.43492 23.4459 6.43652 23.3609C6.43893 23.2758 6.40443 23.2044 6.33382 23.145C6.26482 23.0873 6.1886 23.0664 6.10436 23.0825C6.02091 23.0993 5.94068 23.1531 5.86365 23.2437L5.79866 23.3216C5.72485 23.4098 5.68634 23.4965 5.68393 23.5823C5.68152 23.6682 5.71522 23.7404 5.78583 23.7998C5.85724 23.8591 5.93426 23.8808 6.0161 23.8631C6.09874 23.8455 6.17817 23.7917 6.25439 23.7003L6.32018 23.6216L6.32099 23.6224Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M6.97267 24.3966C6.90367 24.4728 6.82825 24.5153 6.74641 24.5226C6.66457 24.5306 6.58113 24.5041 6.49769 24.4439C6.43912 24.4022 6.3982 24.3501 6.37413 24.2883C6.35006 24.2265 6.34524 24.1599 6.35969 24.0893C6.37413 24.0187 6.40542 23.9481 6.45516 23.8791L6.52898 23.7772C6.57953 23.7074 6.63649 23.6536 6.69988 23.6175C6.76326 23.5814 6.82905 23.5646 6.89565 23.5686C6.96304 23.5726 7.02643 23.5959 7.0866 23.6392C7.17085 23.7002 7.2214 23.7708 7.23744 23.8518C7.25349 23.9328 7.23664 24.0155 7.1869 24.1021L7.1195 24.054C7.19973 23.908 7.17486 23.7892 7.04649 23.6961C6.97508 23.6448 6.89886 23.6304 6.81782 23.6536C6.73678 23.6769 6.66217 23.7347 6.59477 23.8293L6.52497 23.9256C6.45918 24.0163 6.42788 24.1037 6.43029 24.188C6.4327 24.2722 6.4688 24.3388 6.53941 24.3902C6.60921 24.4407 6.6734 24.4616 6.73277 24.4536C6.79215 24.4455 6.84991 24.411 6.90608 24.3509L6.97347 24.399L6.97267 24.3966Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M7.31909 24.9735L7.65768 24.4119L7.55578 24.3501L7.58948 24.2939L7.69138 24.3557L7.73631 24.2811C7.77482 24.2177 7.81975 24.1792 7.87271 24.1648C7.92566 24.1503 7.98022 24.1607 8.03799 24.1952C8.06366 24.2105 8.08613 24.2289 8.10458 24.249L8.06527 24.3028C8.04922 24.2867 8.02996 24.2723 8.0075 24.2586C7.96979 24.2362 7.93368 24.2297 7.89838 24.241C7.86308 24.2522 7.83259 24.2787 7.80691 24.322L7.76038 24.399L7.90801 24.4881L7.87431 24.5443L7.72668 24.4552L7.38809 25.0168L7.31989 24.9751L7.31909 24.9735Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M7.82238 24.8435C7.85528 24.7825 7.8962 24.7336 7.94675 24.6975C7.99649 24.6614 8.05105 24.6413 8.10882 24.6373C8.16659 24.6333 8.22275 24.6461 8.27811 24.6758C8.36236 24.7216 8.41531 24.7874 8.43617 24.8756C8.45703 24.9631 8.44099 25.0561 8.38803 25.154L8.38001 25.1685C8.34711 25.2302 8.30539 25.2792 8.25565 25.3153C8.2059 25.3514 8.15214 25.3715 8.09438 25.3755C8.03661 25.3787 7.98044 25.3658 7.92589 25.3361C7.84164 25.2912 7.78949 25.2246 7.76863 25.1372C7.74777 25.0497 7.76381 24.9566 7.81597 24.8588L7.82319 24.8443L7.82238 24.8435ZM7.88256 24.9013C7.84164 24.9775 7.828 25.0505 7.84084 25.1203C7.85367 25.1901 7.89219 25.2423 7.95637 25.2768C8.01976 25.3105 8.08395 25.3137 8.14974 25.2864C8.21553 25.2591 8.26929 25.2054 8.31261 25.1251L8.31983 25.1115C8.34631 25.0634 8.36075 25.0136 8.36476 24.9639C8.36878 24.9141 8.35995 24.8692 8.33909 24.8291C8.31823 24.7898 8.28694 24.7585 8.24522 24.736C8.18263 24.7023 8.11845 24.6991 8.05265 24.7272C7.98686 24.7553 7.9323 24.809 7.88978 24.8884L7.88256 24.9013Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M8.97134 25.1115C8.9577 25.101 8.94166 25.0922 8.92481 25.0842C8.87988 25.0625 8.83575 25.0577 8.79242 25.0673C8.7491 25.0778 8.70978 25.1034 8.67368 25.1452L8.46106 25.5929L8.38965 25.5592L8.69855 24.9069L8.76915 24.9406L8.72101 25.0449C8.79563 24.9855 8.87506 24.9767 8.95931 25.016C8.97937 25.0256 8.99381 25.036 9.00344 25.0465L8.97054 25.1115H8.97134Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "d": "M9.77199 25.8825C9.79124 25.832 9.78883 25.7854 9.76476 25.7429C9.74069 25.7004 9.68614 25.6474 9.60269 25.5857C9.51925 25.5239 9.46148 25.4685 9.43019 25.4212C9.38526 25.3538 9.37643 25.284 9.40371 25.2126C9.43019 25.1436 9.47994 25.0978 9.55375 25.0762C9.62757 25.0545 9.7086 25.0609 9.79766 25.0946C9.85784 25.1179 9.90758 25.15 9.94609 25.1909C9.98461 25.2326 10.0095 25.2784 10.0199 25.3305C10.0303 25.3819 10.0255 25.4332 10.0063 25.4846L9.92924 25.4549C9.95251 25.3931 9.95091 25.3345 9.92283 25.2808C9.89474 25.227 9.845 25.1861 9.77359 25.1596C9.70459 25.1331 9.64281 25.1275 9.58986 25.1428C9.5369 25.158 9.5008 25.1909 9.48234 25.2407C9.46469 25.2872 9.4687 25.3313 9.49518 25.3746C9.52085 25.418 9.5706 25.4661 9.64361 25.5191C9.71663 25.572 9.76958 25.6186 9.80247 25.6587C9.83537 25.6988 9.85623 25.7389 9.86426 25.7806C9.87228 25.8224 9.86827 25.8649 9.85142 25.9106C9.82414 25.982 9.77359 26.0286 9.70058 26.0502C9.62676 26.0719 9.54332 26.0647 9.45025 26.0294C9.38606 26.0053 9.3315 25.9716 9.28737 25.9283C9.24244 25.8849 9.21436 25.8376 9.20233 25.7862C9.19029 25.7349 9.1943 25.6819 9.21436 25.629L9.29139 25.6579C9.26732 25.7221 9.27213 25.7814 9.30583 25.8368C9.33953 25.8922 9.39569 25.9347 9.47512 25.9652C9.54573 25.9916 9.60831 25.9981 9.66287 25.9828C9.71743 25.9676 9.75433 25.9347 9.77439 25.8833L9.77199 25.8825Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_10",
+ "d": "M10.2131 26.2917C10.1545 26.2733 10.1064 26.2428 10.0679 26.1995C10.0294 26.1561 10.0053 26.104 9.99485 26.0446C9.98442 25.9844 9.98924 25.9226 10.0093 25.8585L10.0181 25.8312C10.039 25.7646 10.0703 25.7092 10.112 25.6643C10.1537 25.6194 10.2027 25.5889 10.258 25.5728C10.3134 25.5568 10.3679 25.5568 10.4209 25.5728C10.5043 25.5985 10.5621 25.6482 10.5934 25.7205C10.6247 25.7927 10.6247 25.8785 10.5942 25.9772L10.5806 26.0197L10.0887 25.8673L10.0839 25.8817C10.0598 25.9596 10.0623 26.0318 10.0903 26.0976C10.1192 26.1633 10.1674 26.2067 10.2356 26.2283C10.2765 26.2412 10.315 26.2444 10.3503 26.2396C10.3856 26.2348 10.4217 26.2195 10.4578 26.1946L10.4939 26.246C10.4129 26.3094 10.319 26.3246 10.2123 26.2917H10.2131ZM10.4008 25.6378C10.3439 25.6202 10.2885 25.6258 10.2364 25.6563C10.1842 25.686 10.1425 25.7349 10.112 25.8031L10.5252 25.9315L10.5276 25.9234C10.5461 25.8569 10.5437 25.7967 10.5212 25.7437C10.4987 25.6908 10.4578 25.6555 10.4008 25.6378Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_11",
+ "d": "M11.1407 25.856C11.1254 25.8488 11.1078 25.8424 11.0893 25.8384C11.0412 25.8255 10.997 25.8287 10.9561 25.8472C10.916 25.8657 10.8823 25.8985 10.8542 25.9459L10.7299 26.4257L10.6528 26.4056L10.8334 25.7068L10.9088 25.726L10.8815 25.8376C10.9441 25.7654 11.0203 25.7413 11.1102 25.7646C11.1318 25.7702 11.1479 25.7774 11.1591 25.7862L11.139 25.856H11.1407Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_12",
+ "d": "M11.3831 26.4659L11.7233 25.9123L11.8036 25.9292L11.392 26.5807L11.3286 26.5678L11.2114 25.8064L11.2917 25.8232L11.3831 26.4667V26.4659Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_13",
+ "d": "M11.895 26.6737L11.8164 26.66L11.936 25.9484L12.0146 25.962L11.895 26.6737ZM11.9568 25.7406C11.9592 25.7261 11.9664 25.7141 11.9777 25.7053C11.9889 25.6964 12.0034 25.694 12.0194 25.6964C12.0362 25.6996 12.0483 25.7069 12.0563 25.7181C12.0643 25.7301 12.0675 25.743 12.0651 25.7582C12.0627 25.7727 12.0555 25.7847 12.0443 25.7927C12.033 25.8007 12.0186 25.804 12.0017 25.8007C11.9849 25.7983 11.9729 25.7911 11.9648 25.7791C11.9568 25.767 11.9544 25.7542 11.9568 25.7398V25.7406Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_14",
+ "d": "M12.4061 26.6929C12.4615 26.7002 12.5096 26.6905 12.5505 26.664C12.5915 26.6376 12.6171 26.5999 12.626 26.5509L12.7022 26.5605C12.6942 26.6039 12.6757 26.6424 12.646 26.6745C12.6163 26.7074 12.5794 26.7314 12.5353 26.7459C12.4912 26.7603 12.4454 26.7651 12.3973 26.7595C12.3034 26.7475 12.2328 26.7058 12.1863 26.6336C12.1398 26.5613 12.1229 26.4699 12.1373 26.36L12.1406 26.3359C12.1494 26.2653 12.1694 26.2043 12.2015 26.153C12.2328 26.1016 12.2737 26.0647 12.3235 26.0406C12.3732 26.0166 12.4294 26.0085 12.4912 26.0166C12.5698 26.0262 12.6316 26.0583 12.6765 26.1112C12.7214 26.1642 12.7407 26.2292 12.7351 26.3062L12.6589 26.2966C12.6621 26.2404 12.6476 26.1923 12.6155 26.153C12.5826 26.1136 12.5385 26.0912 12.4823 26.084C12.4109 26.0751 12.3524 26.0936 12.3058 26.1401C12.2601 26.1867 12.2312 26.2565 12.2192 26.3495L12.216 26.3728C12.2047 26.4643 12.216 26.5381 12.2481 26.5942C12.281 26.6504 12.3339 26.6833 12.4053 26.6921L12.4061 26.6929Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_15",
+ "d": "M13.1466 26.8301C13.0856 26.8261 13.0311 26.8068 12.9837 26.7739C12.9364 26.7402 12.9011 26.6961 12.877 26.6399C12.8529 26.5846 12.8433 26.5228 12.8481 26.4562L12.8497 26.4273C12.8545 26.3583 12.8722 26.2965 12.9027 26.2428C12.9332 26.189 12.9733 26.1481 13.0238 26.12C13.0744 26.0919 13.1265 26.0791 13.1827 26.0831C13.2702 26.0887 13.3376 26.1232 13.3849 26.1866C13.4322 26.25 13.4523 26.3326 13.4451 26.4361L13.4419 26.4811L12.9284 26.4458V26.461C12.9219 26.5429 12.9404 26.6119 12.9837 26.6696C13.027 26.7274 13.084 26.7587 13.1546 26.7635C13.1971 26.7667 13.2357 26.7611 13.2694 26.7483C13.3031 26.7354 13.3343 26.7122 13.3632 26.6801L13.4106 26.721C13.3464 26.802 13.2581 26.8381 13.1474 26.8309L13.1466 26.8301ZM13.1779 26.1505C13.1177 26.1465 13.0664 26.165 13.0222 26.2059C12.9781 26.2468 12.9492 26.3046 12.9356 26.3776L13.3672 26.4073V26.3984C13.3704 26.3294 13.3544 26.2717 13.3199 26.2251C13.2854 26.1794 13.2381 26.1537 13.1779 26.1497V26.1505Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_16",
+ "d": "M14.6863 26.3993C14.6887 26.4884 14.6751 26.5678 14.6454 26.636C14.6165 26.7042 14.5732 26.7571 14.517 26.7949C14.4608 26.8326 14.395 26.8526 14.3196 26.8542C14.2065 26.8566 14.1134 26.8189 14.042 26.7395C13.9706 26.6601 13.9329 26.5517 13.9297 26.4137L13.9273 26.3135C13.9249 26.2252 13.9385 26.1466 13.9682 26.0776C13.9979 26.0086 14.0412 25.9548 14.0974 25.9171C14.1535 25.8794 14.2193 25.8593 14.2939 25.8569C14.3686 25.8553 14.4352 25.8714 14.4929 25.9059C14.5507 25.9404 14.5964 25.9901 14.6293 26.0551C14.6622 26.1201 14.6799 26.1963 14.6839 26.283L14.6871 26.3993H14.6863ZM14.602 26.2958C14.5988 26.1787 14.5707 26.088 14.5162 26.023C14.4616 25.958 14.3886 25.9267 14.2963 25.9291C14.2065 25.9315 14.1351 25.966 14.0829 26.0342C14.0308 26.1024 14.0067 26.1955 14.0091 26.3143L14.0115 26.4154C14.0147 26.5301 14.0436 26.6207 14.0982 26.6873C14.1535 26.7531 14.2265 26.7852 14.318 26.7828C14.4111 26.7804 14.4825 26.7459 14.533 26.6777C14.5836 26.6095 14.6069 26.5164 14.6044 26.3985L14.602 26.2958Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_17",
+ "d": "M15.1989 26.1353C15.182 26.1337 15.1636 26.1337 15.1443 26.1353C15.0946 26.1393 15.0536 26.1562 15.0216 26.1866C14.9895 26.2171 14.9678 26.2597 14.9582 26.3134L14.9983 26.8077L14.9189 26.8141L14.8611 26.0952L14.9389 26.0888L14.9493 26.2027C14.9846 26.1144 15.0488 26.0663 15.1419 26.0591C15.1644 26.0575 15.182 26.0591 15.1949 26.0639L15.1989 26.1361V26.1353Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_18",
+ "d": "M15.3144 26.4129C15.3 26.3005 15.3136 26.2091 15.3545 26.1369C15.3955 26.0646 15.4588 26.0237 15.5439 26.0125C15.641 25.9997 15.7204 26.0293 15.7814 26.0999L15.7718 25.9964L15.8456 25.9868L15.9362 26.6881C15.9483 26.7803 15.9314 26.8565 15.8873 26.9167C15.8424 26.9769 15.7766 27.013 15.6883 27.0242C15.6386 27.0307 15.5896 27.0258 15.5415 27.009C15.4933 26.9921 15.454 26.9673 15.4235 26.9336L15.4621 26.8798C15.527 26.9416 15.5976 26.9673 15.6755 26.9568C15.7413 26.948 15.791 26.9223 15.8223 26.8782C15.8544 26.8341 15.8664 26.7779 15.8592 26.7081L15.8472 26.6183C15.8055 26.6953 15.7365 26.7402 15.6394 26.753C15.5567 26.7635 15.4853 26.7394 15.4268 26.68C15.3682 26.6207 15.3313 26.534 15.3168 26.4217L15.3152 26.4113L15.3144 26.4129ZM15.3963 26.4161C15.4083 26.5075 15.4356 26.5773 15.4789 26.6247C15.5222 26.6728 15.5776 26.6921 15.6442 26.684C15.7413 26.6712 15.8047 26.6191 15.8343 26.526L15.791 26.193C15.7661 26.1497 15.7357 26.1184 15.6971 26.0983C15.6594 26.0791 15.6161 26.0719 15.5672 26.0783C15.5006 26.0871 15.4524 26.12 15.4219 26.177C15.3914 26.2339 15.3834 26.3134 15.3963 26.4153V26.4161Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_19",
+ "d": "M16.6271 26.5773C16.615 26.5565 16.6038 26.5244 16.5934 26.4811C16.5725 26.522 16.5428 26.5565 16.5043 26.5838C16.4658 26.611 16.4225 26.6295 16.3743 26.6391C16.3061 26.652 16.2476 26.6439 16.1978 26.6142C16.1481 26.5846 16.1184 26.5404 16.1071 26.4827C16.0935 26.4137 16.112 26.3535 16.1617 26.3021C16.2115 26.2508 16.2877 26.2155 16.3904 26.1954L16.5324 26.1681L16.5171 26.0879C16.5075 26.0374 16.4842 26.0005 16.4473 25.9772C16.4104 25.9539 16.3623 25.9483 16.3021 25.9595C16.2476 25.97 16.205 25.9924 16.1745 26.0277C16.1441 26.0622 16.1328 26.1 16.14 26.1393L16.0614 26.1537C16.051 26.0975 16.067 26.0438 16.112 25.9924C16.1561 25.9411 16.2171 25.9082 16.2933 25.8938C16.3719 25.8785 16.4385 25.8865 16.4915 25.917C16.5444 25.9475 16.5789 25.9981 16.5934 26.0687L16.6576 26.404C16.6704 26.4722 16.688 26.5228 16.7089 26.5541L16.7105 26.5621L16.6271 26.5781V26.5773ZM16.3695 26.5685C16.4217 26.5581 16.4666 26.5364 16.5027 26.5035C16.5388 26.4706 16.5629 26.4305 16.5733 26.3848L16.5436 26.2291L16.4032 26.2564C16.3254 26.2725 16.2668 26.2981 16.2283 26.3342C16.1898 26.3703 16.1745 26.4129 16.1842 26.461C16.1922 26.5011 16.2131 26.5308 16.2476 26.5517C16.2821 26.5725 16.323 26.5781 16.3703 26.5685H16.3695Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_20",
+ "d": "M16.8277 25.7934L16.8606 25.9122C16.8759 25.8624 16.8999 25.8215 16.9336 25.7886C16.9673 25.7557 17.0074 25.7333 17.0548 25.7212C17.1294 25.702 17.1912 25.7092 17.2385 25.7421C17.2859 25.775 17.3204 25.8336 17.3428 25.9178L17.46 26.3767L17.3829 26.3968L17.265 25.9379C17.2489 25.8753 17.2233 25.8328 17.1896 25.8087C17.1559 25.7846 17.1101 25.7798 17.0532 25.7951C17.005 25.8071 16.9665 25.8328 16.9376 25.8721C16.9088 25.9114 16.8919 25.9587 16.8871 26.0141L17.0099 26.4931L16.9328 26.5131L16.7539 25.8143L16.8277 25.7951V25.7934Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_21",
+ "d": "M17.4094 25.4204C17.4054 25.406 17.4062 25.3923 17.4126 25.3795C17.4191 25.3667 17.4303 25.3578 17.4463 25.353C17.4624 25.3482 17.4768 25.349 17.4897 25.3562C17.5025 25.3634 17.5105 25.3739 17.5153 25.3883C17.5194 25.4028 17.5186 25.4164 17.5121 25.4284C17.5057 25.4413 17.4937 25.4501 17.4776 25.4549C17.4616 25.4597 17.4471 25.4589 17.4351 25.4517C17.4231 25.4445 17.4142 25.434 17.4102 25.4196L17.4094 25.4204ZM17.7689 26.2837L17.6927 26.307L17.4832 25.6162L17.5595 25.5929L17.7689 26.2837Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_22",
+ "d": "M18.0281 26.1313L18.471 25.9772L18.4935 26.0406L17.9575 26.2267L17.9382 26.1714L18.1565 25.4669L17.7561 25.6057L17.7336 25.5399L18.2295 25.3674L18.2495 25.4244L18.0297 26.1297L18.0281 26.1313Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_23",
+ "d": "M19.0799 25.8031C19.0639 25.7854 19.0462 25.7558 19.027 25.7156C19.0149 25.7598 18.9925 25.7999 18.9604 25.8344C18.9283 25.8689 18.889 25.8962 18.844 25.9146C18.7799 25.9411 18.7205 25.9443 18.6659 25.925C18.6114 25.9058 18.5728 25.8689 18.5504 25.8143C18.5239 25.7493 18.5295 25.6868 18.568 25.6266C18.6065 25.5664 18.6739 25.5167 18.7702 25.4765L18.9042 25.4212L18.8729 25.345C18.8529 25.2976 18.8232 25.2655 18.7823 25.2511C18.7413 25.2366 18.6932 25.2398 18.637 25.2631C18.5857 25.284 18.5488 25.3153 18.5255 25.3554C18.503 25.3955 18.499 25.434 18.5143 25.4709L18.4397 25.5006C18.418 25.4477 18.4236 25.3915 18.4565 25.3321C18.4902 25.2727 18.5424 25.2286 18.6146 25.1989C18.6892 25.1684 18.755 25.1628 18.8135 25.1821C18.8721 25.2013 18.9154 25.2447 18.9443 25.3105L19.0743 25.6258C19.1008 25.69 19.1281 25.7357 19.1545 25.7622L19.1578 25.7694L19.0791 25.8023L19.0799 25.8031ZM18.8264 25.8456C18.8761 25.8256 18.9146 25.7951 18.9435 25.755C18.9724 25.7148 18.9877 25.6715 18.9885 25.6242L18.9283 25.4773L18.7967 25.5319C18.7237 25.5632 18.6715 25.6001 18.641 25.6434C18.6106 25.6868 18.6041 25.7309 18.6234 25.7766C18.6386 25.8143 18.6659 25.8392 18.7036 25.8528C18.7413 25.8657 18.7831 25.8633 18.8272 25.8448L18.8264 25.8456Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_24",
+ "d": "M19.083 24.8058L19.1616 24.9727L19.2964 24.9093L19.3245 24.9687L19.1897 25.032L19.3943 25.4677C19.4112 25.5038 19.4304 25.5279 19.4521 25.5391C19.4737 25.5504 19.4994 25.5496 19.5299 25.5351C19.5419 25.5295 19.5604 25.5183 19.5853 25.5014L19.6157 25.5584C19.5997 25.5744 19.5756 25.5897 19.5435 25.6049C19.4938 25.6282 19.4513 25.6306 19.4152 25.6129C19.3791 25.5945 19.3478 25.5576 19.3213 25.5022L19.1167 25.0665L18.9963 25.1227L18.9683 25.0633L19.0886 25.0072L19.01 24.8403L19.0822 24.8066L19.083 24.8058Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_25",
+ "d": "M19.3438 24.6526C19.3374 24.639 19.3358 24.6254 19.3398 24.6117C19.3438 24.5981 19.3535 24.5876 19.3687 24.5796C19.384 24.5716 19.3984 24.5708 19.412 24.5756C19.4257 24.5804 19.4361 24.5893 19.4425 24.6029C19.449 24.6165 19.4506 24.6294 19.4465 24.643C19.4425 24.6566 19.4329 24.6671 19.4177 24.6751C19.4024 24.6831 19.388 24.6839 19.3751 24.6799C19.3623 24.6759 19.3519 24.6663 19.3446 24.6526H19.3438ZM19.8493 25.4389L19.7779 25.475L19.4506 24.8316L19.522 24.7955L19.8493 25.4389Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_26",
+ "d": "M19.8461 25.0264C19.8115 24.9663 19.7931 24.9053 19.7891 24.8435C19.7851 24.7817 19.7971 24.7256 19.8244 24.6742C19.8517 24.6229 19.8926 24.5819 19.9471 24.5515C20.0306 24.5041 20.1148 24.4953 20.1999 24.525C20.2849 24.5547 20.3547 24.6172 20.4093 24.7143L20.4173 24.7288C20.4518 24.7897 20.4711 24.8507 20.4751 24.9125C20.4791 24.9743 20.4671 25.0304 20.4398 25.081C20.4125 25.1315 20.3708 25.1717 20.3162 25.2029C20.2328 25.2503 20.1485 25.2591 20.0635 25.2294C19.9784 25.2005 19.9086 25.1372 19.8533 25.0401L19.8452 25.0264H19.8461ZM19.9271 25.0064C19.9696 25.0818 20.0242 25.1323 20.09 25.158C20.1558 25.1837 20.2207 25.1797 20.2841 25.1436C20.3467 25.1083 20.3844 25.0553 20.3957 24.9855C20.4069 24.9157 20.3908 24.8411 20.3459 24.7617L20.3387 24.748C20.3114 24.6999 20.2777 24.6614 20.2376 24.6317C20.1975 24.602 20.155 24.5851 20.11 24.5811C20.0659 24.5771 20.0226 24.5876 19.9808 24.6108C19.9191 24.6461 19.8822 24.6983 19.8701 24.7697C19.8581 24.8403 19.8749 24.9149 19.9191 24.9935L19.9263 25.0064H19.9271Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_27",
+ "d": "M20.4318 24.2803L20.5016 24.3822C20.5 24.3301 20.5096 24.2835 20.5313 24.2418C20.5521 24.2001 20.5834 24.1664 20.6244 24.1391C20.6893 24.0966 20.7495 24.0838 20.8049 24.0998C20.8602 24.1159 20.9116 24.16 20.9597 24.233L21.2173 24.6302L21.1507 24.6735L20.8923 24.2755C20.857 24.2218 20.8193 24.1889 20.7792 24.1768C20.7391 24.1648 20.695 24.1752 20.6452 24.2073C20.6035 24.2346 20.5754 24.2707 20.561 24.3172C20.5465 24.3638 20.5449 24.4143 20.5586 24.4681L20.8281 24.8829L20.7616 24.9262L20.3684 24.3213L20.4318 24.2795V24.2803Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_28",
+ "d": "M21.6546 24.0886C21.6313 24.0565 21.5993 24.0404 21.5599 24.0404C21.5198 24.0404 21.4701 24.0532 21.4107 24.0805C21.3513 24.1078 21.3016 24.1247 21.2631 24.1311C21.2246 24.1383 21.1901 24.1359 21.1612 24.1263C21.1323 24.1166 21.1074 24.0966 21.0858 24.0677C21.0521 24.022 21.0432 23.9698 21.0593 23.912C21.0753 23.8543 21.1138 23.8029 21.1732 23.7588C21.2382 23.7115 21.3016 23.689 21.3642 23.6922C21.4267 23.6954 21.4773 23.7227 21.515 23.774L21.4508 23.8214C21.4259 23.7877 21.3906 23.7692 21.3457 23.7676C21.3008 23.766 21.2567 23.7813 21.2133 23.8133C21.1708 23.8446 21.1443 23.8791 21.1323 23.9168C21.1203 23.9546 21.1259 23.9883 21.1475 24.0187C21.1692 24.0476 21.1965 24.0621 21.2294 24.0629C21.2623 24.0629 21.312 24.0492 21.3778 24.0212C21.4436 23.9931 21.4966 23.9762 21.5359 23.9706C21.5752 23.965 21.6089 23.9674 21.6386 23.9786C21.6675 23.9899 21.6931 24.0099 21.7156 24.0404C21.7517 24.0894 21.7605 24.1431 21.7429 24.2017C21.7252 24.2603 21.6843 24.3132 21.6201 24.3597C21.5527 24.4095 21.4853 24.4336 21.4195 24.432C21.3529 24.4303 21.3016 24.4039 21.2647 24.3541L21.3289 24.3068C21.3594 24.3429 21.3963 24.3605 21.4412 24.3597C21.4861 24.3589 21.5319 24.3413 21.58 24.306C21.6249 24.2731 21.6538 24.2362 21.6666 24.1969C21.6795 24.1575 21.6755 24.1214 21.653 24.0918L21.6546 24.0886Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_29",
+ "d": "M22.7023 23.6914L22.6518 23.7363L21.8848 22.8778L21.9353 22.8329L22.7023 23.6914Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_30",
+ "d": "M23.418 22.3659C23.3868 22.337 23.3523 22.3258 23.3145 22.3322C23.2776 22.3386 23.2239 22.3627 23.1533 22.4044C23.0827 22.4461 23.0217 22.4742 22.9687 22.4886C22.8684 22.5159 22.785 22.4999 22.7192 22.4397C22.6614 22.3867 22.6358 22.3193 22.6414 22.2383C22.647 22.1573 22.6847 22.0786 22.7529 22.004C22.7986 21.9543 22.8484 21.9182 22.9029 21.8957C22.9567 21.8732 23.0113 21.8668 23.0658 21.8756C23.1204 21.8845 23.1677 21.9077 23.2094 21.9454L23.0955 22.069C23.0586 22.0345 23.0185 22.0193 22.9752 22.0241C22.9326 22.0281 22.8909 22.0522 22.8516 22.0955C22.8147 22.1364 22.7938 22.1757 22.7906 22.2142C22.7874 22.2527 22.801 22.2864 22.8323 22.3145C22.8588 22.3386 22.8917 22.3466 22.931 22.3386C22.9711 22.3306 23.0241 22.3057 23.0923 22.2656C23.1597 22.2255 23.2199 22.1974 23.272 22.1829C23.3242 22.1685 23.3707 22.1661 23.4124 22.1757C23.4541 22.1853 23.4935 22.2062 23.5304 22.2399C23.5897 22.2945 23.6162 22.3611 23.6098 22.4389C23.6034 22.5167 23.5641 22.5953 23.4919 22.6732C23.4445 22.7253 23.3916 22.7638 23.3322 22.7895C23.2736 22.8152 23.2159 22.8248 23.1597 22.8176C23.1035 22.8104 23.0538 22.7871 23.0089 22.7454L23.1228 22.621C23.1637 22.6579 23.207 22.674 23.2544 22.6675C23.3009 22.6611 23.3474 22.633 23.394 22.5825C23.4333 22.5392 23.455 22.4991 23.4574 22.4605C23.4598 22.4228 23.4469 22.3907 23.418 22.3643V22.3659Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_31",
+ "d": "M24.0366 22.0386C23.9724 22.1188 23.8946 22.1629 23.8039 22.1718C23.7133 22.1806 23.6266 22.1517 23.5424 22.0843L23.5271 22.0715C23.471 22.0265 23.43 21.9752 23.4028 21.9182C23.3763 21.8612 23.3659 21.8027 23.3731 21.7441C23.3803 21.6855 23.4028 21.6318 23.4413 21.5836C23.5031 21.5074 23.5753 21.4681 23.6571 21.4657C23.7389 21.4633 23.8256 21.4978 23.9147 21.57L23.9652 21.6109L23.6691 21.9776C23.7189 22.0113 23.7678 22.0249 23.8168 22.0201C23.8657 22.0145 23.9066 21.9912 23.9403 21.9503C23.9869 21.8925 24.0013 21.8267 23.9845 21.7529L24.104 21.7369C24.1193 21.7866 24.1217 21.8372 24.1096 21.8901C24.0976 21.9423 24.0735 21.992 24.0358 22.0386H24.0366ZM23.5432 21.6655C23.5151 21.7 23.5047 21.7377 23.5119 21.7786C23.5191 21.8195 23.5416 21.8604 23.5801 21.9014L23.7742 21.6607L23.7646 21.6534C23.7205 21.6221 23.6788 21.6077 23.6419 21.6101C23.6042 21.6125 23.5713 21.631 23.5432 21.6663V21.6655Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_32",
+ "d": "M24.0584 21.0357C24.0432 21.0509 24.0287 21.0678 24.0151 21.0862C23.9718 21.1464 23.9653 21.2034 23.9958 21.2579L24.3946 21.5484L24.2991 21.6791L23.7158 21.2547L23.8065 21.1295L23.8739 21.1737C23.8466 21.1055 23.853 21.0429 23.8939 20.9867C23.9076 20.9683 23.9212 20.9546 23.9349 20.9458L24.0576 21.0357H24.0584Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_33",
+ "d": "M24.5717 20.9305L24.2243 20.5197L24.3166 20.3801L24.7827 20.9851L24.7057 21.103L23.9644 20.9177L24.0566 20.7773L24.5733 20.9313L24.5717 20.9305Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_34",
+ "d": "M24.2029 20.1997C24.1812 20.1868 24.1676 20.1692 24.1619 20.1475C24.1555 20.1258 24.1603 20.1018 24.1756 20.0769C24.1908 20.052 24.2093 20.0368 24.2318 20.0312C24.2542 20.0255 24.2759 20.0296 24.2975 20.0424C24.3184 20.0552 24.332 20.0721 24.3377 20.0945C24.3433 20.117 24.3385 20.1403 24.324 20.1652C24.3088 20.19 24.2903 20.2053 24.2687 20.2109C24.247 20.2157 24.2253 20.2125 24.2045 20.1997H24.2029ZM25.071 20.5182L24.9876 20.657L24.3681 20.2863L24.4516 20.1475L25.071 20.5182Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_35",
+ "d": "M25.2146 20.0271C25.2339 19.9918 25.2395 19.9565 25.2315 19.922C25.2235 19.8875 25.205 19.861 25.1745 19.8426L25.2475 19.7086C25.286 19.7318 25.3165 19.7639 25.3382 19.8056C25.3599 19.8474 25.3703 19.8931 25.3687 19.9436C25.3671 19.9942 25.3542 20.0423 25.3294 20.0881C25.2812 20.1771 25.2146 20.2317 25.1288 20.2525C25.0429 20.2734 24.9499 20.2566 24.8488 20.202L24.8343 20.194C24.738 20.1418 24.6747 20.0744 24.6442 19.991C24.6137 19.9075 24.6233 19.8217 24.6715 19.7326C24.7124 19.6572 24.7677 19.6075 24.8375 19.5842C24.9073 19.5601 24.9788 19.5665 25.0518 19.6035L24.9788 19.7374C24.9418 19.719 24.9049 19.7158 24.8688 19.7262C24.8327 19.7366 24.8054 19.7599 24.7854 19.796C24.7605 19.8426 24.7581 19.8867 24.7782 19.93C24.7982 19.9733 24.8416 20.0134 24.9098 20.0504L24.933 20.0624C25.002 20.0993 25.0598 20.1153 25.1071 20.1081C25.1545 20.1009 25.1906 20.0744 25.2162 20.0279L25.2146 20.0271Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_36",
+ "d": "M25.6743 19.398C25.6309 19.4911 25.5659 19.5529 25.4809 19.5834C25.3959 19.6139 25.3036 19.6066 25.2065 19.5609L25.188 19.5521C25.1231 19.5216 25.0701 19.4815 25.0308 19.4325C24.9915 19.3836 24.9674 19.329 24.9602 19.2705C24.953 19.2119 24.9618 19.1541 24.9883 19.098C25.03 19.0089 25.0902 18.9535 25.1696 18.9311C25.249 18.9086 25.3405 18.9222 25.4448 18.9704L25.5042 18.9977L25.3052 19.4253C25.3614 19.4462 25.4127 19.4478 25.4584 19.4309C25.505 19.4141 25.5387 19.3812 25.5611 19.3338C25.5924 19.2664 25.5908 19.199 25.5563 19.1316L25.6686 19.0875C25.6951 19.1316 25.7096 19.1814 25.7104 19.2352C25.7112 19.2889 25.6991 19.3427 25.6743 19.3972V19.398ZM25.1054 19.1541C25.087 19.1942 25.0853 19.2335 25.1022 19.2713C25.119 19.309 25.1511 19.3435 25.1977 19.374L25.3285 19.0939L25.3172 19.0891C25.2667 19.0691 25.2234 19.0651 25.1872 19.0763C25.1511 19.0875 25.1239 19.1132 25.1046 19.1541H25.1054Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_37",
+ "d": "M25.8155 17.7453C25.9054 17.7774 25.9784 17.8199 26.0354 17.8753C26.0923 17.9306 26.1284 17.9932 26.1445 18.063C26.1605 18.1328 26.1549 18.2059 26.1284 18.2813C26.102 18.3551 26.061 18.4153 26.0041 18.4602C25.9471 18.5051 25.8797 18.5324 25.8019 18.5404C25.7232 18.5485 25.6406 18.5372 25.5532 18.5067L25.5018 18.4883C25.4127 18.457 25.3389 18.4129 25.282 18.3575C25.225 18.3013 25.1881 18.2387 25.172 18.1681C25.156 18.0975 25.1616 18.0253 25.1881 17.9507C25.2146 17.8761 25.2555 17.8159 25.3116 17.771C25.3678 17.7261 25.4352 17.6996 25.5138 17.6924C25.5925 17.6843 25.6759 17.6964 25.7658 17.7277L25.8163 17.7453H25.8155ZM25.712 17.8873C25.6109 17.8512 25.5259 17.8432 25.4585 17.8625C25.3911 17.8817 25.3445 17.9266 25.3197 17.9972C25.2956 18.0662 25.3036 18.1296 25.3437 18.1874C25.3839 18.2452 25.4529 18.2917 25.5515 18.3278L25.6045 18.3463C25.7048 18.3816 25.7898 18.3896 25.8588 18.3695C25.9278 18.3495 25.9744 18.3053 25.9993 18.2355C26.0241 18.1649 26.0161 18.1015 25.976 18.0446C25.9359 17.9876 25.8637 17.9411 25.761 17.905L25.7128 17.8881L25.712 17.8873Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_38",
+ "d": "M25.8541 17.1956C25.8444 17.2149 25.8372 17.2357 25.8308 17.2574C25.8099 17.3288 25.8236 17.385 25.8709 17.4251L26.3451 17.5615L26.3002 17.7171L25.6069 17.5173L25.6495 17.3689L25.7281 17.3874C25.6783 17.332 25.6639 17.2718 25.6832 17.2052C25.6896 17.1828 25.6976 17.1651 25.708 17.1531L25.8541 17.1956Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_39",
+ "d": "M26.0747 17.182C25.9656 17.1563 25.8846 17.1106 25.8316 17.044C25.7787 16.9774 25.7618 16.902 25.7819 16.8169C25.8003 16.7367 25.8437 16.6805 25.9102 16.6477L25.8412 16.6236L25.8749 16.4816L26.5561 16.6412C26.6484 16.6629 26.7142 16.7086 26.7543 16.7784C26.7944 16.8482 26.8024 16.9317 26.78 17.0296C26.7679 17.0809 26.7455 17.1291 26.7126 17.1732C26.6797 17.2173 26.6428 17.2478 26.6019 17.2655L26.5248 17.1684C26.5938 17.1331 26.6364 17.0801 26.6532 17.0095C26.6652 16.9574 26.6612 16.9124 26.6396 16.8755C26.6179 16.8386 26.5802 16.8137 26.5248 16.8009L26.4775 16.7897C26.5176 16.8466 26.5289 16.9132 26.5112 16.9894C26.4919 17.0713 26.4438 17.1315 26.366 17.1684C26.2881 17.2053 26.1919 17.2101 26.0763 17.1828L26.0747 17.182ZM26.1253 17.028C26.1959 17.0448 26.2545 17.0432 26.3018 17.0239C26.3491 17.0047 26.3788 16.9694 26.3908 16.918C26.4061 16.8547 26.3892 16.8009 26.3419 16.7576L26.033 16.6854C25.9728 16.703 25.9351 16.7431 25.9199 16.8065C25.9078 16.8587 25.9191 16.9036 25.9536 16.9421C25.9881 16.9806 26.045 17.0095 26.1253 17.028Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_40",
+ "d": "M26.6877 16.0219C26.6733 16.0267 26.65 16.0291 26.6179 16.0291C26.662 16.0892 26.6781 16.1558 26.6661 16.2297C26.654 16.3011 26.6235 16.3556 26.5754 16.3941C26.5273 16.4326 26.4727 16.4463 26.4125 16.4359C26.3371 16.423 26.2833 16.3853 26.252 16.3219C26.2208 16.2585 26.2143 16.1751 26.232 16.07L26.2488 15.9721L26.2023 15.9641C26.1654 15.9577 26.1341 15.9633 26.1084 15.9801C26.0828 15.997 26.0667 16.0267 26.0595 16.0684C26.0531 16.1045 26.0571 16.1358 26.0715 16.1623C26.086 16.1887 26.1068 16.204 26.1349 16.2088L26.1076 16.3685C26.0683 16.362 26.0346 16.3428 26.0049 16.3115C25.9752 16.2802 25.9544 16.2401 25.9431 16.1927C25.9311 16.1446 25.9303 16.0941 25.9399 16.0387C25.9544 15.9553 25.9865 15.8927 26.0362 15.8502C26.0868 15.8076 26.1493 15.7924 26.2256 15.8036L26.5465 15.8582C26.6107 15.8694 26.6628 15.8686 26.7046 15.8574L26.7158 15.859L26.6885 16.0219H26.6877ZM26.5433 16.1783C26.5489 16.147 26.5457 16.1157 26.5353 16.0852C26.5248 16.0547 26.508 16.0307 26.4839 16.0122L26.3499 15.9898L26.3355 16.0756C26.3259 16.135 26.3283 16.1807 26.3435 16.2144C26.3588 16.2481 26.386 16.2674 26.4237 16.2738C26.4542 16.2786 26.4807 16.273 26.5024 16.2553C26.524 16.2377 26.5377 16.212 26.5433 16.1783Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_41",
+ "d": "M26.0384 15.453L26.1219 15.457C26.0633 15.3968 26.0392 15.3238 26.0481 15.2379C26.0641 15.0887 26.158 15.0213 26.3289 15.0374L26.8031 15.0879L26.7862 15.2492L26.3217 15.1994C26.2759 15.1946 26.2414 15.201 26.2174 15.2179C26.1933 15.2355 26.1788 15.266 26.174 15.3109C26.1668 15.3759 26.1909 15.4273 26.247 15.4658L26.7573 15.5204L26.7405 15.6816L26.0232 15.6046L26.0392 15.453H26.0384Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_42",
+ "d": "M25.9078 14.8416C25.883 14.84 25.8629 14.8312 25.8477 14.8143C25.8324 14.7975 25.8252 14.7742 25.8276 14.7453C25.8292 14.7165 25.8388 14.694 25.8565 14.6787C25.8741 14.6635 25.895 14.6571 25.9199 14.6587C25.9439 14.6603 25.964 14.6691 25.9792 14.6868C25.9945 14.7036 26.0009 14.7269 25.9993 14.7566C25.9977 14.7855 25.9881 14.8079 25.9712 14.8224C25.9544 14.8368 25.9335 14.844 25.9086 14.8424L25.9078 14.8416ZM26.8257 14.7261L26.8161 14.8882L26.0956 14.8432L26.1052 14.6812L26.8257 14.7261Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_43",
+ "d": "M26.7116 14.3489L26.7196 13.9646L26.8488 13.967L26.8368 14.5527L26.7309 14.5503L26.2535 14.1748L26.2463 14.5343L26.1155 14.5319L26.1267 13.967L26.2294 13.9694L26.7116 14.3497V14.3489Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_44",
+ "d": "M26.8312 13.3741C26.8176 13.3813 26.7951 13.3885 26.7646 13.395C26.82 13.4447 26.8497 13.5065 26.8521 13.5811C26.8545 13.6533 26.8361 13.7135 26.7967 13.7608C26.7574 13.8082 26.7069 13.833 26.6459 13.8354C26.5689 13.8386 26.5087 13.8122 26.4662 13.756C26.4229 13.7006 26.3996 13.6196 26.3956 13.5137L26.3916 13.4142L26.3442 13.4158C26.3065 13.4174 26.2776 13.4287 26.256 13.4503C26.2343 13.472 26.2247 13.5041 26.2255 13.5466C26.2271 13.5835 26.2375 13.6132 26.2568 13.6365C26.276 13.6597 26.3001 13.6702 26.3282 13.6694L26.3338 13.8314C26.2945 13.833 26.2568 13.821 26.2215 13.7961C26.1862 13.7712 26.1581 13.7367 26.1364 13.6918C26.1156 13.6477 26.1035 13.5971 26.1019 13.5418C26.0987 13.4575 26.1172 13.3893 26.1581 13.3372C26.199 13.285 26.2576 13.2578 26.3338 13.2529L26.6587 13.2409C26.7237 13.2385 26.7751 13.2273 26.8128 13.208H26.824L26.8304 13.3725L26.8312 13.3741ZM26.7213 13.5562C26.7205 13.5241 26.7117 13.4944 26.6948 13.4672C26.678 13.4399 26.6563 13.419 26.6299 13.4062L26.4943 13.411L26.4975 13.4985C26.4999 13.5586 26.5119 13.6028 26.5336 13.6324C26.5552 13.6621 26.5857 13.6758 26.6242 13.6742C26.6555 13.6734 26.6796 13.6621 26.6973 13.6405C26.7149 13.6188 26.7229 13.5915 26.7221 13.5562H26.7213Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_45",
+ "d": "M25.8997 12.9119L26.0746 12.8967L26.0641 12.7699L26.1837 12.7595L26.1941 12.8862L26.5953 12.8517C26.6226 12.8493 26.6418 12.8421 26.6531 12.8301C26.6643 12.818 26.6691 12.798 26.6667 12.7707C26.6651 12.7522 26.6611 12.7338 26.6555 12.7145L26.7806 12.7041C26.7943 12.7402 26.8023 12.7747 26.8047 12.8092C26.8151 12.9336 26.7517 13.001 26.6153 13.013L26.2078 13.0475L26.2182 13.1654L26.0986 13.1759L26.0882 13.0579L25.9133 13.0732L25.8997 12.9119Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_46",
+ "d": "M25.8638 12.672C25.8389 12.6752 25.8172 12.6696 25.7996 12.656C25.7819 12.6423 25.7707 12.6207 25.7675 12.5918C25.7643 12.5629 25.7699 12.5388 25.7843 12.5212C25.7988 12.5035 25.818 12.4931 25.8429 12.4899C25.867 12.4867 25.8886 12.4923 25.9063 12.5067C25.9239 12.5212 25.9352 12.542 25.9384 12.5717C25.9416 12.6014 25.9368 12.6239 25.9223 12.6415C25.9079 12.6592 25.8886 12.6696 25.8646 12.672H25.8638ZM26.7463 12.3944L26.7656 12.5557L26.0491 12.6407L26.0298 12.4795L26.7463 12.3944Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_47",
+ "d": "M26.365 12.2814C26.2952 12.2926 26.2302 12.2894 26.17 12.2709C26.1098 12.2525 26.0601 12.2212 26.0216 12.1755C25.9831 12.1305 25.959 12.0752 25.9478 12.0102C25.9317 11.9139 25.9502 11.8312 26.0015 11.7606C26.0537 11.6908 26.1299 11.6443 26.2318 11.6226L26.2695 11.6154C26.3401 11.6042 26.4043 11.6066 26.4645 11.625C26.5246 11.6427 26.5736 11.6748 26.6121 11.7197C26.6506 11.7647 26.6755 11.8208 26.6859 11.8866C26.7028 11.9869 26.6827 12.0728 26.6257 12.1442C26.5688 12.2156 26.4845 12.2605 26.373 12.279L26.365 12.2806V12.2814ZM26.3521 12.1193C26.4251 12.1073 26.4805 12.0824 26.5166 12.0455C26.5535 12.0086 26.5672 11.9628 26.5575 11.9091C26.5487 11.8553 26.5206 11.8168 26.4733 11.7935C26.426 11.7703 26.3618 11.7655 26.2807 11.7791C26.2085 11.7911 26.154 11.816 26.1171 11.8537C26.0801 11.8914 26.0657 11.9372 26.0745 11.9901C26.0834 12.0423 26.1106 12.08 26.1572 12.104C26.2037 12.1281 26.2679 12.1329 26.3505 12.1193H26.3521Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_48",
+ "d": "M25.8461 11.4036L25.9263 11.3803C25.8517 11.3426 25.8044 11.2816 25.7851 11.1974C25.7514 11.0513 25.818 10.9575 25.9849 10.9157L26.4494 10.8082L26.4855 10.9663L26.0298 11.0714C25.9849 11.0818 25.9544 11.0987 25.9375 11.1235C25.9207 11.1476 25.9175 11.1821 25.9271 11.2254C25.9416 11.2888 25.9817 11.3297 26.0467 11.3474L26.5473 11.2319L26.5842 11.3899L25.8814 11.552L25.8469 11.4036H25.8461Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_49",
+ "d": "M26.0946 10.2811C26.0665 10.2891 26.0489 10.3068 26.0416 10.3341C26.0336 10.3613 26.032 10.4031 26.0368 10.4592C26.0416 10.5154 26.04 10.5635 26.0336 10.6044C26.0192 10.6935 25.9758 10.7481 25.9052 10.7689C25.8459 10.7866 25.7881 10.7761 25.7335 10.7376C25.679 10.6991 25.6397 10.6414 25.6164 10.5635C25.5923 10.4809 25.5923 10.4079 25.6188 10.3445C25.6445 10.2811 25.6902 10.2402 25.7552 10.2209L25.8009 10.3766C25.7712 10.3854 25.7496 10.4039 25.7359 10.4319C25.7223 10.46 25.7215 10.4921 25.7319 10.529C25.7424 10.5635 25.7584 10.5884 25.7801 10.6052C25.8025 10.6221 25.8266 10.6269 25.8531 10.6189C25.8772 10.6117 25.8924 10.5964 25.8996 10.5724C25.9068 10.5483 25.9084 10.5042 25.9036 10.4392C25.8988 10.3742 25.9012 10.322 25.9093 10.2811C25.9173 10.241 25.9325 10.2089 25.9534 10.184C25.9742 10.1591 26.0031 10.1415 26.0408 10.1311C26.1034 10.1126 26.1612 10.1238 26.2149 10.164C26.2687 10.2041 26.308 10.2659 26.3329 10.3493C26.3497 10.4063 26.3545 10.4592 26.3465 10.5098C26.3393 10.5603 26.3208 10.6028 26.2928 10.6381C26.2639 10.6734 26.2294 10.6975 26.1877 10.7095L26.1427 10.5587C26.1788 10.5459 26.2029 10.5234 26.2149 10.4921C26.227 10.4608 26.227 10.4239 26.2149 10.3814C26.2029 10.3405 26.1861 10.3116 26.1644 10.2947C26.1427 10.2779 26.1187 10.2731 26.0938 10.2811H26.0946Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_3"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_50",
+ "d": "M8.9457 10.9173H6.97035L6.52184 12.1393H6.13672L7.78312 7.78821H8.13294L9.77933 12.1393H9.39662L8.9457 10.9173ZM7.08428 10.6068H8.82937L7.95642 8.23672L7.08348 10.6068H7.08428Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_51",
+ "d": "M10.8064 12.1401H10.439V7.78906H10.8064V12.1401Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_52",
+ "d": "M15.0067 10.7833C14.9569 11.2415 14.7933 11.5921 14.5149 11.8352C14.2364 12.0783 13.8666 12.1995 13.4044 12.1995C13.0819 12.1995 12.7962 12.1184 12.5483 11.9572C12.3004 11.7959 12.1086 11.5672 11.973 11.2712C11.8375 10.9751 11.7685 10.6373 11.7668 10.2562V9.69135C11.7668 9.30462 11.8342 8.96202 11.9698 8.66355C12.1054 8.36508 12.3004 8.13401 12.5539 7.97194C12.8083 7.80987 13.1003 7.72803 13.4309 7.72803C13.8971 7.72803 14.2653 7.85319 14.5349 8.10432C14.8045 8.35546 14.9618 8.70287 15.0059 9.14736H14.6352C14.5437 8.40841 14.1418 8.03853 13.4309 8.03853C13.0361 8.03853 12.7224 8.18616 12.4881 8.48142C12.2539 8.77668 12.1367 9.18427 12.1367 9.70499V10.2377C12.1367 10.74 12.2507 11.1412 12.4785 11.4396C12.7064 11.7389 13.0153 11.8882 13.4036 11.8882C13.7919 11.8882 14.0776 11.7959 14.2733 11.6113C14.4683 11.4268 14.5895 11.1508 14.6352 10.7817H15.0059L15.0067 10.7833Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_53",
+ "d": "M16.2061 10.3678V12.1401H15.8386V7.78906H17.3205C17.7731 7.78906 18.1301 7.9046 18.3917 8.13567C18.654 8.36675 18.7848 8.68447 18.7848 9.08885C18.7848 9.49323 18.6588 9.81256 18.4069 10.0348C18.155 10.2571 17.7899 10.3678 17.3117 10.3678H16.2061ZM16.2061 10.0573H17.3205C17.6768 10.0573 17.9488 9.97222 18.1365 9.80293C18.3235 9.63364 18.4173 9.39695 18.4173 9.09366C18.4173 8.79038 18.3243 8.55209 18.1381 8.37397C17.952 8.19505 17.6872 8.10438 17.3446 8.10037H16.2061V10.0581V10.0573Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_54",
+ "d": "M21.4823 10.9173H19.507L19.0585 12.1393H18.6733L20.3197 7.78821H20.6696L22.316 12.1393H21.9332L21.4823 10.9173ZM19.6201 10.6068H21.3652L20.4922 8.23672L19.6193 10.6068H19.6201Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_55",
+ "d": "M11.4289 18.1368C11.4289 17.8961 11.3438 17.7051 11.1745 17.5647C11.0052 17.4243 10.6955 17.2911 10.2454 17.1643C9.79532 17.0376 9.46636 16.8996 9.25936 16.7503C8.9641 16.5393 8.81727 16.2625 8.81727 15.9199C8.81727 15.5773 8.95447 15.3165 9.22807 15.1087C9.50167 14.9009 9.85229 14.7966 10.2783 14.7966C10.5672 14.7966 10.8255 14.8528 11.0542 14.9643C11.2821 15.0758 11.4594 15.2315 11.5845 15.4305C11.7097 15.6295 11.7731 15.8517 11.7731 16.0972H11.4024C11.4024 15.7996 11.3005 15.5605 11.0975 15.3791C10.8945 15.1978 10.6217 15.1079 10.2783 15.1079C9.93493 15.1079 9.68059 15.1826 9.48321 15.331C9.28584 15.4794 9.18715 15.6736 9.18715 15.9135C9.18715 16.1349 9.27541 16.3155 9.45272 16.4551C9.63004 16.5947 9.91407 16.7182 10.304 16.8249C10.6947 16.9317 10.99 17.0424 11.1914 17.1571C11.3928 17.2718 11.5444 17.4082 11.6455 17.5679C11.7474 17.7276 11.798 17.9153 11.798 18.1328C11.798 18.4754 11.6608 18.7506 11.3872 18.9576C11.1136 19.1646 10.7525 19.2681 10.304 19.2681C9.99751 19.2681 9.71589 19.2135 9.45994 19.1036C9.204 18.9937 9.00983 18.8404 8.87745 18.643C8.74506 18.4457 8.67847 18.2194 8.67847 17.9651H9.04594C9.04594 18.2716 9.16067 18.5139 9.38934 18.6912C9.618 18.8685 9.92289 18.9568 10.304 18.9568C10.6426 18.9568 10.9146 18.8821 11.12 18.7329C11.3254 18.5837 11.4281 18.3855 11.4281 18.1384L11.4289 18.1368Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_56",
+ "d": "M15.7455 17.267C15.7455 17.6673 15.6765 18.0188 15.5377 18.3221C15.3989 18.6245 15.2015 18.858 14.9448 19.0217C14.688 19.1854 14.3911 19.2664 14.0542 19.2664C13.5463 19.2664 13.1355 19.0843 12.8234 18.7208C12.5105 18.3574 12.354 17.8663 12.354 17.2493V16.8008C12.354 16.4045 12.4246 16.053 12.565 15.7473C12.7054 15.4417 12.9044 15.2066 13.1612 15.0421C13.4179 14.8776 13.714 14.7958 14.0485 14.7958C14.3831 14.7958 14.6784 14.8768 14.9343 15.0381C15.1903 15.1994 15.3876 15.4272 15.5273 15.7225C15.6669 16.0177 15.7391 16.3587 15.7455 16.7479V17.2678V17.267ZM15.378 16.7944C15.378 16.2705 15.2593 15.8597 15.0226 15.5628C14.7851 15.2659 14.4609 15.1175 14.0485 15.1175C13.6361 15.1175 13.3216 15.2667 13.0817 15.5644C12.8418 15.8621 12.7215 16.2785 12.7215 16.8121V17.2662C12.7215 17.7821 12.841 18.1913 13.0801 18.4929C13.3192 18.7946 13.6442 18.9455 14.0542 18.9455C14.4642 18.9455 14.7955 18.7962 15.0282 18.4986C15.2617 18.2009 15.378 17.7861 15.378 17.2541V16.7936V16.7944Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_57",
+ "d": "M19.6922 17.8495C19.6425 18.3076 19.4788 18.6583 19.2004 18.9014C18.922 19.1445 18.5521 19.2656 18.09 19.2656C17.7674 19.2656 17.4818 19.1846 17.2339 19.0233C16.9859 18.862 16.7942 18.6334 16.6586 18.3373C16.523 18.0413 16.454 17.7035 16.4524 17.3224V16.7575C16.4524 16.3708 16.5198 16.0282 16.6554 15.7297C16.791 15.4312 16.9859 15.2002 17.2395 15.0381C17.4938 14.876 17.7859 14.7942 18.1164 14.7942C18.5826 14.7942 18.9509 14.9194 19.2205 15.1705C19.49 15.4216 19.6473 15.769 19.6914 16.2135H19.3208C19.2293 15.4746 18.8273 15.1047 18.1164 15.1047C17.7217 15.1047 17.408 15.2523 17.1737 15.5476C16.9394 15.8428 16.8223 16.2504 16.8223 16.7712V17.3039C16.8223 17.8062 16.9362 18.2073 17.1641 18.5058C17.3919 18.8051 17.7008 18.9543 18.0892 18.9543C18.4775 18.9543 18.7631 18.862 18.9589 18.6775C19.1539 18.493 19.275 18.217 19.3208 17.8479H19.6914L19.6922 17.8495Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_58",
+ "d": "M6.00195 13.5538H22.5871",
+ "stroke": "white",
+ "stroke-width": "0.111926",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_4"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_59",
+ "d": "M8.72524 21.7257C8.71722 21.7089 8.71 21.68 8.70518 21.6374C8.63859 21.7064 8.55916 21.7409 8.46609 21.7409C8.38345 21.7409 8.31525 21.7177 8.26229 21.6711C8.20934 21.6246 8.18286 21.5652 8.18286 21.493C8.18286 21.4056 8.21576 21.3382 8.28235 21.2892C8.34895 21.2411 8.44202 21.217 8.56237 21.217H8.70197V21.1512C8.70197 21.1015 8.68673 21.0614 8.65704 21.0317C8.62736 21.002 8.58323 20.9868 8.52466 20.9868C8.47331 20.9868 8.43078 20.9996 8.39628 21.0253C8.36178 21.0509 8.34413 21.0822 8.34413 21.1191H8.19971C8.19971 21.0774 8.21496 21.0365 8.24464 20.998C8.27433 20.9587 8.31444 20.9282 8.36579 20.9057C8.41634 20.8833 8.47251 20.8712 8.53348 20.8712C8.63057 20.8712 8.70599 20.8953 8.76055 20.9434C8.8151 20.9916 8.84399 21.0582 8.84559 21.1432V21.5291C8.84559 21.6062 8.85522 21.6671 8.87528 21.7129V21.7249H8.72444L8.72524 21.7257ZM8.48695 21.6166C8.53188 21.6166 8.5744 21.6046 8.61452 21.5821C8.65464 21.5588 8.68432 21.5283 8.70197 21.4914V21.3189H8.58965C8.41393 21.3189 8.32568 21.3703 8.32568 21.473C8.32568 21.5179 8.34092 21.5532 8.37061 21.5781C8.4003 21.6037 8.43881 21.6158 8.48615 21.6158L8.48695 21.6166Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_60",
+ "d": "M9.03174 20.6642C9.03174 20.6409 9.03896 20.6209 9.0534 20.6056C9.06784 20.5904 9.0887 20.5815 9.11679 20.5815C9.14487 20.5815 9.16573 20.5896 9.18017 20.6056C9.19461 20.6217 9.20183 20.6409 9.20183 20.6642C9.20183 20.6875 9.19461 20.7067 9.18017 20.722C9.16573 20.7372 9.14487 20.7452 9.11679 20.7452C9.0887 20.7452 9.06784 20.7372 9.0534 20.722C9.03896 20.7067 9.03174 20.6866 9.03174 20.6642ZM9.18659 21.7257H9.04297V20.8864H9.18659V21.7257Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_61",
+ "d": "M9.71276 21.6246C9.76411 21.6246 9.80824 21.6094 9.84675 21.5781C9.88526 21.5468 9.90612 21.5083 9.91013 21.4618H10.0457C10.0433 21.5099 10.0265 21.5556 9.99598 21.599C9.96549 21.6423 9.92457 21.6768 9.87403 21.7025C9.82348 21.7281 9.76892 21.741 9.71276 21.741C9.59882 21.741 9.50736 21.7025 9.43996 21.6262C9.37257 21.55 9.33887 21.4457 9.33887 21.3133V21.2893C9.33887 21.2074 9.35411 21.1352 9.3838 21.071C9.41348 21.0076 9.45681 20.9579 9.51297 20.9226C9.56914 20.8873 9.63573 20.8696 9.71195 20.8696C9.80583 20.8696 9.88446 20.8977 9.94624 20.9539C10.0088 21.01 10.0417 21.0831 10.0457 21.1737H9.91013C9.90612 21.1192 9.88526 21.075 9.84835 21.0397C9.81144 21.0052 9.76571 20.9876 9.71115 20.9876C9.63814 20.9876 9.58198 21.0141 9.54186 21.0662C9.50174 21.1184 9.48168 21.1946 9.48168 21.2941V21.3213C9.48168 21.4184 9.50174 21.4922 9.54106 21.5444C9.58117 21.5965 9.63814 21.623 9.71195 21.623L9.71276 21.6246Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_62",
+ "d": "M10.877 21.3156C10.877 21.4432 10.8481 21.5459 10.7895 21.6245C10.731 21.7024 10.6523 21.7417 10.552 21.7417C10.4518 21.7417 10.3699 21.7096 10.3113 21.6446V22.049H10.1677V20.8872H10.2985L10.3057 20.9803C10.3643 20.9081 10.4453 20.8719 10.5488 20.8719C10.6523 20.8719 10.7294 20.9097 10.7879 20.9859C10.8465 21.0621 10.8762 21.168 10.8762 21.3028V21.3156H10.877ZM10.7334 21.2996C10.7334 21.2049 10.7133 21.1303 10.6732 21.0757C10.6331 21.0212 10.5777 20.9939 10.5071 20.9939C10.4205 20.9939 10.3555 21.0324 10.3113 21.1094V21.5106C10.3547 21.5868 10.4197 21.6253 10.5087 21.6253C10.5777 21.6253 10.6323 21.5981 10.6724 21.5435C10.7133 21.4889 10.7334 21.4079 10.7334 21.3004V21.2996Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_63",
+ "d": "M11.5373 21.7257C11.5292 21.7089 11.522 21.68 11.5172 21.6374C11.4506 21.7064 11.3712 21.7409 11.2781 21.7409C11.1955 21.7409 11.1273 21.7177 11.0743 21.6711C11.0214 21.6246 10.9949 21.5652 10.9949 21.493C10.9949 21.4056 11.0278 21.3382 11.0944 21.2892C11.161 21.2411 11.254 21.217 11.3744 21.217H11.514V21.1512C11.514 21.1015 11.4987 21.0614 11.4691 21.0317C11.4394 21.002 11.3952 20.9868 11.3367 20.9868C11.2853 20.9868 11.2428 20.9996 11.2083 21.0253C11.1738 21.0509 11.1561 21.0822 11.1561 21.1191H11.0117C11.0117 21.0774 11.027 21.0365 11.0567 20.998C11.0863 20.9587 11.1265 20.9282 11.1778 20.9057C11.2284 20.8833 11.2845 20.8712 11.3455 20.8712C11.4426 20.8712 11.518 20.8953 11.5726 20.9434C11.6271 20.9916 11.656 21.0582 11.6576 21.1432V21.5291C11.6576 21.6062 11.6672 21.6671 11.6873 21.7129V21.7249H11.5365L11.5373 21.7257ZM11.299 21.6166C11.3439 21.6166 11.3864 21.6046 11.4265 21.5821C11.4666 21.5588 11.4963 21.5283 11.514 21.4914V21.3189H11.4017C11.2259 21.3189 11.1377 21.3703 11.1377 21.473C11.1377 21.5179 11.1529 21.5532 11.1826 21.5781C11.2123 21.6037 11.2508 21.6158 11.2982 21.6158L11.299 21.6166Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_64",
+ "d": "M11.8462 21.6511C11.8462 21.6262 11.8534 21.6054 11.8687 21.5893C11.8839 21.5733 11.9056 21.5645 11.9353 21.5645C11.9649 21.5645 11.9874 21.5725 12.0026 21.5893C12.0179 21.6062 12.0259 21.6262 12.0259 21.6511C12.0259 21.676 12.0179 21.6944 12.0026 21.7105C11.9874 21.7265 11.9649 21.7346 11.9353 21.7346C11.9056 21.7346 11.8839 21.7265 11.8687 21.7105C11.8534 21.6944 11.8462 21.6744 11.8462 21.6511Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_65",
+ "d": "M12.1841 21.2988C12.1841 21.217 12.2001 21.1423 12.2322 21.0773C12.2643 21.0124 12.3092 20.961 12.367 20.9257C12.4248 20.8904 12.4906 20.8719 12.5644 20.8719C12.6783 20.8719 12.7714 20.9113 12.842 20.9907C12.9126 21.0701 12.9479 21.1752 12.9479 21.306V21.3164C12.9479 21.3983 12.9327 21.4713 12.9014 21.5363C12.8701 21.6013 12.8252 21.6518 12.7674 21.6879C12.7088 21.724 12.6422 21.7425 12.5668 21.7425C12.4529 21.7425 12.3606 21.7032 12.29 21.6237C12.2194 21.5443 12.1841 21.44 12.1841 21.31V21.2996V21.2988ZM12.3277 21.3156C12.3277 21.4087 12.3494 21.4833 12.3927 21.5395C12.436 21.5957 12.4938 21.6237 12.566 21.6237C12.6382 21.6237 12.6968 21.5949 12.7393 21.5379C12.7818 21.4809 12.8035 21.4007 12.8035 21.298C12.8035 21.2057 12.7818 21.1311 12.7377 21.0741C12.6944 21.0172 12.6358 20.9883 12.5636 20.9883C12.4914 20.9883 12.436 21.0164 12.3919 21.0725C12.3478 21.1287 12.3269 21.2097 12.3269 21.3148L12.3277 21.3156Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_66",
+ "d": "M13.4936 21.0156C13.472 21.0124 13.4487 21.01 13.423 21.01C13.3292 21.01 13.265 21.0501 13.2313 21.1304V21.7257H13.0876V20.8865H13.2273L13.2297 20.9835C13.277 20.9089 13.3436 20.8712 13.4294 20.8712C13.4575 20.8712 13.4784 20.8744 13.4928 20.8824V21.0156H13.4936Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_67",
+ "d": "M13.5361 21.2996C13.5361 21.1688 13.5666 21.0645 13.6268 20.9875C13.687 20.9105 13.7672 20.8719 13.8675 20.8719C13.9678 20.8719 14.0496 20.9081 14.1074 20.9803L14.1146 20.8872H14.2454V21.7064C14.2454 21.8147 14.2133 21.9005 14.1491 21.9631C14.0849 22.0257 13.9983 22.057 13.89 22.057C13.8298 22.057 13.7704 22.0442 13.7126 22.0185C13.6549 21.9928 13.6107 21.9575 13.5803 21.9126L13.6549 21.8267C13.7167 21.903 13.7913 21.9407 13.8803 21.9407C13.9501 21.9407 14.0047 21.9206 14.0432 21.8821C14.0825 21.8428 14.1018 21.7874 14.1018 21.716V21.6438C14.044 21.7104 13.9662 21.7433 13.8667 21.7433C13.7672 21.7433 13.6894 21.704 13.6284 21.6245C13.5674 21.5451 13.5369 21.4376 13.5369 21.3012L13.5361 21.2996ZM13.6806 21.3156C13.6806 21.4103 13.6998 21.4849 13.7391 21.5387C13.7776 21.5924 13.8322 21.6197 13.902 21.6197C13.9927 21.6197 14.0593 21.5788 14.101 21.4962V21.1135C14.0568 21.0332 13.9911 20.9931 13.9036 20.9931C13.8338 20.9931 13.7792 21.0204 13.7399 21.0749C13.7006 21.1295 13.6814 21.2097 13.6814 21.3164L13.6806 21.3156Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_68",
+ "d": "M14.4505 21.8228H14.3269L14.7987 20.5968H14.9214L14.4505 21.8228Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_69",
+ "d": "M15.5251 21.5035C15.5251 21.4649 15.5107 21.4345 15.481 21.4128C15.4521 21.3911 15.4008 21.3727 15.3286 21.3574C15.2556 21.3422 15.1986 21.3229 15.1553 21.3013C15.1127 21.2796 15.0815 21.2539 15.0606 21.2234C15.0405 21.1938 15.0301 21.1577 15.0301 21.1167C15.0301 21.0477 15.059 20.99 15.1176 20.9426C15.1761 20.8953 15.2499 20.8712 15.3406 20.8712C15.4361 20.8712 15.5131 20.8961 15.5717 20.945C15.6311 20.994 15.6607 21.0574 15.6607 21.1336H15.5163C15.5163 21.0943 15.4995 21.0606 15.4666 21.0317C15.4337 21.0028 15.3912 20.9892 15.3406 20.9892C15.2901 20.9892 15.2475 21.0004 15.2179 21.0237C15.1882 21.0461 15.1737 21.0758 15.1737 21.1127C15.1737 21.1472 15.1874 21.1737 15.2146 21.1913C15.2419 21.209 15.2917 21.2258 15.3631 21.2419C15.4345 21.2579 15.4931 21.2772 15.5372 21.2997C15.5813 21.3221 15.6142 21.3486 15.6359 21.3799C15.6575 21.4112 15.668 21.4489 15.668 21.4946C15.668 21.5692 15.6383 21.6294 15.5781 21.6752C15.5179 21.7201 15.4401 21.7434 15.3446 21.7434C15.2772 21.7434 15.2179 21.7313 15.1665 21.7081C15.1152 21.684 15.0742 21.6511 15.0453 21.6086C15.0165 21.566 15.0012 21.5195 15.0012 21.4698H15.1448C15.1472 21.5179 15.1665 21.5556 15.2026 21.5845C15.2387 21.6134 15.2861 21.627 15.3446 21.627C15.3992 21.627 15.4425 21.6158 15.4754 21.5941C15.5083 21.5725 15.5243 21.5428 15.5243 21.5059L15.5251 21.5035Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_70",
+ "d": "M15.7778 21.2988C15.7778 21.217 15.7939 21.1423 15.826 21.0773C15.8581 21.0124 15.903 20.961 15.9608 20.9257C16.0185 20.8904 16.0843 20.8719 16.1581 20.8719C16.2721 20.8719 16.3651 20.9113 16.4358 20.9907C16.5064 21.0701 16.5417 21.1752 16.5417 21.306V21.3164C16.5417 21.3983 16.5264 21.4713 16.4951 21.5363C16.4638 21.6013 16.4189 21.6518 16.3611 21.6879C16.3026 21.724 16.236 21.7425 16.1605 21.7425C16.0466 21.7425 15.9543 21.7032 15.8837 21.6237C15.8131 21.5443 15.7778 21.44 15.7778 21.31V21.2996V21.2988ZM15.9223 21.3156C15.9223 21.4087 15.9439 21.4833 15.9872 21.5395C16.0306 21.5957 16.0883 21.6237 16.1605 21.6237C16.2328 21.6237 16.2913 21.5949 16.3339 21.5379C16.3764 21.4809 16.398 21.4007 16.398 21.298C16.398 21.2057 16.3764 21.1311 16.3322 21.0741C16.2889 21.0172 16.2304 20.9883 16.1581 20.9883C16.0859 20.9883 16.0306 21.0164 15.9864 21.0725C15.9423 21.1287 15.9215 21.2097 15.9215 21.3148L15.9223 21.3156Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_71",
+ "d": "M17.0182 21.6246C17.0695 21.6246 17.1137 21.6094 17.1522 21.5781C17.1907 21.5468 17.2115 21.5083 17.2156 21.4618H17.3511C17.3487 21.5099 17.3319 21.5556 17.3014 21.599C17.2709 21.6423 17.23 21.6768 17.1794 21.7025C17.1289 21.7281 17.0743 21.741 17.0182 21.741C16.9042 21.741 16.8128 21.7025 16.7454 21.6262C16.678 21.55 16.6443 21.4457 16.6443 21.3133V21.2893C16.6443 21.2074 16.6595 21.1352 16.6892 21.071C16.7189 21.0076 16.7622 20.9579 16.8184 20.9226C16.8746 20.8873 16.9412 20.8696 17.0174 20.8696C17.1112 20.8696 17.1899 20.8977 17.2517 20.9539C17.3142 21.01 17.3471 21.0831 17.3511 21.1737H17.2156C17.2115 21.1192 17.1907 21.075 17.1538 21.0397C17.1169 21.0052 17.0711 20.9876 17.0166 20.9876C16.9436 20.9876 16.8874 21.0141 16.8473 21.0662C16.8072 21.1184 16.7871 21.1946 16.7871 21.2941V21.3213C16.7871 21.4184 16.8072 21.4922 16.8465 21.5444C16.8866 21.5965 16.9436 21.623 17.0174 21.623L17.0182 21.6246Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_72",
+ "d": "M18.0637 21.3469H18.2202V21.4641H18.0637V21.7264H17.9193V21.4641H17.405V21.3798L17.9105 20.5975H18.0629V21.3477L18.0637 21.3469ZM17.5687 21.3469H17.9201V20.7933L17.9033 20.8246L17.5687 21.3469Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_73",
+ "d": "M18.814 21.5035C18.814 21.4649 18.7995 21.4345 18.7698 21.4128C18.7402 21.3911 18.6896 21.3727 18.6174 21.3574C18.5444 21.3422 18.4874 21.3229 18.4441 21.3013C18.4016 21.2796 18.3703 21.2539 18.3494 21.2234C18.3294 21.1938 18.3189 21.1577 18.3189 21.1167C18.3189 21.0477 18.3478 20.99 18.4064 20.9426C18.4649 20.8953 18.5388 20.8712 18.6294 20.8712C18.7249 20.8712 18.8019 20.8961 18.8605 20.945C18.9199 20.994 18.9496 21.0574 18.9496 21.1336H18.8051C18.8051 21.0943 18.7883 21.0606 18.7554 21.0317C18.7217 21.0036 18.68 20.9892 18.6294 20.9892C18.5789 20.9892 18.5364 21.0004 18.5067 21.0237C18.477 21.0461 18.4625 21.0758 18.4625 21.1127C18.4625 21.1472 18.4762 21.1737 18.5035 21.1913C18.5307 21.209 18.5805 21.2258 18.6519 21.2419C18.7233 21.2579 18.7819 21.2772 18.826 21.2997C18.8701 21.3221 18.903 21.3486 18.9247 21.3799C18.9464 21.4112 18.9568 21.4489 18.9568 21.4946C18.9568 21.5692 18.9271 21.6294 18.8669 21.6752C18.8067 21.7201 18.7289 21.7434 18.6334 21.7434C18.566 21.7434 18.5067 21.7313 18.4553 21.7081C18.404 21.684 18.3631 21.6511 18.3342 21.6086C18.3053 21.566 18.29 21.5195 18.29 21.4698H18.4337C18.4361 21.5179 18.4553 21.5556 18.4914 21.5845C18.5275 21.6126 18.5749 21.627 18.6334 21.627C18.688 21.627 18.7313 21.6158 18.7642 21.5941C18.7971 21.5725 18.8132 21.5428 18.8132 21.5059L18.814 21.5035Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_74",
+ "d": "M19.0664 21.2988C19.0664 21.217 19.0825 21.1423 19.1145 21.0773C19.1466 21.0116 19.1916 20.961 19.2493 20.9257C19.3071 20.8904 19.3729 20.8719 19.4467 20.8719C19.5606 20.8719 19.6537 20.9113 19.7243 20.9907C19.7949 21.0701 19.8302 21.1752 19.8302 21.306V21.3164C19.8302 21.3983 19.815 21.4713 19.7837 21.5363C19.7524 21.6013 19.7075 21.6518 19.6497 21.6879C19.5911 21.724 19.5245 21.7425 19.4491 21.7425C19.3352 21.7425 19.2429 21.7032 19.1723 21.6237C19.1017 21.5443 19.0664 21.44 19.0664 21.31V21.2996V21.2988ZM19.21 21.3156C19.21 21.4087 19.2317 21.4833 19.275 21.5395C19.3183 21.5957 19.3761 21.6237 19.4483 21.6237C19.5205 21.6237 19.5791 21.5949 19.6216 21.5379C19.665 21.4809 19.6858 21.4007 19.6858 21.298C19.6858 21.2057 19.6641 21.1311 19.62 21.0741C19.5767 21.0172 19.5181 20.9883 19.4459 20.9883C19.3737 20.9883 19.3183 21.0164 19.2742 21.0725C19.2301 21.1287 19.2092 21.2097 19.2092 21.3148L19.21 21.3156Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_75",
+ "d": "M25.8569 25.0298V25.1269H25.67V25.6147H25.5536V25.1269H25.3667V25.0298H25.8569ZM26.4892 25.6147L26.4675 25.2713C26.4651 25.2264 26.4651 25.1702 26.4635 25.1076H26.4571C26.4418 25.159 26.425 25.228 26.4073 25.2817L26.3022 25.6059H26.1819L26.0768 25.2729C26.0663 25.228 26.0487 25.159 26.0358 25.1076H26.0294C26.0294 25.1614 26.027 25.2175 26.0254 25.2713L26.0038 25.6147H25.8922L25.9356 25.0306H26.1097L26.2108 25.3162C26.2236 25.3612 26.234 25.4045 26.2493 25.4647H26.2517C26.2669 25.4109 26.2798 25.3612 26.2926 25.3186L26.3937 25.0306H26.5614L26.6063 25.6147H26.49H26.4892Z",
+ "fill": "#231F20"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_6186_11887",
+ "x1": "28",
+ "y1": "14",
+ "x2": "0",
+ "y2": "14",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#2161AD"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.18",
+ "stop-color": "#1F69B3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.47",
+ "stop-color": "#1C82C4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.84",
+ "stop-color": "#16A9E1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#14BDEF"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_6186_11887",
+ "x1": "3.13623",
+ "y1": "13.9999",
+ "x2": "24.8636",
+ "y2": "13.9999",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#2161AD"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.18",
+ "stop-color": "#1F69B3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.47",
+ "stop-color": "#1C82C4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.84",
+ "stop-color": "#16A9E1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#14BDEF"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Soc2"
+}
diff --git a/app/components/base/icons/src/public/common/Soc2.tsx b/app/components/base/icons/src/public/common/Soc2.tsx
new file mode 100644
index 0000000..b94d523
--- /dev/null
+++ b/app/components/base/icons/src/public/common/Soc2.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Soc2.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Soc2'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/SparklesSoft.json b/app/components/base/icons/src/public/common/SparklesSoft.json
new file mode 100644
index 0000000..11ac030
--- /dev/null
+++ b/app/components/base/icons/src/public/common/SparklesSoft.json
@@ -0,0 +1,47 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "sparkles-soft"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "opacity": "0.5",
+ "d": "M10.9963 1.36798C10.9839 1.25339 10.8909 1.16677 10.7802 1.16666C10.6695 1.16654 10.5763 1.25295 10.5636 1.36752C10.5045 1.90085 10.3525 2.26673 10.1143 2.5149C9.87599 2.76307 9.52476 2.92145 9.01275 2.98296C8.90277 2.99618 8.81983 3.09324 8.81995 3.20856C8.82006 3.32388 8.90322 3.42076 9.0132 3.43373C9.51653 3.49312 9.87583 3.65148 10.1201 3.90135C10.3631 4.14986 10.518 4.51523 10.563 5.04321C10.573 5.16035 10.6673 5.25012 10.7802 5.24999C10.8931 5.24986 10.9872 5.15987 10.9969 5.0427C11.0401 4.52364 11.1949 4.15004 11.4394 3.89528C11.684 3.64052 12.0426 3.47926 12.5409 3.43433C12.6534 3.42419 12.7398 3.32619 12.7399 3.20858C12.7401 3.09097 12.6539 2.99277 12.5414 2.98236C12.0346 2.93546 11.6838 2.77407 11.4452 2.52098C11.2054 2.2665 11.0533 1.89229 10.9963 1.36798Z",
+ "fill": "#F5F8FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M7.13646 2.85102C7.10442 2.55638 6.8653 2.33365 6.5806 2.33334C6.29595 2.33304 6.05633 2.55526 6.02374 2.84984C5.87186 4.22127 5.48089 5.1621 4.86827 5.80025C4.25565 6.43838 3.35245 6.84566 2.03587 7.00386C1.75307 7.03781 1.53975 7.28742 1.54004 7.58393C1.54033 7.88049 1.75415 8.12958 2.03701 8.16294C3.33132 8.31566 4.25509 8.72289 4.88328 9.36543C5.50807 10.0045 5.90647 10.9439 6.02222 12.3016C6.04793 12.6029 6.29035 12.8337 6.58066 12.8333C6.87102 12.833 7.11294 12.6016 7.13797 12.3003C7.24885 10.9656 7.64695 10.0049 8.27583 9.34979C8.90477 8.69471 9.82698 8.28002 11.1083 8.16452C11.3976 8.13844 11.6197 7.88644 11.62 7.58399C11.6204 7.28159 11.3988 7.02906 11.1096 7.00229C9.8062 6.88171 8.90432 6.46673 8.29084 5.81589C7.674 5.16152 7.28306 4.19926 7.13646 2.85102Z",
+ "fill": "#F5F8FF"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "SparklesSoft"
+}
diff --git a/app/components/base/icons/src/public/common/SparklesSoft.tsx b/app/components/base/icons/src/public/common/SparklesSoft.tsx
new file mode 100644
index 0000000..b3f94d0
--- /dev/null
+++ b/app/components/base/icons/src/public/common/SparklesSoft.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './SparklesSoft.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'SparklesSoft'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/common/index.ts b/app/components/base/icons/src/public/common/index.ts
new file mode 100644
index 0000000..dba789a
--- /dev/null
+++ b/app/components/base/icons/src/public/common/index.ts
@@ -0,0 +1,15 @@
+export { default as D } from './D'
+export { default as DiagonalDividingLine } from './DiagonalDividingLine'
+export { default as Dify } from './Dify'
+export { default as Gdpr } from './Gdpr'
+export { default as Github } from './Github'
+export { default as Highlight } from './Highlight'
+export { default as Iso } from './Iso'
+export { default as Line3 } from './Line3'
+export { default as Lock } from './Lock'
+export { default as MessageChatSquare } from './MessageChatSquare'
+export { default as MultiPathRetrieval } from './MultiPathRetrieval'
+export { default as NTo1Retrieval } from './NTo1Retrieval'
+export { default as Notion } from './Notion'
+export { default as Soc2 } from './Soc2'
+export { default as SparklesSoft } from './SparklesSoft'
diff --git a/app/components/base/icons/src/public/education/Triangle.json b/app/components/base/icons/src/public/education/Triangle.json
new file mode 100644
index 0000000..ab00049
--- /dev/null
+++ b/app/components/base/icons/src/public/education/Triangle.json
@@ -0,0 +1,27 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "22",
+ "viewBox": "0 0 16 22",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Rectangle 979",
+ "d": "M0 0H16L9.91493 16.7339C8.76529 19.8955 5.76063 22 2.39658 22H0V0Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Triangle"
+}
diff --git a/app/components/base/icons/src/public/education/Triangle.tsx b/app/components/base/icons/src/public/education/Triangle.tsx
new file mode 100644
index 0000000..85aa518
--- /dev/null
+++ b/app/components/base/icons/src/public/education/Triangle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Triangle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Triangle'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/education/index.ts b/app/components/base/icons/src/public/education/index.ts
new file mode 100644
index 0000000..de505db
--- /dev/null
+++ b/app/components/base/icons/src/public/education/index.ts
@@ -0,0 +1 @@
+export { default as Triangle } from './Triangle'
diff --git a/app/components/base/icons/src/public/files/Csv.json b/app/components/base/icons/src/public/files/Csv.json
new file mode 100644
index 0000000..533dcd7
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Csv.json
@@ -0,0 +1,181 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "34",
+ "viewBox": "0 0 32 34",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "File Icons/csv"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "sharp",
+ "filter": "url(#filter0_d_6816_769)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 7.73398C4 5.49377 4 4.37367 4.43597 3.51802C4.81947 2.76537 5.43139 2.15345 6.18404 1.76996C7.03969 1.33398 8.15979 1.33398 10.4 1.33398H18.6667L28 10.6673V24.2673C28 26.5075 28 27.6276 27.564 28.4833C27.1805 29.2359 26.5686 29.8478 25.816 30.2313C24.9603 30.6673 23.8402 30.6673 21.6 30.6673H10.4C8.15979 30.6673 7.03969 30.6673 6.18404 30.2313C5.43139 29.8478 4.81947 29.2359 4.43597 28.4833C4 27.6276 4 26.5075 4 24.2673V7.73398Z",
+ "fill": "#169951"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "CSV",
+ "opacity": "0.96"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.0846 21.8908C12.8419 23.3562 11.8246 24.0562 10.5646 24.0562C9.78992 24.0562 9.20192 23.7948 8.71659 23.3095C8.01659 22.6095 8.04459 21.6762 8.04459 20.6775C8.04459 19.6788 8.01659 18.7455 8.71659 18.0455C9.20192 17.5602 9.78992 17.2988 10.5646 17.2988C11.8246 17.2988 12.8419 17.9988 13.0846 19.4642H11.4233C11.3206 19.0908 11.1153 18.7548 10.5739 18.7548C10.2753 18.7548 10.0513 18.8762 9.92992 19.0348C9.78059 19.2308 9.67792 19.4642 9.67792 20.6775C9.67792 21.8908 9.78059 22.1242 9.92992 22.3202C10.0513 22.4788 10.2753 22.6002 10.5739 22.6002C11.1153 22.6002 11.3206 22.2642 11.4233 21.8908H13.0846Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.4081 21.9655C18.4081 23.3188 17.2414 24.0562 15.8414 24.0562C14.8241 24.0562 13.9934 23.8695 13.3214 23.1788L14.3668 22.1335C14.7121 22.4788 15.3188 22.6002 15.8508 22.6002C16.4948 22.6002 16.8028 22.3855 16.8028 22.0028C16.8028 21.8442 16.7654 21.7135 16.6721 21.6108C16.5881 21.5268 16.4481 21.4615 16.2334 21.4335L15.4308 21.3215C14.8428 21.2375 14.3948 21.0415 14.0961 20.7335C13.7881 20.4162 13.6388 19.9682 13.6388 19.3988C13.6388 18.1855 14.5534 17.2988 16.0654 17.2988C17.0174 17.2988 17.7361 17.5228 18.3054 18.0922L17.2788 19.1188C16.8588 18.6988 16.3081 18.7268 16.0188 18.7268C15.4494 18.7268 15.2161 19.0535 15.2161 19.3428C15.2161 19.4268 15.2441 19.5482 15.3468 19.6508C15.4308 19.7348 15.5708 19.8188 15.8041 19.8468L16.6068 19.9588C17.2041 20.0428 17.6334 20.2295 17.9134 20.5095C18.2681 20.8548 18.4081 21.3495 18.4081 21.9655Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M24.4166 17.3548L22.214 24.0002H21.0006L18.8073 17.3548H20.4966L21.6166 21.0695L22.718 17.3548H24.4166Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "bevel",
+ "opacity": "0.5",
+ "d": "M18.6667 1.33398L28.0001 10.6673H21.3334C19.8607 10.6673 18.6667 9.47341 18.6667 8.00065V1.33398Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_6816_769",
+ "x": "2",
+ "y": "0.333984",
+ "width": "28",
+ "height": "33.334",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_6816_769"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_6816_769",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Csv"
+}
diff --git a/app/components/base/icons/src/public/files/Csv.tsx b/app/components/base/icons/src/public/files/Csv.tsx
new file mode 100644
index 0000000..03ce2fb
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Csv.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Csv.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Csv'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Doc.json b/app/components/base/icons/src/public/files/Doc.json
new file mode 100644
index 0000000..9d219ad
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Doc.json
@@ -0,0 +1,169 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "34",
+ "viewBox": "0 0 32 34",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#filter0_d_17194_49206)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 7.73301C4 5.4928 4 4.37269 4.43597 3.51705C4.81947 2.7644 5.43139 2.15248 6.18404 1.76898C7.03969 1.33301 8.15979 1.33301 10.4 1.33301H18.6667L28 10.6663V24.2663C28 26.5066 28 27.6267 27.564 28.4823C27.1805 29.2349 26.5686 29.8469 25.816 30.2304C24.9603 30.6663 23.8402 30.6663 21.6 30.6663H10.4C8.15979 30.6663 7.03969 30.6663 6.18404 30.2304C5.43139 29.8469 4.81947 29.2349 4.43597 28.4823C4 27.6267 4 26.5066 4 24.2663V7.73301Z",
+ "fill": "#2349A9"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M18.6665 1.33301L27.9998 10.6663H21.3332C19.8604 10.6663 18.6665 9.47243 18.6665 7.99967V1.33301Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "opacity": "0.96"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.6329 21.4112C13.6329 22.2603 13.7059 22.9501 13.0326 23.5793C12.6351 23.9508 12.0754 24.11 11.4751 24.11H9.3335V18.7125H11.4751C12.0754 18.7125 12.6351 18.8717 13.0326 19.2431C13.7059 19.8723 13.6329 20.5622 13.6329 21.4112ZM12.2133 21.4112C12.2133 20.5015 12.1727 20.3499 12.0591 20.1983C11.9293 20.0164 11.7347 19.8951 11.3777 19.8951H10.7531V22.9274H11.3777C11.7347 22.9274 11.9293 22.8061 12.0591 22.6242C12.1727 22.4725 12.2133 22.3285 12.2133 21.4112Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.8275 21.4112C18.8275 22.2224 18.8519 22.9805 18.2435 23.549C17.8217 23.9432 17.3349 24.1555 16.6292 24.1555C15.9234 24.1555 15.4367 23.9432 15.0149 23.549C14.4065 22.9805 14.4308 22.2224 14.4308 21.4112C14.4308 20.6001 14.4065 19.842 15.0149 19.2735C15.4367 18.8793 15.9234 18.667 16.6292 18.667C17.3349 18.667 17.8217 18.8793 18.2435 19.2735C18.8519 19.842 18.8275 20.6001 18.8275 21.4112ZM17.4079 21.4112C17.4079 20.4257 17.3268 20.2438 17.197 20.0846C17.0916 19.9557 16.8888 19.8496 16.6292 19.8496C16.3696 19.8496 16.1668 19.9557 16.0613 20.0846C15.9316 20.2438 15.8504 20.4257 15.8504 21.4112C15.8504 22.3967 15.9316 22.5711 16.0613 22.7303C16.1668 22.8592 16.3696 22.9729 16.6292 22.9729C16.8888 22.9729 17.0916 22.8592 17.197 22.7303C17.3268 22.5711 17.4079 22.3967 17.4079 21.4112Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M24.0002 22.3967C23.7893 23.5869 22.905 24.1555 21.8099 24.1555C21.1366 24.1555 20.6256 23.9432 20.2037 23.549C19.5953 22.9805 19.6197 22.2224 19.6197 21.4112C19.6197 20.6001 19.5953 19.842 20.2037 19.2735C20.6256 18.8793 21.1366 18.667 21.8099 18.667C22.905 18.667 23.7893 19.2356 24.0002 20.4257H22.5562C22.467 20.1225 22.2885 19.8496 21.818 19.8496C21.5584 19.8496 21.3638 19.9481 21.2583 20.077C21.1285 20.2362 21.0393 20.4257 21.0393 21.4112C21.0393 22.3967 21.1285 22.5863 21.2583 22.7455C21.3638 22.8743 21.5584 22.9729 21.818 22.9729C22.2885 22.9729 22.467 22.7 22.5562 22.3967H24.0002Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_17194_49206",
+ "x": "2",
+ "y": "0.333008",
+ "width": "28",
+ "height": "33.333",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_17194_49206"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_17194_49206",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Doc"
+}
diff --git a/app/components/base/icons/src/public/files/Doc.tsx b/app/components/base/icons/src/public/files/Doc.tsx
new file mode 100644
index 0000000..e71773f
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Doc.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Doc.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Doc'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Docx.json b/app/components/base/icons/src/public/files/Docx.json
new file mode 100644
index 0000000..ffa9ef8
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Docx.json
@@ -0,0 +1,178 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "34",
+ "viewBox": "0 0 32 34",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#filter0_d_10291_62253)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 7.73301C4 5.4928 4 4.37269 4.43597 3.51705C4.81947 2.7644 5.43139 2.15248 6.18404 1.76898C7.03969 1.33301 8.15979 1.33301 10.4 1.33301H18.6667L28 10.6663V24.2663C28 26.5065 28 27.6267 27.564 28.4823C27.1805 29.2349 26.5686 29.8469 25.816 30.2304C24.9603 30.6663 23.8402 30.6663 21.6 30.6663H10.4C8.15979 30.6663 7.03969 30.6663 6.18404 30.2304C5.43139 29.8469 4.81947 29.2349 4.43597 28.4823C4 27.6267 4 26.5065 4 24.2663V7.73301Z",
+ "fill": "#2349A9"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M18.6665 1.33301L27.9998 10.6663H21.3332C19.8604 10.6663 18.6665 9.47243 18.6665 7.99967V1.33301Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "opacity": "0.96"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.8443 21.3337C10.8443 22.1587 10.9153 22.8291 10.261 23.4405C9.87477 23.8014 9.33086 23.9561 8.74754 23.9561H6.6665V18.7112H8.74754C9.33086 18.7112 9.87477 18.8659 10.261 19.2268C10.9153 19.8383 10.8443 20.5086 10.8443 21.3337ZM9.46487 21.3337C9.46487 20.4497 9.42545 20.3024 9.31509 20.155C9.18897 19.9782 8.99979 19.8604 8.65295 19.8604H8.04598V22.807H8.65295C8.99979 22.807 9.18897 22.6891 9.31509 22.5123C9.42545 22.365 9.46487 22.225 9.46487 21.3337Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.8922 21.3337C15.8922 22.1219 15.9158 22.8585 15.3246 23.411C14.9147 23.7941 14.4418 24.0003 13.756 24.0003C13.0702 24.0003 12.5972 23.7941 12.1873 23.411C11.5961 22.8585 11.6197 22.1219 11.6197 21.3337C11.6197 20.5454 11.5961 19.8088 12.1873 19.2563C12.5972 18.8733 13.0702 18.667 13.756 18.667C14.4418 18.667 14.9147 18.8733 15.3246 19.2563C15.9158 19.8088 15.8922 20.5454 15.8922 21.3337ZM14.5127 21.3337C14.5127 20.376 14.4339 20.1992 14.3077 20.0445C14.2053 19.9193 14.0082 19.8162 13.756 19.8162C13.5037 19.8162 13.3066 19.9193 13.2042 20.0445C13.078 20.1992 12.9992 20.376 12.9992 21.3337C12.9992 22.2913 13.078 22.4607 13.2042 22.6154C13.3066 22.7407 13.5037 22.8512 13.756 22.8512C14.0082 22.8512 14.2053 22.7407 14.3077 22.6154C14.4339 22.4607 14.5127 22.2913 14.5127 21.3337Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.9186 22.2913C20.7136 23.4478 19.8544 24.0003 18.7902 24.0003C18.136 24.0003 17.6394 23.7941 17.2295 23.411C16.6383 22.8585 16.6619 22.1219 16.6619 21.3337C16.6619 20.5454 16.6383 19.8088 17.2295 19.2563C17.6394 18.8733 18.136 18.667 18.7902 18.667C19.8544 18.667 20.7136 19.2195 20.9186 20.376H19.5154C19.4287 20.0814 19.2553 19.8162 18.7981 19.8162C18.5459 19.8162 18.3567 19.9119 18.2542 20.0372C18.1281 20.1919 18.0414 20.376 18.0414 21.3337C18.0414 22.2913 18.1281 22.4755 18.2542 22.6302C18.3567 22.7554 18.5459 22.8512 18.7981 22.8512C19.2553 22.8512 19.4287 22.586 19.5154 22.2913H20.9186Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M25.9998 23.9561H24.4233L23.501 22.3429L22.5787 23.9561H21.0022L22.7522 21.2674L21.1126 18.7112H22.6812L23.501 20.1919L24.3208 18.7112H25.8895L24.2499 21.2674L25.9998 23.9561Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_10291_62253",
+ "x": "2",
+ "y": "0.333008",
+ "width": "28",
+ "height": "33.333",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_10291_62253"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_10291_62253",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Docx"
+}
diff --git a/app/components/base/icons/src/public/files/Docx.tsx b/app/components/base/icons/src/public/files/Docx.tsx
new file mode 100644
index 0000000..25d5d06
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Docx.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Docx.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Docx'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Html.json b/app/components/base/icons/src/public/files/Html.json
new file mode 100644
index 0000000..f267073
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Html.json
@@ -0,0 +1,178 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "34",
+ "viewBox": "0 0 32 34",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#filter0_d_3055_14424)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z",
+ "fill": "#EC5B27"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "opacity": "0.96"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.2704 24.0002V18.3042H8.87042V20.4962H7.38242V18.3042H5.98242V24.0002H7.38242V21.7442H8.87042V24.0002H10.2704Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.2839 19.5522V18.3042H11.0839V19.5522H12.4839V24.0002H13.8839V19.5522H15.2839Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.4116 24.0002V18.3042H20.0356L18.7556 20.8162L17.4756 18.3042H16.0996V24.0002H17.4996V21.2722L18.3076 22.6802H19.2036L20.0116 21.2722V24.0002H21.4116Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M26.3525 24.0002V22.7522H23.9605V18.3042H22.5605V24.0002H26.3525Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_3055_14424",
+ "x": "2",
+ "y": "0.333496",
+ "width": "28",
+ "height": "33.3335",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_3055_14424"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_3055_14424",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Html"
+}
diff --git a/app/components/base/icons/src/public/files/Html.tsx b/app/components/base/icons/src/public/files/Html.tsx
new file mode 100644
index 0000000..65b333d
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Html.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Html.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Html'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Json.json b/app/components/base/icons/src/public/files/Json.json
new file mode 100644
index 0000000..0801fec
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Json.json
@@ -0,0 +1,178 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "34",
+ "viewBox": "0 0 32 34",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#filter0_d_3055_14428)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z",
+ "fill": "#2D2D2E"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "opacity": "0.96"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.83907 22.0479V18.3039H8.43907V22.0159C8.43907 22.5599 8.12707 22.7999 7.69507 22.7999C7.38307 22.7999 7.23907 22.6879 7.06307 22.5119L6.14307 23.4239C6.60707 23.8879 7.03107 24.0479 7.69507 24.0479C8.76707 24.0479 9.83907 23.3999 9.83907 22.0479Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.7321 22.2559C14.7321 21.7279 14.6121 21.3039 14.3081 21.0079C14.0681 20.7679 13.7001 20.6079 13.1881 20.5359L12.5001 20.4399C12.3001 20.4159 12.1801 20.3439 12.1081 20.2719C12.0201 20.1839 11.9961 20.0799 11.9961 20.0079C11.9961 19.7599 12.1961 19.4799 12.6841 19.4799C12.9321 19.4799 13.4041 19.4559 13.7641 19.8159L14.6441 18.9359C14.1561 18.4479 13.5401 18.2559 12.7241 18.2559C11.4281 18.2559 10.6441 19.0159 10.6441 20.0559C10.6441 20.5439 10.7721 20.9279 11.0361 21.1999C11.2921 21.4639 11.6761 21.6319 12.1801 21.7039L12.8681 21.7999C13.0521 21.8239 13.1721 21.8799 13.2441 21.9519C13.3241 22.0399 13.3561 22.1519 13.3561 22.2879C13.3561 22.6159 13.0921 22.7999 12.5401 22.7999C12.0841 22.7999 11.5641 22.6959 11.2681 22.3999L10.3721 23.2959C10.9481 23.8879 11.6601 24.0479 12.5321 24.0479C13.7321 24.0479 14.7321 23.4159 14.7321 22.2559Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.8023 21.1519C19.8023 20.2959 19.8263 19.4959 19.2263 18.8959C18.8103 18.4799 18.3303 18.2559 17.6343 18.2559C16.9383 18.2559 16.4583 18.4799 16.0423 18.8959C15.4423 19.4959 15.4663 20.2959 15.4663 21.1519C15.4663 22.0079 15.4423 22.8079 16.0423 23.4079C16.4583 23.8239 16.9383 24.0479 17.6343 24.0479C18.3303 24.0479 18.8103 23.8239 19.2263 23.4079C19.8263 22.8079 19.8023 22.0079 19.8023 21.1519ZM18.4023 21.1519C18.4023 22.1919 18.3223 22.3759 18.1943 22.5439C18.0903 22.6799 17.8903 22.7999 17.6343 22.7999C17.3783 22.7999 17.1783 22.6799 17.0743 22.5439C16.9463 22.3759 16.8663 22.1919 16.8663 21.1519C16.8663 20.1119 16.9463 19.9199 17.0743 19.7519C17.1783 19.6159 17.3783 19.5039 17.6343 19.5039C17.8903 19.5039 18.0903 19.6159 18.1943 19.7519C18.3223 19.9199 18.4023 20.1119 18.4023 21.1519Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M25.2154 23.9999V18.3039H23.8154V21.1679L21.9914 18.3039H20.7674V23.9999H22.1674V21.1359L23.9914 23.9999H25.2154Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_3055_14428",
+ "x": "2",
+ "y": "0.333496",
+ "width": "28",
+ "height": "33.3335",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_3055_14428"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_3055_14428",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Json"
+}
diff --git a/app/components/base/icons/src/public/files/Json.tsx b/app/components/base/icons/src/public/files/Json.tsx
new file mode 100644
index 0000000..90812be
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Json.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Json.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Json'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Md.json b/app/components/base/icons/src/public/files/Md.json
new file mode 100644
index 0000000..4a3cb68
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Md.json
@@ -0,0 +1,144 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "34",
+ "viewBox": "0 0 32 34",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#filter0_d_3777_37339)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z",
+ "fill": "#309BEC"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M21.9904 25.3335H10.0096C9.45202 25.3335 9 24.9138 9 24.396V18.271C9 17.7532 9.45202 17.3335 10.0096 17.3335H21.9904C22.548 17.3335 23 17.7532 23 18.271V24.396C23 24.9138 22.548 25.3335 21.9904 25.3335ZM12.3654 23.4585V21.021L13.7115 22.5835L15.0577 21.021V23.4585H16.4038V19.2085H15.0577L13.7115 20.771L12.3654 19.2085H11.0192V23.4585H12.3654ZM20.0385 21.3335H21.3846L19.3654 23.521L17.3462 21.3335H18.6923V19.2085H20.0385V21.3335Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_3777_37339",
+ "x": "2",
+ "y": "0.333496",
+ "width": "28",
+ "height": "33.3335",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_3777_37339"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_3777_37339",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Md"
+}
diff --git a/app/components/base/icons/src/public/files/Md.tsx b/app/components/base/icons/src/public/files/Md.tsx
new file mode 100644
index 0000000..25d4205
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Md.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Md.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Md'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Pdf.json b/app/components/base/icons/src/public/files/Pdf.json
new file mode 100644
index 0000000..7770f27
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Pdf.json
@@ -0,0 +1,169 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "34",
+ "viewBox": "0 0 32 34",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#filter0_d_3055_14420)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z",
+ "fill": "#DD3633"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "opacity": "0.96"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.2801 20.1362C13.2801 19.2002 12.6001 18.3042 11.3361 18.3042H9.08008V24.0002H10.4801V21.9682H11.3361C12.6001 21.9682 13.2801 21.0722 13.2801 20.1362ZM11.8801 20.1362C11.8801 20.4322 11.6561 20.7122 11.2721 20.7122H10.4801V19.5602H11.2721C11.6561 19.5602 11.8801 19.8402 11.8801 20.1362Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.3357 21.1522C18.3357 20.2562 18.4077 19.5282 17.7437 18.8642C17.3517 18.4722 16.7997 18.3042 16.2077 18.3042H14.0957V24.0002H16.2077C16.7997 24.0002 17.3517 23.8322 17.7437 23.4402C18.4077 22.7762 18.3357 22.0482 18.3357 21.1522ZM16.9357 21.1522C16.9357 22.1202 16.8957 22.2722 16.7837 22.4322C16.6557 22.6242 16.4637 22.7522 16.1117 22.7522H15.4957V19.5522H16.1117C16.4637 19.5522 16.6557 19.6802 16.7837 19.8722C16.8957 20.0322 16.9357 20.1922 16.9357 21.1522Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M23.1786 19.5522V18.3042H19.3066V24.0002H20.7066V21.8002H22.8186V20.5522H20.7066V19.5522H23.1786Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_3055_14420",
+ "x": "2",
+ "y": "0.333496",
+ "width": "28",
+ "height": "33.3335",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_3055_14420"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_3055_14420",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Pdf"
+}
diff --git a/app/components/base/icons/src/public/files/Pdf.tsx b/app/components/base/icons/src/public/files/Pdf.tsx
new file mode 100644
index 0000000..15444df
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Pdf.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Pdf.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Pdf'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Txt.json b/app/components/base/icons/src/public/files/Txt.json
new file mode 100644
index 0000000..c689fc6
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Txt.json
@@ -0,0 +1,180 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "34",
+ "viewBox": "0 0 32 34",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#filter0_d_3055_14432)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z",
+ "fill": "#E3E5E8"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.25 7.73349C4.25 6.60926 4.25019 5.78113 4.30367 5.12666C4.3569 4.47511 4.46169 4.01774 4.65873 3.63103C5.01825 2.92542 5.59193 2.35175 6.29754 1.99222C6.68424 1.79518 7.14162 1.6904 7.79317 1.63716C8.44763 1.58369 9.27577 1.5835 10.4 1.5835H18.5631L27.75 10.7704V24.2668C27.75 25.3911 27.7498 26.2192 27.6963 26.8737C27.6431 27.5252 27.5383 27.9826 27.3413 28.3693C26.9817 29.0749 26.4081 29.6486 25.7025 30.0081C25.3158 30.2051 24.8584 30.3099 24.2068 30.3632C23.5524 30.4166 22.7242 30.4168 21.6 30.4168H10.4C9.27577 30.4168 8.44763 30.4166 7.79317 30.3632C7.14162 30.3099 6.68424 30.2051 6.29754 30.0081C5.59193 29.6486 5.01825 29.0749 4.65873 28.3693C4.46169 27.9826 4.3569 27.5252 4.30367 26.8737C4.25019 26.2192 4.25 25.3911 4.25 24.2668V7.73349Z",
+ "stroke": "black",
+ "stroke-opacity": "0.03",
+ "stroke-width": "0.5"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "opacity": "0.96"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.2254 19.5522V18.3042H9.02539V19.5522H10.4254V24.0002H11.8254V19.5522H13.2254Z",
+ "fill": "#667085"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.5371 24.0002L16.7611 21.0802L18.4251 18.3042H16.8331L16.0011 19.9122L15.1691 18.3042H13.5771L15.2411 21.0802L13.4651 24.0002H15.0651L16.0011 22.2482L16.9371 24.0002H18.5371Z",
+ "fill": "#667085"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M22.9754 19.5522V18.3042H18.7754V19.5522H20.1754V24.0002H21.5754V19.5522H22.9754Z",
+ "fill": "#667085"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_3055_14432",
+ "x": "2",
+ "y": "0.333496",
+ "width": "28",
+ "height": "33.3335",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_3055_14432"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_3055_14432",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Txt"
+}
diff --git a/app/components/base/icons/src/public/files/Txt.tsx b/app/components/base/icons/src/public/files/Txt.tsx
new file mode 100644
index 0000000..7b1f16c
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Txt.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Txt.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Txt'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Unknown.json b/app/components/base/icons/src/public/files/Unknown.json
new file mode 100644
index 0000000..f1351e0
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Unknown.json
@@ -0,0 +1,199 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "34",
+ "viewBox": "0 0 32 34",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#filter0_d_3055_14436)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z",
+ "fill": "#E3E5E8"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.25 7.73349C4.25 6.60926 4.25019 5.78113 4.30367 5.12666C4.3569 4.47511 4.46169 4.01774 4.65873 3.63103C5.01825 2.92542 5.59193 2.35175 6.29754 1.99222C6.68424 1.79518 7.14162 1.6904 7.79317 1.63716C8.44763 1.58369 9.27577 1.5835 10.4 1.5835H18.5631L27.75 10.7704V24.2668C27.75 25.3911 27.7498 26.2192 27.6963 26.8737C27.6431 27.5252 27.5383 27.9826 27.3413 28.3693C26.9817 29.0749 26.4081 29.6486 25.7025 30.0081C25.3158 30.2051 24.8584 30.3099 24.2068 30.3632C23.5524 30.4166 22.7242 30.4168 21.6 30.4168H10.4C9.27577 30.4168 8.44763 30.4166 7.79317 30.3632C7.14162 30.3099 6.68424 30.2051 6.29754 30.0081C5.59193 29.6486 5.01825 29.0749 4.65873 28.3693C4.46169 27.9826 4.3569 27.5252 4.30367 26.8737C4.25019 26.2192 4.25 25.3911 4.25 24.2668V7.73349Z",
+ "stroke": "black",
+ "stroke-opacity": "0.03",
+ "stroke-width": "0.5"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M15.9998 23.1992C15.8014 23.1992 15.6039 23.1968 15.4077 23.1924V24.0549C15.4077 24.3819 15.6728 24.647 15.9998 24.647C16.3268 24.647 16.592 24.3819 16.592 24.0549V23.1924C16.3957 23.1968 16.1983 23.1992 15.9998 23.1992Z",
+ "fill": "#98A2B3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12.0984 22.8838L11.757 23.8593C11.649 24.168 11.8117 24.5058 12.1203 24.6138C12.185 24.6364 12.251 24.6472 12.3159 24.6472C12.5605 24.6472 12.7894 24.4944 12.8747 24.2505L13.2936 23.0534C12.8807 23.0073 12.481 22.9506 12.0984 22.8838Z",
+ "fill": "#98A2B3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M20.2431 23.8593L19.9018 22.8838C19.5192 22.9506 19.1195 23.0073 18.7065 23.0534L19.1254 24.2505C19.2108 24.4944 19.4396 24.6472 19.6843 24.6472C19.7491 24.6472 19.8151 24.6364 19.8798 24.6138C20.1885 24.5058 20.3511 24.168 20.2431 23.8593Z",
+ "fill": "#98A2B3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M20.1624 17.2634C20.2697 17.6416 20.3254 18.0369 20.3254 18.4409C20.3254 18.9087 20.05 19.3327 19.6226 19.5228C19.5564 19.5522 17.9801 20.2436 16.0359 20.2436C14.0917 20.2436 12.5153 19.5522 12.4492 19.5228C12.0218 19.3327 11.7464 18.9086 11.7464 18.4409C11.7464 18.0312 11.8037 17.6305 11.914 17.2476C10.3343 17.5645 8.5 18.2009 8.5 19.4464C8.5 20.2859 9.32512 20.9477 10.9525 21.4134C11.4194 21.547 11.9381 21.66 12.4949 21.7506C12.8783 21.813 13.28 21.8648 13.6953 21.9056C14.2455 21.9597 14.8197 21.9942 15.4079 22.0082C15.6039 22.0128 15.8013 22.0153 16 22.0153C16.1987 22.0153 16.3962 22.0128 16.5921 22.0082C17.1803 21.9943 17.7545 21.9596 18.3047 21.9056C18.72 21.8648 19.1217 21.8131 19.5051 21.7506C20.062 21.66 20.5807 21.547 21.0476 21.4134C22.6749 20.9477 23.5 20.2859 23.5 19.4464C23.5 18.2187 21.7108 17.5833 20.1624 17.2634Z",
+ "fill": "#98A2B3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M18.8441 17.1144C18.7585 16.9335 18.6559 16.7622 18.5384 16.6025C18.4174 16.4382 18.2809 16.286 18.1307 16.1486C17.5784 15.6437 16.8433 15.3354 16.036 15.3354C15.2318 15.3354 14.499 15.6411 13.9476 16.1426C13.7974 16.2791 13.6609 16.4303 13.5399 16.5937C13.4217 16.753 13.3185 16.924 13.2322 17.1048C13.039 17.5095 12.9307 17.9624 12.9307 18.4407C12.9307 18.4407 14.321 19.0592 16.036 19.0592C17.751 19.0592 19.1412 18.4407 19.1412 18.4407C19.1412 17.9662 19.0344 17.5167 18.8441 17.1144Z",
+ "fill": "#98A2B3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_3055_14436",
+ "x": "2",
+ "y": "0.333496",
+ "width": "28",
+ "height": "33.3335",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_3055_14436"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_3055_14436",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Unknown"
+}
diff --git a/app/components/base/icons/src/public/files/Unknown.tsx b/app/components/base/icons/src/public/files/Unknown.tsx
new file mode 100644
index 0000000..1b7c658
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Unknown.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Unknown.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Unknown'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Xlsx.json b/app/components/base/icons/src/public/files/Xlsx.json
new file mode 100644
index 0000000..5f0e7a9
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Xlsx.json
@@ -0,0 +1,145 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "26",
+ "viewBox": "0 0 24 26",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#filter0_d_5938_927)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3 5.8C3 4.11984 3 3.27976 3.32698 2.63803C3.6146 2.07354 4.07354 1.6146 4.63803 1.32698C5.27976 1 6.11984 1 7.8 1H14L21 8V18.2C21 19.8802 21 20.7202 20.673 21.362C20.3854 21.9265 19.9265 22.3854 19.362 22.673C18.7202 23 17.8802 23 16.2 23H7.8C6.11984 23 5.27976 23 4.63803 22.673C4.07354 22.3854 3.6146 21.9265 3.32698 21.362C3 20.7202 3 19.8802 3 18.2V5.8Z",
+ "fill": "#169951"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M14 1L21 8H16C14.8954 8 14 7.10457 14 6V1Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M17 12C17.5523 12 18 12.4477 18 13V18C18 18.5523 17.5523 19 17 19H7C6.44772 19 6 18.5523 6 18V13C6 12.4477 6.44772 12 7 12H17ZM11.5 13H7L7 15H11.5V13ZM12.5 18H17V16H12.5V18ZM11.5 16V18H7L7 16H11.5ZM12.5 15H17V13H12.5V15Z",
+ "fill": "white",
+ "fill-opacity": "0.96"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_5938_927",
+ "x": "1",
+ "y": "0",
+ "width": "22",
+ "height": "26",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_5938_927"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_5938_927",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Xlsx"
+}
diff --git a/app/components/base/icons/src/public/files/Xlsx.tsx b/app/components/base/icons/src/public/files/Xlsx.tsx
new file mode 100644
index 0000000..399570b
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Xlsx.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Xlsx.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Xlsx'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/Yaml.json b/app/components/base/icons/src/public/files/Yaml.json
new file mode 100644
index 0000000..aa05cb4
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Yaml.json
@@ -0,0 +1,181 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "fill": "none",
+ "height": "26",
+ "viewBox": "0 0 24 26",
+ "width": "24",
+ "xmlns": "http://www.w3.org/2000/svg",
+ "xmlns:xlink": "http://www.w3.org/1999/xlink"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "a",
+ "color-interpolation-filters": "sRGB",
+ "filterUnits": "userSpaceOnUse",
+ "height": "26",
+ "width": "22",
+ "x": "1",
+ "y": "0"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "result": "hardAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "in2": "BackgroundImageFix",
+ "mode": "normal",
+ "result": "effect1_dropShadow_7605_8828"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_7605_8828",
+ "mode": "normal",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "filter": "url(#a)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m3 5.8c0-1.68016 0-2.52024.32698-3.16197.28762-.56449.74656-1.02343 1.31105-1.31105.64173-.32698 1.48181-.32698 3.16197-.32698h6.2l7 7v10.2c0 1.6802 0 2.5202-.327 3.162-.2876.5645-.7465 1.0234-1.311 1.311-.6418.327-1.4818.327-3.162.327h-8.4c-1.68016 0-2.52024 0-3.16197-.327-.56449-.2876-1.02343-.7465-1.31105-1.311-.32698-.6418-.32698-1.4818-.32698-3.162z",
+ "fill": "#e8eaed"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m16.2 22.75h-8.4c-.8442 0-1.46232-.0002-1.95004-.04-.48479-.0397-.81868-.1172-1.09843-.2597-.51745-.2637-.93815-.6844-1.2018-1.2018-.14254-.2798-.22008-.6137-.25969-1.0985-.03985-.4877-.04004-1.1058-.04004-1.95v-12.4c0-.8442.00019-1.46232.04004-1.95004.03961-.48479.11715-.81868.25969-1.09843.26365-.51745.68435-.93815 1.2018-1.2018.27975-.14254.61364-.22008 1.09843-.25969.48772-.03985 1.10584-.04004 1.95004-.04004h6.0964l6.8536 6.85355v10.09645c0 .8442-.0002 1.4623-.04 1.95-.0397.4848-.1172.8187-.2597 1.0985-.2637.5174-.6844.9381-1.2018 1.2018-.2798.1425-.6137.22-1.0985.2597-.4877.0398-1.1058.04-1.95.04z",
+ "stroke": "#000",
+ "stroke-opacity": ".03",
+ "stroke-width": ".5"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m14 1 7 7h-5c-1.1046 0-2-.89543-2-2z",
+ "fill": "#fff",
+ "opacity": ".5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m11.5264 9-2.15191 3.2267v2.0455h-1.31897v-2.0455l-2.05552-3.2267h1.48242l1.30707 2.0776 1.31781-2.0776z",
+ "fill": "#000"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m13.7426 13.1121h-2.3874l-.4855 1.1724h-1.0572l2.2355-5.27223h1.0813l2.1448 5.27223h-1.1297zm-.3966-1.0526-.7318-1.9348-.8165 1.9348z",
+ "fill": "#cb171e"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "fill": "#000"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m8.05469 14.8635v5.1673h1.10866v-3.5643l1.16025 2.3957h.8727l1.1999-2.4799v3.6474h1.0636v-5.1662h-1.4522l-1.2885 2.3369-1.22722-2.3369z"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m17.9994 18.9079h-2.7272v-4.0456h-1.1296v5.1451h3.8568z"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Yaml"
+}
diff --git a/app/components/base/icons/src/public/files/Yaml.tsx b/app/components/base/icons/src/public/files/Yaml.tsx
new file mode 100644
index 0000000..5f95d27
--- /dev/null
+++ b/app/components/base/icons/src/public/files/Yaml.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Yaml.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Yaml'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/files/index.ts b/app/components/base/icons/src/public/files/index.ts
new file mode 100644
index 0000000..f38c28c
--- /dev/null
+++ b/app/components/base/icons/src/public/files/index.ts
@@ -0,0 +1,11 @@
+export { default as Csv } from './Csv'
+export { default as Doc } from './Doc'
+export { default as Docx } from './Docx'
+export { default as Html } from './Html'
+export { default as Json } from './Json'
+export { default as Md } from './Md'
+export { default as Pdf } from './Pdf'
+export { default as Txt } from './Txt'
+export { default as Unknown } from './Unknown'
+export { default as Xlsx } from './Xlsx'
+export { default as Yaml } from './Yaml'
diff --git a/app/components/base/icons/src/public/knowledge/Chunk.json b/app/components/base/icons/src/public/knowledge/Chunk.json
new file mode 100644
index 0000000..91e85f2
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/Chunk.json
@@ -0,0 +1,116 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "10",
+ "height": "10",
+ "viewBox": "0 0 10 10",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M2.5 10H0V7.5H2.5V10Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M6.25 6.25H3.75V3.75H6.25V6.25Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M2.5 6.25H0V3.75H2.5V6.25Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M6.25 2.5H3.75V0H6.25V2.5Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M2.5 2.5H0V0H2.5V2.5Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M10 2.5H7.5V0H10V2.5Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M9.58342 7.91663H7.91675V9.58329H9.58342V7.91663Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M9.58342 4.16663H7.91675V5.83329H9.58342V4.16663Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "d": "M5.83341 7.91663H4.16675V9.58329H5.83341V7.91663Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Chunk"
+}
diff --git a/app/components/base/icons/src/public/knowledge/Chunk.tsx b/app/components/base/icons/src/public/knowledge/Chunk.tsx
new file mode 100644
index 0000000..a01bd1e
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/Chunk.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Chunk.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Chunk'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/knowledge/Collapse.json b/app/components/base/icons/src/public/knowledge/Collapse.json
new file mode 100644
index 0000000..726b074
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/Collapse.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon L"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z",
+ "fill": "#354052"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z",
+ "fill": "#354052"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z",
+ "fill": "#354052"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Collapse"
+}
diff --git a/app/components/base/icons/src/public/knowledge/Collapse.tsx b/app/components/base/icons/src/public/knowledge/Collapse.tsx
new file mode 100644
index 0000000..6f43dde
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/Collapse.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Collapse.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Collapse'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/knowledge/GeneralType.json b/app/components/base/icons/src/public/knowledge/GeneralType.json
new file mode 100644
index 0000000..5cbfb1a
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/GeneralType.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon L"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6 0.5C6.27615 0.5 6.5 0.72386 6.5 1V1.52755C6.95855 1.57831 7.3967 1.69804 7.80355 1.87619L8.067 1.41997C8.20505 1.18083 8.51085 1.09889 8.75 1.23696C8.98915 1.37503 9.07105 1.68082 8.933 1.91998L8.6692 2.37685C9.033 2.64523 9.3548 2.96707 9.6232 3.33084L10.0801 3.06703C10.3193 2.92896 10.6251 3.0109 10.7632 3.25005C10.9012 3.4892 10.8193 3.79499 10.5801 3.93306L10.1238 4.19649C10.302 4.60333 10.4218 5.0415 10.4725 5.50005H11C11.2761 5.50005 11.5 5.7239 11.5 6.00005C11.5 6.2762 11.2761 6.50005 11 6.50005H10.4725C10.4218 6.9586 10.302 7.3968 10.1238 7.80365L10.5801 8.0671C10.8193 8.20515 10.9012 8.51095 10.7632 8.7501C10.6251 8.98925 10.3193 9.0712 10.0801 8.9331L9.6232 8.6693C9.3548 9.03305 9.03295 9.3549 8.6692 9.62325L8.933 10.0802C9.07105 10.3193 8.98915 10.6251 8.75 10.7632C8.51085 10.9012 8.20505 10.8193 8.067 10.5802L7.80355 10.1239C7.3967 10.3021 6.95855 10.4218 6.5 10.4726V11C6.5 11.2761 6.27615 11.5 6 11.5C5.72385 11.5 5.5 11.2761 5.5 11V10.4726C5.04145 10.4218 4.60328 10.3021 4.19644 10.1239L3.933 10.5802C3.79493 10.8194 3.48914 10.9013 3.24999 10.7633C3.01084 10.6252 2.92891 10.3194 3.06698 10.0802L3.3308 9.62325C2.96702 9.3549 2.64517 9.03305 2.37678 8.66925L1.91986 8.93305C1.68071 9.07115 1.37492 8.9892 1.23685 8.75005C1.09878 8.5109 1.18072 8.2051 1.41986 8.06705L1.87612 7.8036C1.69797 7.39675 1.57824 6.9586 1.52749 6.50005L0.999975 6.5C0.723835 6.5 0.499987 6.2761 0.5 6C0.500015 5.72385 0.72388 5.5 1.00003 5.5L1.5275 5.50005C1.57825 5.0415 1.69796 4.60335 1.87611 4.19652L1.41987 3.93312C1.18072 3.79504 1.09878 3.48925 1.23685 3.2501C1.37492 3.01095 1.68071 2.92901 1.91985 3.06709L2.37675 3.33086C2.64514 2.96708 2.967 2.64524 3.33078 2.37684L3.06698 1.91992C2.92891 1.68077 3.01084 1.37498 3.24999 1.23691C3.48914 1.09884 3.79493 1.18077 3.933 1.41992L4.19642 1.87619C4.60327 1.69803 5.04145 1.57831 5.5 1.52755V1C5.5 0.72386 5.72385 0.5 6 0.5ZM3.83484 3.24991C3.48643 3.52463 3.19141 3.86415 2.96808 4.25014C2.67048 4.7645 2.49999 5.3616 2.49999 6.00005C2.49999 6.6385 2.67048 7.2356 2.96809 7.75C3.19142 8.13595 3.48645 8.4755 3.83486 8.7502L4.8599 6.97475C4.63581 6.71285 4.49999 6.37245 4.49999 6.00005C4.49999 5.62765 4.63581 5.28725 4.8599 5.02535L3.83484 3.24991ZM5.7258 4.52514L4.70041 2.74911C5.10185 2.58847 5.5402 2.50005 6 2.50005C6.63845 2.50005 7.23555 2.67054 7.74995 2.96816C8.28125 3.27557 8.7245 3.71882 9.0319 4.25012C9.2503 4.62764 9.4003 5.04975 9.4646 5.50005H7.41465C7.2087 4.91745 6.6531 4.50005 6 4.50005C5.9065 4.50005 5.8148 4.50865 5.7258 4.52514ZM7.41465 6.50005C7.2087 7.08265 6.6531 7.50005 6 7.50005C5.9065 7.50005 5.8148 7.49145 5.7258 7.47495L4.70043 9.251C5.10185 9.41165 5.5402 9.50005 6 9.50005C6.63845 9.50005 7.23555 9.32955 7.7499 9.03195C8.2812 8.72455 8.72445 8.2813 9.03185 7.75C9.2503 7.3725 9.4003 6.95035 9.4646 6.50005H7.41465Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "GeneralType"
+}
diff --git a/app/components/base/icons/src/public/knowledge/GeneralType.tsx b/app/components/base/icons/src/public/knowledge/GeneralType.tsx
new file mode 100644
index 0000000..29005b8
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/GeneralType.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './GeneralType.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'GeneralType'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/knowledge/LayoutRight2LineMod.json b/app/components/base/icons/src/public/knowledge/LayoutRight2LineMod.json
new file mode 100644
index 0000000..194bec7
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/LayoutRight2LineMod.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon L"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M14.0002 2C14.3684 2 14.6668 2.29848 14.6668 2.66667V13.3333C14.6668 13.7015 14.3684 14 14.0002 14H2.00016C1.63198 14 1.3335 13.7015 1.3335 13.3333V2.66667C1.3335 2.29848 1.63198 2 2.00016 2H14.0002ZM13.3335 3.33333H2.66683V12.6667H13.3335V3.33333ZM14.0002 2.66667V13.3333H10.0002V2.66667H14.0002Z",
+ "fill": "#354052"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LayoutRight2LineMod"
+}
diff --git a/app/components/base/icons/src/public/knowledge/LayoutRight2LineMod.tsx b/app/components/base/icons/src/public/knowledge/LayoutRight2LineMod.tsx
new file mode 100644
index 0000000..18327cd
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/LayoutRight2LineMod.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LayoutRight2LineMod.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LayoutRight2LineMod'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/knowledge/ParentChildType.json b/app/components/base/icons/src/public/knowledge/ParentChildType.json
new file mode 100644
index 0000000..2d3270e
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/ParentChildType.json
@@ -0,0 +1,56 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "10",
+ "height": "11",
+ "viewBox": "0 0 10 11",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M2.70833 3.87501C3.51375 3.87501 4.16666 3.22209 4.16666 2.41668C4.16666 1.61126 3.51375 0.958344 2.70833 0.958344C1.90292 0.958344 1.25 1.61126 1.25 2.41668C1.25 3.22209 1.90292 3.87501 2.70833 3.87501Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M7.29158 3.87501C8.097 3.87501 8.74992 3.22209 8.74992 2.41668C8.74992 1.61126 8.097 0.958344 7.29158 0.958344C6.48617 0.958344 5.83325 1.61126 5.83325 2.41668C5.83325 3.22209 6.48617 3.87501 7.29158 3.87501Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M7.29167 4.70835C6.83771 4.70886 6.39118 4.82363 5.99324 5.04208C5.59529 5.26053 5.25874 5.57563 5.01459 5.95835C5.34482 5.9622 5.66011 6.09658 5.89159 6.33215C6.12306 6.56771 6.25191 6.8853 6.24998 7.21555C6.24805 7.5458 6.11551 7.86187 5.8813 8.09472C5.6471 8.32756 5.33026 8.45826 5 8.45826C4.66975 8.45826 4.35291 8.32756 4.1187 8.09472C3.8845 7.86187 3.75195 7.5458 3.75003 7.21555C3.7481 6.8853 3.87695 6.56771 4.10842 6.33215C4.3399 6.09658 4.65519 5.9622 4.98542 5.95835C4.67086 5.46415 4.20432 5.08546 3.656 4.87926C3.10767 4.67306 2.50721 4.6505 1.94496 4.81497C1.3827 4.97944 0.889064 5.32205 0.538306 5.79125C0.187547 6.26045 -0.00135882 6.83086 7.35834e-06 7.41668V10.125C7.35834e-06 10.2355 0.043906 10.3415 0.122046 10.4196C0.200186 10.4978 0.306167 10.5417 0.416674 10.5417H3.33334V9.50001L1.83334 8.37501C1.78957 8.34218 1.75269 8.30105 1.72481 8.25397C1.69693 8.20688 1.6786 8.15477 1.67086 8.1006C1.65523 7.99121 1.6837 7.88008 1.75001 7.79168C1.81631 7.70327 1.91502 7.64483 2.02441 7.6292C2.13381 7.61357 2.24493 7.64204 2.33334 7.70835L3.88875 8.87501H6.11125L7.66667 7.70835C7.75507 7.64204 7.8662 7.61357 7.97559 7.6292C8.08499 7.64483 8.1837 7.70327 8.25 7.79168C8.31631 7.88008 8.34478 7.99121 8.32915 8.1006C8.31352 8.21 8.25507 8.30871 8.16667 8.37501L6.66667 9.50001V10.5417H9.58333C9.69384 10.5417 9.79982 10.4978 9.87796 10.4196C9.9561 10.3415 10 10.2355 10 10.125V7.41668C9.99912 6.69866 9.71349 6.01029 9.20577 5.50257C8.69805 4.99485 8.00969 4.70923 7.29167 4.70835Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ParentChildType"
+}
diff --git a/app/components/base/icons/src/public/knowledge/ParentChildType.tsx b/app/components/base/icons/src/public/knowledge/ParentChildType.tsx
new file mode 100644
index 0000000..1073150
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/ParentChildType.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ParentChildType.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ParentChildType'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/knowledge/SelectionMod.json b/app/components/base/icons/src/public/knowledge/SelectionMod.json
new file mode 100644
index 0000000..c88e278
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/SelectionMod.json
@@ -0,0 +1,116 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "10",
+ "height": "10",
+ "viewBox": "0 0 10 10",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M2.5 10H0V7.5H2.5V10Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M6.25 6.25H3.75V3.75H6.25V6.25Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M2.5 6.25H0V3.75H2.5V6.25Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M6.25 2.5H3.75V0H6.25V2.5Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M2.5 2.5H0V0H2.5V2.5Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M10 2.5H7.5V0H10V2.5Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M9.58332 7.91663H7.91666V9.58329H9.58332V7.91663Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M9.58332 4.16663H7.91666V5.83329H9.58332V4.16663Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "d": "M5.83332 7.91663H4.16666V9.58329H5.83332V7.91663Z",
+ "fill": "#676F83"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "SelectionMod"
+}
diff --git a/app/components/base/icons/src/public/knowledge/SelectionMod.tsx b/app/components/base/icons/src/public/knowledge/SelectionMod.tsx
new file mode 100644
index 0000000..a2d60fa
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/SelectionMod.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './SelectionMod.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'SelectionMod'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/knowledge/index.ts b/app/components/base/icons/src/public/knowledge/index.ts
new file mode 100644
index 0000000..0af2cf3
--- /dev/null
+++ b/app/components/base/icons/src/public/knowledge/index.ts
@@ -0,0 +1,6 @@
+export { default as Chunk } from './Chunk'
+export { default as Collapse } from './Collapse'
+export { default as GeneralType } from './GeneralType'
+export { default as LayoutRight2LineMod } from './LayoutRight2LineMod'
+export { default as ParentChildType } from './ParentChildType'
+export { default as SelectionMod } from './SelectionMod'
diff --git a/app/components/base/icons/src/public/llm/Anthropic.json b/app/components/base/icons/src/public/llm/Anthropic.json
new file mode 100644
index 0000000..db33abd
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Anthropic.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "6",
+ "fill": "#CA9F7B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.3843 6.43481H12.9687L17.3739 17.5652H19.7896L15.3843 6.43481ZM8.40522 6.43481L4 17.5652H6.4633L7.36417 15.2279H11.9729L12.8737 17.5652H15.337L10.9318 6.43481H8.40522ZM8.16104 13.1607L9.66852 9.24907L11.176 13.1607H8.16104Z",
+ "fill": "#191918"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Anthropic"
+}
diff --git a/app/components/base/icons/src/public/llm/Anthropic.tsx b/app/components/base/icons/src/public/llm/Anthropic.tsx
new file mode 100644
index 0000000..f5de0f5
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Anthropic.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Anthropic.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Anthropic'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/AnthropicDark.json b/app/components/base/icons/src/public/llm/AnthropicDark.json
new file mode 100644
index 0000000..ca066c2
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AnthropicDark.json
@@ -0,0 +1,1046 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "90",
+ "height": "10",
+ "viewBox": "0 0 90 10",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Anthropic",
+ "clip-path": "url(#clip0_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M89.375 -0.00195312H0V9.99805H89.375V-0.00195312Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask1_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_4"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M0 -0.00390625H89.375V9.99609H0V-0.00390625Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask1_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_3"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask2_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_12"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M0 -0.00585938H89.375V9.99414H0V-0.00585938Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask2_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_3"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_4"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask3_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_89"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask3_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_4"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_6"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M18.1273 6.92438L13.7773 0.15625H11.4297V9.82501H13.4321V3.05688L17.7821 9.82501H20.1297V0.15625H18.1273V6.92438Z",
+ "fill": "black",
+ "fill-opacity": "0.95"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask4_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_80"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask4_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_7"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_8"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_9"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M21.7969 2.02094H25.0423V9.82501H27.1139V2.02094H30.3594V0.15625H21.7969V2.02094Z",
+ "fill": "black",
+ "fill-opacity": "0.95"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_6"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask5_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_71"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask5_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_10"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_12"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "d": "M38.6442 4.00994H34.0871V0.15625H32.0156V9.82501H34.0871V5.87463H38.6442V9.82501H40.7156V0.15625H38.6442V4.00994Z",
+ "fill": "black",
+ "fill-opacity": "0.95"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_7"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask6_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_62"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_10",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask6_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_13"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_14"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_15"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_11",
+ "d": "M45.3376 2.02094H47.893C48.9152 2.02094 49.4539 2.39387 49.4539 3.09831C49.4539 3.80275 48.9152 4.17569 47.893 4.17569H45.3376V2.02094ZM51.5259 3.09831C51.5259 1.27506 50.186 0.15625 47.9897 0.15625H43.2656V9.82501H45.3376V6.04037H47.6443L49.7164 9.82501H52.0094L49.715 5.75211C50.8666 5.30941 51.5259 4.37721 51.5259 3.09831Z",
+ "fill": "black",
+ "fill-opacity": "0.95"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_8"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask7_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_53"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_12",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask7_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_16"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_17"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_18"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_13",
+ "d": "M57.8732 8.05653C56.2438 8.05653 55.2496 6.89631 55.2496 5.00404C55.2496 3.08416 56.2438 1.92394 57.8732 1.92394C59.4887 1.92394 60.4691 3.08416 60.4691 5.00404C60.4691 6.89631 59.4887 8.05653 57.8732 8.05653ZM57.8732 -0.00976562C55.0839 -0.00976562 53.1094 2.06206 53.1094 5.00404C53.1094 7.91841 55.0839 9.99023 57.8732 9.99023C60.6486 9.99023 62.6094 7.91841 62.6094 5.00404C62.6094 2.06206 60.6486 -0.00976562 57.8732 -0.00976562Z",
+ "fill": "black",
+ "fill-opacity": "0.95"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_9"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask8_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_44"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_14",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask8_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_19"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_20"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_21"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_15",
+ "d": "M69.1794 4.45194H66.6233V2.02094H69.1794C70.2019 2.02094 70.7407 2.43532 70.7407 3.23644C70.7407 4.03756 70.2019 4.45194 69.1794 4.45194ZM69.2762 0.15625H64.5508V9.82501H66.6233V6.31662H69.2762C71.473 6.31662 72.8133 5.15637 72.8133 3.23644C72.8133 1.3165 71.473 0.15625 69.2762 0.15625Z",
+ "fill": "black",
+ "fill-opacity": "0.95"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_10"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask9_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_35"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_16",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask9_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_22"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_23"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_24"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_17",
+ "d": "M86.8413 6.57863C86.4823 7.51786 85.7642 8.05653 84.7837 8.05653C83.1542 8.05653 82.16 6.89631 82.16 5.00404C82.16 3.08416 83.1542 1.92394 84.7837 1.92394C85.7642 1.92394 86.4823 2.46261 86.8413 3.40183H89.0369C88.4984 1.33002 86.8827 -0.00976562 84.7837 -0.00976562C81.9942 -0.00976562 80.0195 2.06206 80.0195 5.00404C80.0195 7.91841 81.9942 9.99023 84.7837 9.99023C86.8965 9.99023 88.5122 8.63664 89.0508 6.57863H86.8413Z",
+ "fill": "black",
+ "fill-opacity": "0.95"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask10_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_26"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_18",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask10_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_25"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_26"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_27"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_19",
+ "d": "M73.6484 0.15625L77.5033 9.82501H79.6172L75.7624 0.15625H73.6484Z",
+ "fill": "black",
+ "fill-opacity": "0.95"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_12"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask11_5981_49007",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_17"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_20",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask11_5981_49007)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_28"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_29"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_30"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_21",
+ "d": "M3.64038 5.99893L4.95938 2.60106L6.27838 5.99893H3.64038ZM3.85422 0.15625L0 9.82501H2.15505L2.9433 7.79456H6.97558L7.76371 9.82501H9.91875L6.06453 0.15625H3.85422Z",
+ "fill": "black",
+ "fill-opacity": "0.95"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_5981_49007"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "89.375",
+ "height": "10",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AnthropicDark"
+}
diff --git a/app/components/base/icons/src/public/llm/AnthropicDark.tsx b/app/components/base/icons/src/public/llm/AnthropicDark.tsx
new file mode 100644
index 0000000..d174400
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AnthropicDark.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AnthropicDark.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AnthropicDark'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/AnthropicLight.json b/app/components/base/icons/src/public/llm/AnthropicLight.json
new file mode 100644
index 0000000..2d2b0aa
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AnthropicLight.json
@@ -0,0 +1,1046 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "90",
+ "height": "10",
+ "viewBox": "0 0 90 10",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Anthropic",
+ "clip-path": "url(#clip0_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M89.375 -0.00195312H0V9.99805H89.375V-0.00195312Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask1_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_4"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M0 -0.00390625H89.375V9.99609H0V-0.00390625Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask1_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_3"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask2_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_12"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M0 -0.00585938H89.375V9.99414H0V-0.00585938Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask2_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_3"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_4"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask3_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_89"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask3_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_4"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_6"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M18.1273 6.92438L13.7773 0.15625H11.4297V9.82501H13.4321V3.05688L17.7821 9.82501H20.1297V0.15625H18.1273V6.92438Z",
+ "fill": "white",
+ "fill-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask4_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_80"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask4_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_7"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_8"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_9"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M21.7969 2.02094H25.0423V9.82501H27.1139V2.02094H30.3594V0.15625H21.7969V2.02094Z",
+ "fill": "white",
+ "fill-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_6"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask5_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_71"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask5_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_10"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_12"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "d": "M38.6442 4.00994H34.0871V0.15625H32.0156V9.82501H34.0871V5.87463H38.6442V9.82501H40.7156V0.15625H38.6442V4.00994Z",
+ "fill": "white",
+ "fill-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_7"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask6_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_62"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_10",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask6_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_13"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_14"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_15"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_11",
+ "d": "M45.3376 2.02094H47.893C48.9152 2.02094 49.4539 2.39387 49.4539 3.09831C49.4539 3.80275 48.9152 4.17569 47.893 4.17569H45.3376V2.02094ZM51.5259 3.09831C51.5259 1.27506 50.186 0.15625 47.9897 0.15625H43.2656V9.82501H45.3376V6.04037H47.6443L49.7164 9.82501H52.0094L49.715 5.75211C50.8666 5.30941 51.5259 4.37721 51.5259 3.09831Z",
+ "fill": "white",
+ "fill-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_8"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask7_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_53"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_12",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask7_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_16"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_17"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_18"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_13",
+ "d": "M57.8732 8.05653C56.2438 8.05653 55.2496 6.89631 55.2496 5.00404C55.2496 3.08416 56.2438 1.92394 57.8732 1.92394C59.4887 1.92394 60.4691 3.08416 60.4691 5.00404C60.4691 6.89631 59.4887 8.05653 57.8732 8.05653ZM57.8732 -0.00976562C55.0839 -0.00976562 53.1094 2.06206 53.1094 5.00404C53.1094 7.91841 55.0839 9.99023 57.8732 9.99023C60.6486 9.99023 62.6094 7.91841 62.6094 5.00404C62.6094 2.06206 60.6486 -0.00976562 57.8732 -0.00976562Z",
+ "fill": "white",
+ "fill-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_9"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask8_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_44"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_14",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask8_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_19"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_20"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_21"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_15",
+ "d": "M69.1794 4.45194H66.6233V2.02094H69.1794C70.2019 2.02094 70.7407 2.43532 70.7407 3.23644C70.7407 4.03756 70.2019 4.45194 69.1794 4.45194ZM69.2762 0.15625H64.5508V9.82501H66.6233V6.31662H69.2762C71.473 6.31662 72.8133 5.15637 72.8133 3.23644C72.8133 1.3165 71.473 0.15625 69.2762 0.15625Z",
+ "fill": "white",
+ "fill-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_10"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask9_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_35"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_16",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask9_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_22"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_23"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_24"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_17",
+ "d": "M86.8413 6.57863C86.4823 7.51786 85.7642 8.05653 84.7837 8.05653C83.1542 8.05653 82.16 6.89631 82.16 5.00404C82.16 3.08416 83.1542 1.92394 84.7837 1.92394C85.7642 1.92394 86.4823 2.46261 86.8413 3.40183H89.0369C88.4984 1.33002 86.8827 -0.00976562 84.7837 -0.00976562C81.9942 -0.00976562 80.0195 2.06206 80.0195 5.00404C80.0195 7.91841 81.9942 9.99023 84.7837 9.99023C86.8965 9.99023 88.5122 8.63664 89.0508 6.57863H86.8413Z",
+ "fill": "white",
+ "fill-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask10_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_26"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_18",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask10_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_25"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_26"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_27"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_19",
+ "d": "M73.6484 0.15625L77.5033 9.82501H79.6172L75.7624 0.15625H73.6484Z",
+ "fill": "white",
+ "fill-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_12"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask11_5981_52010",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "__lottie_element_17"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_20",
+ "d": "M0 -0.0078125H89.375V9.99219H0V-0.0078125Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask11_5981_52010)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_28"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_29"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_30"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_21",
+ "d": "M3.64038 5.99893L4.95938 2.60106L6.27838 5.99893H3.64038ZM3.85422 0.15625L0 9.82501H2.15505L2.9433 7.79456H6.97558L7.76371 9.82501H9.91875L6.06453 0.15625H3.85422Z",
+ "fill": "white",
+ "fill-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_5981_52010"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "89.375",
+ "height": "10",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AnthropicLight"
+}
diff --git a/app/components/base/icons/src/public/llm/AnthropicLight.tsx b/app/components/base/icons/src/public/llm/AnthropicLight.tsx
new file mode 100644
index 0000000..0cacdf7
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AnthropicLight.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AnthropicLight.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AnthropicLight'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/AnthropicText.json b/app/components/base/icons/src/public/llm/AnthropicText.json
new file mode 100644
index 0000000..7f89795
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AnthropicText.json
@@ -0,0 +1,539 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "90",
+ "height": "20",
+ "viewBox": "0 0 90 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M89.375 4.99805H0V14.998H89.375V4.99805Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask1_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99609H89.375V14.9961H0V4.99609Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask1_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask2_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99414H89.375V14.9941H0V4.99414Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask2_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask3_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask3_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.1273 11.9244L13.7773 5.15625H11.4297V14.825H13.4321V8.05688L17.7821 14.825H20.1297V5.15625H18.1273V11.9244Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask4_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask4_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.7969 7.02094H25.0423V14.825H27.1139V7.02094H30.3594V5.15625H21.7969V7.02094Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask5_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask5_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M38.6442 9.00994H34.0871V5.15625H32.0156V14.825H34.0871V10.8746H38.6442V14.825H40.7156V5.15625H38.6442V9.00994Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask6_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask6_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M45.3376 7.02094H47.893C48.9152 7.02094 49.4539 7.39387 49.4539 8.09831C49.4539 8.80275 48.9152 9.17569 47.893 9.17569H45.3376V7.02094ZM51.5259 8.09831C51.5259 6.27506 50.186 5.15625 47.9897 5.15625H43.2656V14.825H45.3376V11.0404H47.6443L49.7164 14.825H52.0094L49.715 10.7521C50.8666 10.3094 51.5259 9.37721 51.5259 8.09831Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask7_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask7_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M57.8732 13.0565C56.2438 13.0565 55.2496 11.8963 55.2496 10.004C55.2496 8.08416 56.2438 6.92394 57.8732 6.92394C59.4887 6.92394 60.4691 8.08416 60.4691 10.004C60.4691 11.8963 59.4887 13.0565 57.8732 13.0565ZM57.8732 4.99023C55.0839 4.99023 53.1094 7.06206 53.1094 10.004C53.1094 12.9184 55.0839 14.9902 57.8732 14.9902C60.6486 14.9902 62.6094 12.9184 62.6094 10.004C62.6094 7.06206 60.6486 4.99023 57.8732 4.99023Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask8_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask8_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M69.1794 9.45194H66.6233V7.02094H69.1794C70.2019 7.02094 70.7407 7.43532 70.7407 8.23644C70.7407 9.03756 70.2019 9.45194 69.1794 9.45194ZM69.2762 5.15625H64.5508V14.825H66.6233V11.3166H69.2762C71.473 11.3166 72.8133 10.1564 72.8133 8.23644C72.8133 6.3165 71.473 5.15625 69.2762 5.15625Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask9_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask9_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M86.8413 11.5786C86.4823 12.5179 85.7642 13.0565 84.7837 13.0565C83.1542 13.0565 82.16 11.8963 82.16 10.004C82.16 8.08416 83.1542 6.92394 84.7837 6.92394C85.7642 6.92394 86.4823 7.46261 86.8413 8.40183H89.0369C88.4984 6.33002 86.8827 4.99023 84.7837 4.99023C81.9942 4.99023 80.0195 7.06206 80.0195 10.004C80.0195 12.9184 81.9942 14.9902 84.7837 14.9902C86.8965 14.9902 88.5122 13.6366 89.0508 11.5786H86.8413Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask10_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask10_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M73.6484 5.15625L77.5033 14.825H79.6172L75.7624 5.15625H73.6484Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask11_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask11_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.64038 10.9989L4.95938 7.60106L6.27838 10.9989H3.64038ZM3.85422 5.15625L0 14.825H2.15505L2.9433 12.7946H6.97558L7.76371 14.825H9.91875L6.06453 5.15625H3.85422Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_8587_60274"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "89.375",
+ "height": "10",
+ "fill": "white",
+ "transform": "translate(0 5)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AnthropicText"
+}
diff --git a/app/components/base/icons/src/public/llm/AnthropicText.tsx b/app/components/base/icons/src/public/llm/AnthropicText.tsx
new file mode 100644
index 0000000..be9ebd3
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AnthropicText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AnthropicText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AnthropicText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/AzureOpenaiService.json b/app/components/base/icons/src/public/llm/AzureOpenaiService.json
new file mode 100644
index 0000000..bf07b59
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AzureOpenaiService.json
@@ -0,0 +1,74 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "56",
+ "height": "24",
+ "viewBox": "0 0 56 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "2",
+ "y": "1.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#EF4F21"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "2",
+ "y": "12.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#03A4EE"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "13",
+ "y": "1.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#7EB903"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "13",
+ "y": "12.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#FBB604"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M52.276 10.0045C52.7751 8.50639 52.6033 6.86529 51.8051 5.50264C50.6048 3.41259 48.1917 2.33732 45.835 2.84333C44.7866 1.66218 43.2803 0.990477 41.7011 1.0001C39.2922 0.994602 37.1548 2.54563 36.4137 4.83781C34.8661 5.15475 33.5304 6.12346 32.7487 7.49643C31.5394 9.58097 31.8151 12.2087 33.4307 13.9962C32.9316 15.4943 33.1034 17.1354 33.9016 18.498C35.1019 20.5881 37.515 21.6634 39.8717 21.1573C40.9195 22.3385 42.4264 23.0102 44.0056 22.9999C46.4159 23.0061 48.554 21.4537 49.2951 19.1594C50.8426 18.8425 52.1784 17.8738 52.9601 16.5008C54.168 14.4163 53.8916 11.7906 52.2767 10.0031L52.276 10.0045ZM44.007 21.5623C43.0424 21.5637 42.1081 21.2261 41.3677 20.608C41.4014 20.5901 41.4598 20.5578 41.4976 20.5345L45.8783 18.0044C46.1024 17.8772 46.2399 17.6386 46.2385 17.3808V11.2049L48.0899 12.274C48.1099 12.2836 48.1229 12.3028 48.1257 12.3248V17.4393C48.1229 19.7136 46.2812 21.5575 44.007 21.5623ZM35.1494 17.7789C34.6661 16.9443 34.4921 15.9659 34.6578 15.0165C34.6901 15.0357 34.7472 15.0708 34.7878 15.0942L39.1684 17.6242C39.3905 17.7541 39.6655 17.7541 39.8882 17.6242L45.2362 14.5359V16.6741C45.2376 16.6961 45.2272 16.7174 45.2101 16.7311L40.782 19.288C38.8096 20.4238 36.2906 19.7486 35.1501 17.7789H35.1494ZM33.9965 8.21626C34.4777 7.38024 35.2374 6.74085 36.1421 6.40878C36.1421 6.44659 36.1401 6.51328 36.1401 6.56003V11.6208C36.1387 11.878 36.2762 12.1165 36.4996 12.2437L41.8476 15.3313L39.9962 16.4004C39.9776 16.4128 39.9542 16.4149 39.9336 16.4059L35.5048 13.847C33.5365 12.7071 32.8614 10.1887 33.9958 8.21694L33.9965 8.21626ZM49.2078 11.7563L43.8598 8.66795L45.7112 7.59956C45.7298 7.58718 45.7532 7.58512 45.7738 7.59406L50.2026 10.1509C52.1743 11.2901 52.8501 13.8126 51.7109 15.7844C51.229 16.6191 50.47 17.2584 49.566 17.5912V12.3792C49.568 12.122 49.4312 11.8841 49.2085 11.7563H49.2078ZM51.0502 8.98284C51.0179 8.9629 50.9609 8.92852 50.9203 8.90515L46.5397 6.37509C46.3176 6.24515 46.0426 6.24515 45.8199 6.37509L40.4719 9.46341V7.32524C40.4705 7.30324 40.4808 7.28192 40.498 7.26817L44.9261 4.71337C46.8985 3.57553 49.4202 4.25273 50.5573 6.2259C51.0379 7.05917 51.2118 8.03475 51.0489 8.98284H51.0502ZM39.4654 12.7937L37.6133 11.7246C37.5934 11.715 37.5803 11.6958 37.5776 11.6738V6.55935C37.579 4.2823 39.4262 2.43701 41.7032 2.43838C42.6664 2.43838 43.5986 2.77664 44.339 3.39265C44.3053 3.41053 44.2476 3.44284 44.2091 3.46622L39.8284 5.99627C39.6043 6.12346 39.4668 6.36134 39.4682 6.61916L39.4654 12.7924V12.7937ZM40.4712 10.6253L42.8534 9.24959L45.2355 10.6246V13.3754L42.8534 14.7504L40.4712 13.3754V10.6253Z",
+ "fill": "black"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "AzureOpenaiService"
+}
diff --git a/app/components/base/icons/src/public/llm/AzureOpenaiService.tsx b/app/components/base/icons/src/public/llm/AzureOpenaiService.tsx
new file mode 100644
index 0000000..9a82df1
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AzureOpenaiService.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AzureOpenaiService.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AzureOpenaiService'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/AzureOpenaiServiceText.json b/app/components/base/icons/src/public/llm/AzureOpenaiServiceText.json
new file mode 100644
index 0000000..f4342d7
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AzureOpenaiServiceText.json
@@ -0,0 +1,236 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "212",
+ "height": "24",
+ "viewBox": "0 0 212 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "2",
+ "y": "1.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#EF4F21"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "2",
+ "y": "12.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#03A4EE"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "13",
+ "y": "1.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#7EB903"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "13",
+ "y": "12.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#FBB604"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M52.276 10.0045C52.7751 8.50639 52.6033 6.86529 51.8051 5.50264C50.6048 3.41259 48.1917 2.33732 45.835 2.84333C44.7866 1.66218 43.2803 0.990477 41.7011 1.0001C39.2922 0.994602 37.1548 2.54563 36.4137 4.83781C34.8661 5.15475 33.5304 6.12346 32.7487 7.49643C31.5394 9.58097 31.8151 12.2087 33.4307 13.9962C32.9316 15.4943 33.1034 17.1354 33.9016 18.498C35.1019 20.5881 37.515 21.6634 39.8717 21.1573C40.9195 22.3385 42.4264 23.0102 44.0056 22.9999C46.4159 23.0061 48.554 21.4537 49.2951 19.1594C50.8426 18.8425 52.1784 17.8738 52.9601 16.5008C54.168 14.4163 53.8916 11.7906 52.2767 10.0031L52.276 10.0045ZM44.007 21.5623C43.0424 21.5637 42.1081 21.2261 41.3677 20.608C41.4014 20.5901 41.4598 20.5578 41.4976 20.5345L45.8783 18.0044C46.1024 17.8772 46.2399 17.6386 46.2385 17.3808V11.2049L48.0899 12.274C48.1099 12.2836 48.1229 12.3028 48.1257 12.3248V17.4393C48.1229 19.7136 46.2812 21.5575 44.007 21.5623ZM35.1494 17.7789C34.6661 16.9443 34.4921 15.9659 34.6578 15.0165C34.6901 15.0357 34.7472 15.0708 34.7878 15.0942L39.1684 17.6242C39.3905 17.7541 39.6655 17.7541 39.8882 17.6242L45.2362 14.5359V16.6741C45.2376 16.6961 45.2272 16.7174 45.2101 16.7311L40.782 19.288C38.8096 20.4238 36.2906 19.7486 35.1501 17.7789H35.1494ZM33.9965 8.21626C34.4777 7.38024 35.2374 6.74085 36.1421 6.40878C36.1421 6.44659 36.1401 6.51328 36.1401 6.56003V11.6208C36.1387 11.878 36.2762 12.1165 36.4996 12.2437L41.8476 15.3313L39.9962 16.4004C39.9776 16.4128 39.9542 16.4149 39.9336 16.4059L35.5048 13.847C33.5365 12.7071 32.8614 10.1887 33.9958 8.21694L33.9965 8.21626ZM49.2078 11.7563L43.8598 8.66795L45.7112 7.59956C45.7298 7.58718 45.7532 7.58512 45.7738 7.59406L50.2026 10.1509C52.1743 11.2901 52.8501 13.8126 51.7109 15.7844C51.229 16.6191 50.47 17.2584 49.566 17.5912V12.3792C49.568 12.122 49.4312 11.8841 49.2085 11.7563H49.2078ZM51.0502 8.98284C51.0179 8.9629 50.9609 8.92852 50.9203 8.90515L46.5397 6.37509C46.3176 6.24515 46.0426 6.24515 45.8199 6.37509L40.4719 9.46341V7.32524C40.4705 7.30324 40.4808 7.28192 40.498 7.26817L44.9261 4.71337C46.8985 3.57553 49.4202 4.25273 50.5573 6.2259C51.0379 7.05917 51.2118 8.03475 51.0489 8.98284H51.0502ZM39.4654 12.7937L37.6133 11.7246C37.5934 11.715 37.5803 11.6958 37.5776 11.6738V6.55935C37.579 4.2823 39.4262 2.43701 41.7032 2.43838C42.6664 2.43838 43.5986 2.77664 44.339 3.39265C44.3053 3.41053 44.2476 3.44284 44.2091 3.46622L39.8284 5.99627C39.6043 6.12346 39.4668 6.36134 39.4682 6.61916L39.4654 12.7924V12.7937ZM40.4712 10.6253L42.8534 9.24959L45.2355 10.6246V13.3754L42.8534 14.7504L40.4712 13.3754V10.6253Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M64.0195 17.0001H62.0508L65.6353 6.81824H67.9123L71.5018 17.0001H69.533L66.8136 8.90631H66.734L64.0195 17.0001ZM64.0842 13.0079H69.4535V14.4894H64.0842V13.0079Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M72.6639 17.0001V15.8566L76.6014 10.9198V10.8552H72.7931V9.36369H78.8038V10.5917L75.0552 15.4439V15.5086H78.9331V17.0001H72.6639Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M85.4918 13.7884V9.36369H87.2915V17.0001H85.5465V15.6428H85.467C85.2946 16.0704 85.0112 16.42 84.6168 16.6918C84.2257 16.9636 83.7435 17.0995 83.1701 17.0995C82.6696 17.0995 82.2272 16.9885 81.8427 16.7664C81.4615 16.541 81.1632 16.2145 80.9478 15.787C80.7324 15.3561 80.6246 14.8358 80.6246 14.2259V9.36369H82.4244V13.9475C82.4244 14.4314 82.5569 14.8159 82.8221 15.1009C83.0872 15.3859 83.4352 15.5285 83.8661 15.5285C84.1313 15.5285 84.3881 15.4638 84.6367 15.3346C84.8853 15.2053 85.0891 15.0131 85.2482 14.7579C85.4106 14.4993 85.4918 14.1762 85.4918 13.7884Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M89.1422 17.0001V9.36369H90.8873V10.6364H90.9668C91.106 10.1956 91.3446 9.85588 91.6827 9.61724C92.0241 9.37529 92.4135 9.25432 92.851 9.25432C92.9505 9.25432 93.0615 9.25929 93.1841 9.26923C93.3101 9.27586 93.4145 9.28746 93.4973 9.30403V10.9596C93.4211 10.9331 93.3001 10.9099 93.1344 10.89C92.972 10.8668 92.8146 10.8552 92.6621 10.8552C92.334 10.8552 92.039 10.9264 91.7772 11.0689C91.5186 11.2082 91.3148 11.402 91.1657 11.6506C91.0165 11.8992 90.9419 12.1859 90.9419 12.5107V17.0001H89.1422Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M97.7592 17.1492C96.9936 17.1492 96.3324 16.9901 95.7756 16.6719C95.2221 16.3504 94.7962 15.8964 94.4979 15.3097C94.1996 14.7198 94.0504 14.0254 94.0504 13.2266C94.0504 12.4411 94.1996 11.7517 94.4979 11.1584C94.7995 10.5618 95.2204 10.0978 95.7607 9.76639C96.3009 9.43164 96.9356 9.26426 97.6648 9.26426C98.1354 9.26426 98.5795 9.34049 98.9972 9.49295C99.4181 9.6421 99.7893 9.87411 100.111 10.189C100.436 10.5038 100.691 10.9049 100.876 11.3921C101.062 11.876 101.155 12.4527 101.155 13.1222V13.6741H94.8956V12.461H99.4297C99.4264 12.1163 99.3518 11.8097 99.206 11.5412C99.0601 11.2695 98.8563 11.0557 98.5945 10.8999C98.3359 10.7441 98.0343 10.6662 97.6896 10.6662C97.3217 10.6662 96.9986 10.7557 96.7202 10.9347C96.4418 11.1104 96.2247 11.3424 96.0689 11.6307C95.9164 11.9158 95.8385 12.229 95.8352 12.5704V13.6293C95.8352 14.0734 95.9164 14.4546 96.0788 14.7728C96.2412 15.0877 96.4683 15.3296 96.7599 15.4986C97.0516 15.6644 97.393 15.7472 97.7841 15.7472C98.0459 15.7472 98.2829 15.7108 98.495 15.6378C98.7071 15.5616 98.8911 15.4506 99.0469 15.3047C99.2027 15.1589 99.3203 14.9783 99.3999 14.7628L101.08 14.9518C100.974 15.3959 100.772 15.7837 100.474 16.1151C100.179 16.4432 99.8009 16.6984 99.3402 16.8807C98.8795 17.0597 98.3525 17.1492 97.7592 17.1492Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M115.328 11.9091C115.328 13.0062 115.122 13.9458 114.711 14.728C114.303 15.5069 113.747 16.1035 113.041 16.5178C112.338 16.9321 111.541 17.1393 110.649 17.1393C109.758 17.1393 108.959 16.9321 108.253 16.5178C107.55 16.1002 106.994 15.5019 106.583 14.7231C106.175 13.9409 105.971 13.0029 105.971 11.9091C105.971 10.8121 106.175 9.87411 106.583 9.09523C106.994 8.31303 107.55 7.71478 108.253 7.30048C108.959 6.88618 109.758 6.67903 110.649 6.67903C111.541 6.67903 112.338 6.88618 113.041 7.30048C113.747 7.71478 114.303 8.31303 114.711 9.09523C115.122 9.87411 115.328 10.8121 115.328 11.9091ZM113.473 11.9091C113.473 11.1369 113.352 10.4856 113.11 9.95531C112.872 9.42169 112.54 9.019 112.116 8.74721C111.692 8.47212 111.203 8.33457 110.649 8.33457C110.096 8.33457 109.607 8.47212 109.183 8.74721C108.758 9.019 108.425 9.42169 108.183 9.95531C107.945 10.4856 107.825 11.1369 107.825 11.9091C107.825 12.6814 107.945 13.3343 108.183 13.868C108.425 14.3983 108.758 14.801 109.183 15.076C109.607 15.3478 110.096 15.4837 110.649 15.4837C111.203 15.4837 111.692 15.3478 112.116 15.076C112.54 14.801 112.872 14.3983 113.11 13.868C113.352 13.3343 113.473 12.6814 113.473 11.9091Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M116.992 19.8637V9.36369H118.762V10.6265H118.866C118.959 10.4409 119.09 10.2437 119.259 10.0349C119.428 9.82274 119.657 9.6421 119.945 9.49295C120.233 9.34049 120.601 9.26426 121.049 9.26426C121.639 9.26426 122.171 9.41507 122.645 9.71667C123.122 10.015 123.5 10.4574 123.778 11.0441C124.06 11.6274 124.201 12.3433 124.201 13.1918C124.201 14.0304 124.063 14.743 123.788 15.3296C123.513 15.9162 123.138 16.3637 122.664 16.6719C122.19 16.9802 121.654 17.1343 121.054 17.1343C120.616 17.1343 120.253 17.0614 119.965 16.9155C119.676 16.7697 119.444 16.594 119.269 16.3885C119.096 16.1797 118.962 15.9825 118.866 15.7969H118.792V19.8637H116.992ZM118.757 13.1819C118.757 13.6757 118.826 14.1082 118.966 14.4795C119.108 14.8507 119.312 15.1407 119.577 15.3495C119.846 15.555 120.17 15.6577 120.551 15.6577C120.949 15.6577 121.282 15.5517 121.551 15.3395C121.819 15.1241 122.021 14.8308 122.157 14.4596C122.297 14.085 122.366 13.6591 122.366 13.1819C122.366 12.7079 122.298 12.287 122.162 11.9191C122.026 11.5512 121.824 11.2628 121.556 11.054C121.287 10.8452 120.953 10.7408 120.551 10.7408C120.167 10.7408 119.841 10.8419 119.572 11.0441C119.304 11.2463 119.1 11.5296 118.961 11.8942C118.825 12.2588 118.757 12.688 118.757 13.1819Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M129.123 17.1492C128.357 17.1492 127.696 16.9901 127.139 16.6719C126.585 16.3504 126.159 15.8964 125.861 15.3097C125.563 14.7198 125.414 14.0254 125.414 13.2266C125.414 12.4411 125.563 11.7517 125.861 11.1584C126.163 10.5618 126.584 10.0978 127.124 9.76639C127.664 9.43164 128.299 9.26426 129.028 9.26426C129.499 9.26426 129.943 9.34049 130.36 9.49295C130.781 9.6421 131.153 9.87411 131.474 10.189C131.799 10.5038 132.054 10.9049 132.24 11.3921C132.425 11.876 132.518 12.4527 132.518 13.1222V13.6741H126.259V12.461H130.793C130.79 12.1163 130.715 11.8097 130.569 11.5412C130.423 11.2695 130.22 11.0557 129.958 10.8999C129.699 10.7441 129.398 10.6662 129.053 10.6662C128.685 10.6662 128.362 10.7557 128.083 10.9347C127.805 11.1104 127.588 11.3424 127.432 11.6307C127.28 11.9158 127.202 12.229 127.199 12.5704V13.6293C127.199 14.0734 127.28 14.4546 127.442 14.7728C127.605 15.0877 127.832 15.3296 128.123 15.4986C128.415 15.6644 128.756 15.7472 129.147 15.7472C129.409 15.7472 129.646 15.7108 129.858 15.6378C130.07 15.5616 130.254 15.4506 130.41 15.3047C130.566 15.1589 130.684 14.9783 130.763 14.7628L132.444 14.9518C132.337 15.3959 132.135 15.7837 131.837 16.1151C131.542 16.4432 131.164 16.6984 130.703 16.8807C130.243 17.0597 129.716 17.1492 129.123 17.1492Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M135.84 12.5256V17.0001H134.041V9.36369H135.761V10.6613H135.85C136.026 10.2337 136.306 9.894 136.691 9.6421C137.078 9.39021 137.557 9.26426 138.127 9.26426C138.654 9.26426 139.113 9.37695 139.504 9.60233C139.899 9.82771 140.204 10.1542 140.419 10.5817C140.638 11.0093 140.746 11.528 140.742 12.1378V17.0001H138.943V12.4162C138.943 11.9058 138.81 11.5064 138.545 11.2181C138.283 10.9297 137.92 10.7856 137.456 10.7856C137.141 10.7856 136.861 10.8552 136.616 10.9944C136.374 11.1303 136.183 11.3275 136.044 11.586C135.908 11.8445 135.84 12.1577 135.84 12.5256Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M143.959 17.0001H141.99L145.575 6.81824H147.852L151.441 17.0001H149.472L146.753 8.90631H146.673L143.959 17.0001ZM144.024 13.0079H149.393V14.4894H144.024V13.0079Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M154.627 6.81824V17.0001H152.782V6.81824H154.627Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M165.63 9.61724C165.584 9.18306 165.388 8.84499 165.044 8.60304C164.702 8.36109 164.258 8.24011 163.711 8.24011C163.327 8.24011 162.997 8.29811 162.722 8.41412C162.447 8.53012 162.236 8.68756 162.09 8.88642C161.945 9.08528 161.87 9.31232 161.867 9.56753C161.867 9.77965 161.915 9.9636 162.011 10.1194C162.11 10.2752 162.244 10.4077 162.414 10.5171C162.583 10.6232 162.77 10.7127 162.975 10.7856C163.181 10.8585 163.388 10.9198 163.597 10.9695L164.551 11.2082C164.936 11.2976 165.305 11.4186 165.66 11.5711C166.018 11.7235 166.338 11.9158 166.619 12.1478C166.905 12.3798 167.13 12.6599 167.296 12.988C167.461 13.3161 167.544 13.7006 167.544 14.1414C167.544 14.738 167.392 15.2633 167.087 15.7174C166.782 16.1681 166.341 16.5211 165.764 16.7763C165.191 17.0282 164.497 17.1542 163.681 17.1542C162.889 17.1542 162.201 17.0315 161.618 16.7863C161.038 16.541 160.584 16.1831 160.256 15.7124C159.931 15.2418 159.755 14.6684 159.729 13.9922H161.544C161.57 14.3469 161.679 14.6419 161.872 14.8772C162.064 15.1125 162.314 15.2882 162.622 15.4042C162.934 15.5202 163.282 15.5782 163.666 15.5782C164.067 15.5782 164.419 15.5185 164.72 15.3992C165.025 15.2766 165.264 15.1075 165.436 14.8921C165.609 14.6734 165.696 14.4181 165.7 14.1265C165.696 13.8613 165.619 13.6426 165.466 13.4702C165.314 13.2946 165.1 13.1487 164.825 13.0327C164.553 12.9134 164.235 12.8073 163.87 12.7145L162.712 12.4162C161.873 12.2008 161.21 11.8743 160.723 11.4368C160.239 10.996 159.997 10.411 159.997 9.68187C159.997 9.08197 160.16 8.55664 160.485 8.10588C160.813 7.65512 161.258 7.30545 161.822 7.05687C162.385 6.80498 163.023 6.67903 163.736 6.67903C164.459 6.67903 165.092 6.80498 165.635 7.05687C166.182 7.30545 166.611 7.65181 166.923 8.09594C167.234 8.53675 167.395 9.04385 167.405 9.61724H165.63Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M172.49 17.1492C171.724 17.1492 171.063 16.9901 170.506 16.6719C169.953 16.3504 169.527 15.8964 169.228 15.3097C168.93 14.7198 168.781 14.0254 168.781 13.2266C168.781 12.4411 168.93 11.7517 169.228 11.1584C169.53 10.5618 169.951 10.0978 170.491 9.76639C171.031 9.43164 171.666 9.26426 172.395 9.26426C172.866 9.26426 173.31 9.34049 173.728 9.49295C174.149 9.6421 174.52 9.87411 174.841 10.189C175.166 10.5038 175.421 10.9049 175.607 11.3921C175.792 11.876 175.885 12.4527 175.885 13.1222V13.6741H169.626V12.461H174.16C174.157 12.1163 174.082 11.8097 173.936 11.5412C173.791 11.2695 173.587 11.0557 173.325 10.8999C173.066 10.7441 172.765 10.6662 172.42 10.6662C172.052 10.6662 171.729 10.7557 171.451 10.9347C171.172 11.1104 170.955 11.3424 170.799 11.6307C170.647 11.9158 170.569 12.229 170.566 12.5704V13.6293C170.566 14.0734 170.647 14.4546 170.809 14.7728C170.972 15.0877 171.199 15.3296 171.49 15.4986C171.782 15.6644 172.123 15.7472 172.515 15.7472C172.776 15.7472 173.013 15.7108 173.225 15.6378C173.438 15.5616 173.622 15.4506 173.777 15.3047C173.933 15.1589 174.051 14.9783 174.13 14.7628L175.811 14.9518C175.705 15.3959 175.502 15.7837 175.204 16.1151C174.909 16.4432 174.531 16.6984 174.071 16.8807C173.61 17.0597 173.083 17.1492 172.49 17.1492Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M177.408 17.0001V9.36369H179.153V10.6364H179.232C179.372 10.1956 179.61 9.85588 179.948 9.61724C180.29 9.37529 180.679 9.25432 181.117 9.25432C181.216 9.25432 181.327 9.25929 181.45 9.26923C181.576 9.27586 181.68 9.28746 181.763 9.30403V10.9596C181.687 10.9331 181.566 10.9099 181.4 10.89C181.238 10.8668 181.08 10.8552 180.928 10.8552C180.6 10.8552 180.305 10.9264 180.043 11.0689C179.784 11.2082 179.58 11.402 179.431 11.6506C179.282 11.8992 179.208 12.1859 179.208 12.5107V17.0001H177.408Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M190.012 9.36369L187.293 17.0001H185.304L182.585 9.36369H184.504L186.259 15.0363H186.338L188.098 9.36369H190.012Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M191.257 17.0001V9.36369H193.057V17.0001H191.257ZM192.162 8.27989C191.877 8.27989 191.632 8.18542 191.426 7.9965C191.221 7.80427 191.118 7.57392 191.118 7.30545C191.118 7.03367 191.221 6.80332 191.426 6.6144C191.632 6.42217 191.877 6.32605 192.162 6.32605C192.451 6.32605 192.696 6.42217 192.898 6.6144C193.104 6.80332 193.206 7.03367 193.206 7.30545C193.206 7.57392 193.104 7.80427 192.898 7.9965C192.696 8.18542 192.451 8.27989 192.162 8.27989Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M198.239 17.1492C197.477 17.1492 196.822 16.9818 196.275 16.6471C195.731 16.3123 195.312 15.85 195.017 15.26C194.726 14.6667 194.58 13.984 194.58 13.2117C194.58 12.4361 194.729 11.7517 195.027 11.1584C195.325 10.5618 195.746 10.0978 196.29 9.76639C196.837 9.43164 197.483 9.26426 198.229 9.26426C198.849 9.26426 199.397 9.37861 199.874 9.6073C200.355 9.83268 200.738 10.1525 201.023 10.5668C201.308 10.9778 201.47 11.4584 201.51 12.0086H199.79C199.72 11.6407 199.555 11.3341 199.293 11.0888C199.034 10.8403 198.688 10.716 198.254 10.716C197.886 10.716 197.563 10.8154 197.284 11.0143C197.006 11.2098 196.789 11.4915 196.633 11.8594C196.481 12.2273 196.404 12.6681 196.404 13.1819C196.404 13.7022 196.481 14.1497 196.633 14.5242C196.785 14.8954 196.999 15.1821 197.274 15.3843C197.553 15.5832 197.879 15.6826 198.254 15.6826C198.519 15.6826 198.756 15.6329 198.965 15.5334C199.177 15.4307 199.354 15.2832 199.497 15.091C199.639 14.8987 199.737 14.6651 199.79 14.39H201.51C201.467 14.9302 201.308 15.4091 201.033 15.8268C200.758 16.2411 200.383 16.5659 199.909 16.8012C199.435 17.0332 198.878 17.1492 198.239 17.1492Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M206.369 17.1492C205.603 17.1492 204.942 16.9901 204.385 16.6719C203.831 16.3504 203.406 15.8964 203.107 15.3097C202.809 14.7198 202.66 14.0254 202.66 13.2266C202.66 12.4411 202.809 11.7517 203.107 11.1584C203.409 10.5618 203.83 10.0978 204.37 9.76639C204.91 9.43164 205.545 9.26426 206.274 9.26426C206.745 9.26426 207.189 9.34049 207.607 9.49295C208.027 9.6421 208.399 9.87411 208.72 10.189C209.045 10.5038 209.3 10.9049 209.486 11.3921C209.671 11.876 209.764 12.4527 209.764 13.1222V13.6741H203.505V12.461H208.039C208.036 12.1163 207.961 11.8097 207.815 11.5412C207.67 11.2695 207.466 11.0557 207.204 10.8999C206.945 10.7441 206.644 10.6662 206.299 10.6662C205.931 10.6662 205.608 10.7557 205.33 10.9347C205.051 11.1104 204.834 11.3424 204.678 11.6307C204.526 11.9158 204.448 12.229 204.445 12.5704V13.6293C204.445 14.0734 204.526 14.4546 204.688 14.7728C204.851 15.0877 205.078 15.3296 205.369 15.4986C205.661 15.6644 206.002 15.7472 206.393 15.7472C206.655 15.7472 206.892 15.7108 207.104 15.6378C207.317 15.5616 207.5 15.4506 207.656 15.3047C207.812 15.1589 207.93 14.9783 208.009 14.7628L209.69 14.9518C209.584 15.3959 209.381 15.7837 209.083 16.1151C208.788 16.4432 208.41 16.6984 207.95 16.8807C207.489 17.0597 206.962 17.1492 206.369 17.1492Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "AzureOpenaiServiceText"
+}
diff --git a/app/components/base/icons/src/public/llm/AzureOpenaiServiceText.tsx b/app/components/base/icons/src/public/llm/AzureOpenaiServiceText.tsx
new file mode 100644
index 0000000..f91189a
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AzureOpenaiServiceText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AzureOpenaiServiceText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AzureOpenaiServiceText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Azureai.json b/app/components/base/icons/src/public/llm/Azureai.json
new file mode 100644
index 0000000..004da32
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Azureai.json
@@ -0,0 +1,180 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.41642 1.13526H14.9266L8.16839 21.1596C8.09893 21.3654 7.96669 21.5442 7.79029 21.6708C7.61389 21.7975 7.4022 21.8657 7.18504 21.8657H2.11851C1.95397 21.8657 1.79179 21.8266 1.64539 21.7515C1.49898 21.6764 1.37257 21.5675 1.27659 21.4338C1.18062 21.3002 1.11784 21.1456 1.09347 20.9829C1.06909 20.8201 1.08381 20.6539 1.13641 20.498L7.43281 1.84135C7.50224 1.6355 7.6345 1.45662 7.81096 1.3299C7.98742 1.20319 8.19918 1.13527 8.41642 1.13526Z",
+ "fill": "url(#paint0_linear_8587_60253)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.8761 14.5664H7.55255C7.45657 14.5663 7.36278 14.5951 7.28341 14.6491C7.20403 14.703 7.14275 14.7796 7.10754 14.8689C7.07232 14.9582 7.06482 15.056 7.08599 15.1496C7.10717 15.2433 7.15605 15.3283 7.22626 15.3938L13.86 21.5856C14.0531 21.7657 14.3074 21.8659 14.5715 21.8659H20.4171L17.8761 14.5664Z",
+ "fill": "#0078D4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.41509 1.13502C8.19548 1.13417 7.98136 1.20358 7.80399 1.33308C7.62663 1.46259 7.49532 1.64542 7.42924 1.85486L1.14283 20.4808C1.0867 20.6373 1.06907 20.805 1.09145 20.9697C1.11383 21.1344 1.17556 21.2913 1.2714 21.4272C1.36725 21.563 1.4944 21.6737 1.6421 21.75C1.7898 21.8263 1.9537 21.8659 2.11994 21.8655H7.31723C7.5108 21.8309 7.69172 21.7455 7.84151 21.6181C7.9913 21.4907 8.10459 21.3259 8.16982 21.1404L9.42345 17.4456L13.9014 21.6224C14.0891 21.7776 14.3245 21.8635 14.568 21.8655H20.3918L17.8376 14.566L10.3916 14.5678L14.9488 1.13502H8.41509Z",
+ "fill": "url(#paint1_linear_8587_60253)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M16.7308 1.8401C16.6614 1.63458 16.5294 1.456 16.3532 1.3295C16.177 1.20301 15.9656 1.13498 15.7487 1.13501H8.49316C8.71005 1.13502 8.92147 1.20306 9.09765 1.32955C9.27383 1.45604 9.4059 1.6346 9.47527 1.8401L15.7719 20.4975C15.8246 20.6535 15.8393 20.8197 15.815 20.9825C15.7906 21.1452 15.7278 21.2999 15.6319 21.4336C15.5359 21.5673 15.4095 21.6762 15.263 21.7514C15.1166 21.8265 14.9544 21.8657 14.7898 21.8657H22.0456C22.2101 21.8657 22.3723 21.8264 22.5187 21.7513C22.6651 21.6761 22.7915 21.5672 22.8875 21.4335C22.9834 21.2998 23.0461 21.1452 23.0705 20.9824C23.0948 20.8197 23.0801 20.6534 23.0274 20.4975L16.7308 1.8401Z",
+ "fill": "url(#paint2_linear_8587_60253)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_8587_60253",
+ "x1": "10.7892",
+ "y1": "2.67146",
+ "x2": "4.0279",
+ "y2": "22.6454",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#114A8B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#0669BC"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_8587_60253",
+ "x1": "12.8998",
+ "y1": "11.9797",
+ "x2": "11.3359",
+ "y2": "12.5085",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-opacity": "0.3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.071",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.321",
+ "stop-opacity": "0.1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.623",
+ "stop-opacity": "0.05"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-opacity": "0"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint2_linear_8587_60253",
+ "x1": "12.0403",
+ "y1": "2.08863",
+ "x2": "19.4621",
+ "y2": "21.8613",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#3CCBF4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#2892DF"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Azureai"
+}
diff --git a/app/components/base/icons/src/public/llm/Azureai.tsx b/app/components/base/icons/src/public/llm/Azureai.tsx
new file mode 100644
index 0000000..bf7f2da
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Azureai.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Azureai.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Azureai'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/AzureaiText.json b/app/components/base/icons/src/public/llm/AzureaiText.json
new file mode 100644
index 0000000..44976aa
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AzureaiText.json
@@ -0,0 +1,243 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "92",
+ "height": "24",
+ "viewBox": "0 0 92 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.63655 2.50023H15.6036L9.40921 20.8535C9.34555 21.0421 9.22434 21.206 9.06266 21.3221C8.90097 21.4382 8.70695 21.5006 8.5079 21.5007H3.86407C3.71326 21.5007 3.56461 21.4648 3.43042 21.396C3.29623 21.3271 3.18036 21.2273 3.09239 21.1048C3.00442 20.9823 2.94689 20.8406 2.92454 20.6915C2.9022 20.5424 2.91569 20.39 2.9639 20.2471L8.73501 3.1474C8.79864 2.95872 8.91987 2.79477 9.0816 2.67863C9.24334 2.56249 9.43743 2.50024 9.63655 2.50023Z",
+ "fill": "url(#paint0_linear_8587_60561)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.307 14.8105H8.84467C8.7567 14.8104 8.67074 14.8368 8.59799 14.8863C8.52524 14.9358 8.46906 15.006 8.43679 15.0878C8.40451 15.1697 8.39763 15.2593 8.41704 15.3451C8.43645 15.4309 8.48125 15.5089 8.54561 15.5689L14.6259 21.2439C14.8029 21.4091 15.036 21.5009 15.2781 21.5008H20.636L18.307 14.8105Z",
+ "fill": "#0078D4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.63533 2.50001C9.43405 2.49923 9.23778 2.56284 9.07521 2.68154C8.91265 2.80024 8.79229 2.96781 8.73173 3.15978L2.96979 20.2313C2.91834 20.3747 2.90219 20.5284 2.9227 20.6794C2.94321 20.8304 2.99979 20.9742 3.08764 21.0987C3.17549 21.2232 3.29203 21.3247 3.42741 21.3946C3.56278 21.4646 3.71301 21.5009 3.86538 21.5004H8.62906C8.80648 21.4687 8.97231 21.3905 9.1096 21.2738C9.2469 21.157 9.35074 21.0059 9.41052 20.8359L10.5596 17.4495L14.6639 21.2777C14.8359 21.42 15.0517 21.4986 15.2749 21.5004H20.6129L18.2717 14.8102L11.4469 14.8118L15.6239 2.50001H9.63533Z",
+ "fill": "url(#paint1_linear_8587_60561)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.2574 3.14625C17.1938 2.95788 17.0728 2.7942 16.9113 2.67826C16.7498 2.56233 16.556 2.49998 16.3572 2.5H9.70703C9.90582 2.50001 10.0996 2.56237 10.2611 2.67831C10.4226 2.79424 10.5436 2.9579 10.6072 3.14625L16.3785 20.2467C16.4268 20.3896 16.4403 20.542 16.418 20.6911C16.3957 20.8403 16.3381 20.9821 16.2502 21.1046C16.1622 21.2271 16.0463 21.327 15.9121 21.3959C15.7779 21.4647 15.6292 21.5007 15.4784 21.5007H22.1288C22.2796 21.5006 22.4283 21.4647 22.5624 21.3958C22.6966 21.3269 22.8125 21.2271 22.9004 21.1045C22.9884 20.982 23.0459 20.8403 23.0682 20.6911C23.0905 20.5419 23.077 20.3896 23.0287 20.2467L17.2574 3.14625Z",
+ "fill": "url(#paint2_linear_8587_60561)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M34.312 17.0001H32.3433L35.9278 6.81824H38.2048L41.7943 17.0001H39.8255L37.106 8.90631H37.0265L34.312 17.0001ZM34.3766 13.0079H39.746V14.4894H34.3766V13.0079Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M42.9564 17.0001V15.8566L46.8939 10.9198V10.8552H43.0856V9.36369H49.0963V10.5917L45.3477 15.4439V15.5086H49.2255V17.0001H42.9564Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M55.7843 13.7884V9.36369H57.584V17.0001H55.839V15.6428H55.7595C55.5871 16.0704 55.3037 16.42 54.9093 16.6918C54.5182 16.9636 54.036 17.0995 53.4626 17.0995C52.9621 17.0995 52.5196 16.9885 52.1352 16.7664C51.754 16.541 51.4557 16.2145 51.2403 15.787C51.0248 15.3561 50.9171 14.8358 50.9171 14.2259V9.36369H52.7168V13.9475C52.7168 14.4314 52.8494 14.8159 53.1146 15.1009C53.3797 15.3859 53.7277 15.5285 54.1586 15.5285C54.4238 15.5285 54.6806 15.4638 54.9292 15.3346C55.1778 15.2053 55.3816 15.0131 55.5407 14.7579C55.7031 14.4993 55.7843 14.1762 55.7843 13.7884Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M59.4347 17.0001V9.36369H61.1797V10.6364H61.2593C61.3985 10.1956 61.6371 9.85588 61.9752 9.61724C62.3166 9.37529 62.706 9.25432 63.1435 9.25432C63.2429 9.25432 63.354 9.25929 63.4766 9.26923C63.6026 9.27586 63.707 9.28746 63.7898 9.30403V10.9596C63.7136 10.9331 63.5926 10.9099 63.4269 10.89C63.2645 10.8668 63.1071 10.8552 62.9546 10.8552C62.6265 10.8552 62.3315 10.9264 62.0696 11.0689C61.8111 11.2082 61.6073 11.402 61.4581 11.6506C61.309 11.8992 61.2344 12.1859 61.2344 12.5107V17.0001H59.4347Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M68.0517 17.1492C67.2861 17.1492 66.6249 16.9901 66.068 16.6719C65.5145 16.3504 65.0886 15.8964 64.7903 15.3097C64.4921 14.7198 64.3429 14.0254 64.3429 13.2266C64.3429 12.4411 64.4921 11.7517 64.7903 11.1584C65.092 10.5618 65.5129 10.0978 66.0531 9.76639C66.5934 9.43164 67.2281 9.26426 67.9573 9.26426C68.4279 9.26426 68.872 9.34049 69.2896 9.49295C69.7106 9.6421 70.0818 9.87411 70.4033 10.189C70.7281 10.5038 70.9833 10.9049 71.1689 11.3921C71.3545 11.876 71.4473 12.4527 71.4473 13.1222V13.6741H65.1881V12.461H69.7222C69.7189 12.1163 69.6443 11.8097 69.4984 11.5412C69.3526 11.2695 69.1488 11.0557 68.8869 10.8999C68.6284 10.7441 68.3268 10.6662 67.9821 10.6662C67.6142 10.6662 67.2911 10.7557 67.0126 10.9347C66.7342 11.1104 66.5171 11.3424 66.3614 11.6307C66.2089 11.9158 66.131 12.229 66.1277 12.5704V13.6293C66.1277 14.0734 66.2089 14.4546 66.3713 14.7728C66.5337 15.0877 66.7608 15.3296 67.0524 15.4986C67.3441 15.6644 67.6855 15.7472 68.0766 15.7472C68.3384 15.7472 68.5754 15.7108 68.7875 15.6378C68.9996 15.5616 69.1836 15.4506 69.3394 15.3047C69.4951 15.1589 69.6128 14.9783 69.6923 14.7628L71.3727 14.9518C71.2667 15.3959 71.0645 15.7837 70.7662 16.1151C70.4712 16.4432 70.0934 16.6984 69.6327 16.8807C69.172 17.0597 68.645 17.1492 68.0517 17.1492Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M77.8296 17.0001H75.8608L79.4454 6.81824H81.7223L85.3118 17.0001H83.3431L80.6236 8.90631H80.5441L77.8296 17.0001ZM77.8942 13.0079H83.2635V14.4894H77.8942V13.0079Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M88.4974 6.81824V17.0001H86.6529V6.81824H88.4974Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_8587_60561",
+ "x1": "11.8113",
+ "y1": "3.90823",
+ "x2": "5.61444",
+ "y2": "22.2154",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#114A8B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#0669BC"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_8587_60561",
+ "x1": "13.7459",
+ "y1": "12.4397",
+ "x2": "12.3125",
+ "y2": "12.9243",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-opacity": "0.3"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.071",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.321",
+ "stop-opacity": "0.1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.623",
+ "stop-opacity": "0.05"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-opacity": "0"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint2_linear_8587_60561",
+ "x1": "12.9582",
+ "y1": "3.37404",
+ "x2": "19.7606",
+ "y2": "21.4968",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#3CCBF4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#2892DF"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AzureaiText"
+}
diff --git a/app/components/base/icons/src/public/llm/AzureaiText.tsx b/app/components/base/icons/src/public/llm/AzureaiText.tsx
new file mode 100644
index 0000000..cd23769
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/AzureaiText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AzureaiText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AzureaiText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Baichuan.json b/app/components/base/icons/src/public/llm/Baichuan.json
new file mode 100644
index 0000000..196fbad
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Baichuan.json
@@ -0,0 +1,76 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Baichuan"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Union",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.58154 1.7793H5.52779L3.34655 6.20409V17.7335L0.916016 22.2206H6.21333L8.58154 17.7335V1.7793ZM10.5761 1.7793H15.8111V22.2206H10.5761V1.7793ZM22.9166 1.7793H17.6816V6.01712H22.9166V1.7793ZM22.9166 7.38818H17.6816V22.2206H22.9166V7.38818Z",
+ "fill": "url(#paint0_radial_11622_96084)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "radialGradient",
+ "attributes": {
+ "id": "paint0_radial_11622_96084",
+ "cx": "0",
+ "cy": "0",
+ "r": "1",
+ "gradientUnits": "userSpaceOnUse",
+ "gradientTransform": "translate(5.5 5.5) rotate(45) scale(20.5061 22.0704)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#FEBD3F"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.77608",
+ "stop-color": "#FF6933"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Baichuan"
+}
diff --git a/app/components/base/icons/src/public/llm/Baichuan.tsx b/app/components/base/icons/src/public/llm/Baichuan.tsx
new file mode 100644
index 0000000..363820b
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Baichuan.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Baichuan.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Baichuan'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/BaichuanText.json b/app/components/base/icons/src/public/llm/BaichuanText.json
new file mode 100644
index 0000000..c4dc1d1
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/BaichuanText.json
@@ -0,0 +1,156 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "130",
+ "height": "24",
+ "viewBox": "0 0 130 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.58154 1.7793H6.52779L4.34655 6.20409V17.7335L1.91602 22.2206H7.21333L9.58154 17.7335V1.7793ZM11.5761 1.7793H16.8111V22.2206H11.5761V1.7793ZM23.9166 1.7793H18.6816V6.01712H23.9166V1.7793ZM23.9166 7.38818H18.6816V22.2206H23.9166V7.38818Z",
+ "fill": "url(#paint0_radial_11622_96091)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M129.722 6.83203V18H127.482V6.83203H129.722Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M123.196 15.872H118.748L118.012 18H115.66L119.676 6.81604H122.284L126.3 18H123.932L123.196 15.872ZM122.588 14.08L120.972 9.40804L119.356 14.08H122.588Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M110.962 18H108.722L103.65 10.336V18H101.41V6.81598H103.65L108.722 14.496V6.81598H110.962V18Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M97.1258 15.872H92.6778L91.9418 18H89.5898L93.6058 6.81604H96.2138L100.23 18H97.8618L97.1258 15.872ZM96.5178 14.08L94.9018 9.40804L93.2858 14.08H96.5178Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M81.6482 6.83203V13.744C81.6482 14.5014 81.8455 15.0827 82.2402 15.488C82.6349 15.8827 83.1895 16.08 83.9042 16.08C84.6295 16.08 85.1895 15.8827 85.5842 15.488C85.9789 15.0827 86.1762 14.5014 86.1762 13.744V6.83203H88.4322V13.728C88.4322 14.6774 88.2242 15.4827 87.8082 16.144C87.4029 16.7947 86.8535 17.2854 86.1602 17.616C85.4775 17.9467 84.7149 18.112 83.8722 18.112C83.0402 18.112 82.2829 17.9467 81.6002 17.616C80.9282 17.2854 80.3949 16.7947 80.0002 16.144C79.6055 15.4827 79.4082 14.6774 79.4082 13.728V6.83203H81.6482Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M77.557 6.83203V18H75.317V13.248H70.533V18H68.293V6.83203H70.533V11.424H75.317V6.83203H77.557Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M55.7871 12.4C55.7871 11.3013 56.0324 10.32 56.5231 9.45599C57.0244 8.58132 57.7018 7.90399 58.5551 7.42399C59.4191 6.93332 60.3844 6.68799 61.4511 6.68799C62.6991 6.68799 63.7924 7.00799 64.7311 7.64799C65.6698 8.28799 66.3258 9.17332 66.6991 10.304H64.1231C63.8671 9.77065 63.5044 9.37065 63.0351 9.10399C62.5764 8.83732 62.0431 8.70399 61.4351 8.70399C60.7844 8.70399 60.2031 8.85865 59.6911 9.16799C59.1898 9.46665 58.7951 9.89332 58.5071 10.448C58.2298 11.0027 58.0911 11.6533 58.0911 12.4C58.0911 13.136 58.2298 13.7867 58.5071 14.352C58.7951 14.9067 59.1898 15.3387 59.6911 15.648C60.2031 15.9467 60.7844 16.096 61.4351 16.096C62.0431 16.096 62.5764 15.9627 63.0351 15.696C63.5044 15.4187 63.8671 15.0133 64.1231 14.48H66.6991C66.3258 15.6213 65.6698 16.512 64.7311 17.152C63.8031 17.7813 62.7098 18.096 61.4511 18.096C60.3844 18.096 59.4191 17.856 58.5551 17.376C57.7018 16.8853 57.0244 16.208 56.5231 15.344C56.0324 14.48 55.7871 13.4987 55.7871 12.4Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M54.4373 6.83203V18H52.1973V6.83203H54.4373Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M47.913 15.872H43.465L42.729 18H40.377L44.393 6.81598H47.001L51.017 18H48.649L47.913 15.872ZM47.305 14.08L45.689 9.40798L44.073 14.08H47.305Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M37.4395 12.272C38.0688 12.3893 38.5862 12.704 38.9915 13.216C39.3968 13.728 39.5995 14.3146 39.5995 14.976C39.5995 15.5733 39.4502 16.1013 39.1515 16.56C38.8635 17.008 38.4422 17.36 37.8875 17.616C37.3328 17.872 36.6768 18 35.9195 18H31.1035V6.83197H35.7115C36.4688 6.83197 37.1195 6.95464 37.6635 7.19997C38.2182 7.4453 38.6342 7.78664 38.9115 8.22397C39.1995 8.6613 39.3435 9.1573 39.3435 9.71197C39.3435 10.3626 39.1675 10.9066 38.8155 11.344C38.4742 11.7813 38.0155 12.0906 37.4395 12.272ZM33.3435 11.44H35.3915C35.9248 11.44 36.3355 11.3226 36.6235 11.088C36.9115 10.8426 37.0555 10.496 37.0555 10.048C37.0555 9.59997 36.9115 9.2533 36.6235 9.00797C36.3355 8.76264 35.9248 8.63997 35.3915 8.63997H33.3435V11.44ZM35.5995 16.176C36.1435 16.176 36.5648 16.048 36.8635 15.792C37.1728 15.536 37.3275 15.1733 37.3275 14.704C37.3275 14.224 37.1675 13.8506 36.8475 13.584C36.5275 13.3066 36.0955 13.168 35.5515 13.168H33.3435V16.176H35.5995Z",
+ "fill": "#FF6A34"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "radialGradient",
+ "attributes": {
+ "id": "paint0_radial_11622_96091",
+ "cx": "0",
+ "cy": "0",
+ "r": "1",
+ "gradientUnits": "userSpaceOnUse",
+ "gradientTransform": "translate(6.5 5.5) rotate(45) scale(20.5061 22.0704)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#FEBD3F"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "0.77608",
+ "stop-color": "#FF6933"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "BaichuanText"
+}
diff --git a/app/components/base/icons/src/public/llm/BaichuanText.tsx b/app/components/base/icons/src/public/llm/BaichuanText.tsx
new file mode 100644
index 0000000..37d6242
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/BaichuanText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BaichuanText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BaichuanText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Chatglm.json b/app/components/base/icons/src/public/llm/Chatglm.json
new file mode 100644
index 0000000..c01787f
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Chatglm.json
@@ -0,0 +1,72 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_8587_60212",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "1",
+ "y": "2",
+ "width": "23",
+ "height": "21"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M23.8 2H1V22.4H23.8V2Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_8587_60212)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3.86378 14.4544C3.86378 13.0981 4.67438 11.737 6.25923 10.6634C7.83827 9.59364 10.0864 8.89368 12.6282 8.89368C15.17 8.89368 17.4182 9.59364 18.9972 10.6634C19.7966 11.2049 20.399 11.8196 20.7998 12.4699C21.2873 11.5802 21.4969 10.6351 21.3835 9.69252C21.3759 9.62928 21.3824 9.56766 21.4005 9.5106C21.0758 9.21852 20.7259 8.94624 20.3558 8.69556C18.3272 7.32126 15.5915 6.50964 12.6282 6.50964C9.66497 6.50964 6.92918 7.32126 4.90058 8.69556C2.8778 10.0659 1.45703 12.0812 1.45703 14.4544C1.45703 16.8275 2.8778 18.8428 4.90058 20.2132C6.92918 21.5875 9.66497 22.3991 12.6282 22.3991C15.5915 22.3991 18.3272 21.5875 20.3558 20.2132C22.3786 18.8428 23.7994 16.8275 23.7994 14.4544C23.7994 12.9455 23.225 11.5813 22.2868 10.4355C22.2377 11.4917 21.8621 12.5072 21.238 13.43C21.3409 13.7686 21.3926 14.1116 21.3926 14.4544C21.3926 15.8107 20.582 17.1717 18.9972 18.2453C17.4182 19.3151 15.17 20.015 12.6282 20.015C10.0864 20.015 7.83827 19.3151 6.25923 18.2453C4.67438 17.1717 3.86378 15.8107 3.86378 14.4544Z",
+ "fill": "#3762FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3.84445 11.6838C3.20239 13.4885 3.35368 15.1156 4.18868 16.2838C5.02368 17.452 6.52281 18.1339 8.45459 18.1334C10.3826 18.133 12.6296 17.44 14.6939 15.9922C16.7581 14.5444 18.1643 12.6753 18.8052 10.8739C19.4473 9.0692 19.2959 7.44206 18.461 6.27392C17.626 5.10572 16.1269 4.42389 14.1951 4.42431C12.267 4.42475 10.0201 5.11774 7.95575 6.56552C5.89152 8.01332 4.48529 9.8825 3.84445 11.6838ZM1.53559 10.8778C2.36374 8.55002 4.11254 6.28976 6.54117 4.58645C8.96981 2.88312 11.7029 1.99995 14.1945 1.99939C16.6825 1.99884 19.0426 2.8912 20.4589 4.87263C21.8752 6.85406 21.941 9.35564 21.1141 11.6799C20.2859 14.0077 18.5371 16.2679 16.1085 17.9713C13.6798 19.6746 10.9468 20.5578 8.45513 20.5584C5.9672 20.5589 3.60706 19.6665 2.19075 17.6851C0.774446 15.7036 0.708677 13.2021 1.53559 10.8778Z",
+ "fill": "#1041F3"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Chatglm"
+}
diff --git a/app/components/base/icons/src/public/llm/Chatglm.tsx b/app/components/base/icons/src/public/llm/Chatglm.tsx
new file mode 100644
index 0000000..742704f
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Chatglm.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Chatglm.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Chatglm'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/ChatglmText.json b/app/components/base/icons/src/public/llm/ChatglmText.json
new file mode 100644
index 0000000..1fe28ea
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/ChatglmText.json
@@ -0,0 +1,135 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "100",
+ "height": "24",
+ "viewBox": "0 0 100 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M56.5415 9.49683C56.3371 9.38235 56.1222 9.28491 55.8984 9.20565C55.4497 9.04653 54.9672 8.95911 54.4654 8.95911C52.0893 8.95911 50.1562 10.9044 50.1562 13.2955C50.1562 15.6867 52.0893 17.6313 54.4654 17.6313C54.9672 17.6313 55.4497 17.5438 55.8984 17.3847C55.9178 17.3778 55.9378 17.3703 55.9572 17.3627C57.2065 16.8986 58.1845 15.8659 58.582 14.5785V12.0125C58.2489 10.9333 57.5083 10.0333 56.5415 9.49683ZM55.9578 13.9446C55.9397 13.986 55.9197 14.0269 55.8991 14.0665C55.6247 14.5804 55.0854 14.9307 54.466 14.9307C53.5698 14.9307 52.8411 14.1973 52.8411 13.2955C52.8411 12.3936 53.5698 11.6603 54.466 11.6603C55.0854 11.6603 55.6241 12.01 55.8991 12.5244C55.9203 12.5647 55.9403 12.6049 55.9578 12.6471C56.0434 12.8458 56.0909 13.0653 56.0909 13.2955C56.0909 13.5257 56.0434 13.7452 55.9578 13.9446Z",
+ "fill": "#1A2029"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M58.6419 9.49683V17.596H55.959V13.9445C56.0446 13.7458 56.0921 13.5256 56.0921 13.2955C56.0921 13.0653 56.0446 12.8458 55.959 12.6471V9.49683H58.6419Z",
+ "fill": "#1A2029"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M63.4475 7.46912H60.7637V17.6142H63.4475V7.46912Z",
+ "fill": "#1A2029"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M64.8417 9.49683H59.3789V12.1974H64.3659C64.3587 12.0773 64.3545 11.9559 64.3545 11.8339C64.3545 11.0031 64.5285 10.2125 64.8417 9.49683Z",
+ "fill": "#1A2029"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M35.3555 14.908C34.2412 14.908 33.2644 14.3087 32.7257 13.4137C32.4444 12.947 32.2832 12.3999 32.2832 11.8163C32.2832 11.2326 32.4444 10.6849 32.7257 10.2188C33.2644 9.32448 34.2412 8.72448 35.3555 8.72448C36.4699 8.72448 37.4461 9.32388 37.9847 10.2188L40.2809 8.82324C39.2716 7.14714 37.441 6.02454 35.3555 6.02454C33.27 6.02454 31.4388 7.14714 30.4296 8.82324C29.9027 9.69744 29.5996 10.7219 29.5996 11.8169C29.5996 12.9118 29.9027 13.9363 30.4296 14.8105C31.4388 16.4866 33.2694 17.6092 35.3555 17.6092C37.4417 17.6092 39.2716 16.4866 40.2809 14.8105L37.9847 13.415C37.4461 14.3093 36.4692 14.9093 35.3555 14.9093V14.908Z",
+ "fill": "#1A2029"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M79.4097 14.9232H85.1781V17.6237H77.5179V17.6124H76.7265V6.04407H79.4097V14.9232ZM96.7581 6.04971H93.8625L91.4631 10.1371L89.0631 6.04971H86.0763V17.6181H88.7601V10.5352L91.4637 15.1389L94.0749 10.6918V17.6181H96.7581V6.12141V6.04971ZM70.7661 13.2169H73.1445V13.9779C72.5841 14.581 71.7867 14.959 70.9023 14.959C70.0179 14.959 69.2121 14.5773 68.6511 13.9691C68.5089 13.815 68.3811 13.6458 68.2725 13.4647C67.9911 12.998 67.8297 12.4509 67.8297 11.8672C67.8297 11.2836 67.9911 10.7358 68.2725 10.2697C68.8113 9.37545 69.7881 8.77545 70.9023 8.77545C71.7087 8.77545 72.4425 9.08931 72.9909 9.60249L74.8881 7.69311C73.8537 6.69123 72.4479 6.07491 70.9023 6.07491C68.8161 6.07491 66.9855 7.19751 65.9763 8.87355C65.4495 9.74775 65.1465 10.7723 65.1465 11.8672C65.1465 12.9622 65.4495 13.9867 65.9763 14.8609C66.1983 15.2288 66.4587 15.5703 66.7539 15.8791C67.8027 16.9765 69.2751 17.6596 70.9029 17.6596C72.9885 17.6596 74.8191 16.537 75.8283 14.8609V10.5175H70.7661V13.2181V13.2169Z",
+ "fill": "#1A2029"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M49.4752 12.5477V17.6174H46.7954V13.1156C46.7954 12.2603 46.106 11.5666 45.2561 11.5666C44.4061 11.5666 43.7168 12.2597 43.7168 13.1156V17.6174H41.0332V6H43.7168V9.8811C44.3343 9.3333 45.1473 9.00186 46.0373 9.00942C47.9484 9.02514 49.4752 10.6244 49.4752 12.5477Z",
+ "fill": "#1A2029"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_8587_60467",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "2",
+ "y": "1",
+ "width": "23",
+ "height": "22"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M24.8 1.80005H2V22.2H24.8V1.80005Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_8587_60467)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4.86378 14.2544C4.86378 12.8981 5.67438 11.5371 7.25923 10.4634C8.83827 9.39369 11.0864 8.69373 13.6282 8.69373C16.17 8.69373 18.4182 9.39369 19.9972 10.4634C20.7966 11.005 21.399 11.6196 21.7998 12.27C22.2873 11.3803 22.4969 10.4351 22.3835 9.49257C22.3759 9.42933 22.3824 9.36771 22.4005 9.31065C22.0758 9.01857 21.7259 8.74629 21.3558 8.49561C19.3272 7.12131 16.5915 6.30969 13.6282 6.30969C10.665 6.30969 7.92918 7.12131 5.90058 8.49561C3.8778 9.86595 2.45703 11.8813 2.45703 14.2544C2.45703 16.6275 3.8778 18.6429 5.90058 20.0132C7.92918 21.3875 10.665 22.1991 13.6282 22.1991C16.5915 22.1991 19.3272 21.3875 21.3558 20.0132C23.3786 18.6429 24.7994 16.6275 24.7994 14.2544C24.7994 12.7455 24.225 11.3813 23.2868 10.2356C23.2377 11.2918 22.8621 12.3073 22.238 13.2301C22.3409 13.5687 22.3926 13.9117 22.3926 14.2544C22.3926 15.6107 21.582 16.9718 19.9972 18.0454C18.4182 19.1151 16.17 19.8151 13.6282 19.8151C11.0864 19.8151 8.83827 19.1151 7.25923 18.0454C5.67438 16.9718 4.86378 15.6107 4.86378 14.2544Z",
+ "fill": "#3762FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4.84445 11.4838C4.20239 13.2886 4.35368 14.9157 5.18868 16.0839C6.02368 17.2521 7.52281 17.9339 9.45459 17.9334C11.3826 17.933 13.6296 17.24 15.6939 15.7923C17.7581 14.3445 19.1643 12.4753 19.8052 10.674C20.4473 8.86925 20.2959 7.24211 19.461 6.07397C18.626 4.90576 17.1269 4.22394 15.1951 4.22436C13.267 4.22479 11.0201 4.91779 8.95575 6.36557C6.89152 7.81337 5.48529 9.68255 4.84445 11.4838ZM2.53559 10.6778C3.36374 8.35007 5.11254 6.08981 7.54117 4.3865C9.96981 2.68317 12.7029 1.8 15.1945 1.79944C17.6825 1.79889 20.0426 2.69125 21.4589 4.67268C22.8752 6.65411 22.941 9.15569 22.1141 11.48C21.2859 13.8077 19.5371 16.068 17.1085 17.7713C14.6798 19.4747 11.9468 20.3579 9.45513 20.3584C6.9672 20.3589 4.60706 19.4666 3.19075 17.4851C1.77445 15.5037 1.70868 13.0022 2.53559 10.6778Z",
+ "fill": "#1041F3"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ChatglmText"
+}
diff --git a/app/components/base/icons/src/public/llm/ChatglmText.tsx b/app/components/base/icons/src/public/llm/ChatglmText.tsx
new file mode 100644
index 0000000..e97f3fa
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/ChatglmText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ChatglmText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ChatglmText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Cohere.json b/app/components/base/icons/src/public/llm/Cohere.json
new file mode 100644
index 0000000..7062891
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Cohere.json
@@ -0,0 +1,112 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "22",
+ "height": "22",
+ "viewBox": "0 0 22 22",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_13224_9519",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "0",
+ "width": "22",
+ "height": "22"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "clip0_2207_90691"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M21.5 0.5H0.5V21.5H21.5V0.5Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_13224_9519)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M7.30367 13.0035C7.8689 13.0035 8.99327 12.9725 10.5474 12.3326C12.3585 11.587 15.9617 10.2334 18.561 8.84305C20.3788 7.8706 21.1757 6.58448 21.1757 4.85248C21.1757 2.44869 19.2271 0.5 16.8233 0.5H6.75176C3.299 0.5 0.5 3.299 0.5 6.75176C0.5 10.2045 3.12069 13.0035 7.30367 13.0035Z",
+ "fill": "#39594D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.00732 17.3086C9.00732 15.6162 10.0262 14.0902 11.5894 13.4414L14.7612 12.1251C17.9694 10.7936 21.5006 13.1513 21.5006 16.6249C21.5006 19.316 19.3185 21.4974 16.6273 21.4967L13.1933 21.4958C10.8813 21.4952 9.00732 19.6207 9.00732 17.3086Z",
+ "fill": "#D18EE2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M4.10396 13.8277C2.11358 13.8277 0.5 15.4411 0.5 17.4315V17.8984C0.5 19.8887 2.11352 21.5022 4.1039 21.5022C6.09428 21.5022 7.70785 19.8887 7.70785 17.8984V17.4315C7.70785 15.4411 6.09434 13.8277 4.10396 13.8277Z",
+ "fill": "#FF7759"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Cohere"
+}
diff --git a/app/components/base/icons/src/public/llm/Cohere.tsx b/app/components/base/icons/src/public/llm/Cohere.tsx
new file mode 100644
index 0000000..1f16d1c
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Cohere.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Cohere.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Cohere'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/CohereText.json b/app/components/base/icons/src/public/llm/CohereText.json
new file mode 100644
index 0000000..89657cc
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/CohereText.json
@@ -0,0 +1,90 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "120",
+ "height": "24",
+ "viewBox": "0 0 120 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M34.4917 21.9129C37.4378 21.9129 40.0162 20.4398 41.0355 17.4656C41.2334 16.8701 40.9496 16.4743 40.384 16.4743H39.2787C38.7689 16.4743 38.4292 16.7002 38.2013 17.1818C37.3239 18.9108 36.1047 19.5324 34.5757 19.5324C31.8553 19.5324 30.1844 17.6335 30.1844 14.4616C30.1844 11.2896 31.9133 9.39083 34.5177 9.39083C36.1046 9.39083 37.4079 10.0704 38.2293 11.6854C38.4852 12.1671 38.795 12.3929 39.3067 12.3929H40.412C40.9776 12.3929 41.2614 12.0251 41.0635 11.4855C39.8742 8.25556 37.2099 7.01035 34.4917 7.01035C30.3843 7.01035 27.3242 10.0424 27.3242 14.4616C27.3242 18.8808 30.2424 21.9129 34.4917 21.9129ZM108.627 13.1584C108.995 10.75 110.638 9.24892 112.876 9.24892C115.115 9.24892 116.786 10.7779 116.983 13.1584H108.627ZM112.99 21.9129C115.596 21.9129 118.203 20.6956 119.478 17.9474C119.79 17.2958 119.506 16.8421 118.94 16.8421H117.892C117.383 16.8421 117.071 17.0679 116.816 17.5216C115.966 19.0227 114.493 19.6463 112.992 19.6463C110.414 19.6463 108.743 17.8894 108.545 15.0292H118.943C119.508 15.0292 119.878 14.7174 119.878 14.1219C119.764 9.67465 116.876 7.01235 112.88 7.01235C108.885 7.01235 105.713 9.90251 105.713 14.4636C105.713 19.0247 108.801 21.9148 112.994 21.9148L112.99 21.9129ZM96.5025 14.8313H97.4378C98.0035 14.8313 98.3152 14.5196 98.4012 13.9239C98.9409 10.0964 101.182 9.5887 103.564 9.70264C104.074 9.72661 104.491 9.33487 104.491 8.82319V7.94575C104.491 7.38012 104.208 7.03833 103.642 7.01035C101.533 6.9304 99.6525 7.65393 98.5651 9.70264C98.5052 9.81455 98.3373 9.78458 98.3233 9.65866L98.1474 8.11365C98.0915 7.54801 97.7796 7.26418 97.212 7.26418H92.9347C92.435 7.26418 92.0272 7.66993 92.0272 8.17161V8.6533C92.0272 9.15298 92.433 9.56072 92.9347 9.56072H94.6916C95.1912 9.56072 95.599 9.96646 95.599 10.4681V13.9239C95.599 14.4236 96.0048 14.8313 96.5064 14.8313H96.5025ZM92.6788 21.631H101.545C102.111 21.631 102.453 21.2913 102.453 20.7236V20.2418C102.453 19.6762 102.113 19.3345 101.545 19.3345H99.2787C98.7131 19.3345 98.3712 18.9947 98.3712 18.4271V16.8681C98.3712 16.3024 98.0315 15.9606 97.4638 15.9606H96.5005C95.9348 15.9606 95.593 16.3004 95.593 16.8681V18.4271C95.593 18.9927 95.2532 19.3345 94.6856 19.3345H92.6749C92.1092 19.3345 91.7674 19.6743 91.7674 20.2418V20.7236C91.7674 21.2893 92.1073 21.631 92.6749 21.631H92.6788ZM78.9955 13.1604C79.3633 10.752 81.0062 9.25092 83.2449 9.25092C85.4834 9.25092 87.1544 10.7799 87.3522 13.1604H78.9955ZM83.3587 21.9148C85.9651 21.9148 88.5714 20.6977 89.8466 17.9493C90.1585 17.2978 89.8746 16.844 89.309 16.844H88.2617C87.7519 16.844 87.4402 17.0699 87.1844 17.5236C86.3349 19.0247 84.8618 19.6482 83.3607 19.6482C80.7824 19.6482 79.1115 17.8914 78.9136 15.0313H89.311C89.8766 15.0313 90.2464 14.7194 90.2464 14.1238C90.1324 9.67665 87.2443 7.01434 83.2488 7.01434C79.2533 7.01434 76.0814 9.9045 76.0814 14.4656C76.0814 19.0266 79.1694 21.9168 83.3628 21.9168L83.3587 21.9148ZM50.5835 21.9148C54.8329 21.9148 57.8649 18.7708 57.8649 14.4636C57.8649 10.1563 54.8329 7.01235 50.5835 7.01235C46.3342 7.01235 43.3022 10.2143 43.3022 14.4636C43.3022 15.455 43.472 16.5602 43.9816 17.7775C44.2375 18.3731 44.7192 18.4571 45.2289 18.0892L46.0504 17.4936C46.4761 17.1818 46.588 16.8141 46.4461 16.2765C46.2202 15.5689 46.1623 14.9453 46.1623 14.4076C46.1623 11.4335 47.9472 9.39283 50.5815 9.39283C53.2159 9.39283 55.0007 11.4035 55.0007 14.4636C55.0007 17.5236 53.2439 19.5344 50.6375 19.5344C49.7301 19.5344 48.8806 19.3645 47.8612 18.5989C47.4355 18.2592 47.0397 18.2032 46.586 18.5429L45.9624 18.9967C45.4527 19.3645 45.3968 19.8741 45.8764 20.2718C47.3496 21.4611 49.0485 21.9148 50.5795 21.9148H50.5835ZM61.4606 21.631H62.3961C62.8957 21.631 63.3035 21.2252 63.3035 20.7236V13.9539C63.3035 11.0937 64.8324 9.39283 67.213 9.39283C69.3656 9.39283 70.6128 10.8099 70.6128 13.4163V20.7255C70.6128 21.2252 71.0186 21.633 71.5203 21.633H72.4836C72.9833 21.633 73.391 21.2272 73.391 20.7255V12.9625C73.391 9.13899 71.4363 7.01434 68.1224 7.01434C65.8659 7.01434 64.5327 7.93776 63.5373 9.22294C63.4613 9.32088 63.3075 9.26691 63.3075 9.14499V2.99092C63.3014 2.48924 62.8957 2.0835 62.3961 2.0835H61.4606C60.9609 2.0835 60.5532 2.48924 60.5532 2.99092V20.7236C60.5532 21.2232 60.959 21.631 61.4606 21.631Z",
+ "fill": "#39594D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_13223_52628",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "1",
+ "y": "2",
+ "width": "20",
+ "height": "20"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.8354 2.08319H1.00195V21.9165H20.8354V2.08319Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_13223_52628)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M7.42768 13.8921C7.96151 13.8921 9.02342 13.8628 10.4912 13.2585C12.2017 12.5542 15.6047 11.2758 18.0597 9.96274C19.7765 9.04432 20.5291 7.82964 20.5291 6.19387C20.5291 3.92362 18.6887 2.08319 16.4185 2.08319H6.90643C3.64547 2.08319 1.00195 4.72669 1.00195 7.98763C1.00195 11.2486 3.47706 13.8921 7.42768 13.8921Z",
+ "fill": "#39594D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.03711 17.958C9.03711 16.3596 9.99942 14.9184 11.4758 14.3057L14.4713 13.0625C17.5013 11.805 20.8364 14.0316 20.8364 17.3123C20.8364 19.8539 18.7755 21.9141 16.2338 21.9134L12.9906 21.9126C10.807 21.912 9.03711 20.1417 9.03711 17.958Z",
+ "fill": "#D18EE2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.40571 14.6705C2.5259 14.6705 1.00195 16.1943 1.00195 18.0741V18.515C1.00195 20.3947 2.52584 21.9186 4.40565 21.9186C6.28547 21.9186 7.80941 20.3947 7.80941 18.515V18.0741C7.80941 16.1943 6.28552 14.6705 4.40571 14.6705Z",
+ "fill": "#FF7759"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "CohereText"
+}
diff --git a/app/components/base/icons/src/public/llm/CohereText.tsx b/app/components/base/icons/src/public/llm/CohereText.tsx
new file mode 100644
index 0000000..e6d5ceb
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/CohereText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './CohereText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'CohereText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Gpt3.json b/app/components/base/icons/src/public/llm/Gpt3.json
new file mode 100644
index 0000000..383cb98
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Gpt3.json
@@ -0,0 +1,51 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "6",
+ "fill": "#19C37D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.6451 11.6028C19.8209 11.995 19.9325 12.4142 19.9781 12.8419C20.0221 13.2696 20.0001 13.7024 19.9088 14.1234C19.8192 14.5443 19.6637 14.9484 19.4473 15.3203C19.3053 15.5688 19.1379 15.8021 18.9452 16.0168C18.7542 16.2298 18.5412 16.4225 18.3096 16.5916C18.0763 16.7606 17.8278 16.9027 17.564 17.0193C17.302 17.1343 17.0281 17.2222 16.7475 17.2796C16.6156 17.6888 16.4195 18.0759 16.1659 18.4242C15.914 18.7724 15.6081 19.0784 15.2598 19.3303C14.9115 19.5839 14.5261 19.78 14.117 19.9118C13.7079 20.0454 13.2802 20.1113 12.8491 20.1113C12.5634 20.113 12.276 20.0826 11.9953 20.0251C11.7164 19.9659 11.4425 19.8763 11.1805 19.7597C10.9184 19.643 10.6699 19.4977 10.4383 19.3286C10.2084 19.1595 9.99541 18.9651 9.80606 18.7504C9.38342 18.8417 8.95064 18.8637 8.52293 18.8197C8.09522 18.7741 7.67596 18.6625 7.28206 18.4867C6.88985 18.3126 6.52638 18.0759 6.20687 17.7868C5.88735 17.4977 5.61517 17.1596 5.40047 16.7877C5.25677 16.5392 5.13843 16.2771 5.04883 16.005C4.95924 15.7328 4.90007 15.4522 4.86964 15.1665C4.83921 14.8824 4.8409 14.595 4.87133 14.3093C4.90176 14.0253 4.96431 13.7447 5.05391 13.4725C4.76651 13.153 4.52983 12.7895 4.35402 12.3973C4.17989 12.0034 4.06662 11.5859 4.02267 11.1581C3.97702 10.7304 4.00069 10.2976 4.09029 9.8767C4.17989 9.45575 4.33542 9.05171 4.55181 8.67978C4.69382 8.43127 4.86118 8.19628 5.05222 7.98327C5.24325 7.77026 5.45795 7.57754 5.68956 7.40848C5.92116 7.23943 6.17136 7.09573 6.4334 6.98077C6.69713 6.86412 6.971 6.77791 7.25163 6.72043C7.38349 6.30962 7.5796 5.92417 7.83149 5.57592C8.08508 5.22766 8.39107 4.92167 8.73932 4.66809C9.08758 4.4162 9.47302 4.22009 9.88214 4.08654C10.2913 3.95467 10.719 3.88705 11.1501 3.88874C11.4358 3.88705 11.7232 3.91579 12.0038 3.97496C12.2844 4.03413 12.5583 4.12204 12.8203 4.23869C13.0824 4.35703 13.3309 4.50072 13.5625 4.66978C13.7941 4.84053 14.0071 5.03325 14.1964 5.24795C14.6174 5.15835 15.0502 5.13637 15.4779 5.18033C15.9056 5.22428 16.3232 5.33755 16.7171 5.51168C17.1093 5.6875 17.4727 5.92248 17.7923 6.21157C18.1118 6.49896 18.384 6.83538 18.5987 7.209C18.7423 7.45582 18.8607 7.71786 18.9503 7.99173C19.0399 8.26391 19.1007 8.54454 19.1295 8.83024C19.1599 9.11595 19.1599 9.40334 19.1278 9.68905C19.0974 9.97475 19.0348 10.2554 18.9452 10.5276C19.2343 10.8471 19.4693 11.2089 19.6451 11.6028ZM14.0122 18.8197C14.3807 18.6676 14.7154 18.4428 14.9978 18.1604C15.2801 17.8781 15.5049 17.5434 15.6571 17.1731C15.8092 16.8046 15.8887 16.409 15.8887 16.01V12.2401C15.8876 12.2367 15.8864 12.2328 15.8853 12.2283C15.8842 12.2249 15.8825 12.2215 15.8802 12.2181C15.878 12.2147 15.8752 12.2119 15.8718 12.2097C15.8684 12.2063 15.865 12.204 15.8616 12.2029L14.4974 11.4151V15.9695C14.4974 16.0151 14.4906 16.0624 14.4788 16.1064C14.4669 16.152 14.45 16.1943 14.4264 16.2349C14.4027 16.2755 14.3756 16.3126 14.3418 16.3448C14.309 16.3775 14.272 16.4059 14.2319 16.4293L11.0013 18.294C10.9742 18.3109 10.9286 18.3346 10.9049 18.3481C11.0385 18.4613 11.1839 18.5611 11.336 18.649C11.4899 18.7369 11.6488 18.8113 11.8144 18.8722C11.9801 18.9313 12.1509 18.977 12.3233 19.0074C12.4974 19.0378 12.6732 19.053 12.8491 19.053C13.248 19.053 13.6436 18.9736 14.0122 18.8197ZM6.31844 16.2602C6.51962 16.6068 6.78504 16.9077 7.10117 17.1512C7.419 17.3946 7.77908 17.5721 8.16453 17.6752C8.54998 17.7784 8.95233 17.8054 9.34792 17.753C9.74351 17.7006 10.1239 17.5721 10.4705 17.3726L13.7366 15.4877L13.7451 15.4792C13.7473 15.477 13.749 15.4736 13.7501 15.4691C13.7524 15.4657 13.7541 15.4623 13.7552 15.4589V13.8698L9.81283 16.1504C9.77225 16.174 9.72999 16.1909 9.68603 16.2045C9.64039 16.2163 9.59474 16.2214 9.54741 16.2214C9.50176 16.2214 9.45612 16.2163 9.41047 16.2045C9.36652 16.1909 9.32256 16.174 9.28199 16.1504L6.05133 14.284C6.0226 14.2671 5.98033 14.2417 5.95666 14.2265C5.92623 14.4006 5.91102 14.5764 5.91102 14.7523C5.91102 14.9281 5.92792 15.1039 5.95835 15.278C5.98878 15.4505 6.03612 15.6212 6.09529 15.7869C6.15615 15.9526 6.23053 16.1115 6.31844 16.2636V16.2602ZM5.46978 9.21062C5.2703 9.55718 5.14182 9.93925 5.08941 10.3348C5.037 10.7304 5.06405 11.1311 5.16717 11.5182C5.2703 11.9037 5.44781 12.2638 5.69125 12.5816C5.93469 12.8977 6.2373 13.1631 6.58217 13.3626L9.84664 15.2493C9.85002 15.2504 9.85396 15.2515 9.85847 15.2527H9.8703C9.87481 15.2527 9.87876 15.2515 9.88214 15.2493C9.88552 15.2482 9.8889 15.2465 9.89228 15.2442L11.2616 14.453L7.31925 12.1775C7.28037 12.1539 7.24318 12.1251 7.20937 12.093C7.17661 12.0602 7.1482 12.0232 7.12484 11.9831C7.10286 11.9426 7.08427 11.9003 7.07243 11.8547C7.0606 11.8107 7.05384 11.7651 7.05553 11.7177V7.87846C6.88985 7.93932 6.72925 8.0137 6.5771 8.10161C6.42495 8.19121 6.28125 8.29265 6.14601 8.40591C6.01245 8.51918 5.88735 8.64428 5.77408 8.77953C5.66082 8.91308 5.56107 9.05847 5.47316 9.21062H5.46978ZM16.6832 11.8208C16.7238 11.8445 16.761 11.8716 16.7948 11.9054C16.8269 11.9375 16.8557 11.9747 16.8794 12.0153C16.9013 12.0558 16.9199 12.0998 16.9318 12.1437C16.9419 12.1894 16.9487 12.235 16.947 12.2824V16.1216C17.4896 15.9221 17.963 15.5722 18.3129 15.1124C18.6646 14.6525 18.8759 14.1031 18.9249 13.5283C18.974 12.9535 18.859 12.3753 18.5919 11.8631C18.3248 11.3509 17.9174 10.9248 17.417 10.6374L14.1525 8.75079C14.1491 8.74966 14.1452 8.74853 14.1407 8.74741H14.1288C14.1254 8.74853 14.1215 8.74966 14.117 8.75079C14.1136 8.75191 14.1102 8.7536 14.1068 8.75586L12.7443 9.54366L16.6866 11.8208H16.6832ZM18.0441 9.77526H18.0425V9.77695L18.0441 9.77526ZM18.0425 9.77357C18.1405 9.20555 18.0746 8.62061 17.8514 8.08809C17.63 7.55556 17.2597 7.09742 16.7864 6.76607C16.313 6.43641 15.7551 6.24707 15.1787 6.22171C14.6005 6.19804 14.0291 6.33836 13.5287 6.62575L10.2642 8.51073C10.2608 8.51298 10.258 8.5158 10.2558 8.51918L10.249 8.52932C10.2479 8.5327 10.2467 8.53665 10.2456 8.54116C10.2445 8.54454 10.2439 8.54848 10.2439 8.55299V10.1286L14.1863 7.85141C14.2269 7.82774 14.2708 7.81084 14.3148 7.79731C14.3604 7.78548 14.4061 7.78041 14.4517 7.78041C14.499 7.78041 14.5447 7.78548 14.5903 7.79731C14.6343 7.81084 14.6766 7.82774 14.7171 7.85141L17.9478 9.71778C17.9765 9.73469 18.0188 9.75836 18.0425 9.77357ZM9.50007 8.02892C9.50007 7.98327 9.50683 7.93763 9.51867 7.89198C9.5305 7.84803 9.54741 7.80407 9.57108 7.7635C9.59474 7.72462 9.62179 7.68743 9.6556 7.65361C9.68772 7.62149 9.72492 7.59275 9.76549 7.57078L12.9961 5.70609C13.0266 5.6875 13.0688 5.66383 13.0925 5.65199C12.6496 5.28176 12.1086 5.04508 11.5355 4.97239C10.9624 4.89801 10.3809 4.9893 9.85847 5.23443C9.3344 5.47956 8.89147 5.87008 8.5821 6.35696C8.27273 6.84553 8.10874 7.41017 8.10874 7.98834V11.7583C8.10987 11.7628 8.111 11.7667 8.11212 11.7701C8.11325 11.7735 8.11494 11.7769 8.1172 11.7803C8.11945 11.7836 8.12227 11.787 8.12565 11.7904C8.1279 11.7927 8.13128 11.7949 8.13579 11.7972L9.50007 12.585V8.02892ZM10.2405 13.011L11.997 14.0253L13.7535 13.011V10.984L11.9987 9.96968L10.2422 10.984L10.2405 13.011Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "0.5",
+ "y": "0.5",
+ "width": "23",
+ "height": "23",
+ "rx": "5.5",
+ "stroke": "black",
+ "stroke-opacity": "0.05"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Gpt3"
+}
diff --git a/app/components/base/icons/src/public/llm/Gpt3.tsx b/app/components/base/icons/src/public/llm/Gpt3.tsx
new file mode 100644
index 0000000..7926d50
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Gpt3.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Gpt3.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Gpt3'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Gpt4.json b/app/components/base/icons/src/public/llm/Gpt4.json
new file mode 100644
index 0000000..b0d1941
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Gpt4.json
@@ -0,0 +1,51 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "6",
+ "fill": "#AB68FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.6451 11.6028C19.8209 11.995 19.9325 12.4142 19.9781 12.8419C20.0221 13.2696 20.0001 13.7024 19.9088 14.1234C19.8192 14.5443 19.6637 14.9484 19.4473 15.3203C19.3053 15.5688 19.1379 15.8021 18.9452 16.0168C18.7542 16.2298 18.5412 16.4225 18.3096 16.5916C18.0763 16.7606 17.8278 16.9027 17.564 17.0193C17.302 17.1343 17.0281 17.2222 16.7475 17.2796C16.6156 17.6888 16.4195 18.0759 16.1659 18.4242C15.914 18.7724 15.6081 19.0784 15.2598 19.3303C14.9115 19.5839 14.5261 19.78 14.117 19.9118C13.7079 20.0454 13.2802 20.1113 12.8491 20.1113C12.5634 20.113 12.276 20.0826 11.9953 20.0251C11.7164 19.9659 11.4425 19.8763 11.1805 19.7597C10.9184 19.643 10.6699 19.4977 10.4383 19.3286C10.2084 19.1595 9.99541 18.9651 9.80606 18.7504C9.38342 18.8417 8.95064 18.8637 8.52293 18.8197C8.09522 18.7741 7.67596 18.6625 7.28206 18.4867C6.88985 18.3126 6.52638 18.0759 6.20687 17.7868C5.88735 17.4977 5.61517 17.1596 5.40047 16.7877C5.25677 16.5392 5.13843 16.2771 5.04883 16.005C4.95924 15.7328 4.90007 15.4522 4.86964 15.1665C4.83921 14.8824 4.8409 14.595 4.87133 14.3093C4.90176 14.0253 4.96431 13.7447 5.05391 13.4725C4.76651 13.153 4.52983 12.7895 4.35402 12.3973C4.17989 12.0034 4.06662 11.5859 4.02267 11.1581C3.97702 10.7304 4.00069 10.2976 4.09029 9.8767C4.17989 9.45575 4.33542 9.05171 4.55181 8.67978C4.69382 8.43127 4.86118 8.19628 5.05222 7.98327C5.24325 7.77026 5.45795 7.57754 5.68956 7.40848C5.92116 7.23943 6.17136 7.09573 6.4334 6.98077C6.69713 6.86412 6.971 6.77791 7.25163 6.72043C7.38349 6.30962 7.5796 5.92417 7.83149 5.57592C8.08508 5.22766 8.39107 4.92167 8.73932 4.66809C9.08758 4.4162 9.47302 4.22009 9.88214 4.08654C10.2913 3.95467 10.719 3.88705 11.1501 3.88874C11.4358 3.88705 11.7232 3.91579 12.0038 3.97496C12.2844 4.03413 12.5583 4.12204 12.8203 4.23869C13.0824 4.35703 13.3309 4.50072 13.5625 4.66978C13.7941 4.84053 14.0071 5.03325 14.1964 5.24795C14.6174 5.15835 15.0502 5.13637 15.4779 5.18033C15.9056 5.22428 16.3232 5.33755 16.7171 5.51168C17.1093 5.6875 17.4727 5.92248 17.7923 6.21157C18.1118 6.49896 18.384 6.83538 18.5987 7.209C18.7423 7.45582 18.8607 7.71786 18.9503 7.99173C19.0399 8.26391 19.1007 8.54454 19.1295 8.83024C19.1599 9.11595 19.1599 9.40334 19.1278 9.68905C19.0974 9.97475 19.0348 10.2554 18.9452 10.5276C19.2343 10.8471 19.4693 11.2089 19.6451 11.6028ZM14.0122 18.8197C14.3807 18.6676 14.7154 18.4428 14.9978 18.1604C15.2801 17.8781 15.5049 17.5434 15.6571 17.1731C15.8092 16.8046 15.8887 16.409 15.8887 16.01V12.2401C15.8876 12.2367 15.8864 12.2328 15.8853 12.2283C15.8842 12.2249 15.8825 12.2215 15.8802 12.2181C15.878 12.2147 15.8752 12.2119 15.8718 12.2097C15.8684 12.2063 15.865 12.204 15.8616 12.2029L14.4974 11.4151V15.9695C14.4974 16.0151 14.4906 16.0624 14.4788 16.1064C14.4669 16.152 14.45 16.1943 14.4264 16.2349C14.4027 16.2755 14.3756 16.3126 14.3418 16.3448C14.309 16.3775 14.272 16.4059 14.2319 16.4293L11.0013 18.294C10.9742 18.3109 10.9286 18.3346 10.9049 18.3481C11.0385 18.4613 11.1839 18.5611 11.336 18.649C11.4899 18.7369 11.6488 18.8113 11.8144 18.8722C11.9801 18.9313 12.1509 18.977 12.3233 19.0074C12.4974 19.0378 12.6732 19.053 12.8491 19.053C13.248 19.053 13.6436 18.9736 14.0122 18.8197ZM6.31844 16.2602C6.51962 16.6068 6.78504 16.9077 7.10117 17.1512C7.419 17.3946 7.77908 17.5721 8.16453 17.6752C8.54998 17.7784 8.95233 17.8054 9.34792 17.753C9.74351 17.7006 10.1239 17.5721 10.4705 17.3726L13.7366 15.4877L13.7451 15.4792C13.7473 15.477 13.749 15.4736 13.7501 15.4691C13.7524 15.4657 13.7541 15.4623 13.7552 15.4589V13.8698L9.81283 16.1504C9.77225 16.174 9.72999 16.1909 9.68603 16.2045C9.64039 16.2163 9.59474 16.2214 9.54741 16.2214C9.50176 16.2214 9.45612 16.2163 9.41047 16.2045C9.36652 16.1909 9.32256 16.174 9.28199 16.1504L6.05133 14.284C6.0226 14.2671 5.98033 14.2417 5.95666 14.2265C5.92623 14.4006 5.91102 14.5764 5.91102 14.7523C5.91102 14.9281 5.92792 15.1039 5.95835 15.278C5.98878 15.4505 6.03612 15.6212 6.09529 15.7869C6.15615 15.9526 6.23053 16.1115 6.31844 16.2636V16.2602ZM5.46978 9.21062C5.2703 9.55718 5.14182 9.93925 5.08941 10.3348C5.037 10.7304 5.06405 11.1311 5.16717 11.5182C5.2703 11.9037 5.44781 12.2638 5.69125 12.5816C5.93469 12.8977 6.2373 13.1631 6.58217 13.3626L9.84664 15.2493C9.85002 15.2504 9.85396 15.2515 9.85847 15.2527H9.8703C9.87481 15.2527 9.87876 15.2515 9.88214 15.2493C9.88552 15.2482 9.8889 15.2465 9.89228 15.2442L11.2616 14.453L7.31925 12.1775C7.28037 12.1539 7.24318 12.1251 7.20937 12.093C7.17661 12.0602 7.1482 12.0232 7.12484 11.9831C7.10286 11.9426 7.08427 11.9003 7.07243 11.8547C7.0606 11.8107 7.05384 11.7651 7.05553 11.7177V7.87846C6.88985 7.93932 6.72925 8.0137 6.5771 8.10161C6.42495 8.19121 6.28125 8.29265 6.14601 8.40591C6.01245 8.51918 5.88735 8.64428 5.77408 8.77953C5.66082 8.91308 5.56107 9.05847 5.47316 9.21062H5.46978ZM16.6832 11.8208C16.7238 11.8445 16.761 11.8716 16.7948 11.9054C16.8269 11.9375 16.8557 11.9747 16.8794 12.0153C16.9013 12.0558 16.9199 12.0998 16.9318 12.1437C16.9419 12.1894 16.9487 12.235 16.947 12.2824V16.1216C17.4896 15.9221 17.963 15.5722 18.3129 15.1124C18.6646 14.6525 18.8759 14.1031 18.9249 13.5283C18.974 12.9535 18.859 12.3753 18.5919 11.8631C18.3248 11.3509 17.9174 10.9248 17.417 10.6374L14.1525 8.75079C14.1491 8.74966 14.1452 8.74853 14.1407 8.74741H14.1288C14.1254 8.74853 14.1215 8.74966 14.117 8.75079C14.1136 8.75191 14.1102 8.7536 14.1068 8.75586L12.7443 9.54366L16.6866 11.8208H16.6832ZM18.0441 9.77526H18.0425V9.77695L18.0441 9.77526ZM18.0425 9.77357C18.1405 9.20555 18.0746 8.62061 17.8514 8.08809C17.63 7.55556 17.2597 7.09742 16.7864 6.76607C16.313 6.43641 15.7551 6.24707 15.1787 6.22171C14.6005 6.19804 14.0291 6.33836 13.5287 6.62575L10.2642 8.51073C10.2608 8.51298 10.258 8.5158 10.2558 8.51918L10.249 8.52932C10.2479 8.5327 10.2467 8.53665 10.2456 8.54116C10.2445 8.54454 10.2439 8.54848 10.2439 8.55299V10.1286L14.1863 7.85141C14.2269 7.82774 14.2708 7.81084 14.3148 7.79731C14.3604 7.78548 14.4061 7.78041 14.4517 7.78041C14.499 7.78041 14.5447 7.78548 14.5903 7.79731C14.6343 7.81084 14.6766 7.82774 14.7171 7.85141L17.9478 9.71778C17.9765 9.73469 18.0188 9.75836 18.0425 9.77357ZM9.50007 8.02892C9.50007 7.98327 9.50683 7.93763 9.51867 7.89198C9.5305 7.84803 9.54741 7.80407 9.57108 7.7635C9.59474 7.72462 9.62179 7.68743 9.6556 7.65361C9.68772 7.62149 9.72492 7.59275 9.76549 7.57078L12.9961 5.70609C13.0266 5.6875 13.0688 5.66383 13.0925 5.65199C12.6496 5.28176 12.1086 5.04508 11.5355 4.97239C10.9624 4.89801 10.3809 4.9893 9.85847 5.23443C9.3344 5.47956 8.89147 5.87008 8.5821 6.35696C8.27273 6.84553 8.10874 7.41017 8.10874 7.98834V11.7583C8.10987 11.7628 8.111 11.7667 8.11212 11.7701C8.11325 11.7735 8.11494 11.7769 8.1172 11.7803C8.11945 11.7836 8.12227 11.787 8.12565 11.7904C8.1279 11.7927 8.13128 11.7949 8.13579 11.7972L9.50007 12.585V8.02892ZM10.2405 13.011L11.997 14.0253L13.7535 13.011V10.984L11.9987 9.96968L10.2422 10.984L10.2405 13.011Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "0.5",
+ "y": "0.5",
+ "width": "23",
+ "height": "23",
+ "rx": "5.5",
+ "stroke": "black",
+ "stroke-opacity": "0.05"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Gpt4"
+}
diff --git a/app/components/base/icons/src/public/llm/Gpt4.tsx b/app/components/base/icons/src/public/llm/Gpt4.tsx
new file mode 100644
index 0000000..1fa170e
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Gpt4.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Gpt4.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Gpt4'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Huggingface.json b/app/components/base/icons/src/public/llm/Huggingface.json
new file mode 100644
index 0000000..57e10e2
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Huggingface.json
@@ -0,0 +1,158 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.9286 20.2062C16.7767 20.2062 20.7069 16.2761 20.7069 11.428C20.7069 6.57993 16.7767 2.64978 11.9286 2.64978C7.08054 2.64978 3.15039 6.57993 3.15039 11.428C3.15039 16.2761 7.08054 20.2062 11.9286 20.2062Z",
+ "fill": "#FFD21E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.7095 11.4326C20.7095 6.58451 16.7793 2.65436 11.9313 2.65436C7.08318 2.65436 3.15303 6.58451 3.15303 11.4326C3.15303 16.2807 7.08318 20.2108 11.9313 20.2108C16.7793 20.2108 20.7095 16.2807 20.7095 11.4326ZM2.14258 11.4326C2.14258 6.02647 6.52511 1.64392 11.9313 1.64392C17.3374 1.64392 21.7199 6.02647 21.7199 11.4326C21.7199 16.8387 17.3374 21.2213 11.9313 21.2213C6.52511 21.2213 2.14258 16.8387 2.14258 11.4326Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.7822 9.03703C15.1041 9.1507 15.2322 9.81254 15.5574 9.6396C16.1734 9.31212 16.4072 8.54734 16.0797 7.93142C15.7522 7.31553 14.9874 7.08172 14.3715 7.4092C13.7556 7.73669 13.5218 8.50147 13.8493 9.11738C14.0038 9.40809 14.4944 8.9354 14.7822 9.03703Z",
+ "fill": "#3A3B45"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.83422 9.03703C8.5123 9.1507 8.38422 9.81254 8.05901 9.6396C7.4431 9.31212 7.20928 8.54734 7.53676 7.93142C7.86425 7.31553 8.62903 7.08172 9.24494 7.4092C9.86086 7.73669 10.0947 8.50147 9.76719 9.11738C9.61262 9.40809 9.122 8.9354 8.83422 9.03703Z",
+ "fill": "#3A3B45"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.8679 15.1044C14.3507 15.1044 15.1519 12.8908 15.1519 11.7541C15.1519 11.1633 14.7547 11.3492 14.1187 11.6641C13.5309 11.9551 12.739 12.3563 11.8679 12.3563C10.0543 12.3563 8.58398 10.6173 8.58398 11.7541C8.58398 12.8908 9.38514 15.1044 11.8679 15.1044Z",
+ "fill": "#3A3B45"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_8587_60183",
+ "style": "mask-type:alpha",
+ "maskUnits": "userSpaceOnUse",
+ "x": "8",
+ "y": "11",
+ "width": "8",
+ "height": "5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.8562 15.1005C14.339 15.1005 15.1402 12.8869 15.1402 11.7502C15.1402 11.1594 14.743 11.3453 14.1069 11.6602C13.5191 11.9512 12.7273 12.3524 11.8562 12.3524C10.0425 12.3524 8.57227 10.6134 8.57227 11.7502C8.57227 12.8869 9.37342 15.1005 11.8562 15.1005Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_8587_60183)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.9194 17.6824C13.1294 17.6824 14.1103 16.7016 14.1103 15.4916C14.1103 14.5491 13.5152 13.7457 12.6803 13.4364C12.6496 13.425 12.6185 13.4143 12.5872 13.4043C12.3766 13.337 12.1523 14.0606 11.9194 14.0606C11.7018 14.0606 11.4917 13.3324 11.2933 13.3915C10.3884 13.6609 9.72852 14.4991 9.72852 15.4916C9.72852 16.7016 10.7094 17.6824 11.9194 17.6824Z",
+ "fill": "#F94040"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.8698 10.2273C18.3232 10.2273 18.6908 9.85972 18.6908 9.40631C18.6908 8.9529 18.3232 8.58533 17.8698 8.58533C17.4164 8.58533 17.0488 8.9529 17.0488 9.40631C17.0488 9.85972 17.4164 10.2273 17.8698 10.2273Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.11981 10.2273C6.57323 10.2273 6.9408 9.85972 6.9408 9.40631C6.9408 8.9529 6.57323 8.58533 6.11981 8.58533C5.66638 8.58533 5.29883 8.9529 5.29883 9.40631C5.29883 9.85972 5.66638 10.2273 6.11981 10.2273Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.42915 13.0092C4.02018 13.0092 3.65465 13.1771 3.39976 13.4818C3.24214 13.6705 3.07743 13.9746 3.06404 14.4301C2.89252 14.3808 2.72757 14.3533 2.57347 14.3533C2.18193 14.3533 1.82827 14.5033 1.57819 14.7759C1.25687 15.1258 1.11414 15.5557 1.17628 15.9859C1.20584 16.1908 1.2743 16.3744 1.3766 16.5444C1.16087 16.719 1.00198 16.962 0.925188 17.2543C0.865067 17.4834 0.803429 17.9606 1.12526 18.4522C1.10479 18.4842 1.0856 18.5176 1.06766 18.5517C0.874161 18.919 0.861783 19.334 1.03255 19.7205C1.29147 20.3063 1.93487 20.7678 3.18429 21.2632C3.96157 21.5714 4.67267 21.7684 4.67899 21.7702C5.70661 22.0367 6.63596 22.1721 7.44053 22.1721C8.91931 22.1721 9.97801 21.7192 10.5873 20.8259C11.5679 19.3876 11.4277 18.072 10.1589 16.8039C9.45662 16.1021 8.98979 15.0674 8.89254 14.8403C8.69651 14.1679 8.17815 13.4204 7.3165 13.4204C7.244 13.4204 7.17049 13.4262 7.09824 13.4376C6.72084 13.4969 6.39093 13.7142 6.15525 14.0411C5.90087 13.7248 5.65381 13.4732 5.43025 13.3312C5.09327 13.1175 4.75654 13.0092 4.42915 13.0092ZM4.42915 14.0196C4.55799 14.0196 4.71536 14.0744 4.88891 14.1846C5.42773 14.5263 6.46747 16.3136 6.84816 17.0087C6.97573 17.2417 7.19373 17.3402 7.39001 17.3402C7.77953 17.3402 8.08368 16.9529 7.42563 16.4608C6.43615 15.7204 6.78324 14.5102 7.25562 14.4356C7.27633 14.4324 7.29679 14.4308 7.3165 14.4308C7.74594 14.4308 7.93539 15.171 7.93539 15.171C7.93539 15.171 8.49063 16.5654 9.44449 17.5185C10.3984 18.4719 10.4476 19.237 9.75243 20.2566C9.27828 20.9517 8.37064 21.1617 7.44053 21.1617C6.47581 21.1617 5.48684 20.9358 4.93261 20.7921C4.90533 20.785 1.53474 19.8329 1.96165 19.0226C2.03339 18.8864 2.15161 18.8318 2.3004 18.8318C2.90162 18.8318 3.99517 19.7266 4.46528 19.7266C4.57036 19.7266 4.64438 19.6819 4.67469 19.5727C4.87501 18.8541 1.62896 18.5519 1.90254 17.5109C1.95079 17.3268 2.08164 17.252 2.26554 17.2523C3.06 17.2523 4.84243 18.6495 5.21604 18.6495C5.24458 18.6495 5.26504 18.6411 5.27616 18.6234C5.46334 18.3213 5.36078 18.1104 4.0414 17.3119C2.72201 16.5131 1.79594 16.0327 2.32263 15.4592C2.38326 15.393 2.46915 15.3637 2.57347 15.3637C3.3745 15.364 5.26706 17.0863 5.26706 17.0863C5.26706 17.0863 5.77784 17.6175 6.08679 17.6175C6.15777 17.6175 6.21814 17.5895 6.25907 17.5203C6.47808 17.151 4.22479 15.4433 4.09773 14.7388C4.01159 14.2613 4.1581 14.0196 4.42915 14.0196Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.75883 20.2539C10.454 19.2344 10.4048 18.4692 9.4509 17.5159C8.49704 16.5628 7.9418 15.1684 7.9418 15.1684C7.9418 15.1684 7.73441 14.3585 7.26203 14.433C6.78964 14.5075 6.44281 15.7178 7.43228 16.4582C8.42176 17.1984 7.23525 17.7013 6.85456 17.0061C6.47388 16.3109 5.43438 14.5237 4.89531 14.1819C4.35649 13.8402 3.97707 14.0316 4.10414 14.7362C4.2312 15.4407 6.48474 17.1483 6.26547 17.5179C6.04621 17.8872 5.27347 17.0837 5.27347 17.0837C5.27347 17.0837 2.85548 14.8832 2.32903 15.4566C1.80258 16.03 2.72842 16.5105 4.0478 17.3093C5.36744 18.1078 5.46975 18.3187 5.28257 18.6208C5.09513 18.9229 2.18251 16.4673 1.90893 17.5083C1.63561 18.5493 4.88142 18.8514 4.6811 19.5701C4.48078 20.2891 2.3947 18.2098 1.96804 19.0199C1.54113 19.8303 4.91173 20.7824 4.93901 20.7895C6.02777 21.0719 8.79285 21.6703 9.75883 20.2539Z",
+ "fill": "#FFD21E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.5568 13.0092C19.9658 13.0092 20.3313 13.1771 20.5862 13.4818C20.7439 13.6705 20.9086 13.9746 20.9219 14.4301C21.0935 14.3808 21.2584 14.3533 21.4125 14.3533C21.8041 14.3533 22.1577 14.5033 22.4078 14.7759C22.7291 15.1258 22.8718 15.5557 22.8097 15.9859C22.7802 16.1908 22.7117 16.3744 22.6094 16.5444C22.8251 16.719 22.984 16.962 23.0608 17.2543C23.1209 17.4834 23.1826 17.9606 22.8607 18.4522C22.8812 18.4842 22.9004 18.5176 22.9183 18.5517C23.1118 18.919 23.1242 19.334 22.9534 19.7205C22.6945 20.3063 22.0511 20.7678 20.8017 21.2632C20.0244 21.5714 19.3133 21.7684 19.307 21.7702C18.2794 22.0367 17.35 22.1721 16.5455 22.1721C15.0667 22.1721 14.008 21.7192 13.3987 20.8259C12.418 19.3876 12.5582 18.072 13.8271 16.8039C14.5294 16.1021 14.9962 15.0674 15.0935 14.8403C15.2895 14.1679 15.8078 13.4204 16.6695 13.4204C16.742 13.4204 16.8155 13.4262 16.8877 13.4376C17.2651 13.4969 17.5951 13.7142 17.8307 14.0411C18.0851 13.7248 18.3322 13.4732 18.5557 13.3312C18.8927 13.1175 19.2295 13.0092 19.5568 13.0092ZM19.5568 14.0196C19.428 14.0196 19.2706 14.0744 19.0971 14.1846C18.5583 14.5263 17.5185 16.3136 17.1378 17.0087C17.0103 17.2417 16.7923 17.3402 16.596 17.3402C16.2065 17.3402 15.9023 16.9529 16.5604 16.4608C17.5498 15.7204 17.2028 14.5102 16.7304 14.4356C16.7097 14.4324 16.6892 14.4308 16.6695 14.4308C16.2401 14.4308 16.0506 15.171 16.0506 15.171C16.0506 15.171 15.4954 16.5654 14.5415 17.5185C13.5876 18.4719 13.5384 19.237 14.2336 20.2566C14.7077 20.9517 15.6153 21.1617 16.5455 21.1617C17.5102 21.1617 18.4992 20.9358 19.0534 20.7921C19.0807 20.785 22.4513 19.8329 22.0243 19.0226C21.9526 18.8864 21.8344 18.8318 21.6856 18.8318C21.0844 18.8318 19.9908 19.7266 19.5207 19.7266C19.4156 19.7266 19.3416 19.6819 19.3113 19.5727C19.111 18.8541 22.357 18.5519 22.0835 17.5109C22.0352 17.3268 21.9043 17.252 21.7204 17.2523C20.926 17.2523 19.1436 18.6495 18.77 18.6495C18.7414 18.6495 18.7209 18.6411 18.7098 18.6234C18.5226 18.3213 18.6252 18.1104 19.9446 17.3119C21.264 16.5131 22.1901 16.0327 21.6634 15.4592C21.6027 15.393 21.5168 15.3637 21.4125 15.3637C20.6115 15.364 18.7189 17.0863 18.7189 17.0863C18.7189 17.0863 18.2081 17.6175 17.8992 17.6175C17.8282 17.6175 17.7678 17.5895 17.7269 17.5203C17.5079 17.151 19.7612 15.4433 19.8883 14.7388C19.9744 14.2613 19.8279 14.0196 19.5568 14.0196Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.2354 20.2539C13.5402 19.2344 13.5895 18.4692 14.5433 17.5159C15.4972 16.5628 16.0524 15.1684 16.0524 15.1684C16.0524 15.1684 16.2598 14.3585 16.7322 14.433C17.2046 14.5075 17.5514 15.7178 16.5619 16.4582C15.5724 17.1984 16.759 17.7013 17.1396 17.0061C17.5203 16.3109 18.5598 14.5237 19.0989 14.1819C19.6377 13.8402 20.0171 14.0316 19.8901 14.7362C19.763 15.4407 17.5095 17.1483 17.7287 17.5179C17.948 17.8872 18.7207 17.0837 18.7207 17.0837C18.7207 17.0837 21.1387 14.8832 21.6652 15.4566C22.1916 16.03 21.2658 16.5105 19.9464 17.3093C18.6268 18.1078 18.5245 18.3187 18.7116 18.6208C18.8991 18.9229 21.8117 16.4673 22.0853 17.5083C22.3586 18.5493 19.1128 18.8514 19.3131 19.5701C19.5134 20.2891 21.5995 18.2098 22.0262 19.0199C22.4531 19.8303 19.0825 20.7824 19.0552 20.7895C17.9664 21.0719 15.2014 21.6703 14.2354 20.2539Z",
+ "fill": "#FFD21E"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Huggingface"
+}
diff --git a/app/components/base/icons/src/public/llm/Huggingface.tsx b/app/components/base/icons/src/public/llm/Huggingface.tsx
new file mode 100644
index 0000000..1dcee18
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Huggingface.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Huggingface.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Huggingface'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/HuggingfaceText.json b/app/components/base/icons/src/public/llm/HuggingfaceText.json
new file mode 100644
index 0000000..d113e64
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/HuggingfaceText.json
@@ -0,0 +1,322 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "120",
+ "height": "24",
+ "viewBox": "0 0 120 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_8587_60377)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip1_8587_60377)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.9286 20.2062C16.7767 20.2062 20.7069 16.2761 20.7069 11.428C20.7069 6.57993 16.7767 2.64978 11.9286 2.64978C7.08054 2.64978 3.15039 6.57993 3.15039 11.428C3.15039 16.2761 7.08054 20.2062 11.9286 20.2062Z",
+ "fill": "#FFD21E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.7095 11.4326C20.7095 6.58451 16.7793 2.65436 11.9313 2.65436C7.08318 2.65436 3.15303 6.58451 3.15303 11.4326C3.15303 16.2807 7.08318 20.2108 11.9313 20.2108C16.7793 20.2108 20.7095 16.2807 20.7095 11.4326ZM2.14258 11.4326C2.14258 6.02647 6.52511 1.64392 11.9313 1.64392C17.3374 1.64392 21.7199 6.02647 21.7199 11.4326C21.7199 16.8387 17.3374 21.2213 11.9313 21.2213C6.52511 21.2213 2.14258 16.8387 2.14258 11.4326Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.7822 9.03703C15.1041 9.1507 15.2322 9.81254 15.5574 9.6396C16.1734 9.31212 16.4072 8.54734 16.0797 7.93142C15.7522 7.31553 14.9874 7.08172 14.3715 7.4092C13.7556 7.73669 13.5218 8.50147 13.8493 9.11738C14.0038 9.40809 14.4944 8.9354 14.7822 9.03703Z",
+ "fill": "#3A3B45"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.83422 9.03703C8.5123 9.1507 8.38422 9.81254 8.05901 9.6396C7.4431 9.31212 7.20928 8.54734 7.53676 7.93142C7.86425 7.31553 8.62903 7.08172 9.24494 7.4092C9.86086 7.73669 10.0947 8.50147 9.76719 9.11738C9.61262 9.40809 9.122 8.9354 8.83422 9.03703Z",
+ "fill": "#3A3B45"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.8679 15.1044C14.3507 15.1044 15.1519 12.8908 15.1519 11.7541C15.1519 11.1633 14.7547 11.3492 14.1187 11.6641C13.5309 11.9551 12.739 12.3563 11.8679 12.3563C10.0543 12.3563 8.58398 10.6173 8.58398 11.7541C8.58398 12.8908 9.38514 15.1044 11.8679 15.1044Z",
+ "fill": "#3A3B45"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_8587_60377",
+ "style": "mask-type:alpha",
+ "maskUnits": "userSpaceOnUse",
+ "x": "8",
+ "y": "11",
+ "width": "8",
+ "height": "5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.8562 15.1005C14.339 15.1005 15.1402 12.8869 15.1402 11.7502C15.1402 11.1594 14.743 11.3453 14.1069 11.6602C13.5191 11.9512 12.7273 12.3524 11.8562 12.3524C10.0425 12.3524 8.57227 10.6134 8.57227 11.7502C8.57227 12.8869 9.37342 15.1005 11.8562 15.1005Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_8587_60377)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.9194 17.6824C13.1294 17.6824 14.1103 16.7016 14.1103 15.4916C14.1103 14.5491 13.5152 13.7457 12.6803 13.4364C12.6496 13.425 12.6185 13.4143 12.5872 13.4043C12.3766 13.337 12.1523 14.0606 11.9194 14.0606C11.7018 14.0606 11.4917 13.3324 11.2933 13.3915C10.3884 13.6609 9.72852 14.4991 9.72852 15.4916C9.72852 16.7016 10.7094 17.6824 11.9194 17.6824Z",
+ "fill": "#F94040"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.8698 10.2273C18.3232 10.2273 18.6908 9.85972 18.6908 9.40631C18.6908 8.9529 18.3232 8.58533 17.8698 8.58533C17.4164 8.58533 17.0488 8.9529 17.0488 9.40631C17.0488 9.85972 17.4164 10.2273 17.8698 10.2273Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.11981 10.2273C6.57323 10.2273 6.9408 9.85972 6.9408 9.40631C6.9408 8.9529 6.57323 8.58533 6.11981 8.58533C5.66638 8.58533 5.29883 8.9529 5.29883 9.40631C5.29883 9.85972 5.66638 10.2273 6.11981 10.2273Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.42915 13.0092C4.02018 13.0092 3.65465 13.1771 3.39976 13.4818C3.24214 13.6705 3.07743 13.9746 3.06404 14.4301C2.89252 14.3808 2.72757 14.3533 2.57347 14.3533C2.18193 14.3533 1.82827 14.5033 1.57819 14.7759C1.25687 15.1258 1.11414 15.5557 1.17628 15.9859C1.20584 16.1908 1.2743 16.3744 1.3766 16.5444C1.16087 16.719 1.00198 16.962 0.925188 17.2543C0.865067 17.4834 0.803429 17.9606 1.12526 18.4522C1.10479 18.4842 1.0856 18.5176 1.06766 18.5517C0.874161 18.919 0.861783 19.334 1.03255 19.7205C1.29147 20.3063 1.93487 20.7678 3.18429 21.2632C3.96157 21.5714 4.67267 21.7684 4.67899 21.7702C5.70661 22.0367 6.63596 22.1721 7.44053 22.1721C8.91931 22.1721 9.97801 21.7192 10.5873 20.8259C11.5679 19.3876 11.4277 18.072 10.1589 16.8039C9.45662 16.1021 8.98979 15.0674 8.89254 14.8403C8.69651 14.1679 8.17815 13.4204 7.3165 13.4204C7.244 13.4204 7.17049 13.4262 7.09824 13.4376C6.72084 13.4969 6.39093 13.7142 6.15525 14.0411C5.90087 13.7248 5.65381 13.4732 5.43025 13.3312C5.09327 13.1175 4.75654 13.0092 4.42915 13.0092ZM4.42915 14.0196C4.55799 14.0196 4.71536 14.0744 4.88891 14.1846C5.42773 14.5263 6.46747 16.3136 6.84816 17.0087C6.97573 17.2417 7.19373 17.3402 7.39001 17.3402C7.77953 17.3402 8.08368 16.9529 7.42563 16.4608C6.43615 15.7204 6.78324 14.5102 7.25562 14.4356C7.27633 14.4324 7.29679 14.4308 7.3165 14.4308C7.74594 14.4308 7.93539 15.171 7.93539 15.171C7.93539 15.171 8.49063 16.5654 9.44449 17.5185C10.3984 18.4719 10.4476 19.237 9.75243 20.2566C9.27828 20.9517 8.37064 21.1617 7.44053 21.1617C6.47581 21.1617 5.48684 20.9358 4.93261 20.7921C4.90533 20.785 1.53474 19.8329 1.96165 19.0226C2.03339 18.8864 2.15161 18.8318 2.3004 18.8318C2.90162 18.8318 3.99517 19.7266 4.46528 19.7266C4.57036 19.7266 4.64438 19.6819 4.67469 19.5727C4.87501 18.8541 1.62896 18.5519 1.90254 17.5109C1.95079 17.3268 2.08164 17.252 2.26554 17.2523C3.06 17.2523 4.84243 18.6495 5.21604 18.6495C5.24458 18.6495 5.26504 18.6411 5.27616 18.6234C5.46334 18.3213 5.36078 18.1104 4.0414 17.3119C2.72201 16.5131 1.79594 16.0327 2.32263 15.4592C2.38326 15.393 2.46915 15.3637 2.57347 15.3637C3.3745 15.364 5.26706 17.0863 5.26706 17.0863C5.26706 17.0863 5.77784 17.6175 6.08679 17.6175C6.15777 17.6175 6.21814 17.5895 6.25907 17.5203C6.47808 17.151 4.22479 15.4433 4.09773 14.7388C4.01159 14.2613 4.1581 14.0196 4.42915 14.0196Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.75883 20.2539C10.454 19.2344 10.4048 18.4692 9.4509 17.5159C8.49704 16.5628 7.9418 15.1684 7.9418 15.1684C7.9418 15.1684 7.73441 14.3585 7.26203 14.433C6.78964 14.5075 6.44281 15.7178 7.43228 16.4582C8.42176 17.1984 7.23525 17.7013 6.85456 17.0061C6.47388 16.3109 5.43438 14.5237 4.89531 14.1819C4.35649 13.8402 3.97707 14.0316 4.10414 14.7362C4.2312 15.4407 6.48474 17.1483 6.26547 17.5179C6.04621 17.8872 5.27347 17.0837 5.27347 17.0837C5.27347 17.0837 2.85548 14.8832 2.32903 15.4566C1.80258 16.03 2.72842 16.5105 4.0478 17.3093C5.36744 18.1078 5.46975 18.3187 5.28257 18.6208C5.09513 18.9229 2.18251 16.4673 1.90893 17.5083C1.63561 18.5493 4.88142 18.8514 4.6811 19.5701C4.48078 20.2891 2.3947 18.2098 1.96804 19.0199C1.54113 19.8303 4.91173 20.7824 4.93901 20.7895C6.02777 21.0719 8.79285 21.6703 9.75883 20.2539Z",
+ "fill": "#FFD21E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.5568 13.0092C19.9658 13.0092 20.3313 13.1771 20.5862 13.4818C20.7439 13.6705 20.9086 13.9746 20.9219 14.4301C21.0935 14.3808 21.2584 14.3533 21.4125 14.3533C21.8041 14.3533 22.1577 14.5033 22.4078 14.7759C22.7291 15.1258 22.8718 15.5557 22.8097 15.9859C22.7802 16.1908 22.7117 16.3744 22.6094 16.5444C22.8251 16.719 22.984 16.962 23.0608 17.2543C23.1209 17.4834 23.1826 17.9606 22.8607 18.4522C22.8812 18.4842 22.9004 18.5176 22.9183 18.5517C23.1118 18.919 23.1242 19.334 22.9534 19.7205C22.6945 20.3063 22.0511 20.7678 20.8017 21.2632C20.0244 21.5714 19.3133 21.7684 19.307 21.7702C18.2794 22.0367 17.35 22.1721 16.5455 22.1721C15.0667 22.1721 14.008 21.7192 13.3987 20.8259C12.418 19.3876 12.5582 18.072 13.8271 16.8039C14.5294 16.1021 14.9962 15.0674 15.0935 14.8403C15.2895 14.1679 15.8078 13.4204 16.6695 13.4204C16.742 13.4204 16.8155 13.4262 16.8877 13.4376C17.2651 13.4969 17.5951 13.7142 17.8307 14.0411C18.0851 13.7248 18.3322 13.4732 18.5557 13.3312C18.8927 13.1175 19.2295 13.0092 19.5568 13.0092ZM19.5568 14.0196C19.428 14.0196 19.2706 14.0744 19.0971 14.1846C18.5583 14.5263 17.5185 16.3136 17.1378 17.0087C17.0103 17.2417 16.7923 17.3402 16.596 17.3402C16.2065 17.3402 15.9023 16.9529 16.5604 16.4608C17.5498 15.7204 17.2028 14.5102 16.7304 14.4356C16.7097 14.4324 16.6892 14.4308 16.6695 14.4308C16.2401 14.4308 16.0506 15.171 16.0506 15.171C16.0506 15.171 15.4954 16.5654 14.5415 17.5185C13.5876 18.4719 13.5384 19.237 14.2336 20.2566C14.7077 20.9517 15.6153 21.1617 16.5455 21.1617C17.5102 21.1617 18.4992 20.9358 19.0534 20.7921C19.0807 20.785 22.4513 19.8329 22.0243 19.0226C21.9526 18.8864 21.8344 18.8318 21.6856 18.8318C21.0844 18.8318 19.9908 19.7266 19.5207 19.7266C19.4156 19.7266 19.3416 19.6819 19.3113 19.5727C19.111 18.8541 22.357 18.5519 22.0835 17.5109C22.0352 17.3268 21.9043 17.252 21.7204 17.2523C20.926 17.2523 19.1436 18.6495 18.77 18.6495C18.7414 18.6495 18.7209 18.6411 18.7098 18.6234C18.5226 18.3213 18.6252 18.1104 19.9446 17.3119C21.264 16.5131 22.1901 16.0327 21.6634 15.4592C21.6027 15.393 21.5168 15.3637 21.4125 15.3637C20.6115 15.364 18.7189 17.0863 18.7189 17.0863C18.7189 17.0863 18.2081 17.6175 17.8992 17.6175C17.8282 17.6175 17.7678 17.5895 17.7269 17.5203C17.5079 17.151 19.7612 15.4433 19.8883 14.7388C19.9744 14.2613 19.8279 14.0196 19.5568 14.0196Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.2354 20.2539C13.5402 19.2344 13.5895 18.4692 14.5433 17.5159C15.4972 16.5628 16.0524 15.1684 16.0524 15.1684C16.0524 15.1684 16.2598 14.3585 16.7322 14.433C17.2046 14.5075 17.5514 15.7178 16.5619 16.4582C15.5724 17.1984 16.759 17.7013 17.1396 17.0061C17.5203 16.3109 18.5598 14.5237 19.0989 14.1819C19.6377 13.8402 20.0171 14.0316 19.8901 14.7362C19.763 15.4407 17.5095 17.1483 17.7287 17.5179C17.948 17.8872 18.7207 17.0837 18.7207 17.0837C18.7207 17.0837 21.1387 14.8832 21.6652 15.4566C22.1916 16.03 21.2658 16.5105 19.9464 17.3093C18.6268 18.1078 18.5245 18.3187 18.7116 18.6208C18.8991 18.9229 21.8117 16.4673 22.0853 17.5083C22.3586 18.5493 19.1128 18.8514 19.3131 19.5701C19.5134 20.2891 21.5995 18.2098 22.0262 19.0199C22.4531 19.8303 19.0825 20.7824 19.0552 20.7895C17.9664 21.0719 15.2014 21.6703 14.2354 20.2539Z",
+ "fill": "#FFD21E"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M33.1528 17V7.22003H35.3578V10.985H38.7328V7.22003H40.9528V17H38.7328V12.92H35.3578V17H33.1528Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M45.3153 17.18C44.5053 17.18 43.9153 16.915 43.5453 16.385C43.1853 15.845 43.0053 15.11 43.0053 14.18V9.56003H45.2103V13.895C45.2103 14.425 45.2853 14.795 45.4353 15.005C45.5853 15.205 45.8203 15.305 46.1403 15.305C46.4203 15.305 46.6553 15.24 46.8453 15.11C47.0353 14.98 47.2403 14.77 47.4603 14.48V9.56003H49.6653V17H47.8653L47.7003 15.965H47.6553C47.3453 16.335 47.0053 16.63 46.6353 16.85C46.2653 17.07 45.8253 17.18 45.3153 17.18Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M54.2606 20.165C53.6806 20.165 53.1556 20.1 52.6856 19.97C52.2156 19.84 51.8406 19.635 51.5606 19.355C51.2806 19.075 51.1406 18.715 51.1406 18.275C51.1406 17.675 51.4956 17.175 52.2056 16.775V16.715C52.0156 16.585 51.8506 16.42 51.7106 16.22C51.5806 16.02 51.5156 15.765 51.5156 15.455C51.5156 15.185 51.5956 14.925 51.7556 14.675C51.9156 14.425 52.1156 14.22 52.3556 14.06V14C52.0956 13.82 51.8606 13.56 51.6506 13.22C51.4506 12.88 51.3506 12.495 51.3506 12.065C51.3506 11.465 51.4956 10.97 51.7856 10.58C52.0756 10.18 52.4556 9.88003 52.9256 9.68003C53.3956 9.48003 53.8956 9.38003 54.4256 9.38003C54.8656 9.38003 55.2506 9.44003 55.5806 9.56003H58.2956V11.165H57.1106C57.1806 11.275 57.2356 11.415 57.2756 11.585C57.3256 11.755 57.3506 11.94 57.3506 12.14C57.3506 12.71 57.2206 13.18 56.9606 13.55C56.7006 13.92 56.3506 14.195 55.9106 14.375C55.4706 14.555 54.9756 14.645 54.4256 14.645C54.1356 14.645 53.8356 14.595 53.5256 14.495C53.3456 14.645 53.2556 14.83 53.2556 15.05C53.2556 15.24 53.3406 15.38 53.5106 15.47C53.6806 15.56 53.9706 15.605 54.3806 15.605H55.5806C56.5006 15.605 57.2006 15.755 57.6806 16.055C58.1706 16.345 58.4156 16.825 58.4156 17.495C58.4156 18.005 58.2456 18.46 57.9056 18.86C57.5656 19.27 57.0856 19.59 56.4656 19.82C55.8456 20.05 55.1106 20.165 54.2606 20.165ZM54.4256 13.31C54.7156 13.31 54.9556 13.205 55.1456 12.995C55.3456 12.785 55.4456 12.475 55.4456 12.065C55.4456 11.675 55.3456 11.38 55.1456 11.18C54.9556 10.97 54.7156 10.865 54.4256 10.865C54.1356 10.865 53.8906 10.965 53.6906 11.165C53.5006 11.365 53.4056 11.665 53.4056 12.065C53.4056 12.475 53.5006 12.785 53.6906 12.995C53.8906 13.205 54.1356 13.31 54.4256 13.31ZM54.6056 18.785C55.1056 18.785 55.5156 18.695 55.8356 18.515C56.1556 18.335 56.3156 18.12 56.3156 17.87C56.3156 17.64 56.2156 17.485 56.0156 17.405C55.8256 17.325 55.5456 17.285 55.1756 17.285H54.4106C54.1606 17.285 53.9506 17.275 53.7806 17.255C53.6206 17.245 53.4806 17.225 53.3606 17.195C53.0906 17.435 52.9556 17.68 52.9556 17.93C52.9556 18.21 53.1056 18.42 53.4056 18.56C53.7156 18.71 54.1156 18.785 54.6056 18.785Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M62.2733 20.165C61.6933 20.165 61.1683 20.1 60.6983 19.97C60.2283 19.84 59.8533 19.635 59.5733 19.355C59.2933 19.075 59.1533 18.715 59.1533 18.275C59.1533 17.675 59.5083 17.175 60.2183 16.775V16.715C60.0283 16.585 59.8633 16.42 59.7233 16.22C59.5933 16.02 59.5283 15.765 59.5283 15.455C59.5283 15.185 59.6083 14.925 59.7683 14.675C59.9283 14.425 60.1283 14.22 60.3683 14.06V14C60.1083 13.82 59.8733 13.56 59.6633 13.22C59.4633 12.88 59.3633 12.495 59.3633 12.065C59.3633 11.465 59.5083 10.97 59.7983 10.58C60.0883 10.18 60.4683 9.88003 60.9383 9.68003C61.4083 9.48003 61.9083 9.38003 62.4383 9.38003C62.8783 9.38003 63.2633 9.44003 63.5933 9.56003H66.3083V11.165H65.1233C65.1933 11.275 65.2483 11.415 65.2883 11.585C65.3383 11.755 65.3633 11.94 65.3633 12.14C65.3633 12.71 65.2333 13.18 64.9733 13.55C64.7133 13.92 64.3633 14.195 63.9233 14.375C63.4833 14.555 62.9883 14.645 62.4383 14.645C62.1483 14.645 61.8483 14.595 61.5383 14.495C61.3583 14.645 61.2683 14.83 61.2683 15.05C61.2683 15.24 61.3533 15.38 61.5233 15.47C61.6933 15.56 61.9833 15.605 62.3933 15.605H63.5933C64.5133 15.605 65.2133 15.755 65.6933 16.055C66.1833 16.345 66.4283 16.825 66.4283 17.495C66.4283 18.005 66.2583 18.46 65.9183 18.86C65.5783 19.27 65.0983 19.59 64.4783 19.82C63.8583 20.05 63.1233 20.165 62.2733 20.165ZM62.4383 13.31C62.7283 13.31 62.9683 13.205 63.1583 12.995C63.3583 12.785 63.4583 12.475 63.4583 12.065C63.4583 11.675 63.3583 11.38 63.1583 11.18C62.9683 10.97 62.7283 10.865 62.4383 10.865C62.1483 10.865 61.9033 10.965 61.7033 11.165C61.5133 11.365 61.4183 11.665 61.4183 12.065C61.4183 12.475 61.5133 12.785 61.7033 12.995C61.9033 13.205 62.1483 13.31 62.4383 13.31ZM62.6183 18.785C63.1183 18.785 63.5283 18.695 63.8483 18.515C64.1683 18.335 64.3283 18.12 64.3283 17.87C64.3283 17.64 64.2283 17.485 64.0283 17.405C63.8383 17.325 63.5583 17.285 63.1883 17.285H62.4233C62.1733 17.285 61.9633 17.275 61.7933 17.255C61.6333 17.245 61.4933 17.225 61.3733 17.195C61.1033 17.435 60.9683 17.68 60.9683 17.93C60.9683 18.21 61.1183 18.42 61.4183 18.56C61.7283 18.71 62.1283 18.785 62.6183 18.785Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M67.631 17V9.56003H69.836V17H67.631ZM68.726 8.46503C68.356 8.46503 68.056 8.36003 67.826 8.15003C67.596 7.94003 67.481 7.66003 67.481 7.31003C67.481 6.96003 67.596 6.68003 67.826 6.47003C68.056 6.26003 68.356 6.15503 68.726 6.15503C69.096 6.15503 69.396 6.26003 69.626 6.47003C69.856 6.68003 69.971 6.96003 69.971 7.31003C69.971 7.66003 69.856 7.94003 69.626 8.15003C69.396 8.36003 69.096 8.46503 68.726 8.46503Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M71.7765 17V9.56003H73.5765L73.7265 10.505H73.7865C74.1065 10.205 74.4565 9.94503 74.8365 9.72503C75.2265 9.49503 75.6715 9.38003 76.1715 9.38003C76.9815 9.38003 77.5665 9.65003 77.9265 10.19C78.2965 10.72 78.4815 11.45 78.4815 12.38V17H76.2765V12.665C76.2765 12.125 76.2015 11.755 76.0515 11.555C75.9115 11.355 75.6815 11.255 75.3615 11.255C75.0815 11.255 74.8415 11.32 74.6415 11.45C74.4415 11.57 74.2215 11.745 73.9815 11.975V17H71.7765Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M83.0155 20.165C82.4355 20.165 81.9105 20.1 81.4405 19.97C80.9705 19.84 80.5955 19.635 80.3155 19.355C80.0355 19.075 79.8955 18.715 79.8955 18.275C79.8955 17.675 80.2505 17.175 80.9605 16.775V16.715C80.7705 16.585 80.6055 16.42 80.4655 16.22C80.3355 16.02 80.2705 15.765 80.2705 15.455C80.2705 15.185 80.3505 14.925 80.5105 14.675C80.6705 14.425 80.8705 14.22 81.1105 14.06V14C80.8505 13.82 80.6155 13.56 80.4055 13.22C80.2055 12.88 80.1055 12.495 80.1055 12.065C80.1055 11.465 80.2505 10.97 80.5405 10.58C80.8305 10.18 81.2105 9.88003 81.6805 9.68003C82.1505 9.48003 82.6505 9.38003 83.1805 9.38003C83.6205 9.38003 84.0055 9.44003 84.3355 9.56003H87.0505V11.165H85.8655C85.9355 11.275 85.9905 11.415 86.0305 11.585C86.0805 11.755 86.1055 11.94 86.1055 12.14C86.1055 12.71 85.9755 13.18 85.7155 13.55C85.4555 13.92 85.1055 14.195 84.6655 14.375C84.2255 14.555 83.7305 14.645 83.1805 14.645C82.8905 14.645 82.5905 14.595 82.2805 14.495C82.1005 14.645 82.0105 14.83 82.0105 15.05C82.0105 15.24 82.0955 15.38 82.2655 15.47C82.4355 15.56 82.7255 15.605 83.1355 15.605H84.3355C85.2555 15.605 85.9555 15.755 86.4355 16.055C86.9255 16.345 87.1705 16.825 87.1705 17.495C87.1705 18.005 87.0005 18.46 86.6605 18.86C86.3205 19.27 85.8405 19.59 85.2205 19.82C84.6005 20.05 83.8655 20.165 83.0155 20.165ZM83.1805 13.31C83.4705 13.31 83.7105 13.205 83.9005 12.995C84.1005 12.785 84.2005 12.475 84.2005 12.065C84.2005 11.675 84.1005 11.38 83.9005 11.18C83.7105 10.97 83.4705 10.865 83.1805 10.865C82.8905 10.865 82.6455 10.965 82.4455 11.165C82.2555 11.365 82.1605 11.665 82.1605 12.065C82.1605 12.475 82.2555 12.785 82.4455 12.995C82.6455 13.205 82.8905 13.31 83.1805 13.31ZM83.3605 18.785C83.8605 18.785 84.2705 18.695 84.5905 18.515C84.9105 18.335 85.0705 18.12 85.0705 17.87C85.0705 17.64 84.9705 17.485 84.7705 17.405C84.5805 17.325 84.3005 17.285 83.9305 17.285H83.1655C82.9155 17.285 82.7055 17.275 82.5355 17.255C82.3755 17.245 82.2355 17.225 82.1155 17.195C81.8455 17.435 81.7105 17.68 81.7105 17.93C81.7105 18.21 81.8605 18.42 82.1605 18.56C82.4705 18.71 82.8705 18.785 83.3605 18.785Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M91.5562 17V7.22003H97.7212V9.08003H93.7612V11.345H97.1512V13.205H93.7612V17H91.5562Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M100.546 17.18C99.8661 17.18 99.3261 16.965 98.9261 16.535C98.5261 16.095 98.3261 15.56 98.3261 14.93C98.3261 14.15 98.6561 13.54 99.3161 13.1C99.9761 12.66 101.041 12.365 102.511 12.215C102.491 11.885 102.391 11.625 102.211 11.435C102.041 11.235 101.751 11.135 101.341 11.135C101.031 11.135 100.716 11.195 100.396 11.315C100.076 11.435 99.7361 11.6 99.3761 11.81L98.5811 10.355C99.0511 10.065 99.5511 9.83003 100.081 9.65003C100.621 9.47003 101.181 9.38003 101.761 9.38003C102.711 9.38003 103.441 9.65503 103.951 10.205C104.461 10.755 104.716 11.6 104.716 12.74V17H102.916L102.766 16.235H102.706C102.396 16.515 102.061 16.745 101.701 16.925C101.351 17.095 100.966 17.18 100.546 17.18ZM101.296 15.47C101.546 15.47 101.761 15.415 101.941 15.305C102.131 15.185 102.321 15.03 102.511 14.84V13.535C101.731 13.635 101.191 13.795 100.891 14.015C100.591 14.225 100.441 14.475 100.441 14.765C100.441 15.005 100.516 15.185 100.666 15.305C100.826 15.415 101.036 15.47 101.296 15.47Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M109.821 17.18C109.131 17.18 108.506 17.03 107.946 16.73C107.396 16.42 106.956 15.975 106.626 15.395C106.306 14.805 106.146 14.1 106.146 13.28C106.146 12.45 106.326 11.745 106.686 11.165C107.046 10.585 107.521 10.145 108.111 9.84503C108.701 9.53503 109.336 9.38003 110.016 9.38003C110.476 9.38003 110.881 9.45503 111.231 9.60503C111.591 9.75503 111.911 9.94503 112.191 10.175L111.156 11.6C110.806 11.31 110.471 11.165 110.151 11.165C109.621 11.165 109.196 11.355 108.876 11.735C108.566 12.115 108.411 12.63 108.411 13.28C108.411 13.92 108.566 14.435 108.876 14.825C109.196 15.205 109.596 15.395 110.076 15.395C110.316 15.395 110.551 15.345 110.781 15.245C111.011 15.135 111.221 15.005 111.411 14.855L112.281 16.295C111.911 16.615 111.511 16.845 111.081 16.985C110.651 17.115 110.231 17.18 109.821 17.18Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M116.488 17.18C115.778 17.18 115.138 17.025 114.568 16.715C113.998 16.405 113.548 15.96 113.218 15.38C112.888 14.8 112.723 14.1 112.723 13.28C112.723 12.47 112.888 11.775 113.218 11.195C113.558 10.615 113.998 10.17 114.538 9.86003C115.078 9.54003 115.643 9.38003 116.233 9.38003C116.943 9.38003 117.528 9.54003 117.988 9.86003C118.458 10.17 118.808 10.595 119.038 11.135C119.278 11.665 119.398 12.27 119.398 12.95C119.398 13.14 119.388 13.33 119.368 13.52C119.348 13.7 119.328 13.835 119.308 13.925H114.853C114.953 14.465 115.178 14.865 115.528 15.125C115.878 15.375 116.298 15.5 116.788 15.5C117.318 15.5 117.853 15.335 118.393 15.005L119.128 16.34C118.748 16.6 118.323 16.805 117.853 16.955C117.383 17.105 116.928 17.18 116.488 17.18ZM114.838 12.47H117.523C117.523 12.06 117.423 11.725 117.223 11.465C117.033 11.195 116.718 11.06 116.278 11.06C115.938 11.06 115.633 11.18 115.363 11.42C115.093 11.65 114.918 12 114.838 12.47Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_8587_60377"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "119.998",
+ "height": "24",
+ "rx": "6",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip1_8587_60377"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "23.998",
+ "height": "22.2298",
+ "fill": "white",
+ "transform": "translate(0 0.885132)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "HuggingfaceText"
+}
diff --git a/app/components/base/icons/src/public/llm/HuggingfaceText.tsx b/app/components/base/icons/src/public/llm/HuggingfaceText.tsx
new file mode 100644
index 0000000..961d63e
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/HuggingfaceText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './HuggingfaceText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'HuggingfaceText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/HuggingfaceTextHub.json b/app/components/base/icons/src/public/llm/HuggingfaceTextHub.json
new file mode 100644
index 0000000..0500abf
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/HuggingfaceTextHub.json
@@ -0,0 +1,350 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "151",
+ "height": "24",
+ "viewBox": "0 0 151 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_8587_60397)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip1_8587_60397)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.9267 20.2062C17.7747 20.2062 21.7049 16.2761 21.7049 11.428C21.7049 6.57993 17.7747 2.64978 12.9267 2.64978C8.07858 2.64978 4.14844 6.57993 4.14844 11.428C4.14844 16.2761 8.07858 20.2062 12.9267 20.2062Z",
+ "fill": "#FFD21E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.7075 11.4326C21.7075 6.58451 17.7774 2.65436 12.9293 2.65436C8.08123 2.65436 4.15108 6.58451 4.15108 11.4326C4.15108 16.2807 8.08123 20.2108 12.9293 20.2108C17.7774 20.2108 21.7075 16.2807 21.7075 11.4326ZM3.14062 11.4326C3.14062 6.02647 7.52316 1.64392 12.9293 1.64392C18.3354 1.64392 22.718 6.02647 22.718 11.4326C22.718 16.8387 18.3354 21.2213 12.9293 21.2213C7.52316 21.2213 3.14062 16.8387 3.14062 11.4326Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.7803 9.03703C16.1022 9.1507 16.2303 9.81254 16.5555 9.6396C17.1714 9.31212 17.4052 8.54734 17.0777 7.93142C16.7503 7.31553 15.9855 7.08172 15.3696 7.4092C14.7536 7.73669 14.5198 8.50147 14.8473 9.11738C15.0019 9.40809 15.4925 8.9354 15.7803 9.03703Z",
+ "fill": "#3A3B45"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.83227 9.03703C9.51034 9.1507 9.38227 9.81254 9.05706 9.6396C8.44114 9.31212 8.20733 8.54734 8.53481 7.93142C8.8623 7.31553 9.62708 7.08172 10.243 7.4092C10.8589 7.73669 11.0927 8.50147 10.7652 9.11738C10.6107 9.40809 10.12 8.9354 9.83227 9.03703Z",
+ "fill": "#3A3B45"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.866 15.1044C15.3487 15.1044 16.1499 12.8908 16.1499 11.7541C16.1499 11.1633 15.7528 11.3492 15.1167 11.6641C14.5289 11.9551 13.7371 12.3563 12.866 12.3563C11.0523 12.3563 9.58203 10.6173 9.58203 11.7541C9.58203 12.8908 10.3832 15.1044 12.866 15.1044Z",
+ "fill": "#3A3B45"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_8587_60397",
+ "style": "mask-type:alpha",
+ "maskUnits": "userSpaceOnUse",
+ "x": "9",
+ "y": "11",
+ "width": "8",
+ "height": "5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.8543 15.1005C15.337 15.1005 16.1382 12.8869 16.1382 11.7502C16.1382 11.1594 15.7411 11.3453 15.105 11.6602C14.5172 11.9512 13.7253 12.3524 12.8543 12.3524C11.0406 12.3524 9.57031 10.6134 9.57031 11.7502C9.57031 12.8869 10.3715 15.1005 12.8543 15.1005Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_8587_60397)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.9175 17.6824C14.1274 17.6824 15.1083 16.7016 15.1083 15.4916C15.1083 14.5491 14.5133 13.7457 13.6783 13.4364C13.6476 13.425 13.6166 13.4143 13.5852 13.4043C13.3747 13.337 13.1503 14.0606 12.9175 14.0606C12.6999 14.0606 12.4897 13.3324 12.2913 13.3915C11.3864 13.6609 10.7266 14.4991 10.7266 15.4916C10.7266 16.7016 11.7075 17.6824 12.9175 17.6824Z",
+ "fill": "#F94040"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.8679 10.2273C19.3213 10.2273 19.6888 9.85972 19.6888 9.40631C19.6888 8.9529 19.3213 8.58533 18.8679 8.58533C18.4144 8.58533 18.0469 8.9529 18.0469 9.40631C18.0469 9.85972 18.4144 10.2273 18.8679 10.2273Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.11786 10.2273C7.57127 10.2273 7.93885 9.85972 7.93885 9.40631C7.93885 8.9529 7.57127 8.58533 7.11786 8.58533C6.66442 8.58533 6.29688 8.9529 6.29688 9.40631C6.29688 9.85972 6.66442 10.2273 7.11786 10.2273Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.4272 13.0092C5.01822 13.0092 4.6527 13.1771 4.39781 13.4818C4.24018 13.6705 4.07548 13.9746 4.06209 14.4301C3.89057 14.3808 3.72561 14.3533 3.57152 14.3533C3.17997 14.3533 2.82632 14.5033 2.57623 14.7759C2.25491 15.1258 2.11219 15.5557 2.17433 15.9859C2.20389 16.1908 2.27234 16.3744 2.37465 16.5444C2.15892 16.719 2.00003 16.962 1.92323 17.2543C1.86311 17.4834 1.80148 17.9606 2.1233 18.4522C2.10284 18.4842 2.08364 18.5176 2.06571 18.5517C1.87221 18.919 1.85983 19.334 2.03059 19.7205C2.28952 20.3063 2.93292 20.7678 4.18233 21.2632C4.95962 21.5714 5.67072 21.7684 5.67703 21.7702C6.70465 22.0367 7.63401 22.1721 8.43858 22.1721C9.91736 22.1721 10.9761 21.7192 11.5854 20.8259C12.566 19.3876 12.4258 18.072 11.1569 16.8039C10.4547 16.1021 9.98784 15.0674 9.89058 14.8403C9.69456 14.1679 9.1762 13.4204 8.31454 13.4204C8.24205 13.4204 8.16854 13.4262 8.09629 13.4376C7.71889 13.4969 7.38898 13.7142 7.15329 14.0411C6.89891 13.7248 6.65186 13.4732 6.4283 13.3312C6.09132 13.1175 5.75459 13.0092 5.4272 13.0092ZM5.4272 14.0196C5.55603 14.0196 5.71341 14.0744 5.88695 14.1846C6.42577 14.5263 7.46552 16.3136 7.8462 17.0087C7.97377 17.2417 8.19178 17.3402 8.38805 17.3402C8.77758 17.3402 9.08172 16.9529 8.42367 16.4608C7.4342 15.7204 7.78128 14.5102 8.25366 14.4356C8.27438 14.4324 8.29484 14.4308 8.31454 14.4308C8.74398 14.4308 8.93344 15.171 8.93344 15.171C8.93344 15.171 9.48868 16.5654 10.4425 17.5185C11.3964 18.4719 11.4457 19.237 10.7505 20.2566C10.2763 20.9517 9.36869 21.1617 8.43858 21.1617C7.47386 21.1617 6.48488 20.9358 5.93066 20.7921C5.90337 20.785 2.53279 19.8329 2.9597 19.0226C3.03144 18.8864 3.14966 18.8318 3.29845 18.8318C3.89966 18.8318 4.99322 19.7266 5.46332 19.7266C5.56841 19.7266 5.64243 19.6819 5.67274 19.5727C5.87306 18.8541 2.62701 18.5519 2.90059 17.5109C2.94884 17.3268 3.07969 17.252 3.26359 17.2523C4.05805 17.2523 5.84047 18.6495 6.21408 18.6495C6.24263 18.6495 6.26309 18.6411 6.27421 18.6234C6.46139 18.3213 6.35883 18.1104 5.03944 17.3119C3.72006 16.5131 2.79398 16.0327 3.32068 15.4592C3.38131 15.393 3.46719 15.3637 3.57152 15.3637C4.37255 15.364 6.26511 17.0863 6.26511 17.0863C6.26511 17.0863 6.77589 17.6175 7.08483 17.6175C7.15582 17.6175 7.21619 17.5895 7.25711 17.5203C7.47613 17.151 5.22284 15.4433 5.09578 14.7388C5.00964 14.2613 5.15615 14.0196 5.4272 14.0196Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.7569 20.2539C11.4521 19.2344 11.4028 18.4692 10.4489 17.5159C9.49509 16.5628 8.93985 15.1684 8.93985 15.1684C8.93985 15.1684 8.73245 14.3585 8.26007 14.433C7.78769 14.5075 7.44085 15.7178 8.43033 16.4582C9.41981 17.1984 8.2333 17.7013 7.85261 17.0061C7.47193 16.3109 6.43243 14.5237 5.89336 14.1819C5.35454 13.8402 4.97512 14.0316 5.10218 14.7362C5.22925 15.4407 7.48279 17.1483 7.26352 17.5179C7.04426 17.8872 6.27152 17.0837 6.27152 17.0837C6.27152 17.0837 3.85353 14.8832 3.32707 15.4566C2.80063 16.03 3.72646 16.5105 5.04585 17.3093C6.36549 18.1078 6.4678 18.3187 6.28061 18.6208C6.09317 18.9229 3.18056 16.4673 2.90698 17.5083C2.63365 18.5493 5.87947 18.8514 5.67915 19.5701C5.47883 20.2891 3.39275 18.2098 2.96609 19.0199C2.53918 19.8303 5.90978 20.7824 5.93706 20.7895C7.02582 21.0719 9.79089 21.6703 10.7569 20.2539Z",
+ "fill": "#FFD21E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.5549 13.0092C20.9639 13.0092 21.3294 13.1771 21.5843 13.4818C21.7419 13.6705 21.9066 13.9746 21.92 14.4301C22.0915 14.3808 22.2565 14.3533 22.4106 14.3533C22.8021 14.3533 23.1558 14.5033 23.4058 14.7759C23.7272 15.1258 23.8699 15.5557 23.8078 15.9859C23.7782 16.1908 23.7097 16.3744 23.6074 16.5444C23.8232 16.719 23.9821 16.962 24.0588 17.2543C24.119 17.4834 24.1806 17.9606 23.8588 18.4522C23.8792 18.4842 23.8984 18.5176 23.9164 18.5517C24.1099 18.919 24.1223 19.334 23.9515 19.7205C23.6926 20.3063 23.0492 20.7678 21.7997 21.2632C21.0225 21.5714 20.3114 21.7684 20.305 21.7702C19.2774 22.0367 18.3481 22.1721 17.5435 22.1721C16.0647 22.1721 15.006 21.7192 14.3967 20.8259C13.4161 19.3876 13.5563 18.072 14.8252 16.8039C15.5274 16.1021 15.9942 15.0674 16.0915 14.8403C16.2875 14.1679 16.8059 13.4204 17.6675 13.4204C17.74 13.4204 17.8135 13.4262 17.8858 13.4376C18.2632 13.4969 18.5931 13.7142 18.8288 14.0411C19.0832 13.7248 19.3302 13.4732 19.5538 13.3312C19.8908 13.1175 20.2275 13.0092 20.5549 13.0092ZM20.5549 14.0196C20.4261 14.0196 20.2687 14.0744 20.0951 14.1846C19.5563 14.5263 18.5166 16.3136 18.1359 17.0087C18.0083 17.2417 17.7903 17.3402 17.594 17.3402C17.2045 17.3402 16.9004 16.9529 17.5584 16.4608C18.5479 15.7204 18.2008 14.5102 17.7284 14.4356C17.7077 14.4324 17.6872 14.4308 17.6675 14.4308C17.2381 14.4308 17.0486 15.171 17.0486 15.171C17.0486 15.171 16.4934 16.5654 15.5395 17.5185C14.5857 18.4719 14.5364 19.237 15.2316 20.2566C15.7058 20.9517 16.6134 21.1617 17.5435 21.1617C18.5082 21.1617 19.4972 20.9358 20.0514 20.7921C20.0787 20.785 23.4493 19.8329 23.0224 19.0226C22.9506 18.8864 22.8324 18.8318 22.6836 18.8318C22.0824 18.8318 20.9889 19.7266 20.5188 19.7266C20.4137 19.7266 20.3397 19.6819 20.3093 19.5727C20.109 18.8541 23.3551 18.5519 23.0815 17.5109C23.0332 17.3268 22.9024 17.252 22.7185 17.2523C21.924 17.2523 20.1416 18.6495 19.768 18.6495C19.7395 18.6495 19.719 18.6411 19.7079 18.6234C19.5207 18.3213 19.6233 18.1104 20.9426 17.3119C22.262 16.5131 23.1881 16.0327 22.6614 15.4592C22.6008 15.393 22.5149 15.3637 22.4106 15.3637C21.6095 15.364 19.717 17.0863 19.717 17.0863C19.717 17.0863 19.2062 17.6175 18.8972 17.6175C18.8263 17.6175 18.7659 17.5895 18.725 17.5203C18.506 17.151 20.7592 15.4433 20.8863 14.7388C20.9724 14.2613 20.8259 14.0196 20.5549 14.0196Z",
+ "fill": "#FF9D0B"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.2334 20.2539C14.5382 19.2344 14.5875 18.4692 15.5414 17.5159C16.4952 16.5628 17.0505 15.1684 17.0505 15.1684C17.0505 15.1684 17.2578 14.3585 17.7302 14.433C18.2026 14.5075 18.5494 15.7178 17.56 16.4582C16.5705 17.1984 17.757 17.7013 18.1377 17.0061C18.5184 16.3109 19.5579 14.5237 20.0969 14.1819C20.6358 13.8402 21.0152 14.0316 20.8881 14.7362C20.7611 15.4407 18.5075 17.1483 18.7268 17.5179C18.946 17.8872 19.7188 17.0837 19.7188 17.0837C19.7188 17.0837 22.1368 14.8832 22.6632 15.4566C23.1897 16.03 22.2638 16.5105 20.9445 17.3093C19.6248 18.1078 19.5225 18.3187 19.7097 18.6208C19.8971 18.9229 22.8097 16.4673 23.0833 17.5083C23.3566 18.5493 20.1108 18.8514 20.3112 19.5701C20.5115 20.2891 22.5975 18.2098 23.0242 19.0199C23.4511 19.8303 20.0805 20.7824 20.0532 20.7895C18.9645 21.0719 16.1994 21.6703 15.2334 20.2539Z",
+ "fill": "#FFD21E"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M34.1509 17V7.22003H36.3559V10.985H39.7309V7.22003H41.9509V17H39.7309V12.92H36.3559V17H34.1509Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M46.3133 17.18C45.5033 17.18 44.9133 16.915 44.5433 16.385C44.1833 15.845 44.0033 15.11 44.0033 14.18V9.56003H46.2083V13.895C46.2083 14.425 46.2833 14.795 46.4333 15.005C46.5833 15.205 46.8183 15.305 47.1383 15.305C47.4183 15.305 47.6533 15.24 47.8433 15.11C48.0333 14.98 48.2383 14.77 48.4583 14.48V9.56003H50.6633V17H48.8633L48.6983 15.965H48.6533C48.3433 16.335 48.0033 16.63 47.6333 16.85C47.2633 17.07 46.8233 17.18 46.3133 17.18Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M55.2587 20.165C54.6787 20.165 54.1537 20.1 53.6837 19.97C53.2137 19.84 52.8387 19.635 52.5587 19.355C52.2787 19.075 52.1387 18.715 52.1387 18.275C52.1387 17.675 52.4937 17.175 53.2037 16.775V16.715C53.0137 16.585 52.8487 16.42 52.7087 16.22C52.5787 16.02 52.5137 15.765 52.5137 15.455C52.5137 15.185 52.5937 14.925 52.7537 14.675C52.9137 14.425 53.1137 14.22 53.3537 14.06V14C53.0937 13.82 52.8587 13.56 52.6487 13.22C52.4487 12.88 52.3487 12.495 52.3487 12.065C52.3487 11.465 52.4937 10.97 52.7837 10.58C53.0737 10.18 53.4537 9.88003 53.9237 9.68003C54.3937 9.48003 54.8937 9.38003 55.4237 9.38003C55.8637 9.38003 56.2487 9.44003 56.5787 9.56003H59.2937V11.165H58.1087C58.1787 11.275 58.2337 11.415 58.2737 11.585C58.3237 11.755 58.3487 11.94 58.3487 12.14C58.3487 12.71 58.2187 13.18 57.9587 13.55C57.6987 13.92 57.3487 14.195 56.9087 14.375C56.4687 14.555 55.9737 14.645 55.4237 14.645C55.1337 14.645 54.8337 14.595 54.5237 14.495C54.3437 14.645 54.2537 14.83 54.2537 15.05C54.2537 15.24 54.3387 15.38 54.5087 15.47C54.6787 15.56 54.9687 15.605 55.3787 15.605H56.5787C57.4987 15.605 58.1987 15.755 58.6787 16.055C59.1687 16.345 59.4137 16.825 59.4137 17.495C59.4137 18.005 59.2437 18.46 58.9037 18.86C58.5637 19.27 58.0837 19.59 57.4637 19.82C56.8437 20.05 56.1087 20.165 55.2587 20.165ZM55.4237 13.31C55.7137 13.31 55.9537 13.205 56.1437 12.995C56.3437 12.785 56.4437 12.475 56.4437 12.065C56.4437 11.675 56.3437 11.38 56.1437 11.18C55.9537 10.97 55.7137 10.865 55.4237 10.865C55.1337 10.865 54.8887 10.965 54.6887 11.165C54.4987 11.365 54.4037 11.665 54.4037 12.065C54.4037 12.475 54.4987 12.785 54.6887 12.995C54.8887 13.205 55.1337 13.31 55.4237 13.31ZM55.6037 18.785C56.1037 18.785 56.5137 18.695 56.8337 18.515C57.1537 18.335 57.3137 18.12 57.3137 17.87C57.3137 17.64 57.2137 17.485 57.0137 17.405C56.8237 17.325 56.5437 17.285 56.1737 17.285H55.4087C55.1587 17.285 54.9487 17.275 54.7787 17.255C54.6187 17.245 54.4787 17.225 54.3587 17.195C54.0887 17.435 53.9537 17.68 53.9537 17.93C53.9537 18.21 54.1037 18.42 54.4037 18.56C54.7137 18.71 55.1137 18.785 55.6037 18.785Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M63.2714 20.165C62.6914 20.165 62.1664 20.1 61.6964 19.97C61.2264 19.84 60.8514 19.635 60.5714 19.355C60.2914 19.075 60.1514 18.715 60.1514 18.275C60.1514 17.675 60.5064 17.175 61.2164 16.775V16.715C61.0264 16.585 60.8614 16.42 60.7214 16.22C60.5914 16.02 60.5264 15.765 60.5264 15.455C60.5264 15.185 60.6064 14.925 60.7664 14.675C60.9264 14.425 61.1264 14.22 61.3664 14.06V14C61.1064 13.82 60.8714 13.56 60.6614 13.22C60.4614 12.88 60.3614 12.495 60.3614 12.065C60.3614 11.465 60.5064 10.97 60.7964 10.58C61.0864 10.18 61.4664 9.88003 61.9364 9.68003C62.4064 9.48003 62.9064 9.38003 63.4364 9.38003C63.8764 9.38003 64.2614 9.44003 64.5914 9.56003H67.3064V11.165H66.1214C66.1914 11.275 66.2464 11.415 66.2864 11.585C66.3364 11.755 66.3614 11.94 66.3614 12.14C66.3614 12.71 66.2314 13.18 65.9714 13.55C65.7114 13.92 65.3614 14.195 64.9214 14.375C64.4814 14.555 63.9864 14.645 63.4364 14.645C63.1464 14.645 62.8464 14.595 62.5364 14.495C62.3564 14.645 62.2664 14.83 62.2664 15.05C62.2664 15.24 62.3514 15.38 62.5214 15.47C62.6914 15.56 62.9814 15.605 63.3914 15.605H64.5914C65.5114 15.605 66.2114 15.755 66.6914 16.055C67.1814 16.345 67.4264 16.825 67.4264 17.495C67.4264 18.005 67.2564 18.46 66.9164 18.86C66.5764 19.27 66.0964 19.59 65.4764 19.82C64.8564 20.05 64.1214 20.165 63.2714 20.165ZM63.4364 13.31C63.7264 13.31 63.9664 13.205 64.1564 12.995C64.3564 12.785 64.4564 12.475 64.4564 12.065C64.4564 11.675 64.3564 11.38 64.1564 11.18C63.9664 10.97 63.7264 10.865 63.4364 10.865C63.1464 10.865 62.9014 10.965 62.7014 11.165C62.5114 11.365 62.4164 11.665 62.4164 12.065C62.4164 12.475 62.5114 12.785 62.7014 12.995C62.9014 13.205 63.1464 13.31 63.4364 13.31ZM63.6164 18.785C64.1164 18.785 64.5264 18.695 64.8464 18.515C65.1664 18.335 65.3264 18.12 65.3264 17.87C65.3264 17.64 65.2264 17.485 65.0264 17.405C64.8364 17.325 64.5564 17.285 64.1864 17.285H63.4214C63.1714 17.285 62.9614 17.275 62.7914 17.255C62.6314 17.245 62.4914 17.225 62.3714 17.195C62.1014 17.435 61.9664 17.68 61.9664 17.93C61.9664 18.21 62.1164 18.42 62.4164 18.56C62.7264 18.71 63.1264 18.785 63.6164 18.785Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M68.6291 17V9.56003H70.8341V17H68.6291ZM69.7241 8.46503C69.3541 8.46503 69.0541 8.36003 68.8241 8.15003C68.5941 7.94003 68.4791 7.66003 68.4791 7.31003C68.4791 6.96003 68.5941 6.68003 68.8241 6.47003C69.0541 6.26003 69.3541 6.15503 69.7241 6.15503C70.0941 6.15503 70.3941 6.26003 70.6241 6.47003C70.8541 6.68003 70.9691 6.96003 70.9691 7.31003C70.9691 7.66003 70.8541 7.94003 70.6241 8.15003C70.3941 8.36003 70.0941 8.46503 69.7241 8.46503Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M72.7746 17V9.56003H74.5746L74.7246 10.505H74.7846C75.1046 10.205 75.4546 9.94503 75.8346 9.72503C76.2246 9.49503 76.6696 9.38003 77.1696 9.38003C77.9796 9.38003 78.5646 9.65003 78.9246 10.19C79.2946 10.72 79.4796 11.45 79.4796 12.38V17H77.2746V12.665C77.2746 12.125 77.1996 11.755 77.0496 11.555C76.9096 11.355 76.6796 11.255 76.3596 11.255C76.0796 11.255 75.8396 11.32 75.6396 11.45C75.4396 11.57 75.2196 11.745 74.9796 11.975V17H72.7746Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M84.0136 20.165C83.4336 20.165 82.9086 20.1 82.4386 19.97C81.9686 19.84 81.5936 19.635 81.3136 19.355C81.0336 19.075 80.8936 18.715 80.8936 18.275C80.8936 17.675 81.2486 17.175 81.9586 16.775V16.715C81.7686 16.585 81.6036 16.42 81.4636 16.22C81.3336 16.02 81.2686 15.765 81.2686 15.455C81.2686 15.185 81.3486 14.925 81.5086 14.675C81.6686 14.425 81.8686 14.22 82.1086 14.06V14C81.8486 13.82 81.6136 13.56 81.4036 13.22C81.2036 12.88 81.1036 12.495 81.1036 12.065C81.1036 11.465 81.2486 10.97 81.5386 10.58C81.8286 10.18 82.2086 9.88003 82.6786 9.68003C83.1486 9.48003 83.6486 9.38003 84.1786 9.38003C84.6186 9.38003 85.0036 9.44003 85.3336 9.56003H88.0486V11.165H86.8636C86.9336 11.275 86.9886 11.415 87.0286 11.585C87.0786 11.755 87.1036 11.94 87.1036 12.14C87.1036 12.71 86.9736 13.18 86.7136 13.55C86.4536 13.92 86.1036 14.195 85.6636 14.375C85.2236 14.555 84.7286 14.645 84.1786 14.645C83.8886 14.645 83.5886 14.595 83.2786 14.495C83.0986 14.645 83.0086 14.83 83.0086 15.05C83.0086 15.24 83.0936 15.38 83.2636 15.47C83.4336 15.56 83.7236 15.605 84.1336 15.605H85.3336C86.2536 15.605 86.9536 15.755 87.4336 16.055C87.9236 16.345 88.1686 16.825 88.1686 17.495C88.1686 18.005 87.9986 18.46 87.6586 18.86C87.3186 19.27 86.8386 19.59 86.2186 19.82C85.5986 20.05 84.8636 20.165 84.0136 20.165ZM84.1786 13.31C84.4686 13.31 84.7086 13.205 84.8986 12.995C85.0986 12.785 85.1986 12.475 85.1986 12.065C85.1986 11.675 85.0986 11.38 84.8986 11.18C84.7086 10.97 84.4686 10.865 84.1786 10.865C83.8886 10.865 83.6436 10.965 83.4436 11.165C83.2536 11.365 83.1586 11.665 83.1586 12.065C83.1586 12.475 83.2536 12.785 83.4436 12.995C83.6436 13.205 83.8886 13.31 84.1786 13.31ZM84.3586 18.785C84.8586 18.785 85.2686 18.695 85.5886 18.515C85.9086 18.335 86.0686 18.12 86.0686 17.87C86.0686 17.64 85.9686 17.485 85.7686 17.405C85.5786 17.325 85.2986 17.285 84.9286 17.285H84.1636C83.9136 17.285 83.7036 17.275 83.5336 17.255C83.3736 17.245 83.2336 17.225 83.1136 17.195C82.8436 17.435 82.7086 17.68 82.7086 17.93C82.7086 18.21 82.8586 18.42 83.1586 18.56C83.4686 18.71 83.8686 18.785 84.3586 18.785Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M92.5542 17V7.22003H98.7192V9.08003H94.7592V11.345H98.1492V13.205H94.7592V17H92.5542Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M101.544 17.18C100.864 17.18 100.324 16.965 99.9241 16.535C99.5241 16.095 99.3241 15.56 99.3241 14.93C99.3241 14.15 99.6541 13.54 100.314 13.1C100.974 12.66 102.039 12.365 103.509 12.215C103.489 11.885 103.389 11.625 103.209 11.435C103.039 11.235 102.749 11.135 102.339 11.135C102.029 11.135 101.714 11.195 101.394 11.315C101.074 11.435 100.734 11.6 100.374 11.81L99.5791 10.355C100.049 10.065 100.549 9.83003 101.079 9.65003C101.619 9.47003 102.179 9.38003 102.759 9.38003C103.709 9.38003 104.439 9.65503 104.949 10.205C105.459 10.755 105.714 11.6 105.714 12.74V17H103.914L103.764 16.235H103.704C103.394 16.515 103.059 16.745 102.699 16.925C102.349 17.095 101.964 17.18 101.544 17.18ZM102.294 15.47C102.544 15.47 102.759 15.415 102.939 15.305C103.129 15.185 103.319 15.03 103.509 14.84V13.535C102.729 13.635 102.189 13.795 101.889 14.015C101.589 14.225 101.439 14.475 101.439 14.765C101.439 15.005 101.514 15.185 101.664 15.305C101.824 15.415 102.034 15.47 102.294 15.47Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M110.819 17.18C110.129 17.18 109.504 17.03 108.944 16.73C108.394 16.42 107.954 15.975 107.624 15.395C107.304 14.805 107.144 14.1 107.144 13.28C107.144 12.45 107.324 11.745 107.684 11.165C108.044 10.585 108.519 10.145 109.109 9.84503C109.699 9.53503 110.334 9.38003 111.014 9.38003C111.474 9.38003 111.879 9.45503 112.229 9.60503C112.589 9.75503 112.909 9.94503 113.189 10.175L112.154 11.6C111.804 11.31 111.469 11.165 111.149 11.165C110.619 11.165 110.194 11.355 109.874 11.735C109.564 12.115 109.409 12.63 109.409 13.28C109.409 13.92 109.564 14.435 109.874 14.825C110.194 15.205 110.594 15.395 111.074 15.395C111.314 15.395 111.549 15.345 111.779 15.245C112.009 15.135 112.219 15.005 112.409 14.855L113.279 16.295C112.909 16.615 112.509 16.845 112.079 16.985C111.649 17.115 111.229 17.18 110.819 17.18Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M117.486 17.18C116.776 17.18 116.136 17.025 115.566 16.715C114.996 16.405 114.546 15.96 114.216 15.38C113.886 14.8 113.721 14.1 113.721 13.28C113.721 12.47 113.886 11.775 114.216 11.195C114.556 10.615 114.996 10.17 115.536 9.86003C116.076 9.54003 116.641 9.38003 117.231 9.38003C117.941 9.38003 118.526 9.54003 118.986 9.86003C119.456 10.17 119.806 10.595 120.036 11.135C120.276 11.665 120.396 12.27 120.396 12.95C120.396 13.14 120.386 13.33 120.366 13.52C120.346 13.7 120.326 13.835 120.306 13.925H115.851C115.951 14.465 116.176 14.865 116.526 15.125C116.876 15.375 117.296 15.5 117.786 15.5C118.316 15.5 118.851 15.335 119.391 15.005L120.126 16.34C119.746 16.6 119.321 16.805 118.851 16.955C118.381 17.105 117.926 17.18 117.486 17.18ZM115.836 12.47H118.521C118.521 12.06 118.421 11.725 118.221 11.465C118.031 11.195 117.716 11.06 117.276 11.06C116.936 11.06 116.631 11.18 116.361 11.42C116.091 11.65 115.916 12 115.836 12.47Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M125.103 17V7.22003H127.308V10.985H130.683V7.22003H132.903V17H130.683V12.92H127.308V17H125.103Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M137.265 17.18C136.455 17.18 135.865 16.915 135.495 16.385C135.135 15.845 134.955 15.11 134.955 14.18V9.56003H137.16V13.895C137.16 14.425 137.235 14.795 137.385 15.005C137.535 15.205 137.77 15.305 138.09 15.305C138.37 15.305 138.605 15.24 138.795 15.11C138.985 14.98 139.19 14.77 139.41 14.48V9.56003H141.615V17H139.815L139.65 15.965H139.605C139.295 16.335 138.955 16.63 138.585 16.85C138.215 17.07 137.775 17.18 137.265 17.18Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M147.456 17.18C147.126 17.18 146.791 17.1 146.451 16.94C146.121 16.77 145.811 16.525 145.521 16.205H145.461L145.281 17H143.556V6.48503H145.761V9.06503L145.701 10.205C145.991 9.94503 146.306 9.74503 146.646 9.60503C146.986 9.45503 147.326 9.38003 147.666 9.38003C148.266 9.38003 148.786 9.53503 149.226 9.84503C149.666 10.155 150.001 10.595 150.231 11.165C150.471 11.725 150.591 12.385 150.591 13.145C150.591 13.995 150.441 14.725 150.141 15.335C149.841 15.935 149.451 16.395 148.971 16.715C148.501 17.025 147.996 17.18 147.456 17.18ZM146.946 15.38C147.326 15.38 147.651 15.205 147.921 14.855C148.191 14.505 148.326 13.95 148.326 13.19C148.326 11.85 147.896 11.18 147.036 11.18C146.596 11.18 146.171 11.405 145.761 11.855V14.9C145.961 15.08 146.161 15.205 146.361 15.275C146.561 15.345 146.756 15.38 146.946 15.38Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_8587_60397"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "0.998047",
+ "width": "150",
+ "height": "24",
+ "rx": "6",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip1_8587_60397"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "23.998",
+ "height": "22.2298",
+ "fill": "white",
+ "transform": "translate(0.998047 0.885132)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "HuggingfaceTextHub"
+}
diff --git a/app/components/base/icons/src/public/llm/HuggingfaceTextHub.tsx b/app/components/base/icons/src/public/llm/HuggingfaceTextHub.tsx
new file mode 100644
index 0000000..47e3620
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/HuggingfaceTextHub.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './HuggingfaceTextHub.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'HuggingfaceTextHub'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/IflytekSpark.json b/app/components/base/icons/src/public/llm/IflytekSpark.json
new file mode 100644
index 0000000..1803b5f
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/IflytekSpark.json
@@ -0,0 +1,44 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.6547 16.7993C21.3111 18.0034 20.7384 19.0938 20.0054 20.048C18.9058 21.4111 15.1261 21.4111 12.8583 20.8204C10.4072 20.1616 8.6433 18.6395 8.50586 18.5259C9.46797 19.2756 10.6821 19.7072 12.0107 19.7072C15.1948 19.7072 17.7605 17.1174 17.7605 13.9368C17.7605 12.9826 17.5314 12.0966 17.119 11.3015C17.0961 11.2561 17.1419 11.2106 17.1649 11.2333C18.9745 11.5287 22.571 13.2098 21.6547 16.7993Z",
+ "fill": "#2751D0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.9994 12.7773C21.9994 12.8454 21.9306 12.8682 21.8848 12.8C21.0372 11.0053 19.5483 10.46 17.7615 10.0511C16.4099 9.75577 15.5166 9.3014 15.1271 9.09694C15.0355 9.0515 14.9668 8.98335 14.8751 8.93791C12.0575 7.23404 12.0117 4.30339 12.0117 4.30339V0.0550813C12.0117 0.00964486 12.0804 -0.0130733 12.1034 0.0096449L18.7694 6.50706L19.2734 6.98414C20.7394 8.52898 21.7474 10.5509 21.9994 12.7773Z",
+ "fill": "#D82F20"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.0052 20.0462C18.1726 22.4316 15.2863 23.9992 12.0334 23.9992C6.48985 23.9992 2 19.501 2 13.9577C2 11.2543 3.05374 8.8234 4.7947 7.00594L5.29866 6.50614L9.65107 2.25783C9.69688 2.2124 9.7656 2.25783 9.7427 2.30327C9.67397 2.59861 9.55944 3.28015 9.62816 4.18888C9.71979 5.25664 10.0634 6.68789 11.0713 8.27817C11.6898 9.27777 12.5832 10.3228 13.8202 11.4133C13.9577 11.5496 14.118 11.6632 14.2784 11.7995C14.8281 12.3674 15.1488 13.1171 15.1488 13.9577C15.1488 15.6616 13.7515 17.0474 12.0563 17.0474C11.3233 17.0474 10.659 16.7975 10.1321 16.3659C10.0863 16.3204 10.1321 16.2523 10.1779 16.275C10.2925 16.2977 10.407 16.3204 10.5215 16.3204C11.1171 16.3204 11.6211 15.8433 11.6211 15.2299C11.6211 14.8665 11.4378 14.5257 11.163 14.3439C10.4299 13.7533 9.81142 13.1853 9.28455 12.6173C8.55151 11.8222 8.00174 11.0498 7.61231 10.3001C6.81055 11.2997 6.30659 12.5492 6.30659 13.935C6.30659 15.7979 7.17707 17.4563 8.55152 18.5014C8.68896 18.615 10.4528 20.1371 12.9039 20.7959C15.1259 21.432 18.9057 21.4093 20.0052 20.0462Z",
+ "fill": "#69C5F4"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "IflytekSpark"
+}
diff --git a/app/components/base/icons/src/public/llm/IflytekSpark.tsx b/app/components/base/icons/src/public/llm/IflytekSpark.tsx
new file mode 100644
index 0000000..a2573a3
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/IflytekSpark.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './IflytekSpark.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'IflytekSpark'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/IflytekSparkText.json b/app/components/base/icons/src/public/llm/IflytekSparkText.json
new file mode 100644
index 0000000..2b01c14
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/IflytekSparkText.json
@@ -0,0 +1,187 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "150",
+ "height": "24",
+ "viewBox": "0 0 150 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_8587_60507)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.6552 16.7993C19.3116 18.0034 18.7389 19.0938 18.0059 20.048C16.9063 21.4111 13.1266 21.4111 10.8588 20.8204C8.40766 20.1616 6.64379 18.6395 6.50635 18.5259C7.46846 19.2756 8.68255 19.7072 10.0112 19.7072C13.1953 19.7072 15.7609 17.1174 15.7609 13.9368C15.7609 12.9826 15.5319 12.0966 15.1195 11.3015C15.0966 11.2561 15.1424 11.2106 15.1653 11.2333C16.975 11.5287 20.5715 13.2098 19.6552 16.7993Z",
+ "fill": "#2751D0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.9994 12.7773C19.9994 12.8454 19.9306 12.8682 19.8848 12.8C19.0372 11.0053 17.5483 10.46 15.7615 10.0511C14.4099 9.75577 13.5166 9.3014 13.1271 9.09694C13.0355 9.0515 12.9668 8.98335 12.8751 8.93791C10.0575 7.23404 10.0117 4.30339 10.0117 4.30339V0.0550813C10.0117 0.00964486 10.0804 -0.0130733 10.1034 0.0096449L16.7694 6.50706L17.2734 6.98414C18.7394 8.52898 19.7474 10.5509 19.9994 12.7773Z",
+ "fill": "#D82F20"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.0052 20.0462C16.1726 22.4316 13.2863 23.9992 10.0334 23.9992C4.48985 23.9992 0 19.501 0 13.9577C0 11.2543 1.05374 8.8234 2.7947 7.00594L3.29866 6.50614L7.65107 2.25783C7.69688 2.2124 7.7656 2.25783 7.7427 2.30327C7.67397 2.59861 7.55944 3.28015 7.62816 4.18888C7.71979 5.25664 8.06341 6.68789 9.07133 8.27817C9.68983 9.27777 10.5832 10.3228 11.8202 11.4133C11.9577 11.5496 12.118 11.6632 12.2784 11.7995C12.8281 12.3674 13.1488 13.1171 13.1488 13.9577C13.1488 15.6616 11.7515 17.0474 10.0563 17.0474C9.32331 17.0474 8.659 16.7975 8.13213 16.3659C8.08631 16.3204 8.13212 16.2523 8.17794 16.275C8.29247 16.2977 8.40701 16.3204 8.52155 16.3204C9.11714 16.3204 9.62111 15.8433 9.62111 15.2299C9.62111 14.8665 9.43785 14.5257 9.16296 14.3439C8.42992 13.7533 7.81142 13.1853 7.28455 12.6173C6.55151 11.8222 6.00174 11.0498 5.61231 10.3001C4.81055 11.2997 4.30659 12.5492 4.30659 13.935C4.30659 15.7979 5.17707 17.4563 6.55152 18.5014C6.68896 18.615 8.45283 20.1371 10.9039 20.7959C13.1259 21.432 16.9057 21.4093 18.0052 20.0462Z",
+ "fill": "#69C5F4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M27 10.0997V16.3997H29.008V10.0997H27ZM27 7.89966V9.29966H29.008V7.89966H27Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M39.1482 9.09927V7.49927H31.0156V16.2993H33.2245V12.8993H38.8469V11.2993H33.2245V9.09927H39.1482Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M43.367 14.6993V7.49927H41.1582V16.2993H48.2867V14.6993H43.367Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M55.2168 7.60083L52.6064 11.3008L49.9959 7.60083H47.2852L51.502 13.1008V16.4008H53.7108V13.1008L57.9277 7.60083H55.2168Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M58.9316 7.60083V9.20083H62.2449V16.4008H64.4537V9.20083H67.6666V7.60083H58.9316Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M71.8827 14.7993V12.6993H77.7059V11.0993H71.8827V9.09927H77.9067V7.49927H69.6738V16.2993H78.1075V14.6993H71.8827V14.7993Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M85.1353 11.3008L89.4526 7.60083H86.6413L82.3241 11.4008V7.60083H80.1152V16.4008H82.3241V13.8008L83.6293 12.7008L87.0429 16.5008H89.9546L85.1353 11.3008Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M103.167 11.4C102.866 11.3 102.564 11.2001 101.962 11.1001C101.36 11.0001 99.7532 10.8001 99.1508 10.6001C98.7492 10.5001 98.448 10.3 98.448 9.80005C98.448 8.90005 99.6528 8.80005 99.6528 8.80005C99.954 8.80005 100.255 8.80005 100.356 8.80005C101.159 8.80005 102.163 8.90005 102.665 9.60005C102.765 9.70005 102.765 9.70005 102.866 9.90005L104.974 9.40005C104.773 9.10005 104.673 8.90005 104.372 8.60005C103.97 8.20005 103.468 8.00005 103.267 7.90005C102.665 7.60005 101.862 7.30005 100.356 7.30005C98.7492 7.30005 97.8456 7.70005 97.3436 8.10005C97.0423 8.30005 96.2392 8.90005 96.2392 10.1001C96.2392 11.4001 97.2431 12.0001 97.6447 12.2001C98.3476 12.5001 99.2512 12.7 100.858 12.9C101.661 13 102.263 13.1 102.464 13.3C102.665 13.4 102.765 13.6 102.765 13.9C102.765 14.3 102.464 14.6001 102.364 14.7001C101.761 15.1001 100.657 15.1001 100.556 15.1001C99.452 15.1001 98.1468 14.8001 97.6447 13.7001L95.6367 14.2001C95.7371 14.3001 95.7371 14.4001 95.8375 14.6001C95.9379 14.8001 96.2392 15.3001 96.7412 15.6001C97.0424 15.8001 97.2432 15.9001 97.3436 16.0001C97.946 16.3001 98.8496 16.7001 100.456 16.7001C100.757 16.7001 101.058 16.7001 101.36 16.7001C101.862 16.7001 102.364 16.6 102.765 16.4C104.572 15.8 104.874 14.6 104.874 13.8C104.974 12.1 103.669 11.6 103.167 11.4Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M115.318 8.80083C114.816 8.00083 114.012 7.70083 113.109 7.60083C112.908 7.60083 112.607 7.60083 112.406 7.60083H106.984V16.4008H109.193V13.1008H112.306C113.109 13.1008 114.012 13.1008 114.615 12.7008C114.916 12.5008 115.117 12.3008 115.217 12.2008C115.418 12.0008 115.518 11.8008 115.518 11.7008C115.719 11.2008 115.719 10.6008 115.719 10.4008C115.719 9.50083 115.518 9.00083 115.318 8.80083ZM112.908 11.4008C112.607 11.5008 112.205 11.5008 111.804 11.5008H109.093V9.10083H112.205C112.506 9.10083 112.607 9.10083 112.707 9.20083C113.41 9.40083 113.41 10.2008 113.41 10.4008C113.51 10.5008 113.51 11.1008 112.908 11.4008Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M122.345 7.60083H119.936L115.719 16.4008H118.128L118.831 14.7008H123.349L124.052 16.4008H126.562L122.345 7.60083ZM119.634 13.1008L121.241 9.70083L122.747 13.1008H119.634Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M134.594 12.6993C135.498 12.4993 136.301 12.2993 136.703 11.3993C136.904 10.8993 136.904 10.4993 136.904 10.1993C136.904 8.99926 136.301 8.09926 135.097 7.69926C134.695 7.59926 134.394 7.49927 133.59 7.49927H127.566V16.2993H129.775V12.7993H132.285L134.594 16.2993H137.205L134.594 12.6993ZM133.892 11.1993C133.691 11.1993 133.39 11.1993 133.39 11.1993H129.876V9.09927H133.39C133.791 9.09927 134.293 9.09927 134.594 9.49927C134.795 9.69927 134.795 10.0993 134.795 10.1993C134.695 10.8993 134.193 11.1993 133.892 11.1993Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M144.335 11.3008L148.653 7.60083H145.841L141.524 11.4008V7.60083H139.215V16.4008H141.424V13.8008L142.729 12.7008L146.143 16.5008H149.054L144.335 11.3008Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_8587_60507"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "150",
+ "height": "24",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "IflytekSparkText"
+}
diff --git a/app/components/base/icons/src/public/llm/IflytekSparkText.tsx b/app/components/base/icons/src/public/llm/IflytekSparkText.tsx
new file mode 100644
index 0000000..99abd56
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/IflytekSparkText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './IflytekSparkText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'IflytekSparkText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/IflytekSparkTextCn.json b/app/components/base/icons/src/public/llm/IflytekSparkTextCn.json
new file mode 100644
index 0000000..22d1411
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/IflytekSparkTextCn.json
@@ -0,0 +1,98 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "84",
+ "height": "24",
+ "viewBox": "0 0 84 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M34.8763 7.49212H33.1466V11.557H34.4438V13.0273H33.1466V18.7137H31.1574V13.0489H29.752V11.5786H31.179V7.49212H29.8384V6.02185H36.952C37.2547 6.02185 37.4925 6.25969 37.4925 6.56239V17.33H38.4438L37.7736 18.7354L35.4817 18.757L35.4601 8.11915C35.4817 7.7732 35.2222 7.49212 34.8763 7.49212Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M26.1832 11.8599H25.3184V10.3896H27.6102C27.9129 10.3896 28.1508 10.6275 28.1508 10.9302L28.1724 17.3086H29.2319L28.5832 18.7356H26.7238C26.4211 18.7356 26.1832 18.4978 26.1832 18.1951V11.8599Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M28.1724 6.02185H25.3184V7.55699H28.1724V6.02185Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M50.1495 6.02162L45.5873 10.0865H48.6792L52.8306 6.02162H50.1495ZM49.09 11.773H46.1279L49.5873 15.5135H52.5495L49.09 11.773ZM43.4468 17.3514C43.2522 17.3514 43.1225 17.1784 43.1657 16.9838L45.89 6.69189C45.9765 6.34595 45.7171 6 45.3711 6H40.1387V7.44865H43.036C43.3171 7.44865 43.5333 7.72973 43.4468 7.98919L40.7873 18.0216C40.7008 18.3676 40.9603 18.7135 41.3062 18.7135H51.7927L52.5927 17.3297H43.4468V17.3514Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M62.2792 16.465H67.1224V15.3406H62.2792V14.2379H67.1224V13.1569H62.2792V12.2271H67.1224V10.4974V6.56227C67.1224 6.25957 66.8845 6.02173 66.5818 6.02173H55.5332V11.665C55.5332 11.9677 55.771 12.2055 56.0737 12.2055H57.0035L55.5332 14.2379H60.1602V15.3406H55.5548V16.465L60.1602 16.4433V17.3515H55.5548V18.7352H67.1008V17.3515H62.2575V16.465H62.2792ZM57.6305 9.78389H63.7927L64.3981 8.61632H57.6305V7.31903H65.0035V10.8866H57.6305V9.78389ZM60.1602 13.1352H58.3224L59.0359 12.2055H60.1602V13.1352Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M71.549 6.02173H69.4733L71.0085 12.2271H73.0842L71.549 6.02173ZM79.6788 6.02173L78.1436 12.2488H80.2409L81.776 6.02173H79.6788ZM76.6517 12.3136V6.02173H74.5112V12.3136L69.3652 18.7569H71.9814L75.6355 14.2379L79.3112 18.7785L81.949 18.7569L76.6517 12.3136Z",
+ "fill": "#2B2B2D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.8854 16.4979C20.5611 17.6438 20.0206 18.6817 19.3287 19.5898C18.2908 20.8871 14.7233 20.8871 12.5827 20.3249C10.2692 19.6979 8.60434 18.2492 8.47461 18.1411C9.38272 18.8546 10.5287 19.2654 11.7827 19.2654C14.7881 19.2654 17.2097 16.8006 17.2097 13.7735C17.2097 12.8654 16.9935 12.0222 16.6043 11.2654C16.5827 11.2222 16.626 11.179 16.6476 11.2006C18.3557 11.4817 21.7503 13.0817 20.8854 16.4979Z",
+ "fill": "#2751D0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.2102 12.6705C21.2102 12.7353 21.1454 12.7569 21.1021 12.6921C20.3021 10.984 18.8967 10.465 17.2102 10.0759C15.9346 9.79478 15.0913 9.36235 14.7238 9.16775C14.6373 9.12451 14.5724 9.05964 14.4859 9.0164C11.8264 7.39478 11.7832 4.60559 11.7832 4.60559V0.562346C11.7832 0.519102 11.8481 0.497481 11.8697 0.519102L18.1616 6.70289L18.6373 7.15694C20.021 8.62721 20.9724 10.5515 21.2102 12.6705Z",
+ "fill": "#D82F20"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.3286 19.5894C17.5989 21.8596 14.8745 23.3515 11.8043 23.3515C6.57182 23.3515 2.33398 19.0704 2.33398 13.7948C2.33398 11.2218 3.32858 8.90828 4.97182 7.17855L5.4475 6.70288L9.5556 2.65964C9.59885 2.61639 9.66371 2.65964 9.64209 2.70288C9.57723 2.98396 9.46912 3.63261 9.53398 4.49747C9.62047 5.51369 9.9448 6.87585 10.8961 8.38937C11.4799 9.34072 12.3232 10.3353 13.4907 11.3731C13.6205 11.5029 13.7718 11.611 13.9232 11.7407C14.4421 12.2813 14.7448 12.9948 14.7448 13.7948C14.7448 15.4164 13.4259 16.7353 11.8259 16.7353C11.134 16.7353 10.507 16.4975 10.0097 16.0867C9.96642 16.0434 10.0097 15.9786 10.0529 16.0002C10.161 16.0218 10.2691 16.0434 10.3772 16.0434C10.9394 16.0434 11.4151 15.5894 11.4151 15.0056C11.4151 14.6596 11.2421 14.3353 10.9826 14.1623C10.2907 13.6002 9.70695 13.0596 9.20966 12.5191C8.51777 11.7623 7.99885 11.0272 7.63128 10.3137C6.87453 11.265 6.39885 12.4542 6.39885 13.7731C6.39885 15.5461 7.22047 17.1245 8.51777 18.1191C8.6475 18.2272 10.3124 19.6759 12.6259 20.3029C14.7232 20.9083 18.2907 20.8867 19.3286 19.5894Z",
+ "fill": "#69C5F4"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "IflytekSparkTextCn"
+}
diff --git a/app/components/base/icons/src/public/llm/IflytekSparkTextCn.tsx b/app/components/base/icons/src/public/llm/IflytekSparkTextCn.tsx
new file mode 100644
index 0000000..8f9d09e
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/IflytekSparkTextCn.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './IflytekSparkTextCn.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'IflytekSparkTextCn'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Jina.json b/app/components/base/icons/src/public/llm/Jina.json
new file mode 100644
index 0000000..88d70a3
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Jina.json
@@ -0,0 +1,35 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.56053 21.4486C9.07925 21.4486 11.1211 19.4068 11.1211 16.8882C11.1211 14.3696 9.07925 12.3279 6.56053 12.3279C4.04182 12.3279 2 14.3696 2 16.8882C2 19.4068 4.04182 21.4486 6.56053 21.4486Z",
+ "fill": "#EB6161"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M22.0002 3.59467L21.9406 12.3279C21.9406 17.3055 17.9464 21.3591 12.9685 21.4485L12.8789 12.3577L12.8791 3.62447C12.8791 3.02835 13.356 2.55145 13.9522 2.55145H20.9271C21.5233 2.55145 22.0002 2.99854 22.0002 3.59467Z",
+ "fill": "#009191"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Jina"
+}
diff --git a/app/components/base/icons/src/public/llm/Jina.tsx b/app/components/base/icons/src/public/llm/Jina.tsx
new file mode 100644
index 0000000..6fe2403
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Jina.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Jina.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Jina'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/JinaText.json b/app/components/base/icons/src/public/llm/JinaText.json
new file mode 100644
index 0000000..08e76ef
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/JinaText.json
@@ -0,0 +1,82 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "58",
+ "height": "24",
+ "viewBox": "0 0 58 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_13814_61529)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.47132 23.952C6.49932 23.952 8.14332 22.308 8.14332 20.28C8.14332 18.252 6.49932 16.608 4.47132 16.608C2.44332 16.608 0.799316 18.252 0.799316 20.28C0.799316 22.308 2.44332 23.952 4.47132 23.952Z",
+ "fill": "#EB6161"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M16.0387 8.71204C16.5187 8.71204 16.9027 9.09604 16.9027 9.57604L16.8547 16.608C16.8547 20.616 13.6387 23.88 9.63074 23.952H9.51074V16.632H9.53474L9.55874 9.60004C9.55874 9.12004 9.94274 8.73604 10.4227 8.73604H16.0387V8.71204ZM27.3187 8.71204C27.7987 8.71204 28.1827 9.09604 28.1827 9.57604V19.416C28.1827 19.896 27.7987 20.28 27.3187 20.28H21.7027C21.2227 20.28 20.8387 19.896 20.8387 19.416V9.57604C20.8387 9.09604 21.2227 8.71204 21.7027 8.71204H27.3187ZM36.1507 8.68804H36.2707C39.8707 8.73604 42.7987 11.64 42.8947 15.24V19.392C42.8947 19.872 42.5107 20.256 42.0307 20.256H32.9587C32.4787 20.256 32.0947 19.872 32.0947 19.392V9.55204C32.0947 9.07204 32.4787 8.68804 32.9587 8.68804H36.1507ZM51.0067 20.16C47.9827 19.968 45.5587 17.448 45.5587 14.376C45.5587 11.184 48.1507 8.59204 51.3427 8.59204C54.4147 8.59204 56.9347 10.992 57.1267 14.04V19.296C57.1267 19.776 56.7427 20.16 56.2627 20.16H51.0067Z",
+ "fill": "#009191"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M24.4987 7.344C26.5267 7.344 28.1707 5.7 28.1707 3.672C28.1707 1.644 26.5267 0 24.4987 0C22.4707 0 20.8267 1.644 20.8267 3.672C20.8267 5.7 22.4707 7.344 24.4987 7.344Z",
+ "fill": "#FBCB67"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_13814_61529"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "56.4",
+ "height": "24",
+ "fill": "white",
+ "transform": "translate(0.800781)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "JinaText"
+}
diff --git a/app/components/base/icons/src/public/llm/JinaText.tsx b/app/components/base/icons/src/public/llm/JinaText.tsx
new file mode 100644
index 0000000..e5514a5
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/JinaText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './JinaText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'JinaText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Localai.json b/app/components/base/icons/src/public/llm/Localai.json
new file mode 100644
index 0000000..e0f8549
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Localai.json
@@ -0,0 +1,107 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg",
+ "xmlns:xlink": "http://www.w3.org/1999/xlink"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_10164_6300)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "4",
+ "fill": "#1C0120"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "fill": "url(#pattern0)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "pattern",
+ "attributes": {
+ "id": "pattern0",
+ "patternContentUnits": "objectBoundingBox",
+ "width": "1",
+ "height": "1"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "use",
+ "attributes": {
+ "xlink:href": "#image0_10164_6300",
+ "transform": "scale(0.00390625)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_10164_6300"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "4",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "image",
+ "attributes": {
+ "id": "image0_10164_6300",
+ "width": "256",
+ "height": "256",
+ "xlink:href": "data:image/jpeg;base64,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"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Localai"
+}
diff --git a/app/components/base/icons/src/public/llm/Localai.tsx b/app/components/base/icons/src/public/llm/Localai.tsx
new file mode 100644
index 0000000..731f008
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Localai.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Localai.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Localai'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/LocalaiText.json b/app/components/base/icons/src/public/llm/LocalaiText.json
new file mode 100644
index 0000000..849f7ae
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/LocalaiText.json
@@ -0,0 +1,170 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "90",
+ "height": "24",
+ "viewBox": "0 0 90 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg",
+ "xmlns:xlink": "http://www.w3.org/1999/xlink"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_10164_6324)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "4",
+ "fill": "#1E0122"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "fill": "url(#pattern0)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M33.0242 16.528H36.7842V18H31.2002V6.88003H33.0242V16.528Z",
+ "fill": "#1C2B33"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M41.8136 18.144C40.9816 18.144 40.2296 17.9574 39.5576 17.584C38.8856 17.2 38.3576 16.6667 37.9736 15.984C37.5896 15.2907 37.3976 14.4907 37.3976 13.584C37.3976 12.688 37.5949 11.8934 37.9896 11.2C38.3842 10.5067 38.9229 9.97337 39.6056 9.60003C40.2882 9.2267 41.0509 9.04003 41.8936 9.04003C42.7362 9.04003 43.4989 9.2267 44.1816 9.60003C44.8642 9.97337 45.4029 10.5067 45.7976 11.2C46.1922 11.8934 46.3896 12.688 46.3896 13.584C46.3896 14.48 46.1869 15.2747 45.7816 15.968C45.3762 16.6614 44.8216 17.2 44.1176 17.584C43.4242 17.9574 42.6562 18.144 41.8136 18.144ZM41.8136 16.56C42.2829 16.56 42.7202 16.448 43.1256 16.224C43.5416 16 43.8776 15.664 44.1336 15.216C44.3896 14.768 44.5176 14.224 44.5176 13.584C44.5176 12.944 44.3949 12.4054 44.1496 11.968C43.9042 11.52 43.5789 11.184 43.1736 10.96C42.7682 10.736 42.3309 10.624 41.8616 10.624C41.3922 10.624 40.9549 10.736 40.5496 10.96C40.1549 11.184 39.8402 11.52 39.6056 11.968C39.3709 12.4054 39.2536 12.944 39.2536 13.584C39.2536 14.5334 39.4936 15.2694 39.9736 15.792C40.4642 16.304 41.0776 16.56 41.8136 16.56Z",
+ "fill": "#1C2B33"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M47.2647 13.584C47.2647 12.6774 47.446 11.8827 47.8087 11.2C48.182 10.5067 48.694 9.97337 49.3447 9.60003C49.9954 9.2267 50.742 9.04003 51.5847 9.04003C52.6514 9.04003 53.5314 9.29603 54.2247 9.80803C54.9287 10.3094 55.4034 11.0294 55.6487 11.968H53.6807C53.5207 11.5307 53.2647 11.1894 52.9127 10.944C52.5607 10.6987 52.118 10.576 51.5847 10.576C50.838 10.576 50.2407 10.8427 49.7927 11.376C49.3554 11.8987 49.1367 12.6347 49.1367 13.584C49.1367 14.5334 49.3554 15.2747 49.7927 15.808C50.2407 16.3414 50.838 16.608 51.5847 16.608C52.6407 16.608 53.3394 16.144 53.6807 15.216H55.6487C55.3927 16.112 54.9127 16.8267 54.2087 17.36C53.5047 17.8827 52.63 18.144 51.5847 18.144C50.742 18.144 49.9954 17.9574 49.3447 17.584C48.694 17.2 48.182 16.6667 47.8087 15.984C47.446 15.2907 47.2647 14.4907 47.2647 13.584Z",
+ "fill": "#1C2B33"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M56.5384 13.552C56.5384 12.6667 56.7198 11.8827 57.0824 11.2C57.4558 10.5174 57.9571 9.98937 58.5864 9.61603C59.2264 9.23203 59.9304 9.04003 60.6984 9.04003C61.3918 9.04003 61.9944 9.1787 62.5064 9.45603C63.0291 9.7227 63.4451 10.0587 63.7544 10.464V9.18403H65.5944V18H63.7544V16.688C63.4451 17.104 63.0238 17.4507 62.4904 17.728C61.9571 18.0054 61.3491 18.144 60.6664 18.144C59.9091 18.144 59.2158 17.952 58.5864 17.568C57.9571 17.1734 57.4558 16.6294 57.0824 15.936C56.7198 15.232 56.5384 14.4374 56.5384 13.552ZM63.7544 13.584C63.7544 12.976 63.6264 12.448 63.3704 12C63.1251 11.552 62.7998 11.2107 62.3944 10.976C61.9891 10.7414 61.5518 10.624 61.0824 10.624C60.6131 10.624 60.1758 10.7414 59.7704 10.976C59.3651 11.2 59.0344 11.536 58.7784 11.984C58.5331 12.4214 58.4104 12.944 58.4104 13.552C58.4104 14.16 58.5331 14.6934 58.7784 15.152C59.0344 15.6107 59.3651 15.9627 59.7704 16.208C60.1864 16.4427 60.6238 16.56 61.0824 16.56C61.5518 16.56 61.9891 16.4427 62.3944 16.208C62.7998 15.9734 63.1251 15.632 63.3704 15.184C63.6264 14.7254 63.7544 14.192 63.7544 13.584Z",
+ "fill": "#1C2B33"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M69.4942 6.16003V18H67.6702V6.16003H69.4942Z",
+ "fill": "#1C2B33"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M78.2729 15.728H73.6169L72.8169 18H70.9129L74.8969 6.86403H77.0089L80.9929 18H79.0729L78.2729 15.728ZM77.7609 14.24L75.9529 9.07203L74.1289 14.24H77.7609Z",
+ "fill": "#1C2B33"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M84.2292 6.88003V18H82.4052V6.88003H84.2292Z",
+ "fill": "#1C2B33"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "pattern",
+ "attributes": {
+ "id": "pattern0",
+ "patternContentUnits": "objectBoundingBox",
+ "width": "1",
+ "height": "1"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "use",
+ "attributes": {
+ "xlink:href": "#image0_10164_6324",
+ "transform": "scale(0.00390625)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_10164_6324"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "4",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "image",
+ "attributes": {
+ "id": "image0_10164_6324",
+ "width": "256",
+ "height": "256",
+ "xlink:href": "data:image/jpeg;base64,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"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LocalaiText"
+}
diff --git a/app/components/base/icons/src/public/llm/LocalaiText.tsx b/app/components/base/icons/src/public/llm/LocalaiText.tsx
new file mode 100644
index 0000000..aaea98a
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/LocalaiText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LocalaiText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LocalaiText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Microsoft.json b/app/components/base/icons/src/public/llm/Microsoft.json
new file mode 100644
index 0000000..ab2c052
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Microsoft.json
@@ -0,0 +1,76 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "21",
+ "height": "22",
+ "viewBox": "0 0 21 22",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Microsoft"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "id": "Rectangle 1010",
+ "y": "0.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#EF4F21"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "id": "Rectangle 1012",
+ "y": "11.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#03A4EE"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "id": "Rectangle 1011",
+ "x": "11",
+ "y": "0.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#7EB903"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "id": "Rectangle 1013",
+ "x": "11",
+ "y": "11.5",
+ "width": "10",
+ "height": "10",
+ "fill": "#FBB604"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Microsoft"
+}
diff --git a/app/components/base/icons/src/public/llm/Microsoft.tsx b/app/components/base/icons/src/public/llm/Microsoft.tsx
new file mode 100644
index 0000000..0b6e5dc
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Microsoft.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Microsoft.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Microsoft'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/OpenaiBlack.json b/app/components/base/icons/src/public/llm/OpenaiBlack.json
new file mode 100644
index 0000000..9f4a991
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiBlack.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "6",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "OpenaiBlack"
+}
diff --git a/app/components/base/icons/src/public/llm/OpenaiBlack.tsx b/app/components/base/icons/src/public/llm/OpenaiBlack.tsx
new file mode 100644
index 0000000..1b9e3ec
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiBlack.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './OpenaiBlack.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'OpenaiBlack'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/OpenaiBlue.json b/app/components/base/icons/src/public/llm/OpenaiBlue.json
new file mode 100644
index 0000000..5c716f7
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiBlue.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "6",
+ "fill": "#03A4EE"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "OpenaiBlue"
+}
diff --git a/app/components/base/icons/src/public/llm/OpenaiBlue.tsx b/app/components/base/icons/src/public/llm/OpenaiBlue.tsx
new file mode 100644
index 0000000..3dc45a9
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiBlue.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './OpenaiBlue.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'OpenaiBlue'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/OpenaiGreen.json b/app/components/base/icons/src/public/llm/OpenaiGreen.json
new file mode 100644
index 0000000..8980e85
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiGreen.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "6",
+ "fill": "#19C37D"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "OpenaiGreen"
+}
diff --git a/app/components/base/icons/src/public/llm/OpenaiGreen.tsx b/app/components/base/icons/src/public/llm/OpenaiGreen.tsx
new file mode 100644
index 0000000..36f967c
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiGreen.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './OpenaiGreen.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'OpenaiGreen'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/OpenaiText.json b/app/components/base/icons/src/public/llm/OpenaiText.json
new file mode 100644
index 0000000..f5fc3de
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiText.json
@@ -0,0 +1,77 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "52",
+ "height": "20",
+ "viewBox": "0 0 52 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0.00390625 8.70054C0.00390625 12.058 2.16008 14.399 5.14793 14.399C8.13577 14.399 10.2919 12.058 10.2919 8.70054C10.2919 5.34307 8.13577 3.00208 5.14793 3.00208C2.16008 3.00208 0.00390625 5.34307 0.00390625 8.70054ZM8.32058 8.70054C8.32058 11.1031 7.01148 12.6587 5.14793 12.6587C3.28437 12.6587 1.97527 11.1031 1.97527 8.70054C1.97527 6.29794 3.28437 4.74242 5.14793 4.74242C7.01148 4.74242 8.32058 6.29794 8.32058 8.70054Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.8456 14.3975C18.1096 14.3975 19.4033 12.4877 19.4033 10.1929C19.4033 7.89816 18.1096 5.9884 15.8456 5.9884C14.7983 5.9884 14.0283 6.40424 13.52 7.00489V6.14242H11.6719V17.0003H13.52V13.381C14.0283 13.9817 14.7983 14.3975 15.8456 14.3975ZM13.4738 9.96193C13.4738 8.4372 14.3363 7.60554 15.476 7.60554C16.8159 7.60554 17.5398 8.65282 17.5398 10.1929C17.5398 11.7331 16.8159 12.7804 15.476 12.7804C14.3363 12.7804 13.4738 11.9333 13.4738 10.4394V9.96193Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M24.4039 14.3975C26.021 14.3975 27.2993 13.5504 27.8692 12.1335L26.2828 11.5329C26.0364 12.3645 25.3126 12.8266 24.4039 12.8266C23.218 12.8266 22.3863 11.9795 22.2477 10.5934H27.9154V9.97733C27.9154 7.75955 26.6679 5.9884 24.3269 5.9884C21.9859 5.9884 20.4766 7.82115 20.4766 10.1929C20.4766 12.6879 22.0937 14.3975 24.4039 14.3975ZM24.3115 7.54393C25.482 7.54393 26.0364 8.31399 26.0518 9.20727H22.3401C22.6173 8.11378 23.3566 7.54393 24.3115 7.54393Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M29.3008 14.2281H31.1489V9.48449C31.1489 8.32939 31.996 7.71334 32.8277 7.71334C33.8442 7.71334 34.2446 8.4372 34.2446 9.43828V14.2281H36.0927V8.89924C36.0927 7.1589 35.0763 5.9884 33.3821 5.9884C32.3348 5.9884 31.611 6.46584 31.1489 7.00489V6.14242H29.3008V14.2281Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M41.5095 3.172L37.3203 14.2301H39.2763L40.2157 11.7043H44.9901L45.945 14.2301H47.9318L43.7426 3.172H41.5095ZM42.5875 5.35898L44.3433 9.97935H40.8626L42.5875 5.35898Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M51.1042 3.20325H49.1328V14.2613H51.1042V3.20325Z",
+ "fill": "black",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "OpenaiText"
+}
diff --git a/app/components/base/icons/src/public/llm/OpenaiText.tsx b/app/components/base/icons/src/public/llm/OpenaiText.tsx
new file mode 100644
index 0000000..f07995d
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './OpenaiText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'OpenaiText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/OpenaiTransparent.json b/app/components/base/icons/src/public/llm/OpenaiTransparent.json
new file mode 100644
index 0000000..13b9cb4
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiTransparent.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.276 10.0045C21.7751 8.50639 21.6033 6.86529 20.8051 5.50264C19.6048 3.41259 17.1917 2.33732 14.835 2.84333C13.7866 1.66218 12.2803 0.990477 10.7011 1.0001C8.29218 0.994602 6.15478 2.54563 5.41367 4.83781C3.86614 5.15475 2.53036 6.12346 1.74869 7.49643C0.539398 9.58097 0.81508 12.2087 2.43067 13.9962C1.93156 15.4943 2.10343 17.1354 2.9016 18.498C4.10195 20.5881 6.51502 21.6634 8.87173 21.1573C9.91945 22.3385 11.4264 23.0102 13.0056 22.9999C15.4159 23.0061 17.554 21.4537 18.2951 19.1594C19.8426 18.8425 21.1784 17.8738 21.9601 16.5008C23.168 14.4163 22.8916 11.7906 21.2767 10.0031L21.276 10.0045ZM13.007 21.5623C12.0424 21.5637 11.1081 21.2261 10.3677 20.608C10.4014 20.5901 10.4598 20.5578 10.4976 20.5345L14.8783 18.0044C15.1024 17.8772 15.2399 17.6386 15.2385 17.3808V11.2049L17.0899 12.274C17.1099 12.2836 17.1229 12.3028 17.1257 12.3248V17.4393C17.1229 19.7136 15.2812 21.5575 13.007 21.5623ZM4.14939 17.7789C3.66608 16.9443 3.49215 15.9659 3.65783 15.0165C3.69015 15.0357 3.74721 15.0708 3.78777 15.0942L8.16843 17.6242C8.39049 17.7541 8.66548 17.7541 8.88823 17.6242L14.2362 14.5359V16.6741C14.2376 16.6961 14.2272 16.7174 14.2101 16.7311L9.78196 19.288C7.80956 20.4238 5.29061 19.7486 4.15007 17.7789H4.14939ZM2.99647 8.21626C3.47771 7.38024 4.23738 6.74085 5.14212 6.40878C5.14212 6.44659 5.14005 6.51328 5.14005 6.56003V11.6208C5.13868 11.878 5.27618 12.1165 5.49961 12.2437L10.8476 15.3313L8.99616 16.4004C8.9776 16.4128 8.95422 16.4149 8.9336 16.4059L4.50482 13.847C2.53654 12.7071 1.86143 10.1887 2.99578 8.21694L2.99647 8.21626ZM18.2078 11.7563L12.8598 8.66795L14.7112 7.59956C14.7298 7.58718 14.7532 7.58512 14.7738 7.59406L19.2026 10.1509C21.1743 11.2901 21.8501 13.8126 20.7109 15.7844C20.229 16.6191 19.47 17.2584 18.566 17.5912V12.3792C18.568 12.122 18.4312 11.8841 18.2085 11.7563H18.2078ZM20.0502 8.98284C20.0179 8.9629 19.9609 8.92852 19.9203 8.90515L15.5397 6.37509C15.3176 6.24515 15.0426 6.24515 14.8199 6.37509L9.4719 9.46341V7.32524C9.47053 7.30324 9.48084 7.28192 9.49803 7.26817L13.9261 4.71337C15.8985 3.57553 18.4202 4.25273 19.5573 6.2259C20.0379 7.05917 20.2118 8.03475 20.0489 8.98284H20.0502ZM8.46542 12.7937L6.61334 11.7246C6.5934 11.715 6.58034 11.6958 6.57759 11.6738V6.55935C6.57896 4.2823 8.42624 2.43701 10.7032 2.43838C11.6664 2.43838 12.5986 2.77664 13.339 3.39265C13.3053 3.41053 13.2476 3.44284 13.2091 3.46622L8.82841 5.99627C8.60429 6.12346 8.4668 6.36134 8.46817 6.61916L8.46542 12.7924V12.7937ZM9.47121 10.6253L11.8534 9.24959L14.2355 10.6246V13.3754L11.8534 14.7504L9.47121 13.3754V10.6253Z",
+ "fill": "black"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "OpenaiTransparent"
+}
diff --git a/app/components/base/icons/src/public/llm/OpenaiTransparent.tsx b/app/components/base/icons/src/public/llm/OpenaiTransparent.tsx
new file mode 100644
index 0000000..0a90287
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiTransparent.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './OpenaiTransparent.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'OpenaiTransparent'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/OpenaiViolet.json b/app/components/base/icons/src/public/llm/OpenaiViolet.json
new file mode 100644
index 0000000..efff2fe
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiViolet.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "6",
+ "fill": "#AB68FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "OpenaiViolet"
+}
diff --git a/app/components/base/icons/src/public/llm/OpenaiViolet.tsx b/app/components/base/icons/src/public/llm/OpenaiViolet.tsx
new file mode 100644
index 0000000..03e2864
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenaiViolet.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './OpenaiViolet.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'OpenaiViolet'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Openllm.json b/app/components/base/icons/src/public/llm/Openllm.json
new file mode 100644
index 0000000..93eec11
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Openllm.json
@@ -0,0 +1,83 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Camada_2",
+ "clip-path": "url(#clip0_9866_5923)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M23.9181 1.27026C23.8737 1.12859 23.813 0.994621 23.7379 0.871257C23.6473 0.721871 23.5355 0.586942 23.4073 0.470325C23.3861 0.451049 23.3639 0.431773 23.3417 0.413462C23.1856 0.284315 23.0073 0.181191 22.8136 0.109871C22.6199 0.0385512 22.4107 0 22.1929 0H5.99952C5.96289 0 5.92627 0.00192756 5.88965 0.00385512C5.87905 0.00385512 5.86748 0.00578268 5.85688 0.00674646C5.83086 0.00867402 5.80387 0.0115654 5.77785 0.0144567C5.76628 0.0154205 5.75568 0.017348 5.74508 0.0183118C5.71424 0.0231307 5.6834 0.0279496 5.65256 0.0337323C5.64774 0.0337323 5.64388 0.0356599 5.63906 0.0356599C5.60437 0.0424063 5.56967 0.0510803 5.53594 0.0597543C5.5263 0.0626457 5.51666 0.065537 5.50703 0.0674646C5.48197 0.074211 5.45691 0.0819213 5.43185 0.0905953C5.42125 0.0944504 5.41065 0.0973418 5.40101 0.101197C5.37403 0.110835 5.34704 0.120472 5.32102 0.132038C5.31524 0.134929 5.30849 0.136857 5.30271 0.139748C5.2709 0.153241 5.2391 0.167698 5.20729 0.183118C5.19958 0.186973 5.19187 0.190828 5.18416 0.194684C5.16007 0.207213 5.13694 0.219742 5.11381 0.232271C5.10417 0.23709 5.09549 0.242873 5.08586 0.247691C5.06273 0.261184 5.0396 0.275641 5.01646 0.291062C5.00972 0.294917 5.00297 0.299736 4.99719 0.303591C4.96828 0.322866 4.94033 0.343106 4.91238 0.363345C4.90659 0.3672 4.90177 0.372019 4.89696 0.375874C4.87479 0.393222 4.85262 0.41057 4.83142 0.428882C4.82371 0.435628 4.816 0.442375 4.80829 0.449121C4.78805 0.466469 4.76877 0.484781 4.7495 0.503093C4.74372 0.508876 4.73697 0.514658 4.73119 0.520441C4.72058 0.531043 4.70998 0.541644 4.70035 0.552246C4.70035 0.552246 4.70035 0.551282 4.70131 0.550318L0.450084 4.37942C0.161915 4.66759 0 5.05792 0 5.4656V22.5592C0 23.4073 0.687174 24.0955 1.53626 24.0955H18.6298C19.0375 24.0955 19.4278 23.9335 19.716 23.6454L23.5383 19.2072C23.6077 19.1291 23.6714 19.0453 23.7263 18.9566C23.7282 18.9537 23.7301 18.9498 23.7321 18.9469C23.7427 18.9296 23.7523 18.9123 23.7629 18.8949C23.7668 18.8882 23.7706 18.8814 23.7745 18.8747C23.7831 18.8583 23.7918 18.8429 23.8005 18.8265C23.8053 18.8178 23.8101 18.8091 23.814 18.7995C23.8217 18.7841 23.8284 18.7686 23.8362 18.7532C23.841 18.7426 23.8458 18.733 23.8497 18.7224C23.8564 18.7079 23.8622 18.6925 23.8689 18.6771C23.8737 18.6655 23.8786 18.654 23.8824 18.6424C23.8882 18.6279 23.893 18.6135 23.8988 18.5981C23.9036 18.5855 23.9075 18.573 23.9113 18.5605C23.9162 18.546 23.921 18.5316 23.9248 18.5171C23.9287 18.5036 23.9325 18.4901 23.9364 18.4766C23.9402 18.4631 23.9441 18.4487 23.947 18.4342C23.9508 18.4198 23.9537 18.4053 23.9566 18.3908C23.9595 18.3774 23.9624 18.3639 23.9653 18.3504C23.9682 18.3349 23.9711 18.3195 23.974 18.3041C23.9759 18.2906 23.9788 18.2781 23.9807 18.2646C23.9836 18.2482 23.9855 18.2309 23.9875 18.2145C23.9894 18.2019 23.9904 18.1904 23.9923 18.1779C23.9942 18.1586 23.9952 18.1393 23.9971 18.12C23.9971 18.1094 23.999 18.0998 23.999 18.0892C24.001 18.0593 24.001 18.0294 24.001 17.9996V1.80709C24.001 1.62011 23.972 1.43989 23.92 1.27026H23.9181ZM22.1929 0.541644C22.4107 0.541644 22.616 0.597543 22.7953 0.694885C22.8849 0.744038 22.9678 0.802829 23.043 0.871257C23.0584 0.88475 23.0728 0.899207 23.0873 0.9127C23.1162 0.941613 23.1432 0.97149 23.1692 1.00233C23.1952 1.03317 23.2193 1.06594 23.2425 1.09967C23.3793 1.30207 23.4584 1.54494 23.4584 1.80612V17.9996C23.4584 18.0362 23.4564 18.0718 23.4535 18.1075C23.4535 18.1114 23.4535 18.1162 23.4535 18.12C23.4506 18.1538 23.4458 18.1875 23.44 18.2203C23.44 18.2251 23.4381 18.2299 23.4372 18.2357C23.4304 18.2684 23.4237 18.3012 23.415 18.333C23.414 18.3369 23.4131 18.3407 23.4121 18.3446C23.4025 18.3783 23.3919 18.4111 23.3803 18.4429C23.3803 18.4439 23.3803 18.4448 23.3793 18.4458C23.3408 18.5489 23.2887 18.6443 23.2251 18.733V18.7349C23.203 18.7638 23.1808 18.7927 23.1577 18.8197C23.1432 18.8361 23.1287 18.8525 23.1133 18.8689C23.1133 18.8689 23.1133 18.8689 23.1124 18.8698C23.0979 18.8853 23.0825 18.9007 23.0671 18.9151C23.0671 18.9151 23.0661 18.9161 23.0651 18.9171C23.0497 18.9315 23.0333 18.946 23.0169 18.9604C23.0169 18.9604 23.0169 18.9604 23.016 18.9614C22.9312 19.0337 22.8377 19.0944 22.7355 19.1426C22.7336 19.1436 22.7317 19.1445 22.7288 19.1455C22.7114 19.1532 22.6941 19.1609 22.6758 19.1686C22.6709 19.1705 22.6661 19.1725 22.6613 19.1744C22.6459 19.1802 22.6305 19.186 22.615 19.1917C22.6083 19.1937 22.6025 19.1956 22.5958 19.1985C22.5813 19.2033 22.5669 19.2081 22.5524 19.212C22.5447 19.2139 22.5379 19.2158 22.5302 19.2178C22.5167 19.2216 22.5023 19.2255 22.4888 19.2284C22.4811 19.2303 22.4734 19.2322 22.4657 19.2342C22.4522 19.237 22.4377 19.2399 22.4242 19.2428C22.4165 19.2448 22.4078 19.2457 22.4001 19.2476C22.3857 19.2496 22.3712 19.2515 22.3568 19.2534C22.349 19.2544 22.3413 19.2554 22.3327 19.2563C22.3172 19.2582 22.3009 19.2592 22.2845 19.2602C22.2777 19.2602 22.271 19.2611 22.2642 19.2621C22.2411 19.2631 22.2189 19.264 22.1958 19.264H5.99952C5.65063 19.264 5.33451 19.1224 5.10513 18.893C5.04827 18.8361 4.99622 18.7735 4.95093 18.706C4.8372 18.5373 4.76299 18.3407 4.74082 18.1287C4.73697 18.0863 4.73408 18.0429 4.73408 17.9996V1.80709C4.73408 1.78299 4.73408 1.75986 4.736 1.73673C4.736 1.72902 4.73697 1.72227 4.73793 1.71456C4.7389 1.69818 4.74082 1.68276 4.74179 1.66638C4.74179 1.6577 4.74372 1.64999 4.74468 1.64132C4.74661 1.62686 4.74853 1.61144 4.75143 1.59698C4.75239 1.58831 4.75432 1.5806 4.75624 1.57192C4.75914 1.55747 4.76203 1.54205 4.76588 1.52759C4.76781 1.51988 4.76974 1.51217 4.7707 1.50446C4.77456 1.48808 4.77938 1.47169 4.78419 1.45531C4.78612 1.44952 4.78709 1.44374 4.78901 1.43892C4.80251 1.39459 4.81889 1.35122 4.83624 1.30881C4.83624 1.30881 4.83624 1.30689 4.8372 1.30689C4.84588 1.28665 4.85551 1.26641 4.86515 1.24713C4.86708 1.24424 4.86804 1.24038 4.86997 1.23749C4.87864 1.22015 4.88828 1.2028 4.89792 1.18641C4.89985 1.18256 4.90177 1.17967 4.9037 1.17678C4.91334 1.15943 4.92394 1.14304 4.93454 1.12666C4.93647 1.12377 4.93743 1.12184 4.93936 1.11895C4.95189 1.10064 4.96442 1.08232 4.97695 1.06401C5.04634 0.969563 5.12826 0.883786 5.22079 0.811503C5.30078 0.748857 5.38752 0.695849 5.48101 0.654406C5.48293 0.654406 5.48486 0.652479 5.48679 0.651515C5.51666 0.638022 5.54751 0.626457 5.57835 0.614892C5.58027 0.614892 5.58317 0.612964 5.58509 0.612964C5.64678 0.591761 5.71038 0.575377 5.77496 0.562847C5.77978 0.562847 5.7846 0.56092 5.79038 0.559956C5.82122 0.555137 5.85206 0.551282 5.88386 0.548391C5.88965 0.548391 5.89543 0.548391 5.90025 0.547427C5.93302 0.544536 5.96579 0.543572 5.99855 0.543572H22.192L22.1929 0.541644Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M16.2794 11.0016C16.8867 11.0016 17.379 10.5093 17.379 9.90192C17.379 9.29459 16.8867 8.80225 16.2794 8.80225C15.672 8.80225 15.1797 9.29459 15.1797 9.90192C15.1797 10.5093 15.672 11.0016 16.2794 11.0016Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M11.9219 11.0016C12.5293 11.0016 13.0216 10.5093 13.0216 9.90192C13.0216 9.29459 12.5293 8.80225 11.9219 8.80225C11.3146 8.80225 10.8223 9.29459 10.8223 9.90192C10.8223 10.5093 11.3146 11.0016 11.9219 11.0016Z",
+ "fill": "black"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_9866_5923"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24.0945",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Openllm"
+}
diff --git a/app/components/base/icons/src/public/llm/Openllm.tsx b/app/components/base/icons/src/public/llm/Openllm.tsx
new file mode 100644
index 0000000..6497165
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Openllm.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Openllm.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Openllm'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/OpenllmText.json b/app/components/base/icons/src/public/llm/OpenllmText.json
new file mode 100644
index 0000000..d5705de
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenllmText.json
@@ -0,0 +1,143 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "92",
+ "height": "25",
+ "viewBox": "0 0 92 25",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_9850_26886)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M24.9181 1.27026C24.8737 1.12859 24.813 0.994621 24.7379 0.871257C24.6473 0.721871 24.5355 0.586942 24.4073 0.470325C24.3861 0.451049 24.3639 0.431773 24.3417 0.413462C24.1856 0.284315 24.0073 0.181191 23.8136 0.109871C23.6199 0.0385512 23.4107 0 23.1929 0H6.99952C6.96289 0 6.92627 0.00192756 6.88965 0.00385512C6.87905 0.00385512 6.86748 0.00578268 6.85688 0.00674646C6.83086 0.00867402 6.80387 0.0115654 6.77785 0.0144567C6.76628 0.0154205 6.75568 0.017348 6.74508 0.0183118C6.71424 0.0231307 6.6834 0.0279496 6.65256 0.0337323C6.64774 0.0337323 6.64388 0.0356599 6.63906 0.0356599C6.60437 0.0424063 6.56967 0.0510803 6.53594 0.0597543C6.5263 0.0626457 6.51666 0.065537 6.50703 0.0674646C6.48197 0.074211 6.45691 0.0819213 6.43185 0.0905953C6.42125 0.0944504 6.41065 0.0973418 6.40101 0.101197C6.37403 0.110835 6.34704 0.120472 6.32102 0.132038C6.31524 0.134929 6.30849 0.136857 6.30271 0.139748C6.2709 0.153241 6.2391 0.167698 6.20729 0.183118C6.19958 0.186973 6.19187 0.190828 6.18416 0.194684C6.16007 0.207213 6.13694 0.219742 6.11381 0.232271C6.10417 0.23709 6.09549 0.242873 6.08586 0.247691C6.06273 0.261184 6.0396 0.275641 6.01646 0.291062C6.00972 0.294917 6.00297 0.299736 5.99719 0.303591C5.96828 0.322866 5.94033 0.343106 5.91238 0.363345C5.90659 0.3672 5.90177 0.372019 5.89696 0.375874C5.87479 0.393222 5.85262 0.41057 5.83142 0.428882C5.82371 0.435628 5.816 0.442375 5.80829 0.449121C5.78805 0.466469 5.76877 0.484781 5.7495 0.503093C5.74372 0.508876 5.73697 0.514658 5.73119 0.520441C5.72058 0.531043 5.70998 0.541644 5.70035 0.552246C5.70035 0.552246 5.70035 0.551282 5.70131 0.550318L1.45008 4.37942C1.16191 4.66759 1 5.05792 1 5.4656V22.5592C1 23.4073 1.68717 24.0955 2.53626 24.0955H19.6298C20.0375 24.0955 20.4278 23.9335 20.716 23.6454L24.5383 19.2072C24.6077 19.1291 24.6714 19.0453 24.7263 18.9566C24.7282 18.9537 24.7301 18.9498 24.7321 18.9469C24.7427 18.9296 24.7523 18.9123 24.7629 18.8949C24.7668 18.8882 24.7706 18.8814 24.7745 18.8747C24.7831 18.8583 24.7918 18.8429 24.8005 18.8265C24.8053 18.8178 24.8101 18.8091 24.814 18.7995C24.8217 18.7841 24.8284 18.7686 24.8362 18.7532C24.841 18.7426 24.8458 18.733 24.8497 18.7224C24.8564 18.7079 24.8622 18.6925 24.8689 18.6771C24.8737 18.6655 24.8786 18.654 24.8824 18.6424C24.8882 18.6279 24.893 18.6135 24.8988 18.5981C24.9036 18.5855 24.9075 18.573 24.9113 18.5605C24.9162 18.546 24.921 18.5316 24.9248 18.5171C24.9287 18.5036 24.9325 18.4901 24.9364 18.4766C24.9402 18.4631 24.9441 18.4487 24.947 18.4342C24.9508 18.4198 24.9537 18.4053 24.9566 18.3908C24.9595 18.3774 24.9624 18.3639 24.9653 18.3504C24.9682 18.3349 24.9711 18.3195 24.974 18.3041C24.9759 18.2906 24.9788 18.2781 24.9807 18.2646C24.9836 18.2482 24.9855 18.2309 24.9875 18.2145C24.9894 18.2019 24.9904 18.1904 24.9923 18.1779C24.9942 18.1586 24.9952 18.1393 24.9971 18.12C24.9971 18.1094 24.999 18.0998 24.999 18.0892C25.001 18.0593 25.001 18.0294 25.001 17.9996V1.80709C25.001 1.62011 24.972 1.43989 24.92 1.27026H24.9181ZM23.1929 0.541644C23.4107 0.541644 23.616 0.597543 23.7953 0.694885C23.8849 0.744038 23.9678 0.802829 24.043 0.871257C24.0584 0.88475 24.0728 0.899207 24.0873 0.9127C24.1162 0.941613 24.1432 0.97149 24.1692 1.00233C24.1952 1.03317 24.2193 1.06594 24.2425 1.09967C24.3793 1.30207 24.4584 1.54494 24.4584 1.80612V17.9996C24.4584 18.0362 24.4564 18.0718 24.4535 18.1075C24.4535 18.1114 24.4535 18.1162 24.4535 18.12C24.4506 18.1538 24.4458 18.1875 24.44 18.2203C24.44 18.2251 24.4381 18.2299 24.4372 18.2357C24.4304 18.2684 24.4237 18.3012 24.415 18.333C24.414 18.3369 24.4131 18.3407 24.4121 18.3446C24.4025 18.3783 24.3919 18.4111 24.3803 18.4429C24.3803 18.4439 24.3803 18.4448 24.3793 18.4458C24.3408 18.5489 24.2887 18.6443 24.2251 18.733V18.7349C24.203 18.7638 24.1808 18.7927 24.1577 18.8197C24.1432 18.8361 24.1287 18.8525 24.1133 18.8689C24.1133 18.8689 24.1133 18.8689 24.1124 18.8698C24.0979 18.8853 24.0825 18.9007 24.0671 18.9151C24.0671 18.9151 24.0661 18.9161 24.0651 18.9171C24.0497 18.9315 24.0333 18.946 24.0169 18.9604C24.0169 18.9604 24.0169 18.9604 24.016 18.9614C23.9312 19.0337 23.8377 19.0944 23.7355 19.1426C23.7336 19.1436 23.7317 19.1445 23.7288 19.1455C23.7114 19.1532 23.6941 19.1609 23.6758 19.1686C23.6709 19.1705 23.6661 19.1725 23.6613 19.1744C23.6459 19.1802 23.6305 19.186 23.615 19.1917C23.6083 19.1937 23.6025 19.1956 23.5958 19.1985C23.5813 19.2033 23.5669 19.2081 23.5524 19.212C23.5447 19.2139 23.5379 19.2158 23.5302 19.2178C23.5167 19.2216 23.5023 19.2255 23.4888 19.2284C23.4811 19.2303 23.4734 19.2322 23.4657 19.2342C23.4522 19.237 23.4377 19.2399 23.4242 19.2428C23.4165 19.2448 23.4078 19.2457 23.4001 19.2476C23.3857 19.2496 23.3712 19.2515 23.3568 19.2534C23.349 19.2544 23.3413 19.2554 23.3327 19.2563C23.3172 19.2582 23.3009 19.2592 23.2845 19.2602C23.2777 19.2602 23.271 19.2611 23.2642 19.2621C23.2411 19.2631 23.2189 19.264 23.1958 19.264H6.99952C6.65063 19.264 6.33451 19.1224 6.10513 18.893C6.04827 18.8361 5.99622 18.7735 5.95093 18.706C5.8372 18.5373 5.76299 18.3407 5.74082 18.1287C5.73697 18.0863 5.73408 18.0429 5.73408 17.9996V1.80709C5.73408 1.78299 5.73408 1.75986 5.736 1.73673C5.736 1.72902 5.73697 1.72227 5.73793 1.71456C5.7389 1.69818 5.74082 1.68276 5.74179 1.66638C5.74179 1.6577 5.74372 1.64999 5.74468 1.64132C5.74661 1.62686 5.74853 1.61144 5.75143 1.59698C5.75239 1.58831 5.75432 1.5806 5.75624 1.57192C5.75914 1.55747 5.76203 1.54205 5.76588 1.52759C5.76781 1.51988 5.76974 1.51217 5.7707 1.50446C5.77456 1.48808 5.77938 1.47169 5.78419 1.45531C5.78612 1.44952 5.78709 1.44374 5.78901 1.43892C5.80251 1.39459 5.81889 1.35122 5.83624 1.30881C5.83624 1.30881 5.83624 1.30689 5.8372 1.30689C5.84588 1.28665 5.85551 1.26641 5.86515 1.24713C5.86708 1.24424 5.86804 1.24038 5.86997 1.23749C5.87864 1.22015 5.88828 1.2028 5.89792 1.18641C5.89985 1.18256 5.90177 1.17967 5.9037 1.17678C5.91334 1.15943 5.92394 1.14304 5.93454 1.12666C5.93647 1.12377 5.93743 1.12184 5.93936 1.11895C5.95189 1.10064 5.96442 1.08232 5.97695 1.06401C6.04634 0.969563 6.12826 0.883786 6.22079 0.811503C6.30078 0.748857 6.38752 0.695849 6.48101 0.654406C6.48293 0.654406 6.48486 0.652479 6.48679 0.651515C6.51666 0.638022 6.54751 0.626457 6.57835 0.614892C6.58027 0.614892 6.58317 0.612964 6.58509 0.612964C6.64678 0.591761 6.71038 0.575377 6.77496 0.562847C6.77978 0.562847 6.7846 0.56092 6.79038 0.559956C6.82122 0.555137 6.85206 0.551282 6.88386 0.548391C6.88965 0.548391 6.89543 0.548391 6.90025 0.547427C6.93302 0.544536 6.96579 0.543572 6.99855 0.543572H23.192L23.1929 0.541644Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.2794 11.0016C17.8867 11.0016 18.379 10.5093 18.379 9.90192C18.379 9.29459 17.8867 8.80225 17.2794 8.80225C16.672 8.80225 16.1797 9.29459 16.1797 9.90192C16.1797 10.5093 16.672 11.0016 17.2794 11.0016Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.9219 11.0016C13.5293 11.0016 14.0216 10.5093 14.0216 9.90192C14.0216 9.29459 13.5293 8.80225 12.9219 8.80225C12.3146 8.80225 11.8223 9.29459 11.8223 9.90192C11.8223 10.5093 12.3146 11.0016 12.9219 11.0016Z",
+ "fill": "black"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M36.4876 17.098C35.5822 17.098 34.7469 16.888 33.9816 16.468C33.2256 16.0387 32.6236 15.446 32.1756 14.69C31.7369 13.9247 31.5176 13.066 31.5176 12.114C31.5176 11.162 31.7369 10.308 32.1756 9.55204C32.6236 8.79604 33.2256 8.20804 33.9816 7.78804C34.7469 7.35871 35.5822 7.14404 36.4876 7.14404C37.4022 7.14404 38.2376 7.35871 38.9936 7.78804C39.7589 8.20804 40.3609 8.79604 40.7996 9.55204C41.2382 10.308 41.4576 11.162 41.4576 12.114C41.4576 13.066 41.2382 13.9247 40.7996 14.69C40.3609 15.446 39.7589 16.0387 38.9936 16.468C38.2376 16.888 37.4022 17.098 36.4876 17.098ZM36.4876 15.712C37.1316 15.712 37.7056 15.5674 38.2096 15.278C38.7136 14.9794 39.1056 14.5594 39.3856 14.018C39.6749 13.4674 39.8196 12.8327 39.8196 12.114C39.8196 11.3954 39.6749 10.7654 39.3856 10.224C39.1056 9.68271 38.7136 9.26738 38.2096 8.97804C37.7056 8.68871 37.1316 8.54404 36.4876 8.54404C35.8436 8.54404 35.2696 8.68871 34.7656 8.97804C34.2616 9.26738 33.8649 9.68271 33.5756 10.224C33.2956 10.7654 33.1556 11.3954 33.1556 12.114C33.1556 12.8327 33.2956 13.4674 33.5756 14.018C33.8649 14.5594 34.2616 14.9794 34.7656 15.278C35.2696 15.5674 35.8436 15.712 36.4876 15.712Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M44.3441 10.42C44.6148 10.0654 44.9834 9.76671 45.4501 9.52404C45.9168 9.28138 46.4441 9.16004 47.0321 9.16004C47.7041 9.16004 48.3154 9.32804 48.8661 9.66404C49.4261 9.99071 49.8648 10.4527 50.1821 11.05C50.4994 11.6474 50.6581 12.3334 50.6581 13.108C50.6581 13.8827 50.4994 14.578 50.1821 15.194C49.8648 15.8007 49.4261 16.2767 48.8661 16.622C48.3154 16.958 47.7041 17.126 47.0321 17.126C46.4441 17.126 45.9214 17.0094 45.4641 16.776C45.0068 16.5334 44.6334 16.2347 44.3441 15.88V20.668H42.7481V9.28604H44.3441V10.42ZM49.0341 13.108C49.0341 12.576 48.9221 12.1187 48.6981 11.736C48.4834 11.344 48.1941 11.05 47.8301 10.854C47.4754 10.6487 47.0928 10.546 46.6821 10.546C46.2808 10.546 45.8981 10.6487 45.5341 10.854C45.1794 11.0594 44.8901 11.358 44.6661 11.75C44.4514 12.142 44.3441 12.604 44.3441 13.136C44.3441 13.668 44.4514 14.1347 44.6661 14.536C44.8901 14.928 45.1794 15.2267 45.5341 15.432C45.8981 15.6374 46.2808 15.74 46.6821 15.74C47.0928 15.74 47.4754 15.6374 47.8301 15.432C48.1941 15.2174 48.4834 14.9094 48.6981 14.508C48.9221 14.1067 49.0341 13.64 49.0341 13.108Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M59.0264 12.954C59.0264 13.2434 59.0077 13.5047 58.9704 13.738H53.0764C53.123 14.354 53.3517 14.8487 53.7624 15.222C54.173 15.5954 54.677 15.782 55.2744 15.782C56.133 15.782 56.7397 15.4227 57.0944 14.704H58.8164C58.583 15.4134 58.1584 15.9967 57.5424 16.454C56.9357 16.902 56.1797 17.126 55.2744 17.126C54.537 17.126 53.8744 16.9627 53.2864 16.636C52.7077 16.3 52.2504 15.8334 51.9144 15.236C51.5877 14.6294 51.4244 13.9294 51.4244 13.136C51.4244 12.3427 51.583 11.6474 51.9004 11.05C52.227 10.4434 52.6797 9.97671 53.2584 9.65004C53.8464 9.32338 54.5184 9.16004 55.2744 9.16004C56.0024 9.16004 56.651 9.31871 57.2204 9.63604C57.7897 9.95338 58.233 10.4014 58.5504 10.98C58.8677 11.5494 59.0264 12.2074 59.0264 12.954ZM57.3604 12.45C57.351 11.862 57.141 11.3907 56.7304 11.036C56.3197 10.6814 55.811 10.504 55.2044 10.504C54.6537 10.504 54.1824 10.6814 53.7904 11.036C53.3984 11.3814 53.165 11.8527 53.0904 12.45H57.3604Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M64.209 9.16004C64.8157 9.16004 65.357 9.28604 65.833 9.53804C66.3183 9.79004 66.6963 10.1634 66.967 10.658C67.2377 11.1527 67.373 11.75 67.373 12.45V17H65.791V12.688C65.791 11.9974 65.6183 11.47 65.273 11.106C64.9277 10.7327 64.4563 10.546 63.859 10.546C63.2617 10.546 62.7857 10.7327 62.431 11.106C62.0857 11.47 61.913 11.9974 61.913 12.688V17H60.317V9.28604H61.913V10.168C62.1743 9.85071 62.5057 9.60338 62.907 9.42604C63.3177 9.24871 63.7517 9.16004 64.209 9.16004Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M70.7248 15.712H74.0148V17H69.1288V7.27004H70.7248V15.712Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M76.6655 15.712H79.9555V17H75.0695V7.27004H76.6655V15.712Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M91.2582 7.27004V17H89.6622V10.336L86.6942 17H85.5882L82.6062 10.336V17H81.0102V7.27004H82.7322L86.1482 14.9L89.5502 7.27004H91.2582Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_9850_26886"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24.0945",
+ "fill": "white",
+ "transform": "translate(1)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "OpenllmText"
+}
diff --git a/app/components/base/icons/src/public/llm/OpenllmText.tsx b/app/components/base/icons/src/public/llm/OpenllmText.tsx
new file mode 100644
index 0000000..d1b6f6b
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/OpenllmText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './OpenllmText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'OpenllmText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Replicate.json b/app/components/base/icons/src/public/llm/Replicate.json
new file mode 100644
index 0000000..303c239
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Replicate.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "6",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M19.9961 4V5.79H7.93621V19.9017H6V4H19.9961ZM20 7.39453V9.18453H11.5969V19.9012H9.65906V7.39453H20ZM19.9964 12.5773V10.7773H13.3106V19.9007H15.2484V12.5773H19.9964Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Replicate"
+}
diff --git a/app/components/base/icons/src/public/llm/Replicate.tsx b/app/components/base/icons/src/public/llm/Replicate.tsx
new file mode 100644
index 0000000..237b68d
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Replicate.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Replicate.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Replicate'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/ReplicateText.json b/app/components/base/icons/src/public/llm/ReplicateText.json
new file mode 100644
index 0000000..b2d597c
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/ReplicateText.json
@@ -0,0 +1,116 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "92",
+ "height": "24",
+ "viewBox": "0 0 92 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.4933 2V3.79H6.005V17.9017H4V2H18.4933Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.4974 5.39453V7.18453H9.79573V17.9012H7.78906V5.39453H18.4974Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.4936 8.77734V10.5773H13.577V17.9007H11.5703V8.77734H18.4936Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M24.2014 8.60156C26.588 8.60156 28.593 10.1849 28.593 13.1282C28.593 13.3232 28.593 13.4882 28.573 13.7866H21.403C21.4964 15.2782 22.6997 16.2649 24.2114 16.2649C25.4864 16.2649 26.3414 15.6782 26.813 14.8766L28.3464 15.9666C27.523 17.2632 26.1047 18.0849 24.1914 18.0849C21.4247 18.0849 19.4297 16.1199 19.4297 13.3432C19.4397 10.6582 21.4347 8.60156 24.203 8.60156M21.508 12.3149H26.5797C26.363 10.9982 25.3047 10.2882 24.1314 10.2882C22.958 10.2882 21.7764 10.9666 21.508 12.3149Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M30.6328 8.77656H32.6378V9.9999C33.1528 9.2699 34.2628 8.60156 35.5695 8.60156C38.0695 8.60156 39.9611 10.7316 39.9611 13.3432C39.9611 15.9549 38.0678 18.0849 35.5695 18.0849C34.2528 18.0849 33.1411 17.4066 32.6378 16.6749V21.7049H30.6328V8.77656ZM35.2095 10.4216C33.5845 10.4216 32.4728 11.6966 32.4728 13.3432C32.4728 14.9899 33.5845 16.2649 35.2095 16.2649C36.8345 16.2649 37.9245 14.9899 37.9245 13.3432C37.9245 11.6966 36.8128 10.4216 35.2095 10.4216Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M44.0128 4.2207H42.0078V17.8907H44.0128V4.2207Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M47.7139 6.79443C46.9839 6.79443 46.3672 6.19776 46.3672 5.44776C46.3672 4.69776 46.9839 4.12109 47.7139 4.12109C48.4439 4.12109 49.0405 4.72776 49.0405 5.44776C49.0405 6.19943 48.4639 6.79443 47.7139 6.79443ZM46.7155 8.77943H48.7205V17.8928H46.7155V8.77943Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M55.5711 18.0771C52.8345 18.0771 50.7578 16.0304 50.7578 13.3354C50.7578 10.6404 52.8361 8.59375 55.5711 8.59375C57.4528 8.59375 59.0378 9.60208 59.8195 11.1137L58.0711 12.0604C57.6295 11.1354 56.7445 10.4554 55.5711 10.4554C53.9461 10.4554 52.8045 11.7104 52.8045 13.3354C52.8045 14.9604 53.9561 16.2154 55.5711 16.2154C56.7328 16.2154 57.6278 15.5371 58.0711 14.6104L59.8195 15.5571C59.0378 17.0787 57.4428 18.0771 55.5711 18.0771Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M65.3995 8.60156C66.7161 8.60156 67.8061 9.2799 68.3211 9.9999V8.77656H70.3261V17.8899H68.3211V16.6666C67.8061 17.3966 66.7161 18.0766 65.3995 18.0766C62.8995 18.0766 61.0078 15.9466 61.0078 13.3349C61.0078 10.7232 62.9011 8.60323 65.3995 8.60323M65.7695 10.4232C64.1445 10.4232 63.0545 11.6982 63.0545 13.3449C63.0545 14.9916 64.1445 16.2666 65.7695 16.2666C67.3945 16.2666 68.4845 14.9916 68.4845 13.3449C68.4845 11.6982 67.3845 10.4232 65.7695 10.4232Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M73.7627 17.9033V10.57H71.8594V8.78H73.7627V6.25H75.7694V8.78H79.2244V10.57H75.7694V16.1033H79.2244V17.9033H73.7627Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M84.9435 8.60156C87.3302 8.60156 89.3352 10.1849 89.3352 13.1282C89.3352 13.3232 89.3352 13.4882 89.3152 13.7866H82.1452C82.2385 15.2782 83.4419 16.2649 84.9535 16.2649C86.2285 16.2649 87.0835 15.6782 87.5552 14.8766L89.0885 15.9666C88.2652 17.2632 86.8469 18.0849 84.9335 18.0849C82.1669 18.0849 80.1719 16.1199 80.1719 13.3432C80.1919 10.6582 82.1769 8.60156 84.9452 8.60156M82.2502 12.3149H87.3219C87.1052 10.9982 86.0469 10.2882 84.8735 10.2882C83.7002 10.2882 82.5285 10.9666 82.2502 12.3149Z",
+ "fill": "black"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ReplicateText"
+}
diff --git a/app/components/base/icons/src/public/llm/ReplicateText.tsx b/app/components/base/icons/src/public/llm/ReplicateText.tsx
new file mode 100644
index 0000000..667b7d5
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/ReplicateText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ReplicateText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ReplicateText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/XorbitsInference.json b/app/components/base/icons/src/public/llm/XorbitsInference.json
new file mode 100644
index 0000000..b2d3b1a
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/XorbitsInference.json
@@ -0,0 +1,176 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Xorbits Square",
+ "clip-path": "url(#clip0_9850_26870)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M8.00391 12.3124C8.69334 13.0754 9.47526 13.7494 10.3316 14.3188C11.0667 14.8105 11.8509 15.2245 12.6716 15.5541C14.1617 14.1465 15.3959 12.4907 16.3192 10.6606L21.7051 0L12.3133 7.38353C10.5832 8.74456 9.12178 10.416 8.00391 12.3124Z",
+ "fill": "url(#paint0_linear_9850_26870)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M7.23504 18.9512C6.56092 18.5012 5.92386 18.0265 5.3221 17.5394L2.06445 24L7.91975 19.3959C7.69034 19.2494 7.46092 19.103 7.23504 18.9512Z",
+ "fill": "url(#paint1_linear_9850_26870)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M19.3161 8.57474C21.0808 10.9147 21.5961 13.5159 20.3996 15.3053C18.6526 17.9189 13.9161 17.8183 9.82024 15.0812C5.72435 12.3441 3.82024 8.0065 5.56729 5.39297C6.76377 3.60356 9.36318 3.0865 12.2008 3.81886C7.29318 1.73474 2.62376 1.94121 0.813177 4.64474C-1.45976 8.04709 1.64435 14.1177 7.74494 18.1889C13.8455 22.26 20.6361 22.8124 22.9091 19.4118C24.7179 16.703 23.1173 12.3106 19.3161 8.57474Z",
+ "fill": "url(#paint2_linear_9850_26870)"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_9850_26870",
+ "x1": "2.15214",
+ "y1": "24.3018",
+ "x2": "21.2921",
+ "y2": "0.0988218",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#E9A85E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#F52B76"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_9850_26870",
+ "x1": "2.06269",
+ "y1": "24.2294",
+ "x2": "21.2027",
+ "y2": "0.028252",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#E9A85E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#F52B76"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint2_linear_9850_26870",
+ "x1": "-0.613606",
+ "y1": "3.843",
+ "x2": "21.4449",
+ "y2": "18.7258",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#6A0CF5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#AB66F3"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_9850_26870"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "XorbitsInference"
+}
diff --git a/app/components/base/icons/src/public/llm/XorbitsInference.tsx b/app/components/base/icons/src/public/llm/XorbitsInference.tsx
new file mode 100644
index 0000000..8316ce3
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/XorbitsInference.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './XorbitsInference.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'XorbitsInference'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/XorbitsInferenceText.json b/app/components/base/icons/src/public/llm/XorbitsInferenceText.json
new file mode 100644
index 0000000..967ee6d
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/XorbitsInferenceText.json
@@ -0,0 +1,329 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "152",
+ "height": "24",
+ "viewBox": "0 0 152 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "xorbits 1",
+ "clip-path": "url(#clip0_9866_6170)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M8.00391 12.3124C8.69334 13.0754 9.47526 13.7494 10.3316 14.3188C11.0667 14.8105 11.8509 15.2245 12.6716 15.5541C14.1617 14.1465 15.3959 12.4907 16.3192 10.6606L21.7051 0L12.3133 7.38353C10.5832 8.74456 9.12178 10.416 8.00391 12.3124Z",
+ "fill": "url(#paint0_linear_9866_6170)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M7.23504 18.9512C6.56092 18.5012 5.92386 18.0265 5.3221 17.5394L2.06445 24L7.91975 19.3959C7.69034 19.2494 7.46092 19.103 7.23504 18.9512Z",
+ "fill": "url(#paint1_linear_9866_6170)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M19.3161 8.57474C21.0808 10.9147 21.5961 13.5159 20.3996 15.3053C18.6526 17.9189 13.9161 17.8183 9.82024 15.0812C5.72435 12.3441 3.82024 8.0065 5.56729 5.39297C6.76377 3.60356 9.36318 3.0865 12.2008 3.81886C7.29318 1.73474 2.62376 1.94121 0.813177 4.64474C-1.45976 8.04709 1.64435 14.1177 7.74494 18.1889C13.8455 22.26 20.6361 22.8124 22.9091 19.4118C24.7179 16.703 23.1173 12.3106 19.3161 8.57474Z",
+ "fill": "url(#paint2_linear_9866_6170)"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Xorbits Inference"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M35.5162 12.142L38.5402 17H36.7482L34.5502 13.472L32.4922 17H30.7142L33.7382 12.142L30.7002 7.27002H32.4922L34.7042 10.826L36.7762 7.27002H38.5542L35.5162 12.142Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M43.3584 17.126C42.6304 17.126 41.9724 16.9627 41.3844 16.636C40.7964 16.3 40.3344 15.8334 39.9984 15.236C39.6624 14.6294 39.4944 13.9293 39.4944 13.136C39.4944 12.352 39.6671 11.6567 40.0124 11.05C40.3577 10.4434 40.8291 9.97668 41.4264 9.65002C42.0237 9.32335 42.6911 9.16002 43.4284 9.16002C44.1657 9.16002 44.8331 9.32335 45.4304 9.65002C46.0277 9.97668 46.4991 10.4434 46.8444 11.05C47.1897 11.6567 47.3624 12.352 47.3624 13.136C47.3624 13.92 47.185 14.6154 46.8304 15.222C46.4757 15.8287 45.9904 16.3 45.3744 16.636C44.7677 16.9627 44.0957 17.126 43.3584 17.126ZM43.3584 15.74C43.769 15.74 44.1517 15.642 44.5064 15.446C44.8704 15.25 45.1644 14.956 45.3884 14.564C45.6124 14.172 45.7244 13.696 45.7244 13.136C45.7244 12.576 45.6171 12.1047 45.4024 11.722C45.1877 11.33 44.9031 11.036 44.5484 10.84C44.1937 10.644 43.8111 10.546 43.4004 10.546C42.9897 10.546 42.607 10.644 42.2524 10.84C41.9071 11.036 41.6317 11.33 41.4264 11.722C41.221 12.1047 41.1184 12.576 41.1184 13.136C41.1184 13.9667 41.3284 14.6107 41.7484 15.068C42.1777 15.516 42.7144 15.74 43.3584 15.74Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M50.2561 10.406C50.4895 10.014 50.7974 9.71068 51.1801 9.49602C51.5721 9.27202 52.0341 9.16002 52.5661 9.16002V10.812H52.1601C51.5348 10.812 51.0588 10.9707 50.7321 11.288C50.4148 11.6054 50.2561 12.156 50.2561 12.94V17H48.6601V9.28602H50.2561V10.406Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M55.3492 10.434C55.6198 10.0607 55.9885 9.75735 56.4552 9.52402C56.9312 9.28135 57.4585 9.16002 58.0372 9.16002C58.7185 9.16002 59.3345 9.32335 59.8852 9.65002C60.4358 9.97668 60.8698 10.4434 61.1872 11.05C61.5045 11.6473 61.6632 12.3333 61.6632 13.108C61.6632 13.8827 61.5045 14.578 61.1872 15.194C60.8698 15.8007 60.4312 16.2767 59.8712 16.622C59.3205 16.958 58.7092 17.126 58.0372 17.126C57.4398 17.126 56.9078 17.0093 56.4412 16.776C55.9838 16.5427 55.6198 16.244 55.3492 15.88V17H53.7532V6.64002H55.3492V10.434ZM60.0392 13.108C60.0392 12.576 59.9272 12.1187 59.7032 11.736C59.4885 11.344 59.1992 11.05 58.8352 10.854C58.4805 10.6487 58.0978 10.546 57.6872 10.546C57.2858 10.546 56.9032 10.6487 56.5392 10.854C56.1845 11.0594 55.8952 11.358 55.6712 11.75C55.4565 12.142 55.3492 12.604 55.3492 13.136C55.3492 13.668 55.4565 14.1347 55.6712 14.536C55.8952 14.928 56.1845 15.2267 56.5392 15.432C56.9032 15.6374 57.2858 15.74 57.6872 15.74C58.0978 15.74 58.4805 15.6374 58.8352 15.432C59.1992 15.2174 59.4885 14.9093 59.7032 14.508C59.9272 14.1067 60.0392 13.64 60.0392 13.108Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M63.7734 8.26402C63.4841 8.26402 63.2414 8.16602 63.0454 7.97002C62.8494 7.77402 62.7514 7.53135 62.7514 7.24202C62.7514 6.95268 62.8494 6.71002 63.0454 6.51402C63.2414 6.31802 63.4841 6.22002 63.7734 6.22002C64.0534 6.22002 64.2914 6.31802 64.4874 6.51402C64.6834 6.71002 64.7814 6.95268 64.7814 7.24202C64.7814 7.53135 64.6834 7.77402 64.4874 7.97002C64.2914 8.16602 64.0534 8.26402 63.7734 8.26402ZM64.5574 9.28602V17H62.9614V9.28602H64.5574Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M68.2348 10.588V14.858C68.2348 15.1474 68.3002 15.3573 68.4309 15.488C68.5709 15.6093 68.8042 15.67 69.1308 15.67H70.1109V17H68.8508C68.1322 17 67.5815 16.832 67.1988 16.496C66.8162 16.16 66.6248 15.614 66.6248 14.858V10.588H65.7148V9.28602H66.6248V7.36802H68.2348V9.28602H70.1109V10.588H68.2348Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M74.1018 17.126C73.4952 17.126 72.9492 17.0187 72.4638 16.804C71.9878 16.58 71.6098 16.2813 71.3298 15.908C71.0498 15.5253 70.9005 15.1007 70.8818 14.634H72.5338C72.5618 14.9607 72.7158 15.236 72.9958 15.46C73.2852 15.6747 73.6445 15.782 74.0738 15.782C74.5218 15.782 74.8672 15.698 75.1098 15.53C75.3618 15.3527 75.4878 15.1287 75.4878 14.858C75.4878 14.5687 75.3478 14.354 75.0678 14.214C74.7972 14.074 74.3632 13.92 73.7658 13.752C73.1872 13.5933 72.7158 13.4394 72.3518 13.29C71.9878 13.1407 71.6705 12.912 71.3998 12.604C71.1385 12.296 71.0078 11.89 71.0078 11.386C71.0078 10.9753 71.1292 10.602 71.3718 10.266C71.6145 9.92068 71.9598 9.65002 72.4078 9.45402C72.8652 9.25802 73.3878 9.16002 73.9758 9.16002C74.8532 9.16002 75.5578 9.38402 76.0898 9.83202C76.6312 10.2707 76.9205 10.8727 76.9578 11.638H75.3618C75.3338 11.2927 75.1938 11.0173 74.9418 10.812C74.6898 10.6067 74.3492 10.504 73.9198 10.504C73.4998 10.504 73.1778 10.5833 72.9538 10.742C72.7298 10.9007 72.6178 11.1107 72.6178 11.372C72.6178 11.5773 72.6925 11.75 72.8418 11.89C72.9912 12.03 73.1732 12.142 73.3878 12.226C73.6025 12.3007 73.9198 12.3987 74.3398 12.52C74.8998 12.6693 75.3572 12.8233 75.7118 12.982C76.0758 13.1314 76.3885 13.3554 76.6498 13.654C76.9112 13.9527 77.0465 14.3493 77.0558 14.844C77.0558 15.2827 76.9345 15.6747 76.6918 16.02C76.4492 16.3654 76.1038 16.636 75.6558 16.832C75.2172 17.028 74.6992 17.126 74.1018 17.126Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M83.4531 7.27002V17H81.8571V7.27002H83.4531Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M89.1605 9.16002C89.7671 9.16002 90.3085 9.28602 90.7845 9.53802C91.2698 9.79002 91.6478 10.1633 91.9185 10.658C92.1891 11.1527 92.3245 11.75 92.3245 12.45V17H90.7425V12.688C90.7425 11.9973 90.5698 11.47 90.2245 11.106C89.8791 10.7327 89.4078 10.546 88.8105 10.546C88.2131 10.546 87.7371 10.7327 87.3825 11.106C87.0371 11.47 86.8645 11.9973 86.8645 12.688V17H85.2685V9.28602H86.8645V10.168C87.1258 9.85068 87.4571 9.60335 87.8585 9.42602C88.2691 9.24868 88.7031 9.16002 89.1605 9.16002Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M97.3143 10.588H95.8863V17H94.2763V10.588H93.3663V9.28602H94.2763V8.74002C94.2763 7.85335 94.5096 7.20935 94.9763 6.80802C95.4523 6.39735 96.1943 6.19202 97.2023 6.19202V7.52202C96.7169 7.52202 96.3763 7.61535 96.1803 7.80202C95.9843 7.97935 95.8863 8.29202 95.8863 8.74002V9.28602H97.3143V10.588Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M105.519 12.954C105.519 13.2433 105.5 13.5047 105.463 13.738H99.5687C99.6154 14.354 99.844 14.8487 100.255 15.222C100.665 15.5954 101.169 15.782 101.767 15.782C102.625 15.782 103.232 15.4227 103.587 14.704H105.309C105.075 15.4133 104.651 15.9967 104.035 16.454C103.428 16.902 102.672 17.126 101.767 17.126C101.029 17.126 100.367 16.9627 99.7787 16.636C99.2 16.3 98.7427 15.8334 98.4067 15.236C98.08 14.6294 97.9167 13.9293 97.9167 13.136C97.9167 12.3427 98.0754 11.6473 98.3927 11.05C98.7194 10.4434 99.172 9.97668 99.7507 9.65002C100.339 9.32335 101.011 9.16002 101.767 9.16002C102.495 9.16002 103.143 9.31868 103.713 9.63602C104.282 9.95335 104.725 10.4014 105.043 10.98C105.36 11.5493 105.519 12.2073 105.519 12.954ZM103.853 12.45C103.843 11.862 103.633 11.3907 103.223 11.036C102.812 10.6813 102.303 10.504 101.697 10.504C101.146 10.504 100.675 10.6813 100.283 11.036C99.8907 11.3813 99.6574 11.8527 99.5827 12.45H103.853Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M108.405 10.406C108.639 10.014 108.947 9.71068 109.329 9.49602C109.721 9.27202 110.183 9.16002 110.715 9.16002V10.812H110.309C109.684 10.812 109.208 10.9707 108.881 11.288C108.564 11.6054 108.405 12.156 108.405 12.94V17H106.809V9.28602H108.405V10.406Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M118.972 12.954C118.972 13.2433 118.954 13.5047 118.916 13.738H113.022C113.069 14.354 113.298 14.8487 113.708 15.222C114.119 15.5954 114.623 15.782 115.22 15.782C116.079 15.782 116.686 15.4227 117.04 14.704H118.762C118.529 15.4133 118.104 15.9967 117.488 16.454C116.882 16.902 116.126 17.126 115.22 17.126C114.483 17.126 113.82 16.9627 113.232 16.636C112.654 16.3 112.196 15.8334 111.86 15.236C111.534 14.6294 111.37 13.9293 111.37 13.136C111.37 12.3427 111.529 11.6473 111.846 11.05C112.173 10.4434 112.626 9.97668 113.204 9.65002C113.792 9.32335 114.464 9.16002 115.22 9.16002C115.948 9.16002 116.597 9.31868 117.166 9.63602C117.736 9.95335 118.179 10.4014 118.496 10.98C118.814 11.5493 118.972 12.2073 118.972 12.954ZM117.306 12.45C117.297 11.862 117.087 11.3907 116.676 11.036C116.266 10.6813 115.757 10.504 115.15 10.504C114.6 10.504 114.128 10.6813 113.736 11.036C113.344 11.3813 113.111 11.8527 113.036 12.45H117.306Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M124.155 9.16002C124.762 9.16002 125.303 9.28602 125.779 9.53802C126.264 9.79002 126.642 10.1633 126.913 10.658C127.184 11.1527 127.319 11.75 127.319 12.45V17H125.737V12.688C125.737 11.9973 125.564 11.47 125.219 11.106C124.874 10.7327 124.402 10.546 123.805 10.546C123.208 10.546 122.732 10.7327 122.377 11.106C122.032 11.47 121.859 11.9973 121.859 12.688V17H120.263V9.28602H121.859V10.168C122.12 9.85068 122.452 9.60335 122.853 9.42602C123.264 9.24868 123.698 9.16002 124.155 9.16002Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M128.543 13.136C128.543 12.3427 128.701 11.6473 129.019 11.05C129.345 10.4434 129.793 9.97668 130.363 9.65002C130.932 9.32335 131.585 9.16002 132.323 9.16002C133.256 9.16002 134.026 9.38402 134.633 9.83202C135.249 10.2707 135.664 10.9007 135.879 11.722H134.157C134.017 11.3394 133.793 11.0407 133.485 10.826C133.177 10.6113 132.789 10.504 132.323 10.504C131.669 10.504 131.147 10.7373 130.755 11.204C130.372 11.6613 130.181 12.3053 130.181 13.136C130.181 13.9667 130.372 14.6153 130.755 15.082C131.147 15.5487 131.669 15.782 132.323 15.782C133.247 15.782 133.858 15.376 134.157 14.564H135.879C135.655 15.348 135.235 15.9733 134.619 16.44C134.003 16.8973 133.237 17.126 132.323 17.126C131.585 17.126 130.932 16.9627 130.363 16.636C129.793 16.3 129.345 15.8334 129.019 15.236C128.701 14.6294 128.543 13.9293 128.543 13.136Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M144.259 12.954C144.259 13.2433 144.241 13.5047 144.203 13.738H138.309C138.356 14.354 138.585 14.8487 138.995 15.222C139.406 15.5954 139.91 15.782 140.507 15.782C141.366 15.782 141.973 15.4227 142.327 14.704H144.049C143.816 15.4133 143.391 15.9967 142.775 16.454C142.169 16.902 141.413 17.126 140.507 17.126C139.77 17.126 139.107 16.9627 138.519 16.636C137.941 16.3 137.483 15.8334 137.147 15.236C136.821 14.6294 136.657 13.9293 136.657 13.136C136.657 12.3427 136.816 11.6473 137.133 11.05C137.46 10.4434 137.913 9.97668 138.491 9.65002C139.079 9.32335 139.751 9.16002 140.507 9.16002C141.235 9.16002 141.884 9.31868 142.453 9.63602C143.023 9.95335 143.466 10.4014 143.783 10.98C144.101 11.5493 144.259 12.2073 144.259 12.954ZM142.593 12.45C142.584 11.862 142.374 11.3907 141.963 11.036C141.553 10.6813 141.044 10.504 140.437 10.504C139.887 10.504 139.415 10.6813 139.023 11.036C138.631 11.3813 138.398 11.8527 138.323 12.45H142.593Z",
+ "fill": "#1D2939"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_9866_6170",
+ "x1": "2.15214",
+ "y1": "24.3018",
+ "x2": "21.2921",
+ "y2": "0.0988218",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#E9A85E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#F52B76"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_9866_6170",
+ "x1": "2.06269",
+ "y1": "24.2294",
+ "x2": "21.2027",
+ "y2": "0.028252",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#E9A85E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#F52B76"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint2_linear_9866_6170",
+ "x1": "-0.613606",
+ "y1": "3.843",
+ "x2": "21.4449",
+ "y2": "18.7258",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#6A0CF5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#AB66F3"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_9866_6170"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "152",
+ "height": "24",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "XorbitsInferenceText"
+}
diff --git a/app/components/base/icons/src/public/llm/XorbitsInferenceText.tsx b/app/components/base/icons/src/public/llm/XorbitsInferenceText.tsx
new file mode 100644
index 0000000..fb834e7
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/XorbitsInferenceText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './XorbitsInferenceText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'XorbitsInferenceText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/Zhipuai.json b/app/components/base/icons/src/public/llm/Zhipuai.json
new file mode 100644
index 0000000..8795568
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Zhipuai.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "ZHIPU Square"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "shape"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.8923 23.4987C11.8281 23.5139 11.7722 23.5535 11.7365 23.609C11.7008 23.6646 11.6881 23.7319 11.701 23.7966C11.7314 23.9293 11.862 24.0232 11.9919 23.9921C12.0561 23.9771 12.1119 23.9377 12.1476 23.8823C12.1833 23.8268 12.1961 23.7596 12.1832 23.695C12.1528 23.5616 12.0222 23.4677 11.8923 23.4987ZM15.4754 8.52697C16.3105 8.14085 16.681 7.13426 16.3027 6.27944C15.9243 5.42532 14.9403 5.04556 14.1046 5.43238C13.2695 5.81991 12.8982 6.8265 13.2766 7.68062C13.6549 8.53544 14.6389 8.91379 15.4754 8.52697ZM18.0935 13.6284C18.9723 13.358 19.47 12.4107 19.206 11.5129C18.9413 10.6143 18.0152 10.1053 17.1363 10.3757C16.2582 10.646 15.7599 11.5933 16.0246 12.4919C16.2893 13.3898 17.2154 13.8987 18.0935 13.6284ZM5.17233 10.7237C4.84426 11.0278 4.64662 11.4471 4.62083 11.8937C4.59503 12.3403 4.74309 12.7796 5.03398 13.1194C5.17709 13.2847 5.35177 13.4196 5.54777 13.5164C5.74377 13.6132 5.95713 13.6698 6.17533 13.683C6.39352 13.6961 6.61214 13.6655 6.81835 13.593C7.02455 13.5205 7.21418 13.4075 7.3761 13.2606C7.70417 12.9565 7.90182 12.5372 7.92761 12.0906C7.9534 11.644 7.80534 11.2047 7.51445 10.8649C7.37135 10.6996 7.19666 10.5647 7.00066 10.4679C6.80466 10.3711 6.5913 10.3145 6.37311 10.3013C6.15491 10.2882 5.93629 10.3188 5.73009 10.3913C5.52388 10.4638 5.33425 10.5768 5.17233 10.7237ZM19.7686 8.56368C20.1893 8.17968 20.2274 7.51473 19.8526 7.08415C19.7642 6.98189 19.6563 6.89838 19.5352 6.83853C19.414 6.77868 19.2821 6.74371 19.1472 6.73568C19.0123 6.72765 18.8772 6.74673 18.7498 6.79179C18.6224 6.83685 18.5054 6.90698 18.4055 6.99803C18.2027 7.18577 18.0805 7.44488 18.0649 7.72084C18.0492 7.99679 18.1412 8.26806 18.3215 8.47756C18.697 8.90815 19.3472 8.94697 19.7686 8.56368ZM11.946 4.6185C12.5121 4.6185 12.9716 4.14838 12.9716 3.56956C12.9716 2.99074 12.5128 2.52062 11.946 2.52062C11.3792 2.52062 10.9203 2.99003 10.9203 3.56956C10.9203 4.14838 11.3792 4.6185 11.946 4.6185ZM4.80527 8.82979C5.37139 8.82979 5.83022 8.36038 5.83022 7.78085C5.83022 7.20203 5.37139 6.73191 4.80457 6.73191C4.23845 6.73191 3.77892 7.20132 3.77892 7.78085C3.77892 8.35968 4.23845 8.82979 4.80527 8.82979ZM4.11563 15.4361C3.91267 15.6238 3.79043 15.8829 3.77463 16.1588C3.75883 16.4348 3.85071 16.7061 4.03092 16.9157C4.40645 17.3463 5.05727 17.3858 5.47798 17.0018C5.89939 16.6185 5.9368 15.9529 5.56269 15.5223C5.47435 15.42 5.36642 15.3365 5.24528 15.2766C5.12413 15.2168 4.99222 15.1818 4.85733 15.1738C4.72245 15.1658 4.58732 15.1848 4.45993 15.2299C4.33254 15.275 4.21547 15.3451 4.11563 15.4361ZM11.946 21.487C12.5121 21.487 12.9716 21.0176 12.9716 20.438C12.9716 19.8592 12.5128 19.3891 11.946 19.3891C11.3792 19.3891 10.9203 19.8592 10.9203 20.438C10.9203 21.0176 11.3792 21.487 11.946 21.487ZM19.0945 17.2601C19.6613 17.2601 20.1201 16.7907 20.1201 16.2112C20.1201 15.6324 19.6613 15.1623 19.0945 15.1623C18.5283 15.1623 18.0688 15.6317 18.0688 16.2112C18.0688 16.79 18.5276 17.2601 19.0945 17.2601ZM17.0735 3.51521C17.1578 3.52035 17.2422 3.50847 17.3217 3.48028C17.4013 3.45208 17.4743 3.40814 17.5365 3.35108C17.5987 3.29403 17.6488 3.22503 17.6837 3.1482C17.7186 3.07137 17.7377 2.98829 17.7399 2.90391C17.7465 2.81974 17.7362 2.7351 17.7096 2.65498C17.683 2.57486 17.6406 2.50087 17.5849 2.43739C17.5293 2.3739 17.4615 2.3222 17.3855 2.28534C17.3096 2.24847 17.227 2.22719 17.1427 2.22274C17.0586 2.21769 16.9743 2.22962 16.8949 2.25782C16.8154 2.28602 16.7425 2.32991 16.6804 2.38688C16.6183 2.44385 16.5683 2.51273 16.5333 2.58943C16.4984 2.66613 16.4793 2.74907 16.477 2.83332C16.4704 2.91749 16.4807 3.00213 16.5073 3.08225C16.5339 3.16238 16.5763 3.23636 16.632 3.29985C16.6876 3.36333 16.7554 3.41503 16.8314 3.4519C16.9073 3.48876 16.9892 3.51075 17.0735 3.51521ZM6.44292 3.40509C6.51215 3.45127 6.58995 3.48309 6.6717 3.49865C6.75346 3.51422 6.8375 3.51322 6.91886 3.49571C7.00022 3.4782 7.07724 3.44454 7.14535 3.39672C7.21347 3.3489 7.27129 3.2879 7.31539 3.21732C7.40689 3.07395 7.43891 2.90056 7.40464 2.73397C7.37038 2.56738 7.27252 2.4207 7.13186 2.32509C7.06261 2.27879 6.98475 2.24688 6.90293 2.23126C6.8211 2.21563 6.73697 2.2166 6.65552 2.23411C6.57408 2.25163 6.49698 2.28532 6.42882 2.33321C6.36065 2.38109 6.30279 2.44218 6.25869 2.51285C6.16718 2.65622 6.13517 2.82961 6.16944 2.9962C6.2037 3.1628 6.30226 3.30947 6.44292 3.40509ZM1.3528 11.4211C1.03869 11.5771 0.916569 11.9689 1.06975 12.2893C1.10579 12.3647 1.15653 12.4322 1.21899 12.4877C1.28145 12.5432 1.35436 12.5857 1.43346 12.6126C1.51256 12.6396 1.59625 12.6505 1.67961 12.6447C1.76298 12.6388 1.84434 12.6164 1.91892 12.5787C2.23304 12.4227 2.35516 12.031 2.20198 11.7105C2.16593 11.6352 2.11522 11.5678 2.05282 11.5124C1.99041 11.4569 1.91757 11.4145 1.83855 11.3875C1.75954 11.3606 1.67594 11.3497 1.59265 11.3554C1.50936 11.3612 1.42736 11.3835 1.3528 11.4211ZM6.82551 20.4931C6.74132 20.4879 6.65697 20.4998 6.57746 20.528C6.49796 20.5561 6.42494 20.6 6.36275 20.657C6.30057 20.7139 6.25049 20.7829 6.21551 20.8596C6.18054 20.9364 6.16137 21.0194 6.15916 21.1037C6.15254 21.1878 6.16284 21.2725 6.18945 21.3526C6.21606 21.4327 6.25844 21.5067 6.3141 21.5702C6.36975 21.6337 6.43755 21.6854 6.51351 21.7222C6.58946 21.7591 6.67202 21.7804 6.75633 21.7849C6.84046 21.7899 6.92475 21.778 7.00417 21.7498C7.08359 21.7216 7.15652 21.6777 7.21863 21.6207C7.28074 21.5637 7.33075 21.4949 7.36568 21.4182C7.40062 21.3415 7.41976 21.2585 7.42198 21.1743C7.4286 21.0902 7.41832 21.0056 7.39176 20.9255C7.36519 20.8454 7.32287 20.7715 7.26729 20.708C7.21171 20.6445 7.14399 20.5928 7.06812 20.5559C6.99225 20.519 6.90976 20.4976 6.82551 20.4931ZM17.4568 20.6025C17.3875 20.5564 17.3097 20.5247 17.228 20.5092C17.1463 20.4937 17.0623 20.4947 16.9809 20.5122C16.8996 20.5297 16.8226 20.5633 16.7545 20.6111C16.6864 20.6588 16.6285 20.7198 16.5843 20.7903C16.4926 20.9337 16.4605 21.1072 16.4947 21.274C16.529 21.4408 16.627 21.5876 16.7679 21.6832C16.8371 21.7294 16.915 21.7611 16.9968 21.7766C17.0785 21.7922 17.1626 21.7911 17.244 21.7735C17.3253 21.7559 17.4023 21.7222 17.4704 21.6743C17.5385 21.6264 17.5963 21.5654 17.6403 21.4947C17.7318 21.3514 17.7639 21.178 17.7296 21.0114C17.6953 20.8448 17.5975 20.6981 17.4568 20.6025ZM22.6076 11.4599C22.5384 11.4138 22.4606 11.3821 22.3788 11.3666C22.2971 11.3511 22.2131 11.3521 22.1318 11.3696C22.0504 11.3871 21.9734 11.4207 21.9053 11.4685C21.8372 11.5162 21.7793 11.5772 21.7352 11.6477C21.6437 11.791 21.6116 11.9644 21.6459 12.131C21.6802 12.2976 21.778 12.4443 21.9187 12.5399C21.9879 12.5862 22.0658 12.6181 22.1476 12.6337C22.2295 12.6494 22.3136 12.6484 22.395 12.6309C22.4765 12.6134 22.5536 12.5797 22.6217 12.5318C22.6899 12.4839 22.7478 12.4228 22.7919 12.3521C22.8834 12.2088 22.9154 12.0354 22.8811 11.8688C22.8468 11.7022 22.7483 11.5555 22.6076 11.4599ZM22.057 6.30909C22.1043 6.26393 22.1329 6.20263 22.1371 6.13738C22.1413 6.07212 22.1208 6.00768 22.0796 5.95685C22.0366 5.90876 21.9765 5.8794 21.9121 5.87505C21.8478 5.8707 21.7842 5.8917 21.7352 5.93356C21.6879 5.97872 21.6593 6.04001 21.6551 6.10527C21.6509 6.17052 21.6714 6.23496 21.7126 6.28579C21.7556 6.33388 21.8157 6.36325 21.8801 6.3676C21.9444 6.37195 22.0079 6.35095 22.057 6.30909ZM11.9912 0.501088C12.0556 0.486056 12.1116 0.446576 12.1474 0.39099C12.1832 0.335404 12.1961 0.268066 12.1832 0.203206C12.1528 0.0705002 12.0222 -0.0233822 11.8923 0.00767661C11.8282 0.0228647 11.7725 0.0623031 11.7368 0.117713C11.7011 0.173123 11.6883 0.240196 11.701 0.304853C11.7314 0.438265 11.8613 0.532147 11.9912 0.501088ZM1.92669 6.36415C2.05657 6.41073 2.19492 6.33238 2.2408 6.20744C2.2613 6.14447 2.25683 6.07605 2.22832 6.01628C2.19982 5.95651 2.14945 5.90997 2.08763 5.88626C1.95704 5.83968 1.81939 5.91803 1.77351 6.04297C1.75302 6.10594 1.75749 6.17437 1.78599 6.23413C1.8145 6.2939 1.86486 6.34044 1.92669 6.36415ZM1.83492 17.6823C1.78733 17.7274 1.7585 17.7887 1.75418 17.8542C1.74986 17.9196 1.77038 17.9842 1.81163 18.0352C1.85464 18.0833 1.91475 18.1127 1.97912 18.117C2.04349 18.1214 2.10701 18.1004 2.1561 18.0585C2.20349 18.0134 2.2322 17.9522 2.23651 17.8869C2.24083 17.8217 2.22044 17.7572 2.17939 17.7063C2.13638 17.6582 2.07627 17.6288 2.0119 17.6245C1.94753 17.6201 1.88401 17.6404 1.83492 17.6823ZM21.9723 17.6279C21.8425 17.5813 21.7048 17.6597 21.6589 17.7846C21.6384 17.8476 21.6429 17.916 21.6714 17.9758C21.6999 18.0355 21.7503 18.0821 21.8121 18.1058C21.942 18.1524 22.0803 18.074 22.1255 17.9491C22.146 17.8862 22.1417 17.8179 22.1133 17.7581C22.0849 17.6983 22.034 17.6518 21.9723 17.6279Z",
+ "fill": "#3859FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.2901 15.4128C14.9386 15.2962 14.5579 15.3024 14.2104 15.4304C13.8628 15.5583 13.5691 15.8005 13.3772 16.1173L13.3616 16.1483C12.979 16.814 12.2209 17.1662 11.4713 16.9234C11.0652 16.7913 10.7253 16.5083 10.5219 16.1328C10.4896 16.023 10.469 15.9102 10.4604 15.7961C10.4301 15.069 10.9736 14.4577 11.6852 14.4189H11.8539C13.1626 14.4733 14.2722 13.4321 14.3259 12.086C14.3795 10.7399 13.3616 9.61256 12.0452 9.5575H11.6852C10.9736 9.52644 10.476 8.96244 10.5063 8.23468C10.5063 8.06244 10.5374 7.89021 10.6059 7.74126L10.6214 7.69468C10.6539 7.62345 10.6821 7.55038 10.7061 7.47585C10.9814 6.57515 10.4915 5.62009 9.61904 5.33844C8.75362 5.06456 7.81974 5.54174 7.53668 6.45021C7.26139 7.32691 7.72021 8.26574 8.57009 8.57138C8.70774 8.61797 8.79174 8.63421 8.92233 8.6575H8.9908C9.66492 8.73515 10.1929 9.29138 10.1696 9.99585C10.1626 10.2542 10.0779 10.4893 9.94798 10.6848C9.72118 11.0472 9.59453 11.4632 9.58092 11.8904C9.55808 12.3864 9.68605 12.8776 9.94798 13.2994C10.0779 13.4949 10.1619 13.73 10.1696 13.9883C10.2007 14.6928 9.74115 15.2483 9.06774 15.3189H9.05221C8.95339 15.3189 8.83833 15.3422 8.74586 15.3577C7.82821 15.5695 7.28468 16.485 7.4908 17.4013C7.69762 18.3246 8.60045 18.8646 9.45809 18.669C9.67681 18.6217 9.88344 18.5298 10.0651 18.3991C10.2468 18.2685 10.3996 18.1018 10.5141 17.9095C10.7022 17.5817 10.997 17.3283 11.3494 17.1916C11.7018 17.0549 12.0904 17.0432 12.4503 17.1584C12.8562 17.2911 13.147 17.5417 13.3539 17.894L13.3764 17.9335C13.5529 18.2229 13.8896 18.5208 14.287 18.638C15.1906 18.9119 16.0786 18.4107 16.3623 17.534C16.6524 16.6184 16.1322 15.6704 15.2901 15.3973V15.4128Z",
+ "fill": "#3859FF"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Zhipuai"
+}
diff --git a/app/components/base/icons/src/public/llm/Zhipuai.tsx b/app/components/base/icons/src/public/llm/Zhipuai.tsx
new file mode 100644
index 0000000..d06244b
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/Zhipuai.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Zhipuai.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Zhipuai'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/ZhipuaiText.json b/app/components/base/icons/src/public/llm/ZhipuaiText.json
new file mode 100644
index 0000000..12eb65a
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/ZhipuaiText.json
@@ -0,0 +1,44 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "89",
+ "height": "32",
+ "viewBox": "0 0 89 32",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "shape"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M88.8045 8.82998H86.7123V22.4497H88.8045V8.82998ZM80.5485 8.82998L78.4158 22.4497H80.3339L80.5589 20.9156L80.6709 20.1853C80.6916 20.0394 80.8751 19.9142 81.0793 19.9142H82.8855C83.0897 19.9142 83.2732 20.029 83.2939 20.1853L83.4059 20.9156L83.6299 22.4497H85.7429L83.6102 8.82998H80.5485ZM82.7838 18.2963H81.181C81.1522 18.2968 81.1237 18.2909 81.0975 18.279C81.0713 18.2671 81.0481 18.2495 81.0295 18.2275C81.0109 18.2056 80.9975 18.1797 80.9902 18.1519C80.9828 18.1241 80.9818 18.095 80.9871 18.0667L81.7024 12.1175C81.7212 11.95 81.8436 11.8352 81.9772 11.8352C82.109 11.8352 82.2426 11.95 82.253 12.1175L82.9673 18.0657C82.9767 18.1919 82.8855 18.2963 82.7735 18.2963H82.7838ZM14.8563 31.3316C14.7706 31.3519 14.6961 31.4046 14.6485 31.4787C14.6009 31.5528 14.584 31.6425 14.6012 31.7288C14.6417 31.9057 14.8158 32.0309 14.989 31.9895C15.0746 31.9695 15.1491 31.9169 15.1967 31.843C15.2443 31.769 15.2613 31.6795 15.244 31.5933C15.2036 31.4154 15.0295 31.2902 14.8563 31.3316ZM19.6337 11.3693C20.7471 10.8544 21.2412 9.51233 20.7368 8.37257C20.2323 7.23374 18.9203 6.72739 17.8059 7.24316C16.6925 7.75986 16.1975 9.10198 16.7019 10.2408C17.2064 11.3806 18.5184 11.885 19.6337 11.3693ZM23.1245 18.1712C24.2963 17.8107 24.9598 16.5476 24.6078 15.3504C24.2549 14.1523 23.02 13.4737 21.8483 13.8342C20.6775 14.1947 20.013 15.4577 20.3659 16.6559C20.7189 17.853 21.9537 18.5316 23.1245 18.1712ZM5.89628 14.2982C5.45885 14.7037 5.19533 15.2628 5.16094 15.8583C5.12655 16.4537 5.32396 17.0394 5.71181 17.4926C5.90262 17.7129 6.13553 17.8928 6.39686 18.0219C6.6582 18.1509 6.94268 18.2264 7.23361 18.2439C7.52453 18.2615 7.81602 18.2207 8.09096 18.124C8.36591 18.0273 8.61875 17.8766 8.83463 17.6808C9.27207 17.2753 9.53559 16.7162 9.56998 16.1208C9.60437 15.5253 9.40695 14.9396 9.0191 14.4864C8.8283 14.2661 8.59539 14.0862 8.33405 13.9571C8.07272 13.8281 7.78823 13.7526 7.49731 13.7351C7.20639 13.7175 6.91489 13.7583 6.63995 13.855C6.36501 13.9517 6.11217 14.1024 5.89628 14.2982ZM25.3579 11.4182C25.9189 10.9062 25.9697 10.0196 25.4699 9.44551C25.3521 9.30917 25.2082 9.19782 25.0467 9.11802C24.8852 9.03822 24.7093 8.99159 24.5295 8.98088C24.3496 8.97018 24.1694 8.99562 23.9996 9.0557C23.8297 9.11578 23.6736 9.20928 23.5405 9.33068C23.27 9.581 23.1072 9.92649 23.0863 10.2944C23.0654 10.6624 23.1881 11.0241 23.4285 11.3034C23.9292 11.8775 24.796 11.9293 25.3579 11.4182ZM14.9278 6.15798C15.6826 6.15798 16.2953 5.53116 16.2953 4.75939C16.2953 3.98763 15.6836 3.3608 14.9278 3.3608C14.172 3.3608 13.5603 3.98669 13.5603 4.75939C13.5603 5.53116 14.172 6.15798 14.9278 6.15798ZM5.40687 11.773C6.16169 11.773 6.77346 11.1472 6.77346 10.3744C6.77346 9.60268 6.16169 8.97586 5.40593 8.97586C4.65111 8.97586 4.0384 9.60174 4.0384 10.3744C4.0384 11.1462 4.65111 11.773 5.40687 11.773ZM4.48734 20.5815C4.21673 20.8317 4.05374 21.1771 4.03268 21.5451C4.01161 21.913 4.13411 22.2748 4.3744 22.5542C4.87511 23.1283 5.74287 23.181 6.30381 22.669C6.86569 22.158 6.91558 21.2704 6.41675 20.6963C6.29897 20.56 6.15507 20.4486 5.99354 20.3688C5.83201 20.289 5.65613 20.2424 5.47628 20.2317C5.29643 20.221 5.11626 20.2464 4.94641 20.3065C4.77656 20.3666 4.62046 20.4601 4.48734 20.5815ZM14.9278 28.6493C15.6826 28.6493 16.2953 28.0234 16.2953 27.2507C16.2953 26.4789 15.6836 25.8521 14.9278 25.8521C14.172 25.8521 13.5603 26.4789 13.5603 27.2507C13.5603 28.0234 14.172 28.6493 14.9278 28.6493ZM24.4591 23.0135C25.2149 23.0135 25.8266 22.3876 25.8266 21.6149C25.8266 20.8432 25.2149 20.2163 24.4591 20.2163C23.7043 20.2163 23.0916 20.8422 23.0916 21.6149C23.0916 22.3867 23.7033 23.0135 24.4591 23.0135ZM21.7645 4.68692C21.8768 4.69378 21.9894 4.67794 22.0955 4.64035C22.2015 4.60275 22.2989 4.54416 22.3819 4.46809C22.4648 4.39202 22.5315 4.30001 22.5781 4.19757C22.6247 4.09514 22.6502 3.98436 22.653 3.87186C22.6618 3.75964 22.6481 3.64679 22.6126 3.53995C22.5771 3.43312 22.5206 3.33448 22.4464 3.24983C22.3722 3.16518 22.2818 3.09625 22.1805 3.0471C22.0793 2.99794 21.9692 2.96956 21.8568 2.96363C21.7446 2.9569 21.6322 2.9728 21.5263 3.0104C21.4204 3.048 21.3232 3.10652 21.2404 3.18248C21.1575 3.25845 21.0909 3.35029 21.0443 3.45256C20.9977 3.55482 20.9722 3.66541 20.9692 3.77774C20.9604 3.88997 20.9741 4.00282 21.0096 4.10965C21.0451 4.21648 21.1016 4.31513 21.1758 4.39978C21.25 4.48442 21.3404 4.55335 21.4417 4.60251C21.543 4.65166 21.6521 4.68099 21.7645 4.68692ZM7.5904 4.5401C7.68271 4.60167 7.78644 4.6441 7.89544 4.66485C8.00445 4.68561 8.11651 4.68427 8.22499 4.66093C8.33347 4.63758 8.43616 4.5927 8.52697 4.52894C8.61779 4.46518 8.69489 4.38384 8.75369 4.28974C8.8757 4.09858 8.91838 3.8674 8.87269 3.64527C8.827 3.42315 8.69653 3.22758 8.50899 3.1001C8.41664 3.03837 8.31284 2.99582 8.20374 2.97499C8.09464 2.95415 7.98246 2.95544 7.87387 2.9788C7.76528 3.00215 7.66248 3.04708 7.57159 3.11092C7.4807 3.17477 7.40356 3.25622 7.34475 3.35045C7.22275 3.54161 7.18006 3.7728 7.22575 3.99492C7.27144 4.21704 7.40285 4.41261 7.5904 4.5401ZM0.803576 15.2281C0.384753 15.4361 0.221929 15.9584 0.426164 16.3857C0.474224 16.4863 0.541877 16.5762 0.625154 16.6502C0.708432 16.7242 0.805655 16.7809 0.911121 16.8168C1.01659 16.8528 1.12817 16.8673 1.23932 16.8595C1.35047 16.8518 1.45895 16.8219 1.5584 16.7716C1.97722 16.5636 2.14005 16.0413 1.93581 15.614C1.88775 15.5136 1.82013 15.4238 1.73693 15.3498C1.65372 15.2759 1.55659 15.2193 1.45124 15.1833C1.34588 15.1474 1.23442 15.1329 1.12337 15.1405C1.01232 15.1482 0.902978 15.178 0.803576 15.2281ZM8.10052 27.3241C7.98827 27.3172 7.87579 27.333 7.76979 27.3706C7.66378 27.4081 7.56642 27.4666 7.48351 27.5426C7.40059 27.6186 7.33383 27.7105 7.28719 27.8128C7.24055 27.9151 7.215 28.0258 7.21205 28.1382C7.20322 28.2504 7.21695 28.3633 7.25243 28.4701C7.28791 28.577 7.34442 28.6756 7.41863 28.7602C7.49284 28.8449 7.58324 28.9138 7.68451 28.963C7.78578 29.0121 7.89587 29.0405 8.00828 29.0464C8.12045 29.0532 8.23283 29.0373 8.33873 28.9997C8.44462 28.9621 8.54187 28.9035 8.62468 28.8276C8.70749 28.7516 8.77417 28.6598 8.82075 28.5575C8.86733 28.4553 8.89286 28.3447 8.89581 28.2323C8.90464 28.1202 8.89094 28.0074 8.85551 27.9006C8.82009 27.7939 8.76367 27.6953 8.68956 27.6106C8.61545 27.526 8.52515 27.457 8.42399 27.4078C8.32283 27.3586 8.21285 27.3301 8.10052 27.3241ZM22.2756 27.47C22.1832 27.4085 22.0795 27.3662 21.9705 27.3455C21.8615 27.3248 21.7495 27.3262 21.6411 27.3495C21.5326 27.3729 21.43 27.4177 21.3391 27.4814C21.2483 27.5451 21.1712 27.6263 21.1123 27.7203C20.99 27.9116 20.9471 28.143 20.9928 28.3653C21.0385 28.5877 21.1692 28.7834 21.357 28.9109C21.4494 28.9725 21.5531 29.0148 21.6622 29.0355C21.7712 29.0562 21.8833 29.0548 21.9918 29.0313C22.1003 29.0079 22.2029 28.9629 22.2937 28.8991C22.3845 28.8352 22.4615 28.7538 22.5203 28.6596C22.6423 28.4685 22.685 28.2373 22.6393 28.0152C22.5936 27.793 22.4631 27.5975 22.2756 27.47ZM29.1433 15.2799C29.051 15.2184 28.9473 15.1761 28.8383 15.1554C28.7293 15.1347 28.6173 15.1361 28.5088 15.1594C28.4004 15.1828 28.2977 15.2276 28.2069 15.2913C28.1161 15.355 28.0389 15.4362 27.98 15.5302C27.858 15.7214 27.8154 15.9526 27.861 16.1747C27.9067 16.3968 28.0372 16.5924 28.2248 16.7199C28.3171 16.7816 28.4209 16.8241 28.53 16.845C28.6391 16.8658 28.7513 16.8645 28.8599 16.8412C28.9685 16.8178 29.0713 16.7729 29.1621 16.709C29.253 16.6452 29.3302 16.5637 29.389 16.4695C29.511 16.2783 29.5537 16.0472 29.508 15.825C29.4623 15.6029 29.3309 15.4073 29.1433 15.2799ZM28.4092 8.4121C28.4723 8.35188 28.5104 8.27016 28.516 8.18315C28.5215 8.09614 28.4942 8.01022 28.4393 7.94245C28.382 7.87833 28.3018 7.83918 28.216 7.83338C28.1302 7.82757 28.0455 7.85557 27.98 7.91139C27.917 7.9716 27.8789 8.05333 27.8733 8.14034C27.8677 8.22734 27.8951 8.31326 27.9499 8.38104C28.0073 8.44516 28.0874 8.48431 28.1732 8.49011C28.2591 8.49591 28.3438 8.46791 28.4092 8.4121ZM14.988 0.668097C15.0739 0.648054 15.1486 0.595414 15.1964 0.521299C15.2442 0.447185 15.2613 0.357402 15.244 0.270921C15.2036 0.0939798 15.0295 -0.0311966 14.8563 0.0102151C14.7708 0.0304659 14.6965 0.0830504 14.6489 0.156931C14.6013 0.230811 14.5843 0.320241 14.6012 0.40645C14.6417 0.584333 14.8149 0.709509 14.988 0.668097ZM1.56875 8.48551C1.74193 8.54763 1.9264 8.44315 1.98758 8.27657C2.0149 8.19261 2.00894 8.10137 1.97093 8.02168C1.93293 7.94199 1.86578 7.87994 1.78334 7.84833C1.60922 7.78621 1.42569 7.89068 1.36452 8.05727C1.3372 8.14123 1.34315 8.23247 1.38116 8.31216C1.41916 8.39185 1.48632 8.4539 1.56875 8.48551ZM1.4464 23.5763C1.38294 23.6365 1.3445 23.7183 1.33874 23.8055C1.33299 23.8928 1.36034 23.979 1.41534 24.0469C1.47268 24.111 1.55284 24.1502 1.63866 24.156C1.72449 24.1618 1.80918 24.1338 1.87463 24.078C1.93783 24.0179 1.9761 23.9362 1.98186 23.8492C1.98761 23.7622 1.96042 23.6762 1.90569 23.6083C1.84835 23.5442 1.7682 23.5051 1.68237 23.4993C1.59655 23.4935 1.51185 23.5205 1.4464 23.5763ZM28.2963 23.5039C28.1231 23.4417 27.9396 23.5462 27.8784 23.7128C27.8511 23.7968 27.857 23.888 27.895 23.9677C27.933 24.0474 28.0002 24.1094 28.0826 24.141C28.2558 24.2032 28.4403 24.0987 28.5005 23.9321C28.5279 23.8483 28.5221 23.7571 28.4842 23.6774C28.4464 23.5978 28.3785 23.5356 28.2963 23.5039Z",
+ "fill": "#3859FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.3866 20.5504C18.918 20.3949 18.4104 20.4031 17.947 20.5738C17.4836 20.7444 17.0919 21.0674 16.836 21.4897L16.8153 21.5311C16.3052 22.4186 15.2944 22.8883 14.2949 22.5645C13.7534 22.3884 13.3002 22.011 13.029 21.5104C12.986 21.364 12.9585 21.2135 12.9471 21.0614C12.9066 20.092 13.6313 19.277 14.58 19.2252H14.805C16.5499 19.2977 18.0295 17.9094 18.101 16.1146C18.1725 14.3198 16.8153 12.8167 15.06 12.7433H14.58C13.6313 12.7019 12.9678 11.9499 13.0083 10.9795C13.0083 10.7499 13.0497 10.5203 13.141 10.3217L13.1617 10.2595C13.205 10.1646 13.2427 10.0672 13.2746 9.96778C13.6417 8.76684 12.9885 7.49343 11.8252 7.1179C10.6713 6.75272 9.42616 7.38896 9.04875 8.60025C8.68169 9.76919 9.29345 11.021 10.4266 11.4285C10.6102 11.4906 10.7222 11.5123 10.8963 11.5433H10.9876C11.8864 11.6468 12.5904 12.3885 12.5593 13.3278C12.5499 13.6723 12.437 13.9857 12.2638 14.2464C11.9614 14.7295 11.7925 15.2842 11.7744 15.8539C11.7439 16.5152 11.9146 17.1701 12.2638 17.7325C12.437 17.9932 12.549 18.3066 12.5593 18.6511C12.6007 19.5904 11.988 20.3311 11.0902 20.4252H11.0695C10.9377 20.4252 10.7843 20.4563 10.661 20.477C9.43745 20.7593 8.71275 21.98 8.98757 23.2017C9.26333 24.4327 10.4671 25.1527 11.6106 24.892C11.9023 24.8289 12.1778 24.7064 12.42 24.5321C12.6622 24.3579 12.866 24.1357 13.0186 23.8793C13.2694 23.4422 13.6626 23.1044 14.1324 22.9221C14.6022 22.7399 15.1203 22.7243 15.6003 22.8779C16.1415 23.0548 16.5292 23.389 16.805 23.8586L16.8351 23.9113C17.0704 24.2972 17.5193 24.6944 18.0492 24.8506C19.2539 25.2158 20.4379 24.5475 20.8163 23.3786C21.2031 22.1579 20.5095 20.8939 19.3866 20.5297V20.5504ZM75.0064 14.1005C74.4454 14.1005 73.9862 14.5701 73.9862 15.1443C73.9862 15.7184 74.4454 16.188 75.0064 16.188C75.5673 16.188 76.0266 15.7174 76.0266 15.1433C76.0286 14.87 75.9225 14.607 75.7314 14.4117C75.5403 14.2163 75.2797 14.1045 75.0064 14.1005ZM38.1029 10.7395H41.4506C41.5214 10.7415 41.5886 10.7709 41.6381 10.8214C41.6876 10.872 41.7156 10.9398 41.716 11.0106C41.716 11.0426 41.716 11.084 41.6963 11.1047L37.9203 20.3941V22.2831H43.972V20.3631H40.4407C40.3698 20.3611 40.3025 20.3316 40.2529 20.2809C40.2034 20.2301 40.1756 20.162 40.1753 20.0911C40.1753 20.06 40.1753 20.028 40.196 19.997L43.972 10.7075V8.82049H38.1029V10.7395ZM49.6153 14.3198C49.6149 14.3906 49.5869 14.4584 49.5374 14.509C49.4879 14.5595 49.4207 14.5889 49.3499 14.5908H47.524C47.4887 14.5908 47.4536 14.5838 47.421 14.5701C47.3884 14.5564 47.3588 14.5364 47.334 14.5112C47.3092 14.4859 47.2897 14.456 47.2766 14.4232C47.2635 14.3903 47.2571 14.3552 47.2577 14.3198V8.81861H45.1862V22.2821H47.2577V16.7819C47.2578 16.7127 47.2842 16.6461 47.3315 16.5956C47.3789 16.5451 47.4437 16.5144 47.5127 16.5099H49.3396C49.4826 16.5099 49.5946 16.636 49.5946 16.7819V22.2821H51.6972V8.81861H49.5946V14.3188L49.6153 14.3198ZM55.2887 8.81861H53.2182V22.2831H55.2887V8.81861ZM59.8412 8.81861H56.7899V22.2831H58.8605V17.2214H59.8412C61.9127 17.2214 62.9226 16.0525 62.9226 13.8915V12.1381C62.9226 9.98849 61.9127 8.80825 59.8412 8.80825V8.81861ZM60.8511 14.0271C60.8511 14.9871 60.4934 15.3005 59.8412 15.3005H59.1259C59.0907 15.3002 59.0559 15.293 59.0235 15.2792C58.9911 15.2654 58.9617 15.2454 58.9371 15.2202C58.9125 15.1949 58.8932 15.1651 58.8802 15.1324C58.8672 15.0996 58.8608 15.0646 58.8615 15.0294V11.0106C58.8619 10.9398 58.8899 10.872 58.9394 10.8214C58.9889 10.7709 59.0561 10.7415 59.1269 10.7395H59.8412C60.4944 10.7395 60.8511 11.0426 60.8511 12.013V14.0271ZM67.9946 19.2035C67.9946 20.1635 67.5767 20.509 66.9236 20.509C66.2704 20.509 65.8525 20.1645 65.8525 19.2035V8.81955H63.78V19.069C63.78 21.2186 64.8313 22.4497 66.8624 22.4497C68.8934 22.4497 69.9447 21.2186 69.9447 19.068V8.81861H67.9852V19.2035H67.9946Z",
+ "fill": "#3859FF"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ZhipuaiText"
+}
diff --git a/app/components/base/icons/src/public/llm/ZhipuaiText.tsx b/app/components/base/icons/src/public/llm/ZhipuaiText.tsx
new file mode 100644
index 0000000..600ca7c
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/ZhipuaiText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ZhipuaiText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ZhipuaiText'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/ZhipuaiTextCn.json b/app/components/base/icons/src/public/llm/ZhipuaiTextCn.json
new file mode 100644
index 0000000..c5b1755
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/ZhipuaiTextCn.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "86",
+ "height": "32",
+ "viewBox": "0 0 86 32",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "shape"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M85.3919 8.94111H83.2742V22.4705H85.3919V8.94111ZM76.9919 8.94111L74.8272 22.4705H76.7801L77.0154 20.9411L77.133 20.2117C77.1566 20.0705 77.3448 19.9529 77.5566 19.9529H79.3919C79.6036 19.9529 79.7919 20.0705 79.8154 20.2117L79.933 20.9411L80.1683 22.4705H82.3095L80.1213 8.94111H76.9919ZM79.2742 18.3529H77.6507C77.533 18.3529 77.4389 18.2352 77.4389 18.1176L78.1683 12.2117C78.1919 12.047 78.3095 11.9293 78.4507 11.9293C78.5919 11.9293 78.7095 12.047 78.733 12.2117L79.4625 18.1176C79.486 18.2588 79.3919 18.3529 79.2742 18.3529ZM15.2742 31.3176C15.086 31.3176 14.9448 31.4588 14.9448 31.647C14.9448 31.8352 15.086 31.9764 15.2742 31.9764C15.4624 31.9764 15.6036 31.8352 15.6036 31.647C15.6036 31.4588 15.4624 31.3176 15.2742 31.3176ZM19.133 11.6705C19.7321 11.6705 20.3067 11.4325 20.7303 11.0089C21.1539 10.5853 21.3919 10.0108 21.3919 9.4117C21.3919 8.81262 21.1539 8.23808 20.7303 7.81447C20.3067 7.39086 19.7321 7.15288 19.133 7.15288C18.534 7.15288 17.9594 7.39086 17.5358 7.81447C17.1122 8.23808 16.8742 8.81262 16.8742 9.4117C16.8742 10.0108 17.1122 10.5853 17.5358 11.0089C17.9594 11.4325 18.534 11.6705 19.133 11.6705ZM24.5601 17.6752C24.7699 17.4655 24.9363 17.2165 25.0498 16.9424C25.1633 16.6683 25.2218 16.3746 25.2218 16.0779C25.2218 15.7813 25.1633 15.4875 25.0498 15.2135C24.9363 14.9394 24.7699 14.6904 24.5601 14.4806C24.1365 14.057 23.5619 13.8191 22.9628 13.8191C22.3638 13.8191 21.7892 14.0571 21.3656 14.4808C20.942 14.9044 20.7041 15.4789 20.7041 16.078C20.7041 16.6771 20.9421 17.2516 21.3657 17.6752C21.5755 17.885 21.8245 18.0514 22.0985 18.165C22.3726 18.2785 22.6663 18.337 22.9629 18.337C23.2596 18.337 23.5533 18.2785 23.8273 18.165C24.1014 18.0514 24.3504 17.885 24.5601 17.6752ZM9.69233 16.9369C9.9216 16.3834 9.9216 15.7614 9.69232 15.2079C9.46304 14.6544 9.02327 14.2146 8.46974 13.9853C7.91622 13.7561 7.29429 13.7561 6.74077 13.9854C6.18725 14.2146 5.74749 14.6544 5.51821 15.2079C5.28894 15.7615 5.28895 16.3834 5.51823 16.9369C5.74751 17.4904 6.18728 17.9302 6.7408 18.1595C7.01488 18.273 7.30863 18.3314 7.60529 18.3314C7.90195 18.3314 8.1957 18.273 8.46977 18.1595C9.02329 17.9302 9.46306 17.4904 9.69233 16.9369ZM24.9683 11.8823C25.1506 11.8823 25.3312 11.8464 25.4996 11.7766C25.668 11.7069 25.8211 11.6046 25.95 11.4757C26.0789 11.3468 26.1811 11.1937 26.2509 11.0253C26.3207 10.8569 26.3566 10.6764 26.3566 10.4941C26.3566 10.3117 26.3207 10.1312 26.2509 9.9628C26.1811 9.79437 26.0789 9.64133 25.95 9.51242C25.8211 9.38351 25.668 9.28126 25.4996 9.21149C25.3312 9.14173 25.1506 9.10582 24.9683 9.10582C24.6001 9.10582 24.247 9.25208 23.9867 9.51242C23.7264 9.77277 23.5801 10.1259 23.5801 10.4941C23.5801 10.8622 23.7264 11.2153 23.9867 11.4757C24.247 11.736 24.6001 11.8823 24.9683 11.8823ZM15.5904 6.24605C15.77 6.20622 15.9398 6.13112 16.0901 6.02511C16.2403 5.9191 16.368 5.78429 16.4658 5.62851C16.5635 5.47273 16.6293 5.29909 16.6593 5.11766C16.6894 4.93624 16.6831 4.75065 16.6408 4.57168C16.5986 4.39271 16.5212 4.22392 16.4131 4.07512C16.3051 3.92631 16.1685 3.80046 16.0114 3.70486C15.8543 3.60926 15.6798 3.54583 15.498 3.51824C15.3162 3.49066 15.1307 3.49947 14.9523 3.54417C14.5984 3.63287 14.2936 3.85737 14.1039 4.1691C13.9142 4.48083 13.8548 4.85472 13.9387 5.20986C14.0226 5.565 14.2429 5.87284 14.552 6.06676C14.8612 6.26068 15.2342 6.32509 15.5904 6.24605ZM5.60362 11.8823C5.78593 11.8823 5.96645 11.8464 6.13488 11.7766C6.30331 11.7069 6.45635 11.6046 6.58526 11.4757C6.71417 11.3468 6.81642 11.1937 6.88619 11.0253C6.95595 10.8569 6.99186 10.6764 6.99186 10.4941C6.99186 10.3117 6.95595 10.1312 6.88619 9.9628C6.81642 9.79437 6.71417 9.64133 6.58526 9.51242C6.45635 9.38351 6.30331 9.28126 6.13488 9.21149C5.96645 9.14173 5.78593 9.10582 5.60362 9.10582C5.23544 9.10582 4.88234 9.25208 4.62199 9.51242C4.36165 9.77277 4.21539 10.1259 4.21539 10.4941C4.21539 10.8622 4.36165 11.2153 4.62199 11.4757C4.88234 11.736 5.23544 11.8823 5.60362 11.8823ZM6.58904 22.6493C6.71795 22.5204 6.82021 22.3674 6.88997 22.199C6.95974 22.0305 6.99565 21.85 6.99565 21.6677C6.99565 21.4854 6.95974 21.3049 6.88997 21.1364C6.82021 20.968 6.71795 20.815 6.58904 20.6861C6.46012 20.5571 6.30708 20.4549 6.13865 20.3851C5.97022 20.3154 5.7897 20.2794 5.60739 20.2794C5.42508 20.2794 5.24456 20.3154 5.07613 20.3851C4.90769 20.4549 4.75465 20.5571 4.62574 20.6861C4.36539 20.9464 4.21913 21.2995 4.21913 21.6677C4.21913 22.0359 4.36539 22.389 4.62574 22.6493C4.88609 22.9097 5.2392 23.056 5.60739 23.056C5.97558 23.056 6.32869 22.9097 6.58904 22.6493ZM15.5919 28.5983C15.7693 28.5564 15.9367 28.48 16.0846 28.3734C16.2324 28.2668 16.3579 28.1321 16.4537 27.977C16.5495 27.8219 16.6138 27.6495 16.643 27.4696C16.6722 27.2896 16.6656 27.1057 16.6237 26.9283C16.5818 26.7509 16.5054 26.5835 16.3988 26.4356C16.2922 26.2877 16.1575 26.1623 16.0025 26.0665C15.8474 25.9707 15.675 25.9063 15.495 25.8771C15.3151 25.848 15.1312 25.8545 14.9537 25.8964C14.7742 25.9362 14.6044 26.0113 14.4541 26.1174C14.3039 26.2234 14.1762 26.3582 14.0784 26.514C13.9807 26.6697 13.9149 26.8434 13.8849 27.0248C13.8548 27.2062 13.8611 27.3918 13.9034 27.5708C13.9456 27.7497 14.023 27.9185 14.1311 28.0673C14.2391 28.2162 14.3757 28.342 14.5328 28.4376C14.6898 28.5332 14.8644 28.5966 15.0462 28.6242C15.228 28.6518 15.4135 28.643 15.5919 28.5983ZM25.2848 22.9973C25.4634 22.9566 25.6322 22.881 25.7815 22.7747C25.9307 22.6684 26.0574 22.5337 26.1543 22.3782C26.2512 22.2227 26.3164 22.0496 26.3461 21.8688C26.3758 21.6881 26.3694 21.5032 26.3273 21.3249C26.2853 21.1466 26.2083 20.9784 26.1009 20.83C25.9935 20.6815 25.8578 20.5559 25.7015 20.4601C25.5453 20.3644 25.3717 20.3006 25.1907 20.2723C25.0097 20.244 24.8249 20.2518 24.6469 20.2952C24.291 20.3821 23.9839 20.6062 23.7925 20.9185C23.6011 21.2309 23.541 21.6063 23.6251 21.9628C23.7093 22.3193 23.931 22.6281 24.2419 22.8219C24.5528 23.0157 24.9276 23.0788 25.2848 22.9973ZM22.286 4.82347C22.7566 4.82347 23.133 4.447 23.133 3.97641C23.133 3.50582 22.7566 3.12935 22.286 3.12935C21.8154 3.12935 21.4389 3.50582 21.4389 3.97641C21.4389 4.447 21.8154 4.82347 22.286 4.82347ZM8.28598 4.82347C8.75657 4.82347 9.13304 4.447 9.13304 3.97641C9.13304 3.50582 8.75657 3.12935 8.28598 3.12935C7.81539 3.12935 7.43892 3.50582 7.43892 3.97641C7.43892 4.447 7.81539 4.82347 8.28598 4.82347ZM1.29774 15.2235C0.827154 15.2235 0.450684 15.5999 0.450684 16.0705C0.450684 16.5411 0.827154 16.9176 1.29774 16.9176C1.76833 16.9176 2.1448 16.5411 2.1448 16.0705C2.16833 15.5999 1.76833 15.2235 1.29774 15.2235ZM8.28598 27.3176C7.81539 27.3176 7.43892 27.6941 7.43892 28.1646C7.43892 28.6352 7.81539 29.0117 8.28598 29.0117C8.75657 29.0117 9.13304 28.6352 9.13304 28.1646C9.13304 27.6941 8.75657 27.3176 8.28598 27.3176ZM22.286 27.3411C21.8154 27.3411 21.4389 27.7176 21.4389 28.1882C21.4389 28.6588 21.8154 29.0352 22.286 29.0352C22.7566 29.0352 23.133 28.6588 23.133 28.1882C23.133 27.7176 22.7566 27.3411 22.286 27.3411ZM29.2742 15.2235C28.8036 15.2235 28.4272 15.5999 28.4272 16.0705C28.4272 16.5411 28.8036 16.9176 29.2742 16.9176C29.7448 16.9176 30.1213 16.5411 30.1213 16.0705C30.1213 15.5999 29.7448 15.2235 29.2742 15.2235ZM28.7566 8.6117C28.9448 8.6117 29.086 8.47053 29.086 8.28229C29.086 8.09405 28.9448 7.95288 28.7566 7.95288C28.5683 7.95288 28.4272 8.09405 28.4272 8.28229C28.4272 8.47053 28.5919 8.6117 28.7566 8.6117ZM15.2742 0.846995C15.4624 0.846995 15.6036 0.705819 15.6036 0.517583C15.6036 0.329348 15.4624 0.188171 15.2742 0.188171C15.086 0.188171 14.9448 0.329348 14.9448 0.517583C14.9448 0.705819 15.1095 0.846995 15.2742 0.846995ZM1.81539 8.6117C2.00362 8.6117 2.1448 8.47053 2.1448 8.28229C2.1448 8.09405 2.00362 7.95288 1.81539 7.95288C1.62715 7.95288 1.48598 8.09405 1.48598 8.28229C1.48598 8.47053 1.62715 8.6117 1.81539 8.6117ZM1.81539 23.5293C1.62715 23.5293 1.48598 23.6705 1.48598 23.8588C1.48598 24.047 1.62715 24.1882 1.81539 24.1882C2.00362 24.1882 2.1448 24.047 2.1448 23.8588C2.1448 23.6705 1.9801 23.5293 1.81539 23.5293ZM28.7801 23.5058C28.5919 23.5058 28.4507 23.647 28.4507 23.8352C28.4507 24.0235 28.5919 24.1646 28.7801 24.1646C28.9683 24.1646 29.1095 24.0235 29.1095 23.8352C29.1095 23.6705 28.9683 23.5058 28.7801 23.5058Z",
+ "fill": "#3859FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.8154 20.5882C18.8036 20.2588 17.7683 20.6823 17.2272 21.5293L17.2036 21.5764C16.686 22.447 15.6507 22.9176 14.6389 22.6117C14.0742 22.4235 13.6272 22.047 13.3448 21.5529C13.2977 21.4117 13.2742 21.2705 13.2742 21.1058C13.2272 20.1411 13.9801 19.3176 14.9448 19.2941H15.1801C16.9683 19.3646 18.4507 17.9764 18.5213 16.2117C18.5919 14.4235 17.2036 12.9411 15.4389 12.8705H14.9448C13.9801 12.8235 13.2977 12.0705 13.3448 11.1293C13.3448 10.8941 13.3919 10.6823 13.486 10.4705L13.5095 10.3999C13.5566 10.2823 13.5801 10.2352 13.6272 10.1176C14.0036 8.91758 13.3448 7.67052 12.1448 7.29405C10.9683 6.94111 9.69774 7.57641 9.32127 8.75288C8.9448 9.90582 9.5801 11.1529 10.733 11.5529C10.9213 11.6235 11.0389 11.647 11.2036 11.6705L11.2977 11.6941C12.2154 11.7882 12.9213 12.5176 12.8977 13.4588C12.8742 13.7882 12.7801 14.1176 12.5919 14.3764C12.286 14.847 12.1213 15.3882 12.0977 15.9764C12.0742 16.6588 12.2624 17.3176 12.5919 17.8352C12.7801 18.0941 12.8742 18.3999 12.8977 18.7529C12.9448 19.6941 12.3095 20.4235 11.3919 20.5176H11.3683C11.2272 20.5176 11.086 20.5411 10.9683 20.5646C9.72127 20.847 8.99186 22.0705 9.27421 23.2705C9.55657 24.4941 10.7801 25.2235 11.9566 24.9646C12.5919 24.8235 13.086 24.447 13.3919 23.9529C13.9095 23.0588 14.9919 22.6352 16.0272 22.9646C16.5919 23.1293 16.9683 23.4823 17.2507 23.9293L17.2742 23.9764C17.5095 24.3529 17.9566 24.7529 18.4977 24.9176C19.7213 25.2705 20.9213 24.6117 21.2977 23.4588C21.6742 22.2117 20.9683 20.9646 19.8154 20.5882ZM70.2625 16.2588C70.537 16.2588 70.8004 16.1497 70.9945 15.9555C71.1887 15.7614 71.2977 15.498 71.2977 15.2235C71.2977 14.9489 71.1887 14.6856 70.9945 14.4914C70.8004 14.2972 70.537 14.1882 70.2625 14.1882C69.9879 14.1882 69.7245 14.2972 69.5304 14.4914C69.3362 14.6856 69.2272 14.9489 69.2272 15.2235C69.2272 15.498 69.3362 15.7614 69.5304 15.9555C69.7245 16.1497 69.9879 16.2588 70.2625 16.2588ZM43.8624 15.5293C43.7213 15.4588 43.5095 15.2941 43.2036 15.1058C42.3801 14.5411 41.7448 14.1176 41.3448 13.8117H43.9095V12.5882H41.5095C41.5566 12.4705 41.5566 11.2941 41.5566 10.9646C41.5801 10.6823 41.6036 10.447 41.6036 10.2823H43.5095V9.05876H39.5801C39.7683 8.72935 39.9095 8.37641 40.0272 7.95288L38.7095 7.83523C38.3801 8.89405 37.8154 9.8117 37.0154 10.5882C37.3448 10.9176 37.533 11.1293 37.6036 11.2705C37.7213 11.3882 37.7919 11.5058 37.886 11.5764C38.333 11.1293 38.6624 10.7058 38.9213 10.2823H40.2389C40.2389 10.7764 40.1919 12.1646 40.1213 12.5646H37.133V13.7882H39.8625C39.5095 14.6352 38.5448 15.3882 37.0389 15.9999C37.3213 16.3999 37.6036 16.8235 37.8625 17.2941C38.1448 17.0823 38.4507 16.9176 38.733 16.7999V23.5293H40.1448V22.847H47.0625V23.5293H48.5213V16.7529H43.086L43.8624 15.5293ZM38.8036 16.7293C39.7919 16.1176 40.4272 15.4823 40.7566 14.847C40.8977 14.9176 41.086 15.0823 41.2977 15.2705C42.0507 15.8823 42.6625 16.3764 43.086 16.7293H38.8036ZM47.0625 21.7646H40.1448V20.4235H47.0625V21.7646ZM47.0625 19.3176H40.1448V18.0235H47.0625V19.3176Z",
+ "fill": "#3859FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M44.4507 15.6941H49.5095V8.94111H44.4507V15.6941ZM45.7683 10.3058H48.2154V14.4235H45.7683V10.3058ZM54.4742 11.3882L55.7213 10.5411C55.0389 9.55288 54.4507 8.79994 53.9801 8.2117L52.8977 8.94111C53.0389 9.17641 53.2507 9.52935 53.5566 9.97641C54.0036 10.6352 54.3095 11.1058 54.4742 11.3882ZM64.0272 13.9764C64.1448 13.8588 64.286 13.647 64.4742 13.3646C64.8742 12.847 65.1566 12.447 65.2977 12.2117L64.3095 11.5293C64.0977 11.9058 63.6742 12.4705 63.0625 13.247L64.0272 13.9764ZM58.4507 13.247C58.3095 13.0352 58.0977 12.7529 57.7919 12.3999C57.5095 11.9999 57.2742 11.7176 57.133 11.5529L56.2154 12.2352C56.7566 12.9646 57.1801 13.5529 57.4624 13.9999L58.4507 13.247ZM55.2977 20.2823C55.1801 20.3999 55.1095 20.4941 55.086 20.5176V13.9293H52.5213V15.4588H53.6742V20.8941C53.6742 21.4352 53.5566 21.8117 53.2977 22.047L54.1683 23.3882C54.686 22.7058 55.4624 21.8823 56.4977 20.9411C56.3801 20.2117 56.3095 19.647 56.2154 19.2235C56.0507 19.4823 55.7448 19.8352 55.2977 20.2823ZM54.1683 23.4117V23.3882L54.1448 23.4117H54.1683ZM57.0389 23.5764H58.4036V22.9646H63.0389V23.5764H64.4507V17.0352H57.0389V23.5764ZM58.4036 18.2588H63.0389V19.5529H58.4036V18.2588ZM58.4036 20.5882H63.0389V21.8117H58.4036V20.5882Z",
+ "fill": "#3859FF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M65.3213 10.7999V9.647H62.9213C63.2742 9.08229 63.5095 8.72935 63.5801 8.6117C63.6977 8.39994 63.7683 8.25876 63.8625 8.18817L62.4977 7.88229C62.1683 8.49405 61.8154 9.08229 61.4154 9.647H60.0977C59.9566 9.4117 59.7213 9.03523 59.3919 8.54111C59.2036 8.25876 59.0625 8.02347 58.9448 7.85876L57.6272 8.16464C57.8154 8.39994 58.1213 8.89405 58.5448 9.62347H56.2625V10.7764H58.8272V14.7764H55.7683V15.9293H65.6742V14.7764H62.5213V10.7999H65.3213ZM61.3448 14.7764H60.0977V10.7764H61.3448V14.7764Z",
+ "fill": "#3859FF"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ZhipuaiTextCn"
+}
diff --git a/app/components/base/icons/src/public/llm/ZhipuaiTextCn.tsx b/app/components/base/icons/src/public/llm/ZhipuaiTextCn.tsx
new file mode 100644
index 0000000..5311241
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/ZhipuaiTextCn.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ZhipuaiTextCn.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ZhipuaiTextCn'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/llm/index.ts b/app/components/base/icons/src/public/llm/index.ts
new file mode 100644
index 0000000..cc9b531
--- /dev/null
+++ b/app/components/base/icons/src/public/llm/index.ts
@@ -0,0 +1,42 @@
+export { default as AnthropicDark } from './AnthropicDark'
+export { default as AnthropicLight } from './AnthropicLight'
+export { default as AnthropicText } from './AnthropicText'
+export { default as Anthropic } from './Anthropic'
+export { default as AzureOpenaiServiceText } from './AzureOpenaiServiceText'
+export { default as AzureOpenaiService } from './AzureOpenaiService'
+export { default as AzureaiText } from './AzureaiText'
+export { default as Azureai } from './Azureai'
+export { default as BaichuanText } from './BaichuanText'
+export { default as Baichuan } from './Baichuan'
+export { default as ChatglmText } from './ChatglmText'
+export { default as Chatglm } from './Chatglm'
+export { default as CohereText } from './CohereText'
+export { default as Cohere } from './Cohere'
+export { default as Gpt3 } from './Gpt3'
+export { default as Gpt4 } from './Gpt4'
+export { default as HuggingfaceTextHub } from './HuggingfaceTextHub'
+export { default as HuggingfaceText } from './HuggingfaceText'
+export { default as Huggingface } from './Huggingface'
+export { default as IflytekSparkTextCn } from './IflytekSparkTextCn'
+export { default as IflytekSparkText } from './IflytekSparkText'
+export { default as IflytekSpark } from './IflytekSpark'
+export { default as JinaText } from './JinaText'
+export { default as Jina } from './Jina'
+export { default as LocalaiText } from './LocalaiText'
+export { default as Localai } from './Localai'
+export { default as Microsoft } from './Microsoft'
+export { default as OpenaiBlack } from './OpenaiBlack'
+export { default as OpenaiBlue } from './OpenaiBlue'
+export { default as OpenaiGreen } from './OpenaiGreen'
+export { default as OpenaiText } from './OpenaiText'
+export { default as OpenaiTransparent } from './OpenaiTransparent'
+export { default as OpenaiViolet } from './OpenaiViolet'
+export { default as OpenllmText } from './OpenllmText'
+export { default as Openllm } from './Openllm'
+export { default as ReplicateText } from './ReplicateText'
+export { default as Replicate } from './Replicate'
+export { default as XorbitsInferenceText } from './XorbitsInferenceText'
+export { default as XorbitsInference } from './XorbitsInference'
+export { default as ZhipuaiTextCn } from './ZhipuaiTextCn'
+export { default as ZhipuaiText } from './ZhipuaiText'
+export { default as Zhipuai } from './Zhipuai'
diff --git a/app/components/base/icons/src/public/model/Checked.json b/app/components/base/icons/src/public/model/Checked.json
new file mode 100644
index 0000000..7e96db7
--- /dev/null
+++ b/app/components/base/icons/src/public/model/Checked.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.3332 4L5.99984 11.3333L2.6665 8",
+ "stroke": "#155EEF",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Checked"
+}
diff --git a/app/components/base/icons/src/public/model/Checked.tsx b/app/components/base/icons/src/public/model/Checked.tsx
new file mode 100644
index 0000000..ec8b54f
--- /dev/null
+++ b/app/components/base/icons/src/public/model/Checked.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Checked.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Checked'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/model/index.ts b/app/components/base/icons/src/public/model/index.ts
new file mode 100644
index 0000000..719a6f0
--- /dev/null
+++ b/app/components/base/icons/src/public/model/index.ts
@@ -0,0 +1 @@
+export { default as Checked } from './Checked'
diff --git a/app/components/base/icons/src/public/other/DefaultToolIcon.json b/app/components/base/icons/src/public/other/DefaultToolIcon.json
new file mode 100644
index 0000000..32786d2
--- /dev/null
+++ b/app/components/base/icons/src/public/other/DefaultToolIcon.json
@@ -0,0 +1,81 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "opacity": "0.5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "rx": "6",
+ "fill": "#E5E7EB"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "0.25",
+ "y": "0.25",
+ "width": "23.5",
+ "height": "23.5",
+ "rx": "5.75",
+ "stroke": "black",
+ "stroke-opacity": "0.05",
+ "stroke-width": "0.5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.8876 5.30588C11.9601 5.26959 12.019 5.21074 12.0553 5.13817L12.414 4.4208C12.5522 4.1444 12.9466 4.1444 13.0848 4.4208L13.4435 5.13817C13.4797 5.21074 13.5386 5.26959 13.6112 5.30588L14.3285 5.66457C14.6049 5.80276 14.6049 6.19719 14.3285 6.33539L13.6112 6.69407C13.5386 6.73036 13.4797 6.78921 13.4435 6.86178L13.0848 7.57916C12.9466 7.85555 12.5522 7.85555 12.414 7.57916L12.0553 6.86178C12.019 6.78921 11.9601 6.73036 11.8876 6.69407L11.1702 6.33539C10.8938 6.19719 10.8938 5.80276 11.1702 5.66457L11.8876 5.30588Z",
+ "fill": "#667085"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.88756 6.55588C7.96013 6.51959 8.01898 6.46074 8.05527 6.38817L8.28895 5.9208C8.42715 5.6444 8.82158 5.6444 8.95978 5.9208L9.19346 6.38817C9.22975 6.46074 9.2886 6.51959 9.36117 6.55588L9.82854 6.78956C10.1049 6.92776 10.1049 7.32219 9.82854 7.46039L9.36117 7.69407C9.2886 7.73036 9.22975 7.78921 9.19346 7.86178L8.95978 8.32915C8.82158 8.60555 8.42715 8.60555 8.28895 8.32915L8.05527 7.86178C8.01898 7.78921 7.96013 7.73036 7.88756 7.69407L7.42019 7.46039C7.14379 7.32219 7.14379 6.92776 7.42019 6.78957L7.88756 6.55588Z",
+ "fill": "#667085"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M17.9417 5.91012C18.1985 6.08504 18.2648 6.43496 18.0899 6.6917L16.0062 9.74998H17.4375C17.7482 9.74998 18 10.0018 18 10.3125V18.1875C18 18.9124 17.4124 19.5 16.6875 19.5H7.3125C6.58763 19.5 6 18.9123 6 18.1875V10.3125C6 10.0018 6.25184 9.74998 6.5625 9.74998H14.6449L17.1601 6.05826C17.3351 5.80152 17.685 5.7352 17.9417 5.91012ZM10.3125 12.75C10.0018 12.75 9.75 13.0018 9.75 13.3125C9.75 13.6231 10.0018 13.875 10.3125 13.875H13.6875C13.9982 13.875 14.25 13.6231 14.25 13.3125C14.25 13.0018 13.9982 12.75 13.6875 12.75H10.3125Z",
+ "fill": "#667085"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "DefaultToolIcon"
+}
diff --git a/app/components/base/icons/src/public/other/DefaultToolIcon.tsx b/app/components/base/icons/src/public/other/DefaultToolIcon.tsx
new file mode 100644
index 0000000..dd28b8a
--- /dev/null
+++ b/app/components/base/icons/src/public/other/DefaultToolIcon.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './DefaultToolIcon.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'DefaultToolIcon'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/other/Icon3Dots.json b/app/components/base/icons/src/public/other/Icon3Dots.json
new file mode 100644
index 0000000..b59b293
--- /dev/null
+++ b/app/components/base/icons/src/public/other/Icon3Dots.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103",
+ "stroke": "#667085",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Icon3Dots"
+}
diff --git a/app/components/base/icons/src/public/other/Icon3Dots.tsx b/app/components/base/icons/src/public/other/Icon3Dots.tsx
new file mode 100644
index 0000000..bcc2cee
--- /dev/null
+++ b/app/components/base/icons/src/public/other/Icon3Dots.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Icon3Dots.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Icon3Dots'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/other/Message3Fill.json b/app/components/base/icons/src/public/other/Message3Fill.json
new file mode 100644
index 0000000..ae84890
--- /dev/null
+++ b/app/components/base/icons/src/public/other/Message3Fill.json
@@ -0,0 +1,173 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "message-3-fill"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector",
+ "filter": "url(#filter0_d_1071_49501)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2 8.99374C2 5.68349 4.67654 3 8.00066 3H15.9993C19.3134 3 22 5.69478 22 8.99374V21H8.00066C4.68659 21 2 18.3052 2 15.0063V8.99374ZM14 11V13H16V11H14ZM8 11V13H10V11H8Z",
+ "fill": "url(#paint0_linear_1071_49501)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_1071_49501",
+ "x": "1.5",
+ "y": "2.75",
+ "width": "21",
+ "height": "19",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feComposite",
+ "attributes": {
+ "in2": "hardAlpha",
+ "operator": "out"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_1071_49501"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_1071_49501",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_1071_49501",
+ "x1": "12",
+ "y1": "3",
+ "x2": "12",
+ "y2": "21",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#296DFF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#0BA5EC"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Message3Fill"
+}
diff --git a/app/components/base/icons/src/public/other/Message3Fill.tsx b/app/components/base/icons/src/public/other/Message3Fill.tsx
new file mode 100644
index 0000000..0411377
--- /dev/null
+++ b/app/components/base/icons/src/public/other/Message3Fill.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Message3Fill.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Message3Fill'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/other/RowStruct.json b/app/components/base/icons/src/public/other/RowStruct.json
new file mode 100644
index 0000000..49ef717
--- /dev/null
+++ b/app/components/base/icons/src/public/other/RowStruct.json
@@ -0,0 +1,56 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "624",
+ "height": "48",
+ "viewBox": "0 0 624 48",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "8",
+ "y": "7",
+ "width": "16",
+ "height": "16",
+ "rx": "5",
+ "fill": "#F2F4F7"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "32",
+ "y": "10",
+ "width": "233",
+ "height": "10",
+ "rx": "3",
+ "fill": "#EAECF0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "x": "32",
+ "y": "31",
+ "width": "345",
+ "height": "6",
+ "rx": "3",
+ "fill": "#F2F4F7"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "RowStruct"
+}
diff --git a/app/components/base/icons/src/public/other/RowStruct.tsx b/app/components/base/icons/src/public/other/RowStruct.tsx
new file mode 100644
index 0000000..14487c8
--- /dev/null
+++ b/app/components/base/icons/src/public/other/RowStruct.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './RowStruct.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'RowStruct'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/other/index.ts b/app/components/base/icons/src/public/other/index.ts
new file mode 100644
index 0000000..a7558ca
--- /dev/null
+++ b/app/components/base/icons/src/public/other/index.ts
@@ -0,0 +1,4 @@
+export { default as Icon3Dots } from './Icon3Dots'
+export { default as DefaultToolIcon } from './DefaultToolIcon'
+export { default as Message3Fill } from './Message3Fill'
+export { default as RowStruct } from './RowStruct'
diff --git a/app/components/base/icons/src/public/plugins/Google.json b/app/components/base/icons/src/public/plugins/Google.json
new file mode 100644
index 0000000..198050e
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/Google.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M22.501 12.2331C22.501 11.3698 22.4296 10.7398 22.2748 10.0864H12.2153V13.983H18.12C18.001 14.9514 17.3582 16.4097 15.9296 17.3897L15.9096 17.5202L19.0902 19.9349L19.3106 19.9564C21.3343 18.1247 22.501 15.4297 22.501 12.2331Z",
+ "fill": "#4285F4"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.2147 22.5001C15.1075 22.5001 17.5361 21.5667 19.3099 19.9567L15.929 17.39C15.0242 18.0083 13.8099 18.44 12.2147 18.44C9.38142 18.44 6.97669 16.6083 6.11947 14.0767L5.99382 14.0871L2.68656 16.5955L2.64331 16.7133C4.40519 20.1433 8.02423 22.5001 12.2147 22.5001Z",
+ "fill": "#34A853"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.11997 14.0765C5.89379 13.4232 5.76289 12.7231 5.76289 11.9998C5.76289 11.2764 5.89379 10.5765 6.10807 9.92313L6.10208 9.78398L2.75337 7.23535L2.64381 7.28642C1.91765 8.70977 1.50098 10.3081 1.50098 11.9998C1.50098 13.6915 1.91765 15.2897 2.64381 16.7131L6.11997 14.0765Z",
+ "fill": "#FBBC05"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.2148 5.55997C14.2267 5.55997 15.5838 6.41163 16.3576 7.12335L19.3814 4.23C17.5243 2.53834 15.1076 1.5 12.2148 1.5C8.02426 1.5 4.4052 3.85665 2.64331 7.28662L6.10759 9.92332C6.97672 7.39166 9.38146 5.55997 12.2148 5.55997Z",
+ "fill": "#EB4335"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Google"
+}
diff --git a/app/components/base/icons/src/public/plugins/Google.tsx b/app/components/base/icons/src/public/plugins/Google.tsx
new file mode 100644
index 0000000..7d8d667
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/Google.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Google.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Google'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/plugins/PartnerDark.json b/app/components/base/icons/src/public/plugins/PartnerDark.json
new file mode 100644
index 0000000..af3f208
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/PartnerDark.json
@@ -0,0 +1,447 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "viewBox": "0 0 20 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Partner"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_6296_109592",
+ "style": "mask-type:alpha",
+ "maskUnits": "userSpaceOnUse",
+ "x": "1",
+ "y": "0",
+ "width": "18",
+ "height": "20"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Mask"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z",
+ "fill": "#932F19"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z",
+ "fill": "url(#paint0_linear_6296_109592)",
+ "fill-opacity": "0.9"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.47222 1.78016C8.45993 1.20991 8.90155 0.958665 9.36471 0.860217C9.78356 0.771189 10.2164 0.771189 10.6353 0.860217C11.0984 0.958665 11.5401 1.20991 12.5278 1.78016L15.8547 3.70096C16.8424 4.27121 17.2808 4.52805 17.5976 4.87994C17.8842 5.19815 18.1006 5.57304 18.2329 5.98028C18.3792 6.43061 18.3825 6.9387 18.3825 8.0792V11.9208C18.3825 13.0613 18.3792 13.5694 18.2329 14.0197C18.1006 14.427 17.8842 14.8018 17.5976 15.1201C17.2808 15.4719 16.8424 15.7288 15.8547 16.299L12.5278 18.2198C11.5401 18.7901 11.0984 19.0413 10.6353 19.1398C10.2164 19.2288 9.78356 19.2288 9.36471 19.1398C8.90155 19.0413 8.45993 18.7901 7.47222 18.2198L4.1453 16.299C3.1576 15.7288 2.7192 15.4719 2.40236 15.1201C2.11584 14.8018 1.89939 14.427 1.76707 14.0197C1.62075 13.5694 1.61752 13.0613 1.61752 11.9208V8.0792C1.61752 6.9387 1.62075 6.43061 1.76707 5.98028C1.89939 5.57304 2.11584 5.19815 2.40236 4.87994C2.7192 4.52805 3.1576 4.27121 4.1453 3.70096L7.47222 1.78016Z",
+ "stroke": "url(#paint1_linear_6296_109592)",
+ "stroke-opacity": "0.8",
+ "stroke-width": "0.555556"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_6296_109592)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "badge-bg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z",
+ "fill": "#932F19"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z",
+ "fill": "url(#paint2_linear_6296_109592)",
+ "fill-opacity": "0.9"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.58333 1.97261C8.58402 1.39487 8.99036 1.16698 9.41092 1.07758C9.7993 0.99503 10.2007 0.99503 10.5891 1.07758C11.0096 1.16698 11.416 1.39487 12.4167 1.97261L15.7436 3.89341C16.7443 4.47116 17.1448 4.70911 17.4325 5.02863C17.6982 5.3237 17.8989 5.67133 18.0216 6.04895C18.1544 6.45786 18.1603 6.92371 18.1603 8.0792V11.9208C18.1603 13.0763 18.1544 13.5421 18.0216 13.951C17.8989 14.3287 17.6982 14.6763 17.4325 14.9714C17.1448 15.2909 16.7443 15.5288 15.7436 16.1066L12.4167 18.0274C11.416 18.6051 11.0096 18.833 10.5891 18.9224C10.2007 19.005 9.7993 19.005 9.41092 18.9224C8.99036 18.833 8.58402 18.6051 7.58333 18.0274L4.25641 16.1066C3.25572 15.5288 2.8552 15.2909 2.5675 14.9714C2.30182 14.6763 2.10112 14.3287 1.97842 13.951C1.84556 13.5421 1.83975 13.0763 1.83975 11.9208V8.0792C1.83975 6.92371 1.84556 6.45786 1.97842 6.04895C2.10112 5.67133 2.30182 5.3237 2.5675 5.02863C2.8552 4.70911 3.25572 4.47116 4.25641 3.89341L7.58333 1.97261Z",
+ "stroke": "url(#paint3_linear_6296_109592)",
+ "stroke-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "handshake",
+ "filter": "url(#filter0_d_6296_109592)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.0969 9.64841C10.895 9.44642 10.5675 9.44642 10.3656 9.64841L9.99991 10.0141C9.59596 10.418 8.94109 10.418 8.53717 10.0141C8.13325 9.61015 8.13325 8.95527 8.53717 8.55135L11.4491 5.63868C12.5371 5.39255 13.7238 5.69302 14.5709 6.54011C15.8221 7.79128 15.8807 9.78339 14.7469 11.104L13.6567 12.2081L11.0969 9.64841ZM5.42889 6.54011C6.55286 5.41614 8.27475 5.25452 9.57067 6.05524L7.80581 7.81999C6.99797 8.62783 6.99797 9.9376 7.80581 10.7454C8.58917 11.5288 9.8445 11.5525 10.6564 10.8167L10.7313 10.7454L12.9253 12.9395L10.7313 15.1336C10.3273 15.5375 9.67245 15.5375 9.26855 15.1336L5.42889 11.2939C4.11615 9.9812 4.11615 7.85284 5.42889 6.54011Z",
+ "fill": "url(#paint4_linear_6296_109592)",
+ "shape-rendering": "crispEdges"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "highlight",
+ "opacity": "0.5",
+ "d": "M0 0H15.5556L5.26663 20H0V0Z",
+ "fill": "url(#paint5_linear_6296_109592)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_6296_109592",
+ "x": "3.94434",
+ "y": "5.30556",
+ "width": "12.1111",
+ "height": "10.881",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feComposite",
+ "attributes": {
+ "in2": "hardAlpha",
+ "operator": "out"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_6296_109592"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_6296_109592",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_6296_109592",
+ "x1": "0",
+ "y1": "0",
+ "x2": "22.6412",
+ "y2": "1.78551",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#FF692E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#E04F16"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_6296_109592",
+ "x1": "8.55422",
+ "y1": "-1.28187e-07",
+ "x2": "19.7802",
+ "y2": "12.7346",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#FF4405"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint2_linear_6296_109592",
+ "x1": "0",
+ "y1": "0",
+ "x2": "22.6412",
+ "y2": "1.78551",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#FF692E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#E04F16"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint3_linear_6296_109592",
+ "x1": "8.55422",
+ "y1": "-1.28187e-07",
+ "x2": "19.7802",
+ "y2": "12.7346",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#FF4405"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint4_linear_6296_109592",
+ "x1": "9.99989",
+ "y1": "5.55556",
+ "x2": "9.99989",
+ "y2": "15.4365",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.95"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white",
+ "stop-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint5_linear_6296_109592",
+ "x1": "-4.78632",
+ "y1": "4.375",
+ "x2": "16.2164",
+ "y2": "10.4",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.12"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "PartnerDark"
+}
diff --git a/app/components/base/icons/src/public/plugins/PartnerDark.tsx b/app/components/base/icons/src/public/plugins/PartnerDark.tsx
new file mode 100644
index 0000000..4277762
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/PartnerDark.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './PartnerDark.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'PartnerDark'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/plugins/PartnerLight.json b/app/components/base/icons/src/public/plugins/PartnerLight.json
new file mode 100644
index 0000000..3d7391b
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/PartnerLight.json
@@ -0,0 +1,446 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "viewBox": "0 0 20 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Partner"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_6291_109635",
+ "style": "mask-type:alpha",
+ "maskUnits": "userSpaceOnUse",
+ "x": "1",
+ "y": "0",
+ "width": "18",
+ "height": "20"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Mask"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z",
+ "fill": "#F9DBAF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z",
+ "fill": "url(#paint0_linear_6291_109635)",
+ "fill-opacity": "0.9"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.47222 1.78016C8.45993 1.20991 8.90155 0.958665 9.36471 0.860217C9.78356 0.771189 10.2164 0.771189 10.6353 0.860217C11.0984 0.958665 11.5401 1.20991 12.5278 1.78016L15.8547 3.70096C16.8424 4.27121 17.2808 4.52805 17.5976 4.87994C17.8842 5.19815 18.1006 5.57304 18.2329 5.98028C18.3792 6.43061 18.3825 6.9387 18.3825 8.0792V11.9208C18.3825 13.0613 18.3792 13.5694 18.2329 14.0197C18.1006 14.427 17.8842 14.8018 17.5976 15.1201C17.2808 15.4719 16.8424 15.7288 15.8547 16.299L12.5278 18.2198C11.5401 18.7901 11.0984 19.0413 10.6353 19.1398C10.2164 19.2288 9.78356 19.2288 9.36471 19.1398C8.90155 19.0413 8.45993 18.7901 7.47222 18.2198L4.1453 16.299C3.1576 15.7288 2.7192 15.4719 2.40236 15.1201C2.11584 14.8018 1.89939 14.427 1.76707 14.0197C1.62075 13.5694 1.61752 13.0613 1.61752 11.9208V8.0792C1.61752 6.9387 1.62075 6.43061 1.76707 5.98028C1.89939 5.57304 2.11584 5.19815 2.40236 4.87994C2.7192 4.52805 3.1576 4.27121 4.1453 3.70096L7.47222 1.78016Z",
+ "stroke": "url(#paint1_linear_6291_109635)",
+ "stroke-opacity": "0.8",
+ "stroke-width": "0.555556"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_6291_109635)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "badge-bg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z",
+ "fill": "#F9DBAF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33333 1.5396C8.30481 0.978718 8.79055 0.698276 9.30696 0.58851C9.76388 0.491388 10.2361 0.491388 10.693 0.58851C11.2094 0.698276 11.6952 0.978718 12.6667 1.5396L15.9936 3.4604C16.9651 4.02128 17.4508 4.30172 17.8041 4.69407C18.1166 5.04121 18.3528 5.45018 18.4971 5.89444C18.6603 6.39655 18.6603 6.95744 18.6603 8.0792V11.9208C18.6603 13.0426 18.6603 13.6034 18.4971 14.1056C18.3528 14.5498 18.1166 14.9588 17.8041 15.3059C17.4508 15.6983 16.9651 15.9787 15.9936 16.5396L12.6667 18.4604C11.6952 19.0213 11.2094 19.3017 10.693 19.4115C10.2361 19.5086 9.76388 19.5086 9.30696 19.4115C8.79055 19.3017 8.30481 19.0213 7.33333 18.4604L4.00641 16.5396C3.03493 15.9787 2.5492 15.6983 2.19593 15.3059C1.88336 14.9588 1.64724 14.5498 1.50289 14.1056C1.33975 13.6034 1.33975 13.0426 1.33975 11.9208V8.0792C1.33975 6.95744 1.33975 6.39655 1.50289 5.89444C1.64724 5.45018 1.88336 5.04121 2.19593 4.69407C2.5492 4.30172 3.03493 4.02128 4.00641 3.4604L7.33333 1.5396Z",
+ "fill": "url(#paint2_linear_6291_109635)",
+ "fill-opacity": "0.9"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.58333 1.97261C8.58402 1.39487 8.99036 1.16698 9.41092 1.07758C9.7993 0.99503 10.2007 0.99503 10.5891 1.07758C11.0096 1.16698 11.416 1.39487 12.4167 1.97261L15.7436 3.89341C16.7443 4.47116 17.1448 4.70911 17.4325 5.02863C17.6982 5.3237 17.8989 5.67133 18.0216 6.04895C18.1544 6.45786 18.1603 6.92371 18.1603 8.0792V11.9208C18.1603 13.0763 18.1544 13.5421 18.0216 13.951C17.8989 14.3287 17.6982 14.6763 17.4325 14.9714C17.1448 15.2909 16.7443 15.5288 15.7436 16.1066L12.4167 18.0274C11.416 18.6051 11.0096 18.833 10.5891 18.9224C10.2007 19.005 9.7993 19.005 9.41092 18.9224C8.99036 18.833 8.58402 18.6051 7.58333 18.0274L4.25641 16.1066C3.25572 15.5288 2.8552 15.2909 2.5675 14.9714C2.30182 14.6763 2.10112 14.3287 1.97842 13.951C1.84556 13.5421 1.83975 13.0763 1.83975 11.9208V8.0792C1.83975 6.92371 1.84556 6.45786 1.97842 6.04895C2.10112 5.67133 2.30182 5.3237 2.5675 5.02863C2.8552 4.70911 3.25572 4.47116 4.25641 3.89341L7.58333 1.97261Z",
+ "stroke": "url(#paint3_linear_6291_109635)",
+ "stroke-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "handshake",
+ "filter": "url(#filter0_d_6291_109635)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.0969 9.64852C10.895 9.44652 10.5675 9.44652 10.3656 9.64852L9.99991 10.0142C9.59596 10.4181 8.94109 10.4181 8.53717 10.0142C8.13325 9.61025 8.13325 8.95537 8.53717 8.55146L11.4491 5.63879C12.5371 5.39265 13.7238 5.69313 14.5709 6.54022C15.8221 7.79139 15.8807 9.7835 14.7469 11.1041L13.6567 12.2083L11.0969 9.64852ZM5.42889 6.54022C6.55286 5.41625 8.27475 5.25463 9.57067 6.05534L7.80581 7.8201C6.99797 8.62794 6.99797 9.93771 7.80581 10.7456C8.58917 11.5289 9.8445 11.5526 10.6564 10.8168L10.7313 10.7456L12.9253 12.9396L10.7313 15.1337C10.3273 15.5376 9.67245 15.5376 9.26855 15.1337L5.42889 11.294C4.11615 9.98131 4.11615 7.85295 5.42889 6.54022Z",
+ "fill": "url(#paint4_linear_6291_109635)",
+ "shape-rendering": "crispEdges"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "highlight",
+ "opacity": "0.5",
+ "d": "M0 0H15.5556L5.26663 20H0V0Z",
+ "fill": "url(#paint5_linear_6291_109635)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_6291_109635",
+ "x": "3.94434",
+ "y": "5.30566",
+ "width": "12.1111",
+ "height": "10.8809",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feComposite",
+ "attributes": {
+ "in2": "hardAlpha",
+ "operator": "out"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_6291_109635"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_6291_109635",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_6291_109635",
+ "x1": "0",
+ "y1": "0",
+ "x2": "22.6412",
+ "y2": "1.78551",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#FF692E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#E04F16"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_6291_109635",
+ "x1": "8.55422",
+ "y1": "-1.28187e-07",
+ "x2": "19.7802",
+ "y2": "12.7346",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.95"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#E62E05"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint2_linear_6291_109635",
+ "x1": "0",
+ "y1": "0",
+ "x2": "22.6412",
+ "y2": "1.78551",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#FF692E"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#E04F16"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint3_linear_6291_109635",
+ "x1": "8.55422",
+ "y1": "-1.28187e-07",
+ "x2": "19.7802",
+ "y2": "12.7346",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.95"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#E62E05"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint4_linear_6291_109635",
+ "x1": "9.99989",
+ "y1": "5.55566",
+ "x2": "9.99989",
+ "y2": "15.4366",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white",
+ "stop-opacity": "0.9"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint5_linear_6291_109635",
+ "x1": "-4.78632",
+ "y1": "4.375",
+ "x2": "16.2164",
+ "y2": "10.4",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.12"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white",
+ "stop-opacity": "0.3"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "PartnerLight"
+}
diff --git a/app/components/base/icons/src/public/plugins/PartnerLight.tsx b/app/components/base/icons/src/public/plugins/PartnerLight.tsx
new file mode 100644
index 0000000..3591c96
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/PartnerLight.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './PartnerLight.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'PartnerLight'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/plugins/VerifiedDark.json b/app/components/base/icons/src/public/plugins/VerifiedDark.json
new file mode 100644
index 0000000..ed22826
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/VerifiedDark.json
@@ -0,0 +1,457 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "viewBox": "0 0 20 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Verified"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_6296_109593",
+ "style": "mask-type:alpha",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "0",
+ "width": "20",
+ "height": "20"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Mask"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.08817 1.62521C9.14394 0.569383 10.8558 0.569374 11.9116 1.62521L12.8128 2.52641C12.9819 2.69542 13.2111 2.79037 13.4501 2.79037H14.5059C15.9991 2.79037 17.2095 4.00082 17.2095 5.49398V6.54981C17.2095 6.78882 17.3045 7.01805 17.4735 7.18706L18.3747 8.08826C19.4305 9.1441 19.4305 10.8559 18.3747 11.9118L17.4735 12.813C17.3045 12.982 17.2095 13.2112 17.2095 13.4502V14.506C17.2095 15.9992 15.9991 17.2096 14.5059 17.2096H13.4501C13.2111 17.2096 12.9819 17.3046 12.8128 17.4736L11.9116 18.3748C10.8558 19.4306 9.14403 19.4306 8.08817 18.3748L7.18696 17.4736C7.01795 17.3046 6.78873 17.2096 6.54972 17.2096H5.49389C4.00072 17.2096 2.79028 15.9992 2.79028 14.506V13.4502C2.79028 13.2112 2.69533 12.982 2.52632 12.813L1.62513 11.9118C0.569295 10.8559 0.569295 9.1441 1.62512 8.08826L2.52632 7.18706C2.69533 7.01806 2.79028 6.78882 2.79028 6.54981V5.49398C2.79028 4.00082 4.00072 2.79037 5.49389 2.79037H6.54972C6.78873 2.79037 7.01795 2.69542 7.18696 2.52641L8.08817 1.62521Z",
+ "fill": "#003DC1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.08817 1.62521C9.14394 0.569383 10.8558 0.569374 11.9116 1.62521L12.8128 2.52641C12.9819 2.69542 13.2111 2.79037 13.4501 2.79037H14.5059C15.9991 2.79037 17.2095 4.00082 17.2095 5.49398V6.54981C17.2095 6.78882 17.3045 7.01805 17.4735 7.18706L18.3747 8.08826C19.4305 9.1441 19.4305 10.8559 18.3747 11.9118L17.4735 12.813C17.3045 12.982 17.2095 13.2112 17.2095 13.4502V14.506C17.2095 15.9992 15.9991 17.2096 14.5059 17.2096H13.4501C13.2111 17.2096 12.9819 17.3046 12.8128 17.4736L11.9116 18.3748C10.8558 19.4306 9.14403 19.4306 8.08817 18.3748L7.18696 17.4736C7.01795 17.3046 6.78873 17.2096 6.54972 17.2096H5.49389C4.00072 17.2096 2.79028 15.9992 2.79028 14.506V13.4502C2.79028 13.2112 2.69533 12.982 2.52632 12.813L1.62513 11.9118C0.569295 10.8559 0.569295 9.1441 1.62512 8.08826L2.52632 7.18706C2.69533 7.01806 2.79028 6.78882 2.79028 6.54981V5.49398C2.79028 4.00082 4.00072 2.79037 5.49389 2.79037H6.54972C6.78873 2.79037 7.01795 2.69542 7.18696 2.52641L8.08817 1.62521Z",
+ "fill": "url(#paint0_linear_6296_109593)",
+ "fill-opacity": "0.9"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.27881 1.81585L8.27881 1.81585C9.2293 0.865317 10.7704 0.865301 11.721 1.81585L12.6222 2.71705L12.6222 2.71709C12.8418 2.9366 13.1395 3.05997 13.4501 3.05997H14.5059C15.8502 3.05997 16.9399 4.14972 16.9399 5.49398V6.54981C16.9399 6.86036 17.0633 7.15813 17.2828 7.37768L17.2829 7.3777L18.1841 8.2789L18.3747 8.08826L18.1841 8.27891C19.1346 9.22945 19.1346 10.7706 18.1841 11.7211L17.2829 12.6224C17.0633 12.8419 16.9399 13.1397 16.9399 13.4502V14.506C16.9399 15.8503 15.8502 16.94 14.5059 16.94H13.4501C13.1395 16.94 12.8418 17.0634 12.6222 17.2829L12.6222 17.2829L11.721 18.1841C10.7704 19.1347 9.22939 19.1347 8.27881 18.1841L7.37761 17.2829L7.37759 17.2829C7.15804 17.0634 6.86027 16.94 6.54972 16.94H5.49389C4.14962 16.94 3.05989 15.8503 3.05989 14.506V13.4502C3.05989 13.1398 2.93655 12.8419 2.71696 12.6224C2.71696 12.6223 2.71695 12.6223 2.71694 12.6223L1.81577 11.7211C0.865224 10.7706 0.865226 9.22945 1.81576 8.2789L2.71696 7.3777C2.71696 7.3777 2.71696 7.3777 2.71696 7.3777C2.93654 7.15813 3.05989 6.86033 3.05989 6.54981V5.49398C3.05989 4.14972 4.14963 3.05997 5.49389 3.05997H6.54972C6.86024 3.05997 7.15803 2.93662 7.3776 2.71706L7.37761 2.71705L8.27881 1.81585Z",
+ "stroke": "url(#paint1_linear_6296_109593)",
+ "stroke-opacity": "0.8",
+ "stroke-width": "0.539216"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_6296_109593)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "badge-bg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.08817 1.62521C9.14394 0.569383 10.8558 0.569374 11.9116 1.62521L12.8128 2.52641C12.9819 2.69542 13.2111 2.79037 13.4501 2.79037H14.5059C15.9991 2.79037 17.2095 4.00082 17.2095 5.49398V6.54981C17.2095 6.78882 17.3045 7.01805 17.4735 7.18706L18.3747 8.08826C19.4305 9.1441 19.4305 10.8559 18.3747 11.9118L17.4735 12.813C17.3045 12.982 17.2095 13.2112 17.2095 13.4502V14.506C17.2095 15.9992 15.9991 17.2096 14.5059 17.2096H13.4501C13.2111 17.2096 12.9819 17.3046 12.8128 17.4736L11.9116 18.3748C10.8558 19.4306 9.14403 19.4306 8.08817 18.3748L7.18696 17.4736C7.01795 17.3046 6.78873 17.2096 6.54972 17.2096H5.49389C4.00072 17.2096 2.79028 15.9992 2.79028 14.506V13.4502C2.79028 13.2112 2.69533 12.982 2.52632 12.813L1.62513 11.9118C0.569295 10.8559 0.569295 9.1441 1.62512 8.08826L2.52632 7.18706C2.69533 7.01806 2.79028 6.78882 2.79028 6.54981V5.49398C2.79028 4.00082 4.00072 2.79037 5.49389 2.79037H6.54972C6.78873 2.79037 7.01795 2.69542 7.18696 2.52641L8.08817 1.62521Z",
+ "fill": "#003DC1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.08817 1.62521C9.14394 0.569383 10.8558 0.569374 11.9116 1.62521L12.8128 2.52641C12.9819 2.69542 13.2111 2.79037 13.4501 2.79037H14.5059C15.9991 2.79037 17.2095 4.00082 17.2095 5.49398V6.54981C17.2095 6.78882 17.3045 7.01805 17.4735 7.18706L18.3747 8.08826C19.4305 9.1441 19.4305 10.8559 18.3747 11.9118L17.4735 12.813C17.3045 12.982 17.2095 13.2112 17.2095 13.4502V14.506C17.2095 15.9992 15.9991 17.2096 14.5059 17.2096H13.4501C13.2111 17.2096 12.9819 17.3046 12.8128 17.4736L11.9116 18.3748C10.8558 19.4306 9.14403 19.4306 8.08817 18.3748L7.18696 17.4736C7.01795 17.3046 6.78873 17.2096 6.54972 17.2096H5.49389C4.00072 17.2096 2.79028 15.9992 2.79028 14.506V13.4502C2.79028 13.2112 2.69533 12.982 2.52632 12.813L1.62513 11.9118C0.569295 10.8559 0.569295 9.1441 1.62512 8.08826L2.52632 7.18706C2.69533 7.01806 2.79028 6.78882 2.79028 6.54981V5.49398C2.79028 4.00082 4.00072 2.79037 5.49389 2.79037H6.54972C6.78873 2.79037 7.01795 2.69542 7.18696 2.52641L8.08817 1.62521Z",
+ "fill": "url(#paint2_linear_6296_109593)",
+ "fill-opacity": "0.9"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.44172 1.97876L8.44173 1.97875C9.30224 1.11821 10.6975 1.11818 11.5581 1.97876L12.4593 2.87997L12.4593 2.88003C12.7221 3.1427 13.0784 3.29037 13.4501 3.29037H14.5059C15.723 3.29037 16.7095 4.27696 16.7095 5.49398V6.54981C16.7095 6.92148 16.8572 7.27785 17.1199 7.54057L17.1199 7.54061L18.0211 8.44182L18.3747 8.08826L18.0211 8.44182C18.8817 9.30239 18.8817 10.6976 18.0211 11.5582L17.1199 12.4594C16.8572 12.7222 16.7095 13.0786 16.7095 13.4502V14.506C16.7095 15.7231 15.723 16.7096 14.5059 16.7096H13.4501C13.0784 16.7096 12.7221 16.8573 12.4594 17.1199L12.4593 17.12L11.5581 18.0212C10.6975 18.8818 9.30233 18.8818 8.44172 18.0212L7.54052 17.12L7.54048 17.12C7.27775 16.8573 6.92139 16.7096 6.54972 16.7096H5.49389C4.27686 16.7096 3.29028 15.7231 3.29028 14.506V13.4502C3.29028 13.0787 3.14267 12.7222 2.87984 12.4594L1.97868 11.5582C1.11811 10.6976 1.11811 9.30238 1.97867 8.44181L2.87986 7.54062C2.87987 7.54062 2.87987 7.54061 2.87987 7.54061C3.14266 7.27784 3.29028 6.92143 3.29028 6.54981V5.49398C3.29028 4.27696 4.27687 3.29037 5.49389 3.29037H6.54972C6.92135 3.29037 7.27774 3.14273 7.54051 2.87998L7.54052 2.87997L8.44172 1.97876Z",
+ "stroke": "url(#paint3_linear_6296_109593)",
+ "stroke-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "check",
+ "filter": "url(#filter0_d_6296_109593)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M13.4219 6.98132C13.8732 7.28924 13.9829 7.89545 13.667 8.33533L10.04 13.3858C9.87754 13.612 9.62408 13.7602 9.34287 13.7934C9.06166 13.8266 8.77923 13.7417 8.56605 13.5599L6.49346 11.7923C6.0789 11.4387 6.03689 10.8245 6.39963 10.4204C6.76238 10.0163 7.39252 9.97533 7.80709 10.3289L9.04316 11.3831L12.0328 7.22026C12.3487 6.78038 12.9706 6.6734 13.4219 6.98132Z",
+ "fill": "url(#paint4_linear_6296_109593)",
+ "shape-rendering": "crispEdges"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "highlight",
+ "opacity": "0.5",
+ "d": "M0 0H15.5556L5.26663 20H0V0Z",
+ "fill": "url(#paint5_linear_6296_109593)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_6296_109593",
+ "x": "5.65283",
+ "y": "6.55549",
+ "width": "8.69458",
+ "height": "7.995",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feComposite",
+ "attributes": {
+ "in2": "hardAlpha",
+ "operator": "out"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_6296_109593"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_6296_109593",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_6296_109593",
+ "x1": "16.302",
+ "y1": "19.1667",
+ "x2": "-0.37184",
+ "y2": "14.8201",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#296DFF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#5289FF"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_6296_109593",
+ "x1": "8.67462",
+ "y1": "0.833336",
+ "x2": "18.9651",
+ "y2": "12.5067",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#296DFF"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint2_linear_6296_109593",
+ "x1": "16.302",
+ "y1": "19.1667",
+ "x2": "-0.37184",
+ "y2": "14.8201",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#296DFF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#5289FF"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint3_linear_6296_109593",
+ "x1": "8.67462",
+ "y1": "0.833336",
+ "x2": "18.9651",
+ "y2": "12.5067",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#296DFF"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint4_linear_6296_109593",
+ "x1": "10.0001",
+ "y1": "6.80549",
+ "x2": "10.0001",
+ "y2": "13.8005",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.95"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white",
+ "stop-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint5_linear_6296_109593",
+ "x1": "-4.78632",
+ "y1": "4.375",
+ "x2": "16.2164",
+ "y2": "10.4",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.12"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white",
+ "stop-opacity": "0.2"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "VerifiedDark"
+}
diff --git a/app/components/base/icons/src/public/plugins/VerifiedDark.tsx b/app/components/base/icons/src/public/plugins/VerifiedDark.tsx
new file mode 100644
index 0000000..03d045d
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/VerifiedDark.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './VerifiedDark.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'VerifiedDark'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/plugins/VerifiedLight.json b/app/components/base/icons/src/public/plugins/VerifiedLight.json
new file mode 100644
index 0000000..b31fe65
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/VerifiedLight.json
@@ -0,0 +1,456 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "viewBox": "0 0 20 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Verified"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_6295_120949",
+ "style": "mask-type:alpha",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "0",
+ "width": "20",
+ "height": "20"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Mask"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.08817 1.62512C9.14394 0.569299 10.8558 0.56929 11.9116 1.62512L12.8128 2.52633C12.9819 2.69533 13.2111 2.79028 13.4501 2.79028H14.5059C15.9991 2.79028 17.2095 4.00074 17.2095 5.4939V6.54972C17.2095 6.78874 17.3045 7.01796 17.4735 7.18697L18.3747 8.08818C19.4305 9.14401 19.4305 10.8559 18.3747 11.9117L17.4735 12.8129C17.3045 12.9819 17.2095 13.2112 17.2095 13.4502V14.5059C17.2095 15.9991 15.9991 17.2095 14.5059 17.2095H13.4501C13.2111 17.2095 12.9819 17.3045 12.8128 17.4735L11.9116 18.3747C10.8558 19.4305 9.14403 19.4305 8.08817 18.3747L7.18696 17.4735C7.01795 17.3045 6.78873 17.2095 6.54972 17.2095H5.49389C4.00072 17.2095 2.79028 15.9991 2.79028 14.5059V13.4502C2.79028 13.2112 2.69533 12.9819 2.52632 12.8129L1.62513 11.9117C0.569295 10.8559 0.569295 9.14401 1.62512 8.08818L2.52632 7.18697C2.69533 7.01797 2.79028 6.78874 2.79028 6.54972V5.4939C2.79028 4.00074 4.00072 2.79028 5.49389 2.79028H6.54972C6.78873 2.79028 7.01795 2.69533 7.18696 2.52633L8.08817 1.62512Z",
+ "fill": "#B2CAFF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.08817 1.62512C9.14394 0.569299 10.8558 0.56929 11.9116 1.62512L12.8128 2.52633C12.9819 2.69533 13.2111 2.79028 13.4501 2.79028H14.5059C15.9991 2.79028 17.2095 4.00074 17.2095 5.4939V6.54972C17.2095 6.78874 17.3045 7.01796 17.4735 7.18697L18.3747 8.08818C19.4305 9.14401 19.4305 10.8559 18.3747 11.9117L17.4735 12.8129C17.3045 12.9819 17.2095 13.2112 17.2095 13.4502V14.5059C17.2095 15.9991 15.9991 17.2095 14.5059 17.2095H13.4501C13.2111 17.2095 12.9819 17.3045 12.8128 17.4735L11.9116 18.3747C10.8558 19.4305 9.14403 19.4305 8.08817 18.3747L7.18696 17.4735C7.01795 17.3045 6.78873 17.2095 6.54972 17.2095H5.49389C4.00072 17.2095 2.79028 15.9991 2.79028 14.5059V13.4502C2.79028 13.2112 2.69533 12.9819 2.52632 12.8129L1.62513 11.9117C0.569295 10.8559 0.569295 9.14401 1.62512 8.08818L2.52632 7.18697C2.69533 7.01797 2.79028 6.78874 2.79028 6.54972V5.4939C2.79028 4.00074 4.00072 2.79028 5.49389 2.79028H6.54972C6.78873 2.79028 7.01795 2.69533 7.18696 2.52633L8.08817 1.62512Z",
+ "fill": "url(#paint0_linear_6295_120949)",
+ "fill-opacity": "0.9"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.27881 1.81577L8.27881 1.81576C9.2293 0.865233 10.7704 0.865217 11.721 1.81577L12.6222 2.71697L12.6222 2.71701C12.8418 2.93652 13.1395 3.05989 13.4501 3.05989H14.5059C15.8502 3.05989 16.9399 4.14963 16.9399 5.4939V6.54972C16.9399 6.86027 17.0633 7.15805 17.2828 7.3776L17.2829 7.37762L18.1841 8.27882L18.3747 8.08818L18.1841 8.27882C19.1346 9.22937 19.1346 10.7705 18.1841 11.7211L17.2829 12.6223C17.0633 12.8418 16.9399 13.1396 16.9399 13.4502V14.5059C16.9399 15.8502 15.8502 16.9399 14.5059 16.9399H13.4501C13.1395 16.9399 12.8418 17.0633 12.6222 17.2828L12.6222 17.2829L11.721 18.1841C10.7704 19.1346 9.22939 19.1346 8.27881 18.1841L7.37761 17.2829L7.37759 17.2828C7.15804 17.0633 6.86027 16.9399 6.54972 16.9399H5.49389C4.14962 16.9399 3.05989 15.8502 3.05989 14.5059V13.4502C3.05989 13.1397 2.93655 12.8418 2.71696 12.6223C2.71696 12.6223 2.71695 12.6223 2.71694 12.6222L1.81577 11.7211C0.865224 10.7705 0.865226 9.22936 1.81576 8.27882L2.71696 7.37762C2.71696 7.37762 2.71696 7.37762 2.71696 7.37762C2.93654 7.15805 3.05989 6.86024 3.05989 6.54972V5.4939C3.05989 4.14964 4.14963 3.05989 5.49389 3.05989H6.54972C6.86024 3.05989 7.15803 2.93653 7.3776 2.71698L7.37761 2.71697L8.27881 1.81577Z",
+ "stroke": "url(#paint1_linear_6295_120949)",
+ "stroke-opacity": "0.8",
+ "stroke-width": "0.539216"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_6295_120949)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "badge-bg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.08817 1.62512C9.14394 0.569299 10.8558 0.56929 11.9116 1.62512L12.8128 2.52633C12.9819 2.69533 13.2111 2.79028 13.4501 2.79028H14.5059C15.9991 2.79028 17.2095 4.00074 17.2095 5.4939V6.54972C17.2095 6.78874 17.3045 7.01796 17.4735 7.18697L18.3747 8.08818C19.4305 9.14401 19.4305 10.8559 18.3747 11.9117L17.4735 12.8129C17.3045 12.9819 17.2095 13.2112 17.2095 13.4502V14.5059C17.2095 15.9991 15.9991 17.2095 14.5059 17.2095H13.4501C13.2111 17.2095 12.9819 17.3045 12.8128 17.4735L11.9116 18.3747C10.8558 19.4305 9.14403 19.4305 8.08817 18.3747L7.18696 17.4735C7.01795 17.3045 6.78873 17.2095 6.54972 17.2095H5.49389C4.00072 17.2095 2.79028 15.9991 2.79028 14.5059V13.4502C2.79028 13.2112 2.69533 12.9819 2.52632 12.8129L1.62513 11.9117C0.569295 10.8559 0.569295 9.14401 1.62512 8.08818L2.52632 7.18697C2.69533 7.01797 2.79028 6.78874 2.79028 6.54972V5.4939C2.79028 4.00074 4.00072 2.79028 5.49389 2.79028H6.54972C6.78873 2.79028 7.01795 2.69533 7.18696 2.52633L8.08817 1.62512Z",
+ "fill": "#B2CAFF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.08817 1.62512C9.14394 0.569299 10.8558 0.56929 11.9116 1.62512L12.8128 2.52633C12.9819 2.69533 13.2111 2.79028 13.4501 2.79028H14.5059C15.9991 2.79028 17.2095 4.00074 17.2095 5.4939V6.54972C17.2095 6.78874 17.3045 7.01796 17.4735 7.18697L18.3747 8.08818C19.4305 9.14401 19.4305 10.8559 18.3747 11.9117L17.4735 12.8129C17.3045 12.9819 17.2095 13.2112 17.2095 13.4502V14.5059C17.2095 15.9991 15.9991 17.2095 14.5059 17.2095H13.4501C13.2111 17.2095 12.9819 17.3045 12.8128 17.4735L11.9116 18.3747C10.8558 19.4305 9.14403 19.4305 8.08817 18.3747L7.18696 17.4735C7.01795 17.3045 6.78873 17.2095 6.54972 17.2095H5.49389C4.00072 17.2095 2.79028 15.9991 2.79028 14.5059V13.4502C2.79028 13.2112 2.69533 12.9819 2.52632 12.8129L1.62513 11.9117C0.569295 10.8559 0.569295 9.14401 1.62512 8.08818L2.52632 7.18697C2.69533 7.01797 2.79028 6.78874 2.79028 6.54972V5.4939C2.79028 4.00074 4.00072 2.79028 5.49389 2.79028H6.54972C6.78873 2.79028 7.01795 2.69533 7.18696 2.52633L8.08817 1.62512Z",
+ "fill": "url(#paint2_linear_6295_120949)",
+ "fill-opacity": "0.9"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.44172 1.97868L8.44173 1.97867C9.30224 1.11812 10.6975 1.1181 11.5581 1.97868L12.4593 2.87988L12.4593 2.87995C12.7221 3.14262 13.0784 3.29028 13.4501 3.29028H14.5059C15.723 3.29028 16.7095 4.27687 16.7095 5.4939V6.54972C16.7095 6.9214 16.8572 7.27776 17.1199 7.54049L17.1199 7.54053L18.0211 8.44173L18.3747 8.08818L18.0211 8.44174C18.8817 9.3023 18.8817 10.6976 18.0211 11.5582L17.1199 12.4594C16.8572 12.7221 16.7095 13.0785 16.7095 13.4502V14.5059C16.7095 15.723 15.723 16.7095 14.5059 16.7095H13.4501C13.0784 16.7095 12.7221 16.8573 12.4594 17.1198L12.4593 17.1199L11.5581 18.0211C10.6975 18.8817 9.30233 18.8817 8.44172 18.0211L7.54052 17.1199L7.54048 17.1199C7.27775 16.8572 6.92139 16.7095 6.54972 16.7095H5.49389C4.27686 16.7095 3.29028 15.723 3.29028 14.5059V13.4502C3.29028 13.0786 3.14267 12.7221 2.87984 12.4593L1.97868 11.5582C1.11811 10.6976 1.11811 9.3023 1.97867 8.44173L2.87986 7.54054C2.87987 7.54053 2.87987 7.54053 2.87987 7.54053C3.14266 7.27775 3.29028 6.92134 3.29028 6.54972V5.4939C3.29028 4.27688 4.27687 3.29028 5.49389 3.29028H6.54972C6.92135 3.29028 7.27774 3.14265 7.54051 2.87989L7.54052 2.87988L8.44172 1.97868Z",
+ "stroke": "url(#paint3_linear_6295_120949)",
+ "stroke-opacity": "0.8"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "check",
+ "filter": "url(#filter0_d_6295_120949)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M13.4219 6.98125C13.8732 7.28917 13.9829 7.89538 13.667 8.33526L10.04 13.3857C9.87754 13.6119 9.62408 13.7601 9.34287 13.7933C9.06166 13.8266 8.77923 13.7417 8.56605 13.5599L6.49346 11.7922C6.0789 11.4386 6.03689 10.8244 6.39963 10.4203C6.76238 10.0162 7.39252 9.97526 7.80709 10.3288L9.04316 11.3831L12.0328 7.22019C12.3487 6.78031 12.9706 6.67333 13.4219 6.98125Z",
+ "fill": "url(#paint4_linear_6295_120949)",
+ "shape-rendering": "crispEdges"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "highlight",
+ "opacity": "0.5",
+ "d": "M0 0H15.5556L5.26663 20H0V0Z",
+ "fill": "url(#paint5_linear_6295_120949)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "filter",
+ "attributes": {
+ "id": "filter0_d_6295_120949",
+ "x": "5.65283",
+ "y": "6.55542",
+ "width": "8.69458",
+ "height": "7.99512",
+ "filterUnits": "userSpaceOnUse",
+ "color-interpolation-filters": "sRGB"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "feFlood",
+ "attributes": {
+ "flood-opacity": "0",
+ "result": "BackgroundImageFix"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "in": "SourceAlpha",
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
+ "result": "hardAlpha"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feOffset",
+ "attributes": {
+ "dy": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feGaussianBlur",
+ "attributes": {
+ "stdDeviation": "0.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feComposite",
+ "attributes": {
+ "in2": "hardAlpha",
+ "operator": "out"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feColorMatrix",
+ "attributes": {
+ "type": "matrix",
+ "values": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in2": "BackgroundImageFix",
+ "result": "effect1_dropShadow_6295_120949"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "feBlend",
+ "attributes": {
+ "mode": "normal",
+ "in": "SourceGraphic",
+ "in2": "effect1_dropShadow_6295_120949",
+ "result": "shape"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_6295_120949",
+ "x1": "16.302",
+ "y1": "19.1666",
+ "x2": "-0.37184",
+ "y2": "14.82",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#155AEF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#5289FF"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint1_linear_6295_120949",
+ "x1": "8.67462",
+ "y1": "0.833252",
+ "x2": "18.9651",
+ "y2": "12.5066",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.95"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#155AEF"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint2_linear_6295_120949",
+ "x1": "16.302",
+ "y1": "19.1666",
+ "x2": "-0.37184",
+ "y2": "14.82",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#155AEF"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#5289FF"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint3_linear_6295_120949",
+ "x1": "8.67462",
+ "y1": "0.833252",
+ "x2": "18.9651",
+ "y2": "12.5066",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.95"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#155AEF"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint4_linear_6295_120949",
+ "x1": "10.0001",
+ "y1": "6.80542",
+ "x2": "10.0001",
+ "y2": "13.8004",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white",
+ "stop-opacity": "0.9"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint5_linear_6295_120949",
+ "x1": "-4.78632",
+ "y1": "4.375",
+ "x2": "16.2164",
+ "y2": "10.4",
+ "gradientUnits": "userSpaceOnUse"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "white",
+ "stop-opacity": "0.12"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "white",
+ "stop-opacity": "0.3"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "VerifiedLight"
+}
diff --git a/app/components/base/icons/src/public/plugins/VerifiedLight.tsx b/app/components/base/icons/src/public/plugins/VerifiedLight.tsx
new file mode 100644
index 0000000..675a584
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/VerifiedLight.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './VerifiedLight.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'VerifiedLight'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/plugins/WebReader.json b/app/components/base/icons/src/public/plugins/WebReader.json
new file mode 100644
index 0000000..58c8283
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/WebReader.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.59235 3.32566C10.3587 3.11341 11.1661 3 12 3C13.962 3 15.7773 3.62779 17.2561 4.69345C16.4693 5.21349 15.8824 5.77819 15.4756 6.38193C14.854 7.30445 14.6947 8.25844 14.8234 9.12887C14.9484 9.97416 15.3366 10.696 15.7446 11.2301C16.1402 11.7479 16.6256 12.181 17.0531 12.3946C18.1294 12.9327 19.3714 13.2022 20.2999 13.341C21.1399 13.4667 22.9206 13.8871 22.9865 12.5492C22.9955 12.3672 23 12.1841 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C12.1841 23 12.3672 22.9955 12.5492 22.9865C13.1008 22.9593 13.526 22.4902 13.4988 21.9385C13.4716 21.3869 13.0024 20.9618 12.4508 20.9889C12.3015 20.9963 12.1512 21 12 21C8.49063 21 5.45038 18.9914 3.96619 16.0611L4.93474 15.502L8.50745 16.1706C9.43309 16.3439 10.2876 15.6313 10.2834 14.6896L10.2694 11.5365L12.0952 8.41051C12.3911 7.90404 12.3646 7.27161 12.0274 6.79167L9.59235 3.32566Z",
+ "fill": "#444CE7"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M13.9456 12.6561C13.5777 12.5165 13.1621 12.6057 12.8839 12.884C12.6056 13.1623 12.5164 13.5778 12.656 13.9458L15.8228 22.2945C15.969 22.68 16.3367 22.9362 16.7489 22.9399C17.1611 22.9435 17.5333 22.6938 17.6863 22.3111L19.007 19.0071L22.311 17.6865C22.6937 17.5334 22.9434 17.1612 22.9397 16.749C22.9361 16.3368 22.6799 15.9691 22.2944 15.8229L13.9456 12.6561Z",
+ "fill": "#444CE7"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "WebReader"
+}
diff --git a/app/components/base/icons/src/public/plugins/WebReader.tsx b/app/components/base/icons/src/public/plugins/WebReader.tsx
new file mode 100644
index 0000000..b23007d
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/WebReader.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './WebReader.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'WebReader'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/plugins/Wikipedia.json b/app/components/base/icons/src/public/plugins/Wikipedia.json
new file mode 100644
index 0000000..af2d505
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/Wikipedia.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M23.8431 5.0001H19.2179H19.0609V5.15706V5.66001V5.81696H19.2179H19.5393C19.9131 5.81696 20.2502 6.00882 20.4411 6.33021C20.632 6.65161 20.6392 7.0394 20.4603 7.36765L15.3174 16.8077L12.9751 11.2238L15.1813 7.17527C15.6379 6.33743 16.5143 5.81696 17.4684 5.81696H17.5726H17.7296V5.66001V5.15706V5.0001H17.5726H12.9474H12.7905V5.15706V5.66001V5.81696H12.9474H13.2688C13.6426 5.81696 13.9797 6.00882 14.1706 6.33021C14.3615 6.65161 14.3687 7.0394 14.1899 7.36765L12.5896 10.305L11.1634 6.9051C11.0601 6.65867 11.0856 6.38965 11.2336 6.16714C11.3816 5.94462 11.6197 5.81696 11.887 5.81696H12.2526H12.4095V5.66001V5.15706V5.0001H12.2526H6.72092H6.56396V5.15706V5.66001V5.81696H6.72092H6.79699C7.88821 5.81696 8.866 6.46719 9.28817 7.47344L11.3954 12.497L9.04698 16.8077L4.89304 6.9051C4.78966 6.65867 4.81525 6.38965 4.9632 6.16714C5.11116 5.94462 5.34932 5.81696 5.61657 5.81696H6.17832H6.33527V5.66001V5.15706V5.0001H6.17832H0.156957H0V5.15706V5.66001V5.81696H0.156957H0.52654C1.61776 5.81696 2.59561 6.46719 3.01772 7.47344L7.80628 18.889C7.89004 19.0887 8.08425 19.2177 8.30111 19.2177C8.50014 19.2177 8.67588 19.1131 8.77125 18.9381L9.39589 17.7918L11.7807 13.4155L14.0767 18.889C14.1604 19.0886 14.3547 19.2176 14.5715 19.2176C14.7705 19.2176 14.9463 19.1131 15.0417 18.938L15.6663 17.7917L21.4517 7.17517C21.9083 6.33733 22.7847 5.81686 23.7388 5.81686H23.843H24V5.6599V5.15696V5H23.8431V5.0001Z",
+ "fill": "#222A30"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Wikipedia"
+}
diff --git a/app/components/base/icons/src/public/plugins/Wikipedia.tsx b/app/components/base/icons/src/public/plugins/Wikipedia.tsx
new file mode 100644
index 0000000..0477e9c
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/Wikipedia.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Wikipedia.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Wikipedia'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/plugins/index.ts b/app/components/base/icons/src/public/plugins/index.ts
new file mode 100644
index 0000000..87dc371
--- /dev/null
+++ b/app/components/base/icons/src/public/plugins/index.ts
@@ -0,0 +1,7 @@
+export { default as Google } from './Google'
+export { default as PartnerDark } from './PartnerDark'
+export { default as PartnerLight } from './PartnerLight'
+export { default as VerifiedDark } from './VerifiedDark'
+export { default as VerifiedLight } from './VerifiedLight'
+export { default as WebReader } from './WebReader'
+export { default as Wikipedia } from './Wikipedia'
diff --git a/app/components/base/icons/src/public/thought/DataSet.json b/app/components/base/icons/src/public/thought/DataSet.json
new file mode 100644
index 0000000..5be61da
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/DataSet.json
@@ -0,0 +1,64 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_7847_32895)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.5 2.5C10.5 3.32843 8.48528 4 6 4C3.51472 4 1.5 3.32843 1.5 2.5M10.5 2.5C10.5 1.67157 8.48528 1 6 1C3.51472 1 1.5 1.67157 1.5 2.5M10.5 2.5V9.5C10.5 10.33 8.5 11 6 11C3.5 11 1.5 10.33 1.5 9.5V2.5M10.5 6C10.5 6.83 8.5 7.5 6 7.5C3.5 7.5 1.5 6.83 1.5 6",
+ "stroke": "#667085",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_7847_32895"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "DataSet"
+}
diff --git a/app/components/base/icons/src/public/thought/DataSet.tsx b/app/components/base/icons/src/public/thought/DataSet.tsx
new file mode 100644
index 0000000..28c38c3
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/DataSet.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './DataSet.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'DataSet'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/thought/Loading.json b/app/components/base/icons/src/public/thought/Loading.json
new file mode 100644
index 0000000..23e6866
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/Loading.json
@@ -0,0 +1,64 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_7998_4025)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6 1.125V2.375M6 9V11M2.875 6H1.125M10.625 6H9.875M9.22855 9.22855L8.875 8.875M9.33211 2.70789L8.625 3.415M2.46079 9.53921L3.875 8.125M2.56434 2.60434L3.625 3.665",
+ "stroke": "#667085",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_7998_4025"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Loading"
+}
diff --git a/app/components/base/icons/src/public/thought/Loading.tsx b/app/components/base/icons/src/public/thought/Loading.tsx
new file mode 100644
index 0000000..11389b8
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/Loading.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Loading.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Loading'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/thought/Search.json b/app/components/base/icons/src/public/thought/Search.json
new file mode 100644
index 0000000..1ad8876
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/Search.json
@@ -0,0 +1,64 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_7847_32899)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.5 10.5L8.75005 8.75M10 5.75C10 8.09721 8.09721 10 5.75 10C3.40279 10 1.5 8.09721 1.5 5.75C1.5 3.40279 3.40279 1.5 5.75 1.5C8.09721 1.5 10 3.40279 10 5.75Z",
+ "stroke": "#667085",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_7847_32899"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Search"
+}
diff --git a/app/components/base/icons/src/public/thought/Search.tsx b/app/components/base/icons/src/public/thought/Search.tsx
new file mode 100644
index 0000000..2f469d2
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/Search.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Search.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Search'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/thought/ThoughtList.json b/app/components/base/icons/src/public/thought/ThoughtList.json
new file mode 100644
index 0000000..d5e13c3
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/ThoughtList.json
@@ -0,0 +1,83 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4 6C4 5.72386 4.22386 5.5 4.5 5.5L10.5 5.5C10.7761 5.5 11 5.72386 11 6C11 6.27614 10.7761 6.5 10.5 6.5L4.5 6.5C4.22386 6.5 4 6.27614 4 6Z",
+ "fill": "#667085"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4 3C4 2.72386 4.22386 2.5 4.5 2.5L10.5 2.5C10.7761 2.5 11 2.72386 11 3C11 3.27614 10.7761 3.5 10.5 3.5L4.5 3.5C4.22386 3.5 4 3.27614 4 3Z",
+ "fill": "#667085"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4 9C4 8.72386 4.22386 8.5 4.5 8.5L10.5 8.5C10.7761 8.5 11 8.72386 11 9C11 9.27614 10.7761 9.5 10.5 9.5L4.5 9.5C4.22386 9.5 4 9.27614 4 9Z",
+ "fill": "#667085"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1 6C1 5.44772 1.44772 5 2 5C2.55228 5 3 5.44772 3 6C3 6.55228 2.55228 7 2 7C1.44772 7 1 6.55228 1 6Z",
+ "fill": "#667085"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1 3C1 2.44772 1.44772 2 2 2C2.55228 2 3 2.44772 3 3C3 3.55228 2.55228 4 2 4C1.44772 4 1 3.55228 1 3Z",
+ "fill": "#667085"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1 9C1 8.44772 1.44772 8 2 8C2.55228 8 3 8.44772 3 9C3 9.55228 2.55228 10 2 10C1.44772 10 1 9.55228 1 9Z",
+ "fill": "#667085"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ThoughtList"
+}
diff --git a/app/components/base/icons/src/public/thought/ThoughtList.tsx b/app/components/base/icons/src/public/thought/ThoughtList.tsx
new file mode 100644
index 0000000..99b42ae
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/ThoughtList.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ThoughtList.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ThoughtList'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/thought/WebReader.json b/app/components/base/icons/src/public/thought/WebReader.json
new file mode 100644
index 0000000..ba2bc48
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/WebReader.json
@@ -0,0 +1,64 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_7847_32887)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.5 1.75V1M2.53033 2.53033L2 2M2.53033 6.5L2 7.03033M6.5 2.53033L7.03033 2M1.75 4.5H1M7.93224 8.09479L6.68637 10.4085C6.54404 10.6728 6.47287 10.805 6.38725 10.8384C6.31295 10.8674 6.22926 10.8592 6.16199 10.8164C6.08447 10.767 6.04028 10.6235 5.95191 10.3366L4.22259 4.72263C4.1504 4.48825 4.1143 4.37107 4.14335 4.29192C4.16865 4.22298 4.22298 4.16865 4.29192 4.14335C4.37107 4.1143 4.48825 4.1504 4.72262 4.2226L10.3366 5.95192C10.6235 6.0403 10.767 6.08449 10.8164 6.16201C10.8592 6.22928 10.8674 6.31297 10.8384 6.38727C10.805 6.47289 10.6728 6.54406 10.4085 6.68639L8.09479 7.93224C8.05551 7.95339 8.03587 7.96396 8.01868 7.97755C8.00341 7.98961 7.98961 8.00341 7.97755 8.01868C7.96396 8.03587 7.95339 8.05551 7.93224 8.09479Z",
+ "stroke": "#667085",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_7847_32887"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "WebReader"
+}
diff --git a/app/components/base/icons/src/public/thought/WebReader.tsx b/app/components/base/icons/src/public/thought/WebReader.tsx
new file mode 100644
index 0000000..b23007d
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/WebReader.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './WebReader.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'WebReader'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/thought/index.ts b/app/components/base/icons/src/public/thought/index.ts
new file mode 100644
index 0000000..8a45489
--- /dev/null
+++ b/app/components/base/icons/src/public/thought/index.ts
@@ -0,0 +1,5 @@
+export { default as DataSet } from './DataSet'
+export { default as Loading } from './Loading'
+export { default as Search } from './Search'
+export { default as ThoughtList } from './ThoughtList'
+export { default as WebReader } from './WebReader'
diff --git a/app/components/base/icons/src/public/tracing/LangfuseIcon.json b/app/components/base/icons/src/public/tracing/LangfuseIcon.json
new file mode 100644
index 0000000..c2c8a73
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/LangfuseIcon.json
@@ -0,0 +1,236 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "74",
+ "height": "16",
+ "viewBox": "0 0 74 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_20135_12984",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "0",
+ "width": "96",
+ "height": "16"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "clip0_823_291"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M95.5733 0H0V16H95.5733V0Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_20135_12984)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M21.2832 11.5431V3.72656H22.3735V10.4972H26.3932V11.5431H21.2832ZM27.6995 7.44766C27.9198 6.31372 28.8889 5.5761 30.1224 5.5761C31.543 5.5761 32.4791 6.40179 32.4791 8.02014V10.233C32.4791 10.4862 32.5893 10.5963 32.8316 10.5963H33.0849V11.5431H32.7765C32.0717 11.5431 31.6532 11.1688 31.543 10.6513C31.3228 11.1908 30.64 11.6752 29.7259 11.6752C28.5475 11.6752 27.6004 11.0587 27.6004 10.0128C27.6004 8.80179 28.4924 8.46051 29.836 8.2073L31.4109 7.89904C31.3999 7.0073 30.8933 6.56693 30.1114 6.56693C29.4506 6.56693 28.966 6.96326 28.8338 7.52473L27.6995 7.44766ZM28.7237 9.99078C28.7347 10.3981 29.0871 10.7394 29.8581 10.7394C30.7391 10.7394 31.4329 10.1229 31.4329 9.07702V8.82381L30.1774 9.04399C29.3625 9.18711 28.7237 9.25317 28.7237 9.99078ZM34.5453 5.70821H35.5255L35.5585 6.68803C35.8669 5.93941 36.5166 5.5761 37.2986 5.5761C38.5981 5.5761 39.2369 6.5339 39.2369 7.78895V11.5431H38.1686V8.06418C38.1686 7.02931 37.8272 6.48987 37.0232 6.48987C36.1752 6.48987 35.6136 7.02931 35.6136 8.06418V11.5431H34.5453V5.70821ZM43.2303 11.2348C41.7876 11.2348 40.7634 10.0789 40.7634 8.43849C40.7634 6.74308 41.7876 5.5761 43.2303 5.5761C44.0122 5.5761 44.6951 5.99445 44.9594 6.59996L44.9704 5.70821H45.9946V10.9045C45.9836 12.5009 44.9704 13.3266 43.4065 13.3266C42.129 13.3266 41.2039 12.655 40.9286 11.6422L42.0519 11.5651C42.2832 12.0715 42.7347 12.3688 43.4065 12.3688C44.3536 12.3688 44.9153 11.9394 44.9263 11.1357V10.266C44.629 10.8275 43.9241 11.2348 43.2303 11.2348ZM41.8867 8.42748C41.8867 9.5284 42.4704 10.299 43.4286 10.299C44.3647 10.299 44.9373 9.5284 44.9483 8.42748C44.9704 7.33757 44.3867 6.56693 43.4286 6.56693C42.4704 6.56693 41.8867 7.33757 41.8867 8.42748ZM48.9967 5.455C48.9967 4.3761 49.5364 3.72656 50.7258 3.72656H52.3337V4.67335H50.7038C50.3293 4.67335 50.065 4.95959 50.065 5.43298V6.08253H52.2566V7.02931H50.065V11.5431H48.9967V7.02931H47.4659V6.08253H48.9967V5.455ZM58.9041 11.5431H57.8909L57.8798 10.5963C57.5715 11.3229 56.9327 11.6752 56.1838 11.6752C54.9063 11.6752 54.2786 10.7174 54.2786 9.46234V5.70821H55.3468V9.18711C55.3468 10.222 55.6883 10.7614 56.4592 10.7614C57.2851 10.7614 57.8358 10.222 57.8358 9.18711V5.70821H58.9041V11.5431ZM64.5277 7.53574C64.4065 6.91922 63.8338 6.56693 63.151 6.56693C62.5894 6.56693 62.0718 6.84216 62.0828 7.38161C62.0828 7.9651 62.7876 8.09721 63.4374 8.26234C64.5497 8.53757 65.662 8.94491 65.662 10.0348C65.662 11.1798 64.5607 11.6752 63.3493 11.6752C61.9837 11.6752 60.8713 10.9045 60.7832 9.69354L61.9066 9.62748C62.0167 10.277 62.6004 10.6844 63.3493 10.6844C63.933 10.6844 64.5387 10.5302 64.5387 9.97977C64.5387 9.4073 63.8008 9.30821 63.151 9.15409C62.0497 8.88987 60.9594 8.48253 60.9594 7.42565C60.9594 6.24766 62.0167 5.5761 63.2502 5.5761C64.4836 5.5761 65.4417 6.31372 65.629 7.46968L64.5277 7.53574ZM67.2104 8.62565C67.2104 6.76509 68.2787 5.5761 69.9196 5.5761C71.2302 5.5761 72.4196 6.42381 72.5077 8.52656V8.9339H68.3448C68.4329 10.0348 68.9945 10.6844 69.9196 10.6844C70.5033 10.6844 71.032 10.3431 71.2853 9.75959L72.4196 9.85867C72.0892 10.9706 71.087 11.6752 69.9196 11.6752C68.2787 11.6752 67.2104 10.4862 67.2104 8.62565ZM68.3778 8.07519H71.3403C71.1861 6.96326 70.5804 6.56693 69.9196 6.56693C69.0716 6.56693 68.532 7.1284 68.3778 8.07519Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask1_20135_12984",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "17",
+ "height": "18"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "clip1_823_291"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M16.3621 -0.0512695H0.203125V16.1021H16.3621V-0.0512695Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask1_20135_12984)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M14.6259 11.2357C13.9141 12.1984 12.8241 12.8406 11.5941 12.9344C11.5558 12.937 11.5175 12.9397 11.4787 12.9419C10.0365 13.0136 8.94706 12.3558 8.22466 11.7452C6.94631 11.0687 5.94609 10.8983 5.36089 10.751C4.93532 10.6438 4.56293 10.4296 4.40334 10.3225C4.26183 10.2384 3.97722 10.0434 3.76496 9.67965C3.52716 9.27204 3.51333 8.88257 3.51706 8.71705C3.641 8.70048 3.80113 8.68224 3.98839 8.67048C4.1416 8.66082 4.29002 8.65709 4.45654 8.65652C5.74819 8.65494 6.7499 8.71812 7.47874 9.0417C7.87295 9.21632 8.23842 9.4488 8.56395 9.73215C8.98265 10.0975 9.83862 10.6749 10.8935 10.4778C11.0276 10.4526 11.1563 10.4194 11.2803 10.3787C11.6601 10.3241 12.3097 10.2801 13.0747 10.4831C13.8008 10.676 14.3232 11.0092 14.6259 11.2357Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "1.70667",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M14.53 4.60662C14.2091 4.19101 13.819 3.79812 13.3584 3.53003C12.8675 3.2445 12.2411 2.99862 11.4835 2.93199C9.63248 2.76913 8.36691 3.79548 8.13634 3.98954C7.84947 4.25868 6.70187 5.21101 5.32048 5.73977C5.07981 5.82545 4.61653 6.02793 4.20477 6.48007C3.87909 6.83749 3.7197 7.20339 3.6416 7.43076C3.80631 7.45351 3.97632 7.46992 4.15164 7.47994C5.49102 7.55452 6.64184 7.56193 7.39466 7.19337C7.89196 6.95015 8.32815 6.60377 8.70431 6.1982C9.38222 5.4669 10.3709 5.14067 11.271 5.36436C11.6843 5.42197 12.4042 5.46588 13.2368 5.21101C13.8116 5.03492 14.2399 4.81337 14.53 4.60662Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "1.70667",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M1.96963 4.91518C1.45614 4.65135 1.05528 4.347 0.781876 4.10874C0.629046 3.97549 0.391602 4.08476 0.391602 4.28837V5.95295C0.391602 6.02543 0.424389 6.09419 0.480445 6.13896L1.16264 6.79512C1.19859 6.53125 1.2758 6.17255 1.44926 5.77597C1.61267 5.40184 1.80886 5.11558 1.96963 4.91518Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "1.70667",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M12.9521 8.63005C13.0302 8.38964 13.0735 8.13742 13.0799 7.8804C13.0853 7.67736 13.0617 7.6015 13.0264 7.4049C13.3895 7.34397 13.8428 7.24459 14.2561 7.1377C14.6929 7.02499 15.0158 6.89407 15.3789 6.76367C15.4318 7.01747 15.4874 7.14092 15.5067 7.32899C15.5248 7.50642 15.5361 7.69019 15.5392 7.8804C15.5489 8.47138 15.4767 9.0073 15.3655 9.47698C15.0233 9.29954 14.617 9.11577 14.1492 8.95439C13.714 8.8037 13.3093 8.70115 12.9521 8.63005Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "1.70667",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M0.766014 12.1447C0.609481 12.2583 0.391602 12.1463 0.391602 11.9516V9.90721C0.391602 9.84531 0.415399 9.78667 0.456648 9.74292C0.477272 9.72104 0.49631 9.70877 0.504771 9.70397L1.18061 9.41382C1.23032 9.6848 1.3123 10.0091 1.44926 10.3622C1.6095 10.775 1.79987 11.1094 1.96963 11.3638C1.56825 11.6241 1.16686 11.8844 0.766014 12.1447Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "1.70667",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.11863 3.21273C6.47036 3.1457 7.48116 3.71166 8.00219 4.08992C7.60778 4.43817 6.54047 5.27853 5.27812 5.76389C5.19298 5.79436 5.08001 5.83945 4.95131 5.90513C4.03786 6.35487 3.49469 7.25118 3.47044 8.20872C3.46637 8.3699 3.4746 8.53046 3.49592 8.68826C3.49361 8.68857 3.49131 8.68888 3.48903 8.68918C3.48531 8.85338 3.49914 9.23978 3.73679 9.64428C3.94894 10.0051 4.23338 10.1986 4.37481 10.282C4.44499 10.3288 4.55634 10.3962 4.69529 10.466C4.8585 10.5529 5.03948 10.6258 5.2391 10.6822C5.26968 10.6911 5.30062 10.6995 5.33181 10.7072C5.40448 10.7254 5.48364 10.7442 5.56903 10.7644C6.17131 10.9074 7.08394 11.1238 8.20285 11.7118C8.31591 11.8066 8.43766 11.9022 8.56827 11.9956C8.52858 12.0311 8.49519 12.0621 8.46819 12.0875C8.23747 12.2826 6.97098 13.3142 5.11863 13.1505C4.36047 13.0836 3.73309 12.8364 3.24236 12.5494C2.4156 12.0663 1.79088 11.302 1.45008 10.4075C1.2305 9.83086 1.03909 9.08515 1.02527 8.20765C1.01304 7.45826 1.1332 6.79817 1.29696 6.25074C1.79833 4.57812 3.26043 3.35145 5.00327 3.22017L5.00335 3.22016C5.0416 3.21751 5.07986 3.21485 5.11863 3.21273ZM14.5861 11.1844C14.2827 10.9597 13.7622 10.6316 13.0411 10.4415C12.2766 10.2401 11.6274 10.2837 11.2478 10.3378C11.1239 10.3782 10.9952 10.4112 10.8613 10.4362C9.80694 10.6318 8.95148 10.0588 8.53303 9.69637C8.45168 9.62603 8.36781 9.55891 8.28165 9.49501C8.56326 9.2476 8.87288 9.03413 9.21043 8.8683C9.96382 8.49841 11.1154 8.50582 12.4558 8.58025C14.3028 8.68336 15.5788 9.56295 16.0882 9.96688C16.145 10.0121 16.1775 10.0801 16.1775 10.1524V11.8123C16.1775 12.0158 15.9388 12.1247 15.7851 11.9914C15.5098 11.7531 15.1049 11.4483 14.5861 11.1844ZM8.66435 6.22472C8.54326 6.35584 8.41593 6.48083 8.28237 6.59819C8.54101 6.79004 8.82057 6.95244 9.11629 7.08249C9.84473 7.40351 10.8459 7.46623 12.1367 7.46465C14.0301 7.46199 15.4241 6.74925 16.0637 6.36126C16.1344 6.31822 16.1775 6.2417 16.1775 6.15878V4.12158C16.1775 3.92758 15.9585 3.81597 15.8011 3.92917C15.4285 4.19722 14.8745 4.53933 14.1601 4.80844C13.9028 4.96005 13.5822 5.11485 13.2001 5.23242C12.367 5.48857 11.6466 5.44446 11.2329 5.38654C10.3323 5.16172 9.34277 5.48964 8.66435 6.22472Z",
+ "fill": "#E11312"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_10",
+ "d": "M8.00166 4.09005L8.13707 4.2433L8.32826 4.07447L8.12183 3.92461L8.00166 4.09005ZM5.11809 3.21286L5.10798 3.00864L5.10745 3.00866L5.10692 3.0087L5.11809 3.21286ZM5.27759 5.76403L5.34647 5.95659L5.34877 5.95577L5.35102 5.9549L5.27759 5.76403ZM4.95078 5.90527L5.04115 6.08868L5.04247 6.08807L5.04379 6.0874L4.95078 5.90527ZM3.49538 8.6884L3.52217 8.89108L3.72555 8.86425L3.69809 8.661L3.49538 8.6884ZM3.4885 8.68932L3.46154 8.48664L3.28798 8.50969L3.28401 8.68467L3.4885 8.68932ZM4.37427 10.2822L4.48774 10.112L4.48307 10.1089L4.47824 10.1061L4.37427 10.2822ZM4.69475 10.4661L4.79093 10.2857L4.78879 10.2845L4.78663 10.2834L4.69475 10.4661ZM5.23857 10.6823L5.29549 10.486L5.29487 10.4858L5.29421 10.4856L5.23857 10.6823ZM8.20232 11.7119L8.33384 11.5553L8.31701 11.5412L8.29748 11.5309L8.20232 11.7119ZM8.56773 11.9957L8.70411 12.1481L8.89429 11.978L8.68678 11.8295L8.56773 11.9957ZM8.46766 12.0877L8.59975 12.2438L8.60404 12.2402L8.60808 12.2364L8.46766 12.0877ZM3.24183 12.5496L3.34511 12.3731L3.34505 12.373L3.24183 12.5496ZM1.02474 8.20779L1.22926 8.20456L1.22925 8.20446L1.02474 8.20779ZM1.29642 6.25088L1.10049 6.19214L1.10045 6.1923L1.29642 6.25088ZM5.00274 3.2203L4.98903 3.01629L4.9882 3.01635L4.98737 3.01641L5.00274 3.2203ZM5.00281 3.2203L5.01652 3.42431L5.01698 3.42428L5.00281 3.2203ZM13.0406 10.4417L13.0928 10.2439H13.0927L13.0406 10.4417ZM14.5855 11.1845L14.4638 11.3488L14.4775 11.359L14.4928 11.3667L14.5855 11.1845ZM11.2473 10.338L11.2183 10.1356L11.2007 10.1381L11.1838 10.1436L11.2473 10.338ZM10.8607 10.4363L10.8981 10.6373H10.8982L10.8607 10.4363ZM8.5325 9.6965L8.66648 9.54197L8.66627 9.54177L8.5325 9.6965ZM8.28112 9.49515L8.14612 9.34159L7.95594 9.50864L8.15931 9.65939L8.28112 9.49515ZM12.4553 8.58039L12.4667 8.37622H12.4666L12.4553 8.58039ZM16.0877 9.96702L16.2149 9.80692L16.2148 9.80687L16.0877 9.96702ZM15.7846 11.9915L15.9187 11.8371L15.9185 11.8369L15.7846 11.9915ZM8.28183 6.59833L8.14678 6.44477L7.95666 6.61177L8.15998 6.76257L8.28183 6.59833ZM9.11576 7.08262L9.19829 6.89553L9.19814 6.89548L9.11576 7.08262ZM12.1362 7.46478L12.1365 7.66925H12.1365L12.1362 7.46478ZM16.0632 6.3614L16.1693 6.53622L16.1696 6.53607L16.0632 6.3614ZM14.1596 4.80857L14.0874 4.61723L14.0709 4.62346L14.0557 4.63242L14.1596 4.80857ZM11.2324 5.38667L11.1828 5.58506L11.1933 5.58767L11.204 5.58915L11.2324 5.38667ZM8.12183 3.92461C7.57989 3.53114 6.52347 2.93845 5.10798 3.00864L5.12822 3.41708C6.41618 3.35322 7.38138 3.89245 7.88144 4.25549L8.12183 3.92461ZM5.35102 5.9549C6.64538 5.45722 7.73371 4.59944 8.13707 4.2433L7.86625 3.9368C7.48074 4.27718 6.43449 5.10015 5.20416 5.5732L5.35102 5.9549ZM5.04379 6.0874C5.16309 6.02647 5.26772 5.98471 5.34647 5.95659L5.20871 5.57152C5.11717 5.60423 4.99585 5.65269 4.85776 5.72318L5.04379 6.0874ZM3.67439 8.21402C3.69676 7.3308 4.19746 6.50412 5.04115 6.08868L4.8604 5.72186C3.87719 6.20595 3.29156 7.17188 3.26543 8.2037L3.67439 8.21402ZM3.69809 8.661C3.6783 8.51455 3.67058 8.36487 3.67439 8.21402L3.26543 8.2037C3.2611 8.3752 3.26984 8.5467 3.29268 8.71575L3.69809 8.661ZM3.51546 8.892C3.5177 8.8917 3.51993 8.89139 3.52217 8.89108L3.4686 8.48566C3.46623 8.48597 3.46387 8.48633 3.46154 8.48664L3.51546 8.892ZM3.91263 9.54085C3.70211 9.18256 3.68969 8.83956 3.69299 8.69392L3.28401 8.68467C3.27987 8.86752 3.29509 9.29732 3.55989 9.74798L3.91263 9.54085ZM4.47824 10.1061C4.35261 10.032 4.10041 9.86028 3.91261 9.54079L3.55989 9.74798C3.79637 10.1503 4.11309 10.3655 4.2703 10.4583L4.47824 10.1061ZM4.78663 10.2834C4.6552 10.2174 4.55104 10.1543 4.48774 10.112L4.26081 10.4523C4.33787 10.5037 4.45643 10.5752 4.60289 10.6488L4.78663 10.2834ZM5.29421 10.4856C5.10788 10.4329 4.94058 10.3654 4.79093 10.2857L4.59858 10.6466C4.77536 10.7407 4.97 10.819 5.18294 10.8791L5.29421 10.4856ZM5.38088 10.509C5.35225 10.5019 5.32376 10.4941 5.29549 10.486L5.18161 10.8787C5.21454 10.8883 5.24788 10.8973 5.28168 10.9058L5.38088 10.509ZM5.61575 10.5656C5.53005 10.5453 5.45212 10.5268 5.38088 10.509L5.28168 10.9058C5.35572 10.9243 5.43616 10.9433 5.52125 10.9635L5.61575 10.5656ZM8.29748 11.5309C7.155 10.9306 6.22187 10.7094 5.61575 10.5656L5.52125 10.9635C6.11975 11.1055 7.01177 11.3174 8.10715 11.8929L8.29748 11.5309ZM8.68678 11.8295C8.56093 11.7394 8.44327 11.6471 8.33384 11.5553L8.07085 11.8685C8.18744 11.9664 8.31338 12.0652 8.44864 12.162L8.68678 11.8295ZM8.60808 12.2364C8.63406 12.2119 8.66607 12.1821 8.70411 12.1481L8.4313 11.8434C8.39004 11.8803 8.35526 11.9126 8.32724 11.939L8.60808 12.2364ZM5.10009 13.3543C7.03682 13.5255 8.35798 12.4482 8.59975 12.2438L8.33558 11.9315C8.11585 12.1173 6.90412 13.1032 5.13615 12.947L5.10009 13.3543ZM3.13854 12.726C3.65082 13.0256 4.30703 13.2843 5.10011 13.3544L5.13615 12.947C4.4129 12.8831 3.8143 12.6475 3.34511 12.3731L3.13854 12.726ZM1.25838 10.4804C1.61483 11.416 2.26927 12.2181 3.1386 12.7261L3.34505 12.373C2.56087 11.9148 1.96586 11.1883 1.64069 10.3349L1.25838 10.4804ZM0.820219 8.21101C0.834481 9.11662 1.03203 9.88594 1.25838 10.4804L1.64071 10.3349C1.4279 9.77599 1.24263 9.05395 1.22926 8.20456L0.820219 8.21101ZM1.10045 6.1923C0.93163 6.75664 0.807599 7.43774 0.820219 8.21116L1.22925 8.20446C1.21742 7.47904 1.3337 6.83991 1.49239 6.30946L1.10045 6.1923ZM4.98737 3.01641C3.15623 3.15434 1.62504 4.44222 1.10049 6.19214L1.49236 6.30956C1.97055 4.7143 3.36357 3.54883 5.0181 3.4242L4.98737 3.01641ZM4.9891 3.01629L4.98903 3.01629L5.01644 3.42432L5.01652 3.42431L4.9891 3.01629ZM5.10692 3.0087C5.0664 3.01091 5.02666 3.01368 4.98864 3.01632L5.01698 3.42428C5.05547 3.42161 5.09225 3.41906 5.12929 3.41703L5.10692 3.0087ZM12.9885 10.6393C13.6767 10.8208 14.1738 11.134 14.4638 11.3488L14.7073 11.0202C14.3904 10.7855 13.8465 10.4426 13.0928 10.2439L12.9885 10.6393ZM11.2762 10.5404C11.6387 10.4886 12.2586 10.4471 12.9885 10.6393L13.0927 10.2439C12.2935 10.0333 11.6151 10.0789 11.2183 10.1356L11.2762 10.5404ZM10.8982 10.6373C11.0409 10.6107 11.1782 10.5756 11.3107 10.5324L11.1838 10.1436C11.0685 10.1812 10.9485 10.2119 10.8232 10.2353L10.8982 10.6373ZM8.39858 9.85098C8.83155 10.2261 9.75005 10.8503 10.8981 10.6373L10.8234 10.2353C9.86276 10.4135 9.07035 9.89182 8.66648 9.54197L8.39858 9.85098ZM8.15931 9.65939C8.24138 9.72027 8.32126 9.78422 8.39873 9.85118L8.66627 9.54177C8.58108 9.46816 8.49323 9.39782 8.40297 9.3309L8.15931 9.65939ZM9.1197 8.68492C8.76425 8.85959 8.43969 9.08364 8.14612 9.34159L8.41617 9.64876C8.68576 9.41187 8.98056 9.20894 9.30011 9.05195L9.1197 8.68492ZM12.4666 8.37622C11.7952 8.33895 11.162 8.31784 10.5994 8.35373C10.0385 8.38951 9.53134 8.4828 9.1197 8.68492L9.30011 9.05195C9.64185 8.88418 10.0872 8.79621 10.6255 8.76186C11.1622 8.72761 11.7749 8.74739 12.4439 8.78455L12.4666 8.37622ZM16.2148 9.80687C15.6896 9.39035 14.3735 8.4827 12.4667 8.37622L12.4438 8.78455C14.231 8.88428 15.467 9.73586 15.9605 10.1272L16.2148 9.80687ZM16.3815 10.1525C16.3815 10.0185 16.3211 9.89131 16.2149 9.80692L15.9604 10.1271C15.9679 10.1331 15.9724 10.1419 15.9724 10.1525H16.3815ZM16.3815 11.8124V10.1525H15.9724V11.8124H16.3815ZM15.6504 12.1459C15.9368 12.3945 16.3815 12.1909 16.3815 11.8124H15.9724C15.9724 11.822 15.9699 11.8273 15.9676 11.8307C15.9648 11.8349 15.9601 11.8393 15.9534 11.8423C15.9468 11.8453 15.9404 11.846 15.9355 11.8455C15.9315 11.8449 15.926 11.8434 15.9187 11.8371L15.6504 12.1459ZM14.4928 11.3667C14.9936 11.6215 15.3848 11.916 15.6507 12.1461L15.9185 11.8369C15.6338 11.5905 15.2152 11.2754 14.6783 11.0023L14.4928 11.3667ZM8.41683 6.75194C8.55613 6.62956 8.68852 6.49957 8.81416 6.36354L8.51353 6.08612C8.39694 6.21239 8.27472 6.33236 8.14678 6.44477L8.41683 6.75194ZM9.19814 6.89548C8.91638 6.77157 8.65006 6.61683 8.40369 6.43414L8.15998 6.76257C8.43089 6.96352 8.7237 7.13359 9.03343 7.26982L9.19814 6.89548ZM12.136 7.26031C10.8405 7.26189 9.88163 7.19672 9.19829 6.89553L9.03328 7.26972C9.80676 7.61062 10.8502 7.67084 12.1365 7.66925L12.136 7.26031ZM15.9571 6.18662C15.3346 6.56423 13.9777 7.2577 12.136 7.26031L12.1365 7.66925C14.0813 7.66655 15.5126 6.93458 16.1693 6.53622L15.9571 6.18662ZM15.9724 6.15892C15.9724 6.17047 15.9666 6.18085 15.9568 6.18678L16.1696 6.53607C16.3012 6.45591 16.3815 6.31319 16.3815 6.15892H15.9724ZM15.9724 4.12171V6.15892H16.3815V4.12171H15.9724ZM15.92 4.09528C15.9427 4.07894 15.9724 4.09516 15.9724 4.12171H16.3815C16.3815 3.76028 15.9731 3.55327 15.6811 3.76334L15.92 4.09528ZM14.2317 4.99991C14.9668 4.72302 15.5366 4.37113 15.92 4.09528L15.6811 3.76334C15.3193 4.02358 14.7812 4.35591 14.0874 4.61723L14.2317 4.99991ZM13.2597 5.42798C13.6594 5.30504 13.9946 5.14315 14.2634 4.98473L14.0557 4.63242C13.8099 4.77723 13.5039 4.92497 13.1394 5.03712L13.2597 5.42798ZM11.204 5.58915C11.6356 5.64963 12.3885 5.69589 13.2597 5.42798L13.1395 5.03711C12.3443 5.28157 11.6564 5.23961 11.2608 5.18419L11.204 5.58915ZM8.81416 6.36354C9.44768 5.67713 10.3626 5.38033 11.1828 5.58506L11.2819 5.18828C10.3008 4.94339 9.23685 5.30248 8.51348 6.08617L8.81416 6.36354Z",
+ "fill": "black"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LangfuseIcon"
+}
diff --git a/app/components/base/icons/src/public/tracing/LangfuseIcon.tsx b/app/components/base/icons/src/public/tracing/LangfuseIcon.tsx
new file mode 100644
index 0000000..7f0f115
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/LangfuseIcon.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LangfuseIcon.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LangfuseIcon'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/tracing/LangfuseIconBig.json b/app/components/base/icons/src/public/tracing/LangfuseIconBig.json
new file mode 100644
index 0000000..8172de6
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/LangfuseIconBig.json
@@ -0,0 +1,236 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "111",
+ "height": "24",
+ "viewBox": "0 0 111 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_20135_18315",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "0",
+ "width": "144",
+ "height": "24"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "clip0_823_291"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M143.36 0H0V24H143.36V0Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_20135_18315)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M31.9258 17.3144V5.5896H33.5612V15.7456H39.5908V17.3144H31.9258ZM41.5502 11.1713C41.8806 9.47033 43.3343 8.36391 45.1845 8.36391C47.3155 8.36391 48.7197 9.60244 48.7197 12.03V15.3492C48.7197 15.729 48.8849 15.8942 49.2483 15.8942H49.6283V17.3144H49.1657C48.1085 17.3144 47.4807 16.7529 47.3155 15.9768C46.9852 16.7859 45.9609 17.5125 44.5898 17.5125C42.8222 17.5125 41.4016 16.5878 41.4016 15.019C41.4016 13.2024 42.7396 12.6905 44.755 12.3107L47.1173 11.8483C47.1008 10.5107 46.3409 9.85015 45.168 9.85015C44.1768 9.85015 43.45 10.4446 43.2517 11.2868L41.5502 11.1713ZM43.0865 14.9859C43.1031 15.5969 43.6317 16.1089 44.7881 16.1089C46.1096 16.1089 47.1503 15.1841 47.1503 13.6153V13.2355L45.2671 13.5657C44.0447 13.7804 43.0865 13.8795 43.0865 14.9859ZM51.8189 8.56208H53.2892L53.3387 10.0318C53.8013 8.90887 54.7759 8.36391 55.9488 8.36391C57.8981 8.36391 58.8563 9.80061 58.8563 11.6832V17.3144H57.2539V12.096C57.2539 10.5437 56.7418 9.73455 55.5358 9.73455C54.2638 9.73455 53.4213 10.5437 53.4213 12.096V17.3144H51.8189V8.56208ZM64.8465 16.852C62.6824 16.852 61.1461 15.118 61.1461 12.6575C61.1461 10.1144 62.6824 8.36391 64.8465 8.36391C66.0193 8.36391 67.0436 8.99143 67.44 9.89969L67.4565 8.56208H68.9929V16.3566C68.9763 18.7511 67.4565 19.9896 65.1108 19.9896C63.1945 19.9896 61.8069 18.9823 61.3939 17.463L63.0789 17.3474C63.4258 18.107 64.1031 18.5529 65.1108 18.5529C66.5315 18.5529 67.3739 17.9089 67.3905 16.7034V15.3988C66.9444 16.241 65.8872 16.852 64.8465 16.852ZM62.8311 12.641C62.8311 14.2924 63.7066 15.4483 65.1438 15.4483C66.548 15.4483 67.407 14.2924 67.4235 12.641C67.4565 11.0061 66.581 9.85015 65.1438 9.85015C63.7066 9.85015 62.8311 11.0061 62.8311 12.641ZM73.4961 8.18226C73.4961 6.56391 74.3055 5.5896 76.0897 5.5896H78.5015V7.00978H76.0566C75.495 7.00978 75.0985 7.43914 75.0985 8.14923V9.12354H78.3859V10.5437H75.0985V17.3144H73.4961V10.5437H71.1999V9.12354H73.4961V8.18226ZM88.3571 17.3144H86.8373L86.8207 15.8942C86.3582 16.9841 85.4001 17.5125 84.2767 17.5125C82.3605 17.5125 81.4189 16.0758 81.4189 14.1933V8.56208H83.0212V13.7804C83.0212 15.3327 83.5334 16.1419 84.6897 16.1419C85.9287 16.1419 86.7547 15.3327 86.7547 13.7804V8.56208H88.3571V17.3144ZM96.7925 11.3034C96.6108 10.3786 95.7518 9.85015 94.7275 9.85015C93.885 9.85015 93.1086 10.263 93.1251 11.0722C93.1251 11.9474 94.1824 12.1456 95.1571 12.3933C96.8255 12.8061 98.494 13.4171 98.494 15.052C98.494 16.7694 96.842 17.5125 95.0249 17.5125C92.9765 17.5125 91.308 16.3566 91.1758 14.5401L92.8608 14.441C93.026 15.4153 93.9016 16.0263 95.0249 16.0263C95.9004 16.0263 96.809 15.7951 96.809 14.9694C96.809 14.1107 95.7022 13.9621 94.7275 13.7309C93.0756 13.3346 91.4402 12.7235 91.4402 11.1382C91.4402 9.37125 93.026 8.36391 94.8762 8.36391C96.7264 8.36391 98.1636 9.47033 98.4444 11.2043L96.7925 11.3034ZM100.817 12.9382C100.817 10.1474 102.419 8.36391 104.88 8.36391C106.846 8.36391 108.63 9.63547 108.763 12.7896V13.4006H102.518C102.65 15.052 103.493 16.0263 104.88 16.0263C105.756 16.0263 106.549 15.5144 106.929 14.6391L108.63 14.7878C108.135 16.4557 106.632 17.5125 104.88 17.5125C102.419 17.5125 100.817 15.729 100.817 12.9382ZM102.568 12.1125H107.011C106.78 10.4446 105.872 9.85015 104.88 9.85015C103.608 9.85015 102.799 10.6924 102.568 12.1125Z",
+ "fill": "black"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask1_20135_18315",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "-1",
+ "width": "25",
+ "height": "26"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "clip1_823_291"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M24.5471 -0.0771484H0.308594V24.1529H24.5471V-0.0771484Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask1_20135_18315)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M21.9423 16.8532C20.8746 18.2972 19.2396 19.2605 17.3946 19.4012C17.3372 19.4051 17.2797 19.4092 17.2215 19.4124C15.0582 19.5201 13.424 18.5334 12.3404 17.6174C10.4229 16.6027 8.92256 16.3471 8.04475 16.1261C7.4064 15.9654 6.84782 15.644 6.60842 15.4833C6.39617 15.3572 5.96925 15.0647 5.65086 14.5191C5.29416 13.9077 5.27342 13.3235 5.279 13.0752C5.46493 13.0504 5.70512 13.023 5.98601 13.0054C6.21582 12.9909 6.43845 12.9853 6.68823 12.9844C8.62571 12.982 10.1283 13.0768 11.2215 13.5622C11.8128 13.8241 12.361 14.1728 12.8493 14.5979C13.4774 15.1459 14.7613 16.012 16.3437 15.7164C16.5448 15.6786 16.7379 15.6287 16.9239 15.5677C17.4935 15.4857 18.4679 15.4198 19.6154 15.7243C20.7046 16.0136 21.4882 16.5134 21.9423 16.8532Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "2.56",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M21.8003 6.90944C21.319 6.28602 20.7339 5.69669 20.043 5.29456C19.3066 4.86626 18.367 4.49744 17.2306 4.3975C14.4541 4.15321 12.5557 5.69273 12.2099 5.98382C11.7796 6.38753 10.0582 7.81602 7.98609 8.60917C7.62509 8.73768 6.93016 9.0414 6.31253 9.71961C5.82401 10.2557 5.58492 10.8046 5.46777 11.1457C5.71483 11.1798 5.96985 11.2044 6.23284 11.2194C8.2419 11.3313 9.96813 11.3424 11.0974 10.7896C11.8433 10.4247 12.4976 9.90517 13.0618 9.29681C14.0787 8.19987 15.5618 7.71051 16.9118 8.04605C17.5318 8.13247 18.6117 8.19833 19.8605 7.81602C20.7228 7.55189 21.3652 7.21957 21.8003 6.90944Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "2.56",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M2.95884 7.37229C2.1886 6.97653 1.58732 6.52001 1.17721 6.16263C0.947963 5.96275 0.591797 6.12665 0.591797 6.43206V8.92893C0.591797 9.03766 0.640978 9.14079 0.725063 9.20796L1.74835 10.1922C1.80229 9.79638 1.9181 9.25834 2.17829 8.66347C2.4234 8.10227 2.71769 7.67288 2.95884 7.37229Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "2.56",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M19.4326 12.9446C19.5497 12.584 19.6146 12.2056 19.6243 11.8201C19.6323 11.5156 19.597 11.4018 19.5441 11.1069C20.0886 11.0155 20.7686 10.8664 21.3886 10.7061C22.0438 10.537 22.5282 10.3406 23.0727 10.145C23.1521 10.5257 23.2355 10.7109 23.2644 10.993C23.2916 11.2591 23.3085 11.5348 23.3132 11.8201C23.3277 12.7066 23.2194 13.5105 23.0526 14.215C22.5394 13.9488 21.9299 13.6732 21.2282 13.4311C20.5754 13.2051 19.9683 13.0512 19.4326 12.9446Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "2.56",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M1.15342 18.2166C0.918616 18.3871 0.591797 18.2191 0.591797 17.927V14.8605C0.591797 14.7676 0.627493 14.6796 0.689366 14.614C0.720303 14.5812 0.748859 14.5628 0.761552 14.5556L1.77532 14.1204C1.84988 14.5268 1.97284 15.0133 2.17829 15.5429C2.41864 16.1621 2.7042 16.6637 2.95884 17.0454C2.35676 17.4358 1.75469 17.8263 1.15342 18.2166Z",
+ "fill": "#0A60B5",
+ "stroke": "black",
+ "stroke-width": "2.56",
+ "stroke-miterlimit": "10"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M7.68233 4.81872C9.70993 4.71818 11.2261 5.56713 12.0077 6.13451C11.4161 6.65689 9.81509 7.91742 7.92157 8.64547C7.79386 8.69117 7.62441 8.7588 7.43136 8.85733C6.06118 9.53194 5.24643 10.8764 5.21006 12.3127C5.20395 12.5545 5.21629 12.7953 5.24827 13.032C5.24481 13.0325 5.24136 13.033 5.23794 13.0334C5.23236 13.2797 5.2531 13.8593 5.60958 14.4661C5.9278 15.0073 6.35446 15.2975 6.5666 15.4227C6.67187 15.4928 6.83891 15.5939 7.04732 15.6986C7.29214 15.829 7.56361 15.9383 7.86305 16.0229C7.90892 16.0362 7.95532 16.0488 8.00211 16.0605C8.11111 16.0877 8.22985 16.1159 8.35794 16.1463C9.26137 16.3607 10.6303 16.6854 12.3087 17.5673C12.4783 17.7095 12.6609 17.8529 12.8568 17.993C12.7973 18.0463 12.7472 18.0927 12.7067 18.1309C12.3606 18.4235 10.4609 19.9709 7.68233 19.7254C6.5451 19.625 5.60404 19.2542 4.86793 18.8238C3.62779 18.0991 2.69071 16.9526 2.17951 15.6109C1.85014 14.7459 1.56303 13.6274 1.5423 12.3111C1.52395 11.187 1.70419 10.1969 1.94983 9.37575C2.70188 6.86682 4.89504 5.0268 7.5093 4.82989L7.50941 4.82988C7.5668 4.82589 7.62418 4.82191 7.68233 4.81872ZM21.8835 16.7762C21.4284 16.4391 20.6476 15.947 19.5661 15.6619C18.4192 15.3597 17.4455 15.4251 16.8761 15.5064C16.6902 15.567 16.4972 15.6164 16.2963 15.6539C14.7148 15.9473 13.4316 15.0879 12.8039 14.5442C12.6819 14.4387 12.5561 14.338 12.4269 14.2422C12.8493 13.871 13.3137 13.5508 13.82 13.3021C14.9501 12.7473 16.6775 12.7584 18.6881 12.87C21.4586 13.0247 23.3726 14.3441 24.1367 14.95C24.222 15.0177 24.2707 15.1198 24.2707 15.2282V17.718C24.2707 18.0233 23.9125 18.1867 23.682 17.9867C23.2692 17.6292 22.6618 17.1721 21.8835 16.7762ZM13.0009 9.33672C12.8193 9.5334 12.6283 9.72087 12.4279 9.89693C12.8159 10.1847 13.2353 10.4283 13.6788 10.6234C14.7715 11.1049 16.2732 11.199 18.2095 11.1966C21.0495 11.1926 23.1406 10.1235 24.1 9.54153C24.206 9.47696 24.2707 9.36218 24.2707 9.23781V6.182C24.2707 5.89101 23.9421 5.72359 23.706 5.8934C23.1472 6.29546 22.3162 6.80863 21.2445 7.21229C20.8586 7.43971 20.3776 7.6719 19.8046 7.84826C18.5548 8.23249 17.4742 8.16632 16.8538 8.07944C15.5028 7.74222 14.0186 8.2341 13.0009 9.33672Z",
+ "fill": "#E11312"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_10",
+ "d": "M12.0069 6.13459L12.21 6.36447L12.4968 6.11122L12.1871 5.88642L12.0069 6.13459ZM7.68154 4.8188L7.66636 4.51247L7.66557 4.51251L7.66477 4.51255L7.68154 4.8188ZM7.92078 8.64555L8.0241 8.9344L8.02755 8.93317L8.03092 8.93187L7.92078 8.64555ZM7.43056 8.85741L7.56612 9.13253L7.56811 9.13161L7.57008 9.13062L7.43056 8.85741ZM5.24747 13.0321L5.28765 13.3361L5.59271 13.2959L5.55152 12.991L5.24747 13.0321ZM5.23715 13.0335L5.1967 12.7295L4.93636 12.764L4.93041 13.0265L5.23715 13.0335ZM6.56581 15.4228L6.736 15.1676L6.729 15.1629L6.72175 15.1587L6.56581 15.4228ZM7.04653 15.6987L7.19079 15.428L7.18759 15.4263L7.18433 15.4247L7.04653 15.6987ZM7.86225 16.023L7.94762 15.7285L7.9467 15.7282L7.94571 15.7279L7.86225 16.023ZM12.3079 17.5673L12.5052 17.3324L12.4799 17.3112L12.4506 17.2958L12.3079 17.5673ZM12.856 17.9931L13.0606 18.2216L13.3458 17.9664L13.0346 17.7437L12.856 17.9931ZM12.7059 18.131L12.904 18.3652L12.9105 18.3598L12.9165 18.3541L12.7059 18.131ZM4.86713 18.8239L5.02207 18.5591L5.02197 18.559L4.86713 18.8239ZM1.5415 12.3112L1.84828 12.3064L1.84827 12.3062L1.5415 12.3112ZM1.94903 9.37583L1.65512 9.28773L1.65507 9.28796L1.94903 9.37583ZM7.5085 4.82997L7.48794 4.52395L7.48669 4.52403L7.48544 4.52413L7.5085 4.82997ZM7.50862 4.82996L7.52918 5.13598L7.52987 5.13593L7.50862 4.82996ZM19.5653 15.662L19.6435 15.3654H19.6435L19.5653 15.662ZM21.8827 16.7763L21.7001 17.0227L21.7207 17.038L21.7436 17.0496L21.8827 16.7763ZM16.8753 15.5065L16.8319 15.2028L16.8055 15.2066L16.7801 15.2149L16.8753 15.5065ZM16.2955 15.654L16.3515 15.9555H16.3517L16.2955 15.654ZM12.8031 14.5443L13.0041 14.3125L13.0038 14.3122L12.8031 14.5443ZM12.4261 14.2422L12.2236 14.0119L11.9383 14.2625L12.2434 14.4886L12.4261 14.2422ZM18.6873 12.8701L18.7044 12.5638H18.7042L18.6873 12.8701ZM24.1359 14.95L24.3267 14.7099L24.3266 14.7098L24.1359 14.95ZM23.6813 17.9868L23.8824 17.7552L23.8821 17.7549L23.6813 17.9868ZM12.4271 9.89701L12.2246 9.66667L11.9394 9.91717L12.2444 10.1434L12.4271 9.89701ZM13.678 10.6234L13.8018 10.3428L13.8016 10.3427L13.678 10.6234ZM18.2087 11.1967L18.2091 11.5034H18.2092L18.2087 11.1967ZM24.0992 9.54161L24.2584 9.80384L24.2588 9.80361L24.0992 9.54161ZM21.2437 7.21237L21.1355 6.92536L21.1107 6.9347L21.088 6.94815L21.2437 7.21237ZM16.853 8.07952L16.7786 8.37711L16.7943 8.38102L16.8104 8.38324L16.853 8.07952ZM12.1871 5.88642C11.3742 5.29623 9.7896 4.40718 7.66636 4.51247L7.69672 5.12514C9.62867 5.02934 11.0765 5.83819 11.8266 6.38275L12.1871 5.88642ZM8.03092 8.93187C9.97246 8.18534 11.605 6.89867 12.21 6.36447L11.8038 5.90471C11.2255 6.41528 9.65613 7.64973 7.81063 8.35932L8.03092 8.93187ZM7.57008 9.13062C7.74904 9.03922 7.90597 8.97657 8.0241 8.9344L7.81746 8.35679C7.68016 8.40586 7.49818 8.47855 7.29104 8.58429L7.57008 9.13062ZM5.51598 12.3205C5.54953 10.9957 6.30059 9.75569 7.56612 9.13253L7.29499 8.5823C5.82017 9.30843 4.94173 10.7573 4.90255 12.3051L5.51598 12.3205ZM5.55152 12.991C5.52184 12.7713 5.51027 12.5468 5.51598 12.3205L4.90255 12.3051C4.89604 12.5623 4.90915 12.8196 4.94341 13.0731L5.55152 12.991ZM5.27759 13.3375C5.28094 13.3371 5.28429 13.3366 5.28765 13.3361L5.20729 12.728C5.20373 12.7285 5.2002 12.729 5.1967 12.7295L5.27759 13.3375ZM5.87334 14.3108C5.55756 13.7734 5.53893 13.2588 5.54388 13.0404L4.93041 13.0265C4.92419 13.3008 4.94703 13.9455 5.34423 14.6215L5.87334 14.3108ZM6.72175 15.1587C6.53331 15.0475 6.15501 14.7899 5.87331 14.3107L5.34423 14.6215C5.69895 15.2249 6.17402 15.5477 6.40985 15.6869L6.72175 15.1587ZM7.18433 15.4247C6.98719 15.3256 6.83096 15.2309 6.736 15.1676L6.39562 15.678C6.51119 15.755 6.68904 15.8623 6.90873 15.9728L7.18433 15.4247ZM7.94571 15.7279C7.66622 15.6489 7.41526 15.5476 7.19079 15.428L6.90227 15.9694C7.16743 16.1106 7.4594 16.2279 7.7788 16.3182L7.94571 15.7279ZM8.07572 15.763C8.03277 15.7523 7.99004 15.7407 7.94762 15.7285L7.7768 16.3176C7.8262 16.3319 7.87621 16.3455 7.92691 16.3581L8.07572 15.763ZM8.42802 15.8479C8.29947 15.8174 8.18257 15.7897 8.07572 15.763L7.92691 16.3581C8.03798 16.3859 8.15864 16.4145 8.28627 16.4448L8.42802 15.8479ZM12.4506 17.2958C10.7369 16.3954 9.3372 16.0636 8.42802 15.8479L8.28627 16.4448C9.18402 16.6578 10.522 16.9755 12.1651 17.8389L12.4506 17.2958ZM13.0346 17.7437C12.8458 17.6086 12.6693 17.4702 12.5052 17.3324L12.1107 17.8023C12.2855 17.949 12.4745 18.0973 12.6774 18.2425L13.0346 17.7437ZM12.9165 18.3541C12.9555 18.3173 13.0035 18.2727 13.0606 18.2216L12.6514 17.7646C12.5895 17.8199 12.5373 17.8684 12.4953 17.908L12.9165 18.3541ZM7.65454 20.031C10.5596 20.2878 12.5414 18.6718 12.904 18.3652L12.5078 17.8968C12.1782 18.1755 10.3606 19.6543 7.70861 19.42L7.65454 20.031ZM4.7122 19.0885C5.48062 19.538 6.46494 19.9259 7.65455 20.0311L7.70861 19.42C6.62375 19.3242 5.72585 18.9707 5.02207 18.5591L4.7122 19.0885ZM1.89197 15.7201C2.42664 17.1235 3.4083 18.3266 4.71229 19.0886L5.02197 18.559C3.84569 17.8717 2.95318 16.7819 2.46543 15.5018L1.89197 15.7201ZM1.23472 12.316C1.25612 13.6744 1.55244 14.8284 1.89197 15.7201L2.46546 15.5019C2.14624 14.6635 1.86835 13.5804 1.84828 12.3064L1.23472 12.316ZM1.65507 9.28796C1.40184 10.1345 1.21579 11.1561 1.23472 12.3163L1.84827 12.3062C1.83052 11.2181 2.00495 10.2594 2.24298 9.4637L1.65507 9.28796ZM7.48544 4.52413C4.73874 4.73102 2.44195 6.66285 1.65512 9.28773L2.24293 9.46385C2.96021 7.07095 5.04976 5.32275 7.53155 5.13581L7.48544 4.52413ZM7.48805 4.52394L7.48794 4.52395L7.52906 5.13599L7.52918 5.13598L7.48805 4.52394ZM7.66477 4.51255C7.60399 4.51588 7.54439 4.52003 7.48736 4.52399L7.52987 5.13593C7.58761 5.13192 7.64276 5.1281 7.69834 5.12505L7.66477 4.51255ZM19.4871 15.9585C20.5195 16.2307 21.2651 16.7006 21.7001 17.0227L22.0654 16.5298C21.5901 16.1778 20.7741 15.6634 19.6435 15.3654L19.4871 15.9585ZM16.9186 15.8101C17.4624 15.7325 18.3923 15.6701 19.4871 15.9585L19.6435 15.3654C18.4447 15.0495 17.427 15.1179 16.8319 15.2028L16.9186 15.8101ZM16.3517 15.9555C16.5658 15.9156 16.7717 15.8629 16.9704 15.7981L16.7801 15.2149C16.6071 15.2713 16.4271 15.3174 16.2392 15.3524L16.3517 15.9555ZM12.6023 14.776C13.2517 15.3386 14.6295 16.275 16.3515 15.9555L16.2395 15.3524C14.7985 15.6197 13.6099 14.8372 13.0041 14.3125L12.6023 14.776ZM12.2434 14.4886C12.3665 14.5799 12.4863 14.6758 12.6025 14.7763L13.0038 14.3122C12.876 14.2017 12.7442 14.0962 12.6089 13.9959L12.2434 14.4886ZM13.6839 13.0269C13.1508 13.2889 12.6639 13.625 12.2236 14.0119L12.6286 14.4726C13.033 14.1173 13.4752 13.8129 13.9546 13.5774L13.6839 13.0269ZM18.7042 12.5638C17.6973 12.5079 16.7474 12.4763 15.9035 12.5301C15.0621 12.5838 14.3014 12.7237 13.6839 13.0269L13.9546 13.5774C14.4672 13.3258 15.1352 13.1938 15.9426 13.1423C16.7477 13.0909 17.6667 13.1206 18.6702 13.1763L18.7042 12.5638ZM24.3266 14.7098C23.5387 14.085 21.5647 12.7236 18.7044 12.5638L18.6702 13.1763C21.3509 13.3259 23.2049 14.6033 23.9452 15.1903L24.3266 14.7098ZM24.5767 15.2283C24.5767 15.0273 24.4861 14.8365 24.3267 14.7099L23.945 15.1902C23.9563 15.1992 23.9631 15.2124 23.9631 15.2283H24.5767ZM24.5767 17.7181V15.2283H23.9631V17.7181H24.5767ZM23.4801 18.2183C23.9096 18.5912 24.5767 18.2859 24.5767 17.7181H23.9631C23.9631 17.7326 23.9593 17.7405 23.9559 17.7456C23.9516 17.7519 23.9445 17.7584 23.9345 17.7629C23.9246 17.7675 23.915 17.7685 23.9076 17.7677C23.9016 17.7669 23.8933 17.7646 23.8824 17.7552L23.4801 18.2183ZM21.7436 17.0496C22.4948 17.4318 23.0817 17.8734 23.4804 18.2186L23.8821 17.7549C23.4551 17.3852 22.8272 16.9126 22.0218 16.5029L21.7436 17.0496ZM12.6296 10.1274C12.8386 9.94385 13.0372 9.74886 13.2256 9.54483L12.7747 9.1287C12.5998 9.31809 12.4165 9.49805 12.2246 9.66667L12.6296 10.1274ZM13.8016 10.3427C13.379 10.1569 12.9795 9.92476 12.6099 9.65072L12.2444 10.1434C12.6507 10.4448 13.0899 10.6999 13.5545 10.9042L13.8016 10.3427ZM18.2083 10.89C16.2651 10.8924 14.8268 10.7946 13.8018 10.3428L13.5543 10.9041C14.7145 11.4154 16.2797 11.5058 18.2091 11.5034L18.2083 10.89ZM23.94 9.27945C23.0063 9.84586 20.971 10.8861 18.2083 10.89L18.2092 11.5034C21.1263 11.4993 23.2733 10.4014 24.2584 9.80384L23.94 9.27945ZM23.9631 9.23789C23.9631 9.25522 23.9542 9.27078 23.9396 9.27968L24.2588 9.80361C24.4563 9.68338 24.5767 9.4693 24.5767 9.23789H23.9631ZM23.9631 6.18208V9.23789H24.5767V6.18208H23.9631ZM23.8844 6.14243C23.9185 6.11792 23.9631 6.14225 23.9631 6.18208H24.5767C24.5767 5.63993 23.9641 5.32941 23.526 5.64453L23.8844 6.14243ZM21.3519 7.49938C22.4546 7.08404 23.3093 6.55621 23.8844 6.14243L23.526 5.64453C22.9834 6.03488 22.1762 6.53338 21.1355 6.92536L21.3519 7.49938ZM19.894 8.14148C20.4934 7.95707 20.9962 7.71423 21.3995 7.4766L21.088 6.94815C20.7192 7.16536 20.2602 7.38697 19.7135 7.55519L19.894 8.14148ZM16.8104 8.38324C17.4579 8.47395 18.5872 8.54334 19.894 8.14148L19.7136 7.55517C18.5209 7.92187 17.4889 7.85892 16.8955 7.7758L16.8104 8.38324ZM13.2256 9.54483C14.1759 8.5152 15.5483 8.07001 16.7786 8.37711L16.9273 7.78194C15.4556 7.41459 13.8597 7.95323 12.7746 9.12877L13.2256 9.54483Z",
+ "fill": "black"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LangfuseIconBig"
+}
diff --git a/app/components/base/icons/src/public/tracing/LangfuseIconBig.tsx b/app/components/base/icons/src/public/tracing/LangfuseIconBig.tsx
new file mode 100644
index 0000000..69ac5aa
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/LangfuseIconBig.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LangfuseIconBig.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LangfuseIconBig'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/tracing/LangsmithIcon.json b/app/components/base/icons/src/public/tracing/LangsmithIcon.json
new file mode 100644
index 0000000..293c4bf
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/LangsmithIcon.json
@@ -0,0 +1,188 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "84",
+ "height": "14",
+ "viewBox": "0 0 84 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_20135_16592",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "0",
+ "width": "84",
+ "height": "14"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "a"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M83.2164 0.600098H0.799805V13.4001H83.2164V0.600098Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_20135_16592)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M31.0264 3.12256V10.8845H36.3737V9.71251H32.2403V3.12256H31.0264Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M39.2238 4.96436C38.0585 4.96436 37.1871 5.51066 36.8333 6.46298C36.8108 6.52391 36.7427 6.70772 36.7427 6.70772L37.7416 7.35386L37.8773 7.00007C38.1087 6.39693 38.5367 6.11584 39.2238 6.11584C39.911 6.11584 40.3042 6.44916 40.297 7.10554C40.297 7.13216 40.295 7.21255 40.295 7.21255C40.295 7.21255 39.3856 7.36 39.0109 7.43936C37.4119 7.77728 36.7422 8.38759 36.7422 9.38599C36.7422 9.91796 37.0376 10.494 37.5767 10.817C37.9003 11.0106 38.3227 11.0838 38.7892 11.0838C39.0959 11.0838 39.3938 11.0382 39.6698 10.9542C40.297 10.7459 40.4721 10.3363 40.4721 10.3363V10.8718H41.511V7.04308C41.511 5.74157 40.6559 4.96436 39.2238 4.96436ZM40.3011 9.05012C40.3011 9.45255 39.8628 10.0193 38.8419 10.0193C38.5536 10.0193 38.3494 9.94304 38.2132 9.82938C38.0309 9.67732 37.971 9.45869 37.9961 9.26567C38.0068 9.1817 38.0575 9.00096 38.2454 8.84429C38.4374 8.68404 38.7769 8.56935 39.3012 8.45517C39.7323 8.36148 40.3016 8.25805 40.3016 8.25805V9.05063L40.3011 9.05012Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M45.3523 4.96438C45.2079 4.96438 45.0671 4.97462 44.9304 4.99356C44.0001 5.13334 43.7277 5.60591 43.7277 5.60591L43.7287 5.13334H42.5645V10.8729H43.7784V7.68924C43.7784 6.60739 44.5674 6.11484 45.3006 6.11484C46.0932 6.11484 46.4782 6.54083 46.4782 7.41788V10.8729H47.6921V7.25097C47.6921 5.8399 46.7956 4.96387 45.3528 4.96387L45.3523 4.96438Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M52.7575 5.12922V5.72058C52.7575 5.72058 52.4601 4.96436 51.1067 4.96436C49.4253 4.96436 48.3809 6.12455 48.3809 7.99284C48.3809 9.04704 48.7178 9.877 49.3122 10.4013C49.7745 10.8088 50.392 11.0177 51.1272 11.0321C51.6387 11.0418 51.97 10.9025 52.1769 10.7709C52.5742 10.518 52.7217 10.2779 52.7217 10.2779C52.7217 10.2779 52.7048 10.4658 52.6741 10.7203C52.6521 10.9046 52.6106 11.0341 52.6106 11.0341C52.4258 11.692 51.885 12.0725 51.0965 12.0725C50.308 12.0725 49.8303 11.8129 49.7356 11.3014L48.5555 11.6536C48.7592 12.6367 49.6819 13.2234 51.0233 13.2234C51.9352 13.2234 52.65 12.9756 53.1482 12.4861C53.6505 11.9926 53.9054 11.2814 53.9054 10.3721V5.12871H52.7575V5.12922ZM52.6813 8.04455C52.6813 9.19348 52.1201 9.87956 51.18 9.87956C50.1729 9.87956 49.5953 9.19143 49.5953 7.99232C49.5953 6.79322 50.1729 6.11533 51.18 6.11533C52.0976 6.11533 52.6725 6.79834 52.6813 7.89812V8.04455Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M61.022 9.69984C61.1858 9.40237 61.2688 9.05165 61.2688 8.65689C61.2688 8.26214 61.1986 7.95904 61.0599 7.71379C60.9211 7.46752 60.7419 7.2663 60.5279 7.11526C60.3123 6.9632 60.0845 6.84339 59.852 6.7584C59.6186 6.67341 59.404 6.6048 59.2151 6.55513L57.8291 6.16857C57.654 6.12198 57.4789 6.0631 57.3079 5.99296C57.1354 5.9223 56.9884 5.82451 56.8722 5.70215C56.7534 5.57773 56.693 5.41594 56.693 5.21984C56.693 5.01402 56.7632 4.83124 56.9009 4.67661C57.0376 4.52352 57.2199 4.40474 57.4431 4.32333C57.6648 4.24192 57.909 4.2025 58.1691 4.20608C58.4364 4.21325 58.6919 4.26804 58.9279 4.36941C59.1649 4.47079 59.3687 4.62029 59.5336 4.81383C59.6938 5.00224 59.8049 5.23162 59.8643 5.49632L61.2042 5.26336C61.0901 4.80461 60.8955 4.40679 60.6252 4.08116C60.3497 3.74938 60.0026 3.49236 59.593 3.31776C59.1829 3.14266 58.7093 3.05204 58.185 3.04845C57.6689 3.04487 57.1912 3.1273 56.7688 3.2937C56.3474 3.45959 56.008 3.71252 55.7596 4.04532C55.5118 4.3776 55.3859 4.79437 55.3859 5.28384C55.3859 5.61869 55.4417 5.90285 55.5523 6.12916C55.6629 6.35597 55.8072 6.54439 55.9808 6.69031C56.1554 6.83674 56.3428 6.95245 56.5384 7.0354C56.7355 7.11885 56.9214 7.18644 57.0913 7.23559L59.0892 7.82644C59.2335 7.86996 59.3626 7.92218 59.4727 7.98157C59.5838 8.04148 59.6759 8.10906 59.7471 8.18228C59.8188 8.256 59.8741 8.341 59.9109 8.4352C59.9478 8.52941 59.9662 8.63284 59.9662 8.7424C59.9662 8.98765 59.8874 9.19808 59.7312 9.36653C59.5771 9.53344 59.3738 9.66247 59.1276 9.749C58.8823 9.83552 58.6176 9.87956 58.3401 9.87956C57.8716 9.87956 57.4518 9.75156 57.0929 9.49914C56.7391 9.25031 56.5 8.89498 56.3822 8.4434L55.0879 8.64C55.1678 9.12743 55.3516 9.55495 55.6342 9.91028C55.9219 10.2723 56.2947 10.5544 56.7411 10.7484C57.1886 10.943 57.6996 11.0418 58.2587 11.0418C58.6519 11.0418 59.0334 10.9916 59.3933 10.8923C59.7522 10.7935 60.0758 10.6429 60.3548 10.4448C60.6334 10.2477 60.8576 9.99629 61.0209 9.69882L61.022 9.69984Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M67.38 6.22747C67.5479 6.13173 67.7405 6.08309 67.9514 6.08309C68.2939 6.08309 68.5699 6.19777 68.7706 6.42459C68.9708 6.65038 69.0727 6.96629 69.0727 7.36513V10.8309H70.3158V7.04053C70.3158 6.4292 70.1453 5.92897 69.8094 5.55419C69.4741 5.18043 68.9846 4.99048 68.3543 4.99048C67.9734 4.99048 67.6237 5.07547 67.314 5.24289C67.0237 5.40008 66.7856 5.61921 66.6074 5.89365L66.5838 5.93L66.5634 5.89211C66.4226 5.63201 66.2229 5.41953 65.9694 5.26081C65.6832 5.08161 65.3218 4.99048 64.8958 4.99048C64.5082 4.99048 64.1534 5.07649 63.8421 5.24545C63.603 5.37499 63.3987 5.54446 63.2349 5.74824L63.1893 5.80507V5.13435H62.0967V10.8309H63.3506V7.31752C63.3506 6.95451 63.453 6.65499 63.6552 6.42766C63.858 6.19931 64.1309 6.0836 64.4667 6.0836C64.8026 6.0836 65.0903 6.19931 65.2916 6.42766C65.4918 6.65499 65.5931 6.97601 65.5931 7.38101V10.8309H66.8306V7.31752C66.8306 7.06254 66.8803 6.83931 66.9786 6.65345C67.0774 6.46709 67.2126 6.32424 67.3805 6.22798L67.38 6.22747Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M74.2724 9.3726C74.2796 9.6286 74.3487 9.88358 74.4787 10.1293C74.6257 10.3981 74.8438 10.5978 75.1269 10.7222C75.4126 10.8472 75.7408 10.9153 76.1028 10.924C76.4597 10.9327 76.8293 10.9025 77.2016 10.8344V9.80064C76.8514 9.85081 76.5339 9.86412 76.2585 9.83955C75.9682 9.81395 75.7541 9.68851 75.621 9.46732C75.5509 9.35366 75.513 9.20467 75.5074 9.02547C75.5022 8.84985 75.4992 8.64403 75.4992 8.4126V6.04563H77.2016V5.08204H75.4992V3.13184H74.2617V5.08204H73.209V6.04563H74.2617V8.48787C74.2617 8.81657 74.2652 9.11456 74.2724 9.37312V9.3726Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "d": "M80.8767 4.95543C80.7436 4.95543 80.6141 4.96414 80.4881 4.98052C79.5726 5.12337 79.3033 5.5898 79.3033 5.5898V5.4531H79.3028V3.11377H78.0889V10.8649H79.3028V7.68132C79.3028 6.5923 80.0918 6.09668 80.825 6.09668C81.6176 6.09668 82.0026 6.52267 82.0026 7.39972V10.8649H83.2165V7.23281C83.2165 5.8499 82.298 4.95595 80.8772 4.95595L80.8767 4.95543Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_10",
+ "d": "M72.3934 5.13281H71.1855V10.8775H72.3934V5.13281Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_11",
+ "d": "M71.7889 4.70524C72.2236 4.70524 72.5758 4.35291 72.5758 3.91829C72.5758 3.48368 72.2236 3.13135 71.7889 3.13135C71.3542 3.13135 71.002 3.48368 71.002 3.91829C71.002 4.35291 71.3542 4.70524 71.7889 4.70524Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_12",
+ "d": "M15.5941 10.4208C15.524 10.5375 15.313 10.5452 15.1333 10.4372C15.0412 10.3819 14.97 10.3056 14.9331 10.2226C14.8993 10.1474 14.8988 10.0762 14.9311 10.0224C14.968 9.96099 15.0442 9.92976 15.1344 9.92976C15.2152 9.92976 15.3074 9.95485 15.3924 10.0061C15.5721 10.1141 15.6648 10.304 15.5946 10.4208H15.5941ZM25.9939 7.0001C25.9939 10.5288 23.1226 13.4001 19.5939 13.4001H7.20859C3.67989 13.4001 0.808594 10.5293 0.808594 7.0001C0.808594 3.47088 3.67989 0.600098 7.20859 0.600098H19.5939C23.1231 0.600098 25.9939 3.47139 25.9939 7.0001ZM13.1427 10.2098C13.2435 10.0875 12.7776 9.74288 12.6824 9.61642C12.4888 9.4065 12.4878 9.10442 12.3573 8.85917C12.0378 8.11882 11.6707 7.3841 11.1571 6.75741C10.6144 6.07184 9.94472 5.50455 9.35643 4.86096C8.9197 4.41194 8.80296 3.77245 8.41743 3.28963C7.88597 2.50474 6.20559 2.29072 5.95931 3.3992C5.96034 3.43402 5.94959 3.45603 5.91937 3.47805C5.78318 3.57687 5.66184 3.69002 5.55995 3.82672C5.3106 4.17386 5.2722 4.76266 5.5835 5.07447C5.59374 4.91011 5.59937 4.75498 5.72942 4.63722C5.97007 4.84407 6.33358 4.91677 6.61262 4.76266C7.22907 5.64279 7.07547 6.86032 7.56494 7.80855C7.70011 8.0328 7.8363 8.26167 8.00987 8.45827C8.15067 8.67741 8.63707 8.93597 8.66574 9.13872C8.67086 9.48688 8.6299 9.8673 8.85825 10.1586C8.96577 10.3767 8.70158 10.5959 8.48859 10.5687C8.21211 10.6066 7.8747 10.3829 7.63252 10.5206C7.54702 10.6133 7.3796 10.5109 7.30587 10.6394C7.28027 10.706 7.14203 10.7997 7.22446 10.8637C7.31611 10.794 7.4011 10.7213 7.52449 10.7628C7.50606 10.8631 7.58542 10.8775 7.6484 10.9067C7.64635 10.9748 7.60641 11.0444 7.65864 11.1022C7.71956 11.0408 7.75592 10.9538 7.85268 10.9282C8.17422 11.3567 8.50139 10.4945 9.1972 10.8826C9.05588 10.8759 8.93044 10.8933 8.83521 11.0096C8.81166 11.0357 8.79169 11.0664 8.83316 11.1002C9.20846 10.858 9.20641 11.1831 9.45012 11.0833C9.63752 10.9855 9.82388 10.8631 10.0466 10.898C9.83003 10.9604 9.82132 11.1345 9.69435 11.2814C9.67284 11.304 9.6626 11.3296 9.68769 11.3669C10.1372 11.3291 10.1741 11.1796 10.5371 10.9963C10.8079 10.8309 11.0778 11.2318 11.3123 11.0034C11.364 10.9538 11.4346 10.9707 11.4986 10.964C11.4167 10.5273 10.5161 11.0439 10.5304 10.4581C10.8202 10.261 10.7537 9.88368 10.7731 9.57904C11.1064 9.76387 11.4771 9.87139 11.8038 10.048C11.9687 10.3143 12.2272 10.666 12.5718 10.643C12.581 10.6164 12.5892 10.5928 12.5989 10.5657C12.7034 10.5836 12.8375 10.6527 12.8949 10.5206C13.051 10.6839 13.2804 10.6757 13.4847 10.6338C13.6357 10.5109 13.2005 10.3358 13.1422 10.2093L13.1427 10.2098ZM17.8147 8.14595L17.1296 7.22128C16.5316 7.90531 16.1322 8.23863 16.1251 8.24477C16.1215 8.24835 15.74 8.61955 15.3924 8.93802C15.0514 9.25034 14.7821 9.49763 14.6449 9.76797C14.607 9.84272 14.5246 10.1182 14.6403 10.3936C14.7294 10.6066 14.9111 10.7582 15.1809 10.8442C15.2618 10.8698 15.3392 10.8811 15.4129 10.8811C15.8988 10.8811 16.2177 10.3936 16.2198 10.3895C16.2239 10.3839 16.6371 9.79357 17.1404 9.0481C17.3078 8.80029 17.4993 8.53815 17.8147 8.14544V8.14595ZM21.0357 10.2754C21.0357 10.1392 20.986 10.0076 20.8959 9.9057L20.8109 9.80944C20.2974 9.2273 18.979 7.73277 18.4659 7.15216C17.8218 6.42307 17.1015 5.49379 17.0416 5.41597L16.955 5.23677V4.92138C16.955 4.80567 16.932 4.69251 16.8874 4.58602L16.7041 4.15082C16.7016 4.14467 16.7006 4.13751 16.7016 4.13085L16.7088 4.07043C16.7098 4.06071 16.7144 4.052 16.7221 4.04535C16.8649 3.91939 17.3964 3.51082 18.2192 3.54512C18.3267 3.54973 18.3456 3.49085 18.3487 3.46576C18.3635 3.34493 18.0876 3.20259 17.8305 3.14986C17.4773 3.07767 16.5383 2.88618 15.7872 3.37923L15.7815 3.38333C15.2961 3.78883 14.906 4.09859 14.9019 4.10167L14.8932 4.11037C14.8876 4.11703 14.7504 4.28138 14.7836 4.49079C14.8051 4.62698 14.7345 4.67562 14.7304 4.67818C14.7263 4.68074 14.63 4.74115 14.5307 4.67306C14.4104 4.58295 14.2015 4.73757 14.159 4.77136L13.8436 5.04272L13.8375 5.04887C13.8318 5.05552 13.6967 5.21373 13.8774 5.46768C14.0336 5.68733 14.0888 5.76055 14.2245 5.92951C14.3623 6.10051 14.6106 6.31709 14.6239 6.32835C14.63 6.33347 14.7816 6.44816 14.9905 6.28842C15.162 6.15683 15.2997 6.03805 15.2997 6.03805C15.311 6.02883 15.4103 5.94691 15.4149 5.82608C15.4165 5.79127 15.4149 5.76106 15.4149 5.73341C15.4124 5.64842 15.4119 5.62333 15.4759 5.58237C15.5066 5.58237 15.6008 5.61667 15.6817 5.65763C15.6904 5.66275 15.8926 5.77642 16.0764 5.76823C16.1921 5.78359 16.3201 5.91517 16.3642 5.96893C16.3683 5.97303 16.7594 6.38365 17.3104 7.10403C17.4153 7.24074 17.8008 7.75427 17.9063 7.89763C18.0824 8.13725 18.3492 8.49975 18.6359 8.8904C19.1326 9.56675 19.6896 10.325 19.9425 10.666C20.0265 10.7792 20.1489 10.856 20.2871 10.8826L20.3808 10.9005C20.4167 10.9072 20.4525 10.9108 20.4883 10.9108C20.6542 10.9108 20.8114 10.8381 20.9153 10.709L20.921 10.7019C20.9957 10.6071 21.0367 10.4858 21.0367 10.3609V10.2754H21.0357ZM21.4765 4.20253L21.3674 4.09347C21.3357 4.06173 21.2912 4.04279 21.2461 4.04637C21.201 4.04842 21.1585 4.0689 21.1294 4.10371L20.4433 4.91523C20.4238 4.93827 20.3962 4.95261 20.3665 4.95568L20.1223 4.98026C20.091 4.98333 20.0598 4.9736 20.0357 4.95363L19.6456 4.62339C19.6205 4.60189 19.6056 4.57117 19.6046 4.5384L19.599 4.34282C19.598 4.31466 19.6077 4.28701 19.6256 4.26551L20.2928 3.46167C20.3429 3.40125 20.3424 3.3137 20.2917 3.25328L20.2247 3.17392C20.1806 3.12221 20.1079 3.10327 20.0444 3.12733C19.8867 3.18723 19.4894 3.34237 19.2022 3.49802C18.7962 3.71715 18.5141 4.0648 18.4654 4.40528C18.4296 4.65463 18.4444 5.06576 18.4567 5.28848C18.4613 5.37603 18.4419 5.46359 18.3994 5.54192C18.3472 5.6392 18.255 5.79485 18.1147 5.98224C18.043 6.08106 17.998 6.11741 17.936 6.19063L18.6907 7.07792C18.8725 6.86595 19.0317 6.70519 19.1704 6.55005C19.4239 6.26794 19.5027 6.26538 19.7137 6.25821C19.8437 6.2536 20.0219 6.24797 20.304 6.17731C21.0741 5.9848 21.3178 5.15127 21.328 5.1144L21.5195 4.35715C21.5333 4.30237 21.5169 4.24298 21.477 4.20304L21.4765 4.20253ZM9.63496 9.48842C9.55202 9.812 9.52488 10.3634 9.10402 10.3793C9.0692 10.5662 9.23355 10.6363 9.38255 10.5764C9.53051 10.5083 9.60066 10.6302 9.65032 10.7515C9.87867 10.7848 10.2166 10.6752 10.2294 10.4049C9.8884 10.2083 9.78293 9.83453 9.63445 9.48842H9.63496Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LangsmithIcon"
+}
diff --git a/app/components/base/icons/src/public/tracing/LangsmithIcon.tsx b/app/components/base/icons/src/public/tracing/LangsmithIcon.tsx
new file mode 100644
index 0000000..696442c
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/LangsmithIcon.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LangsmithIcon.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LangsmithIcon'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/tracing/LangsmithIconBig.json b/app/components/base/icons/src/public/tracing/LangsmithIconBig.json
new file mode 100644
index 0000000..18b1761
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/LangsmithIconBig.json
@@ -0,0 +1,188 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "124",
+ "height": "20",
+ "viewBox": "0 0 124 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Clip path group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_20135_18175",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "0",
+ "width": "124",
+ "height": "20"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "a"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M123.825 0.399902H0.200195V19.5999H123.825V0.399902Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_20135_18175)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M45.54 4.18408V15.827H53.561V14.069H47.361V4.18408H45.54Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M57.8358 6.94629C56.0878 6.94629 54.7807 7.76575 54.25 9.19423C54.2162 9.28562 54.1141 9.56133 54.1141 9.56133L55.6124 10.5305L55.8159 9.99986C56.1631 9.09515 56.8051 8.67352 57.8358 8.67352C58.8664 8.67352 59.4563 9.17349 59.4455 10.1581C59.4455 10.198 59.4424 10.3186 59.4424 10.3186C59.4424 10.3186 58.0785 10.5398 57.5163 10.6588C55.1178 11.1657 54.1133 12.0811 54.1133 13.5787C54.1133 14.3767 54.5564 15.2407 55.3651 15.7253C55.8505 16.0156 56.4841 16.1254 57.1837 16.1254C57.6438 16.1254 58.0908 16.0571 58.5047 15.9311C59.4455 15.6185 59.7082 15.0041 59.7082 15.0041V15.8075H61.2664V10.0644C61.2664 8.11211 59.9839 6.94629 57.8358 6.94629ZM59.4517 13.0749C59.4517 13.6786 58.7942 14.5288 57.2629 14.5288C56.8305 14.5288 56.524 14.4143 56.3197 14.2438C56.0463 14.0157 55.9565 13.6878 55.9941 13.3983C56.0102 13.2723 56.0863 13.0012 56.3681 12.7662C56.6561 12.5258 57.1653 12.3538 57.9517 12.1825C58.5984 12.042 59.4524 11.8868 59.4524 11.8868V13.0757L59.4517 13.0749Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M67.0275 6.94657C66.8109 6.94657 66.5997 6.96193 66.3946 6.99034C64.9992 7.20001 64.5906 7.90887 64.5906 7.90887L64.5921 7.20001H62.8457V15.8093H64.6666V11.0339C64.6666 9.41108 65.8501 8.67226 66.9499 8.67226C68.1388 8.67226 68.7163 9.31124 68.7163 10.6268V15.8093H70.5372V10.3765C70.5372 8.25985 69.1925 6.9458 67.0282 6.9458L67.0275 6.94657Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M78.1373 7.19359V8.08063C78.1373 8.08063 77.6911 6.94629 75.6611 6.94629C73.139 6.94629 71.5723 8.68658 71.5723 11.489C71.5723 13.0703 72.0776 14.3152 72.9693 15.1017C73.6628 15.713 74.589 16.0264 75.6918 16.0479C76.4591 16.0624 76.9559 15.8536 77.2664 15.6562C77.8623 15.2768 78.0835 14.9166 78.0835 14.9166C78.0835 14.9166 78.0582 15.1984 78.0121 15.5801C77.9791 15.8566 77.9169 16.0509 77.9169 16.0509C77.6396 17.0378 76.8285 17.6084 75.6457 17.6084C74.463 17.6084 73.7465 17.2191 73.6044 16.4518L71.8342 16.9802C72.1398 18.4548 73.5238 19.3349 75.5359 19.3349C76.9037 19.3349 77.976 18.9632 78.7233 18.229C79.4767 17.4886 79.8591 16.4219 79.8591 15.0579V7.19282H78.1373V7.19359ZM78.0229 11.5666C78.0229 13.29 77.1811 14.3191 75.7709 14.3191C74.2603 14.3191 73.394 13.2869 73.394 11.4882C73.394 9.68959 74.2603 8.67275 75.7709 8.67275C77.1473 8.67275 78.0098 9.69726 78.0229 11.3469V11.5666Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M90.532 14.0495C90.7777 13.6033 90.9022 13.0772 90.9022 12.4851C90.9022 11.893 90.7969 11.4383 90.5888 11.0704C90.3807 10.701 90.1119 10.3992 89.7909 10.1727C89.4675 9.94455 89.1258 9.76484 88.7771 9.63735C88.4269 9.50987 88.1051 9.40695 87.8217 9.33246L85.7427 8.75262C85.4801 8.68273 85.2174 8.59441 84.9609 8.48919C84.7021 8.38321 84.4817 8.23652 84.3073 8.05298C84.1292 7.86635 84.0385 7.62367 84.0385 7.32952C84.0385 7.02079 84.1437 6.74661 84.3503 6.51467C84.5554 6.28504 84.8288 6.10687 85.1637 5.98475C85.4962 5.86264 85.8625 5.80351 86.2527 5.80888C86.6536 5.81963 87.0368 5.90181 87.3909 6.05387C87.7464 6.20594 88.0521 6.43019 88.2994 6.7205C88.5398 7.00312 88.7064 7.34719 88.7955 7.74424L90.8054 7.3948C90.6341 6.70667 90.3423 6.10994 89.9368 5.62149C89.5236 5.12383 89.0029 4.73829 88.3885 4.4764C87.7733 4.21375 87.0629 4.07781 86.2765 4.07243C85.5023 4.06706 84.7858 4.19071 84.1522 4.44031C83.5201 4.68914 83.011 5.06853 82.6385 5.56773C82.2668 6.06616 82.0778 6.69131 82.0778 7.42552C82.0778 7.92779 82.1615 8.35403 82.3274 8.69349C82.4933 9.03371 82.7099 9.31634 82.9702 9.53522C83.2321 9.75487 83.5132 9.92843 83.8066 10.0529C84.1023 10.178 84.3811 10.2794 84.636 10.3531L87.6328 11.2394C87.8493 11.3047 88.0429 11.383 88.208 11.4721C88.3747 11.562 88.5129 11.6633 88.6197 11.7732C88.7272 11.8838 88.8101 12.0113 88.8654 12.1526C88.9207 12.2939 88.9484 12.449 88.9484 12.6134C88.9484 12.9812 88.8301 13.2969 88.5958 13.5496C88.3647 13.7999 88.0598 13.9935 87.6904 14.1232C87.3225 14.253 86.9254 14.3191 86.5092 14.3191C85.8065 14.3191 85.1767 14.1271 84.6383 13.7485C84.1077 13.3752 83.749 12.8422 83.5724 12.1648L81.6309 12.4598C81.7507 13.1909 82.0264 13.8322 82.4503 14.3652C82.8819 14.9081 83.441 15.3313 84.1107 15.6224C84.782 15.9142 85.5484 16.0624 86.3871 16.0624C86.9769 16.0624 87.5491 15.9872 88.089 15.8382C88.6273 15.69 89.1127 15.4642 89.5313 15.167C89.9491 14.8713 90.2855 14.4942 90.5304 14.048L90.532 14.0495Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M100.071 8.84108C100.322 8.69747 100.611 8.62451 100.928 8.62451C101.441 8.62451 101.855 8.79654 102.156 9.13676C102.457 9.47545 102.61 9.94931 102.61 10.5476V15.7462H104.474V10.0607C104.474 9.14368 104.218 8.39334 103.715 7.83116C103.212 7.27052 102.477 6.9856 101.532 6.9856C100.961 6.9856 100.436 7.11308 99.9714 7.36422C99.536 7.6 99.1789 7.9287 98.9116 8.34035L98.8763 8.39488L98.8455 8.33804C98.6343 7.9479 98.3348 7.62918 97.9547 7.3911C97.5253 7.1223 96.9831 6.9856 96.3442 6.9856C95.7628 6.9856 95.2306 7.11462 94.7636 7.36806C94.405 7.56236 94.0985 7.81657 93.8528 8.12224L93.7844 8.20748V7.2014H92.1455V15.7462H94.0263V10.4762C94.0263 9.93164 94.1799 9.48236 94.4833 9.14137C94.7874 8.79884 95.1968 8.62528 95.7006 8.62528C96.2044 8.62528 96.636 8.79884 96.9378 9.14137C97.2381 9.48236 97.3902 9.9639 97.3902 10.5714V15.7462H99.2464V10.4762C99.2464 10.0937 99.3209 9.75884 99.4684 9.48006C99.6166 9.20051 99.8194 8.98624 100.071 8.84185L100.071 8.84108Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M110.408 13.5589C110.418 13.9429 110.522 14.3254 110.717 14.694C110.938 15.0972 111.265 15.3967 111.689 15.5834C112.118 15.7707 112.61 15.8729 113.153 15.8859C113.689 15.899 114.243 15.8537 114.801 15.7515V14.201C114.276 14.2762 113.8 14.2962 113.387 14.2593C112.951 14.2209 112.63 14.0328 112.431 13.701C112.325 13.5305 112.269 13.307 112.26 13.0382C112.252 12.7748 112.248 12.466 112.248 12.1189V8.56844H114.801V7.12307H112.248V4.19775H110.392V7.12307H108.812V8.56844H110.392V12.2318C110.392 12.7249 110.397 13.1718 110.408 13.5597V13.5589Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "d": "M120.316 6.93339C120.116 6.93339 119.922 6.94645 119.733 6.97103C118.359 7.1853 117.955 7.88495 117.955 7.88495V7.67989H117.955V4.1709H116.134V15.7977H117.955V11.0222C117.955 9.38869 119.138 8.64527 120.238 8.64527C121.427 8.64527 122.004 9.28424 122.004 10.5998V15.7977H123.825V10.3495C123.825 8.27509 122.448 6.93416 120.316 6.93416L120.316 6.93339Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_10",
+ "d": "M107.589 7.19922H105.777V15.8162H107.589V7.19922Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_11",
+ "d": "M106.682 6.55761C107.334 6.55761 107.863 6.02913 107.863 5.37719C107.863 4.72527 107.334 4.19678 106.682 4.19678C106.03 4.19678 105.502 4.72527 105.502 5.37719C105.502 6.02913 106.03 6.55761 106.682 6.55761Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_12",
+ "d": "M22.3912 15.1309C22.286 15.306 21.9696 15.3175 21.7 15.1555C21.5618 15.0725 21.455 14.9581 21.3997 14.8337C21.349 14.7208 21.3483 14.614 21.3966 14.5334C21.4519 14.4412 21.5664 14.3944 21.7015 14.3944C21.8229 14.3944 21.9611 14.432 22.0886 14.5088C22.3582 14.6709 22.4972 14.9558 22.392 15.1309H22.3912ZM37.9908 9.9999C37.9908 15.293 33.6839 19.5999 28.3908 19.5999H9.81289C4.51983 19.5999 0.212891 15.2937 0.212891 9.9999C0.212891 4.70608 4.51983 0.399902 9.81289 0.399902H28.3908C33.6846 0.399902 37.9908 4.70685 37.9908 9.9999ZM18.714 14.8145C18.8653 14.6309 18.1664 14.1141 18.0236 13.9244C17.7333 13.6095 17.7317 13.1564 17.5359 12.7885C17.0567 11.678 16.506 10.5759 15.7357 9.63587C14.9216 8.60752 13.9171 7.75657 13.0347 6.7912C12.3795 6.11766 12.2044 5.15843 11.6261 4.43421C10.829 3.25686 8.30838 2.93584 7.93897 4.59856C7.94051 4.65078 7.92438 4.68381 7.87906 4.71683C7.67477 4.86505 7.49276 5.03478 7.33992 5.23984C6.96591 5.76054 6.90831 6.64374 7.37525 7.11145C7.39061 6.86493 7.39906 6.63222 7.59413 6.45558C7.9551 6.76585 8.50037 6.87491 8.91893 6.64374C9.8436 7.96393 9.6132 9.79024 10.3474 11.2126C10.5502 11.549 10.7545 11.8923 11.0148 12.1872C11.226 12.5159 11.9556 12.9037 11.9986 13.2078C12.0063 13.7301 11.9449 14.3007 12.2874 14.7377C12.4487 15.0649 12.0524 15.3936 11.7329 15.3529C11.3182 15.4097 10.8121 15.0741 10.4488 15.2807C10.3205 15.4197 10.0694 15.2661 9.9588 15.4588C9.9204 15.5587 9.71304 15.6992 9.83669 15.7952C9.97416 15.6908 10.1017 15.5817 10.2867 15.6439C10.2591 15.7945 10.3781 15.816 10.4726 15.8597C10.4695 15.9619 10.4096 16.0663 10.488 16.1531C10.5793 16.061 10.6339 15.9304 10.779 15.892C11.2613 16.5348 11.7521 15.2415 12.7958 15.8236C12.5838 15.8137 12.3957 15.8398 12.2528 16.0141C12.2175 16.0533 12.1875 16.0994 12.2497 16.15C12.8127 15.7868 12.8096 16.2745 13.1752 16.1247C13.4563 15.978 13.7358 15.7945 14.0699 15.8467C13.745 15.9404 13.732 16.2015 13.5415 16.4219C13.5093 16.4557 13.4939 16.4941 13.5315 16.5502C14.2058 16.4933 14.2611 16.2691 14.8057 15.9941C15.2119 15.7461 15.6167 16.3474 15.9684 16.0049C16.046 15.9304 16.152 15.9557 16.248 15.9458C16.1251 15.2907 14.7742 16.0656 14.7957 15.187C15.2304 14.8913 15.1305 14.3253 15.1597 13.8683C15.6597 14.1456 16.2157 14.3068 16.7057 14.5718C16.953 14.9712 17.3408 15.4988 17.8577 15.4642C17.8715 15.4243 17.8838 15.389 17.8984 15.3483C18.0551 15.3751 18.2563 15.4788 18.3423 15.2807C18.5765 15.5257 18.9206 15.5134 19.227 15.4504C19.4536 15.2661 18.8008 15.0034 18.7132 14.8137L18.714 14.8145ZM25.722 11.7187L24.6944 10.3317C23.7974 11.3577 23.1984 11.8577 23.1876 11.8669C23.1822 11.8723 22.6101 12.4291 22.0886 12.9068C21.5771 13.3753 21.1731 13.7462 20.9673 14.1517C20.9105 14.2638 20.7868 14.677 20.9604 15.0902C21.094 15.4097 21.3667 15.637 21.7714 15.766C21.8928 15.8044 22.0087 15.8213 22.1193 15.8213C22.8482 15.8213 23.3266 15.0902 23.3297 15.0841C23.3358 15.0756 23.9556 14.1901 24.7106 13.0719C24.9617 12.7002 25.2489 12.307 25.722 11.7179V11.7187ZM30.5535 14.9128C30.5535 14.7085 30.479 14.5111 30.3438 14.3583L30.2163 14.2139C29.446 13.3407 27.4684 11.0989 26.6989 10.228C25.7328 9.13437 24.6522 7.74045 24.5623 7.62371L24.4325 7.35491V6.88182C24.4325 6.70825 24.398 6.53853 24.3312 6.37878L24.0562 5.72598C24.0524 5.71677 24.0508 5.70601 24.0524 5.69603L24.0631 5.60541C24.0647 5.59081 24.0716 5.57776 24.0831 5.56777C24.2974 5.37885 25.0946 4.76598 26.3287 4.81744C26.49 4.82435 26.5184 4.73603 26.523 4.6984C26.5453 4.51715 26.1314 4.30365 25.7458 4.22454C25.2159 4.11625 23.8074 3.82902 22.6807 4.56861L22.6723 4.57475C21.9442 5.18301 21.359 5.64765 21.3529 5.65225L21.3398 5.66531C21.3314 5.67529 21.1255 5.92182 21.1755 6.23593C21.2077 6.44022 21.1017 6.51318 21.0956 6.51702C21.0894 6.52086 20.9451 6.61149 20.7961 6.50934C20.6156 6.37417 20.3022 6.60611 20.2385 6.6568L19.7654 7.06384L19.7562 7.07305C19.7477 7.08304 19.545 7.32035 19.8161 7.70128C20.0503 8.03075 20.1333 8.14057 20.3368 8.39401C20.5434 8.65053 20.9159 8.97539 20.9358 8.99229C20.9451 8.99997 21.1724 9.172 21.4857 8.93238C21.743 8.73501 21.9496 8.55683 21.9496 8.55683C21.9665 8.54301 22.1155 8.42013 22.1224 8.23888C22.1247 8.18665 22.1224 8.14134 22.1224 8.09987C22.1186 7.97238 22.1178 7.93475 22.2138 7.87331C22.2599 7.87331 22.4012 7.92477 22.5225 7.98621C22.5356 7.99389 22.8389 8.16438 23.1147 8.15209C23.2882 8.17513 23.4802 8.37251 23.5463 8.45315C23.5524 8.45929 24.1392 9.07523 24.9655 10.1558C25.123 10.3609 25.7013 11.1312 25.8595 11.3462C26.1237 11.7056 26.5238 12.2494 26.9539 12.8354C27.6988 13.8499 28.5344 14.9873 28.9138 15.4988C29.0398 15.6685 29.2233 15.7837 29.4307 15.8236L29.5712 15.8505C29.625 15.8605 29.6787 15.8659 29.7325 15.8659C29.9813 15.8659 30.2171 15.7568 30.373 15.5633L30.3815 15.5525C30.4936 15.4105 30.555 15.2284 30.555 15.0411V14.9128H30.5535ZM31.2147 5.80355L31.0512 5.63997C31.0035 5.59235 30.9367 5.56393 30.8691 5.56931C30.8016 5.57238 30.7378 5.6031 30.694 5.65533L29.6649 6.87261C29.6357 6.90717 29.5943 6.92867 29.5497 6.93328L29.1834 6.97014C29.1365 6.97475 29.0897 6.96016 29.0536 6.93021L28.4684 6.43485C28.4307 6.40259 28.4085 6.35651 28.4069 6.30736L28.3985 6.01398C28.397 5.97174 28.4115 5.93027 28.4384 5.89801L29.4391 4.69225C29.5144 4.60163 29.5136 4.4703 29.4376 4.37968L29.337 4.26064C29.2709 4.18307 29.1619 4.15465 29.0667 4.19075C28.8301 4.28061 28.2341 4.51331 27.8033 4.74678C27.1943 5.07549 26.7711 5.59696 26.6981 6.10768C26.6444 6.48169 26.6666 7.0984 26.6851 7.43248C26.692 7.56381 26.6628 7.69513 26.5991 7.81264C26.5207 7.95856 26.3825 8.19203 26.1721 8.47312C26.0645 8.62134 25.997 8.67587 25.904 8.78569L27.0361 10.1166C27.3087 9.79869 27.5475 9.55753 27.7557 9.32483C28.1358 8.90166 28.2541 8.89782 28.5705 8.88707C28.7656 8.88016 29.0329 8.87171 29.456 8.76573C30.6111 8.47696 30.9767 7.22665 30.992 7.17136L31.2793 6.03549C31.3 5.95331 31.2754 5.86422 31.2155 5.80432L31.2147 5.80355ZM13.4524 13.7324C13.328 14.2178 13.2873 15.0449 12.656 15.0687C12.6038 15.349 12.8503 15.4542 13.0738 15.3644C13.2958 15.2622 13.401 15.445 13.4755 15.627C13.818 15.677 14.3249 15.5126 14.3441 15.1071C13.8326 14.8122 13.6744 14.2516 13.4517 13.7324H13.4524Z",
+ "fill": "#1C3C3C"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LangsmithIconBig"
+}
diff --git a/app/components/base/icons/src/public/tracing/LangsmithIconBig.tsx b/app/components/base/icons/src/public/tracing/LangsmithIconBig.tsx
new file mode 100644
index 0000000..2e652d5
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/LangsmithIconBig.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LangsmithIconBig.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LangsmithIconBig'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/tracing/OpikIcon.json b/app/components/base/icons/src/public/tracing/OpikIcon.json
new file mode 100644
index 0000000..c9f3ad7
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/OpikIcon.json
@@ -0,0 +1,163 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "47.133904",
+ "height": "16",
+ "viewBox": "0 0 47.133904 16",
+ "fill": "none",
+ "version": "1.1",
+ "id": "svg6",
+ "sodipodi:docname": "opik-icon.svg",
+ "inkscape:version": "1.3.2 (091e20ef0f, 2023-11-25)",
+ "xmlns:inkscape": "http://www.inkscape.org/namespaces/inkscape",
+ "xmlns:sodipodi": "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd",
+ "xmlns": "http://www.w3.org/2000/svg",
+ "xmlns:svg": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "sodipodi:namedview",
+ "attributes": {
+ "id": "namedview6",
+ "pagecolor": "#b95d5d",
+ "bordercolor": "#666666",
+ "borderopacity": "1.0",
+ "inkscape:showpageshadow": "2",
+ "inkscape:pageopacity": "0.0",
+ "inkscape:pagecheckerboard": "0",
+ "inkscape:deskcolor": "#d1d1d1",
+ "inkscape:zoom": "18.615087",
+ "inkscape:cx": "34.541874",
+ "inkscape:cy": "18.882533",
+ "inkscape:window-width": "2560",
+ "inkscape:window-height": "1371",
+ "inkscape:window-x": "0",
+ "inkscape:window-y": "0",
+ "inkscape:window-maximized": "1",
+ "inkscape:current-layer": "svg6"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "47.119099",
+ "height": "15.98219",
+ "fill": "#ffffff",
+ "id": "rect1",
+ "x": "0",
+ "y": "0",
+ "style": "stroke-width:0.0455515;fill:none",
+ "inkscape:label": "rect1"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M 9.6391824,3.9256084 C 7.4584431,2.9677242 4.8694901,3.9910489 3.8733677,6.2551834 2.8772499,8.519327 3.8730396,11.117275 6.0537561,12.075159 c 0.8795869,0.38635 1.8205107,0.450735 2.6986394,0.243012 0.3780009,-0.08943 0.7570043,0.144295 0.8464576,0.521993 0.089499,0.377699 -0.1443649,0.7564 -0.5224113,0.845827 C 7.9135024,13.961058 6.6590133,13.876457 5.4876434,13.361931 2.568556,12.079712 1.2888532,8.636894 2.5855671,5.6895232 3.8822857,2.7421295 7.286235,1.3566284 10.205295,2.6388372 11.986296,3.4211403 13.15908,5.0124429 13.505682,6.7988966 13.579642,7.1799648 13.330421,7.548739 12.949049,7.6226396 12.567721,7.6964947 12.198606,7.447473 12.124692,7.0664048 11.860478,5.7048679 10.972279,4.5111667 9.6391824,3.9256084 Z m 2.3662996,7.7665706 c 0.136116,0.570532 -0.216457,1.14325 -0.787445,1.279258 -0.570989,0.135962 -1.14421,-0.216283 -1.2802814,-0.786816 -0.1361171,-0.570532 0.2164564,-1.143295 0.7874454,-1.279258 0.570987,-0.136008 1.14421,0.216283 1.280281,0.786816 z m 0.885967,-0.810128 c 0.762836,-0.181679 1.233846,-0.9468664 1.052022,-1.7090479 -0.181824,-0.7622275 -0.947622,-1.2328598 -1.710414,-1.0511819 -0.762838,0.1816779 -1.233846,0.9468196 -1.052023,1.7090471 0.181823,0.7622277 0.947623,1.2328597 1.710415,1.0511827 z",
+ "fill": "url(#paint0_linear_3874_31725)",
+ "id": "path1",
+ "style": "fill:url(#paint0_linear_3874_31725);stroke-width:0.0455515"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m 20.686606,11.857146 c -0.721642,0 -1.364084,-0.153857 -1.927326,-0.461616 -0.563197,-0.316594 -1.007638,-0.747475 -1.333234,-1.292646 -0.325641,-0.54517 -0.488416,-1.165106 -0.488416,-1.8598076 0,-0.703444 0.162775,-1.32338 0.488416,-1.8598079 0.325596,-0.5451702 0.770037,-0.9716351 1.333234,-1.2794403 0.563242,-0.3077596 1.205684,-0.4616167 1.927326,-0.4616167 0.730437,0 1.377254,0.1538571 1.940495,0.4616167 0.571992,0.3078052 1.016434,0.7298533 1.333234,1.2662813 0.325641,0.5363823 0.488417,1.1606894 0.488417,1.8729669 0,0.6947016 -0.162776,1.3146376 -0.488417,1.8598076 -0.3168,0.545171 -0.761242,0.976052 -1.333234,1.292646 -0.563241,0.307759 -1.210058,0.461616 -1.940495,0.461616 z m 0,-1.411304 c 0.404796,0 0.765617,-0.08797 1.082418,-0.263821 0.316846,-0.17585 0.563242,-0.4308815 0.739232,-0.7650049 0.184831,-0.3341689 0.277246,-0.7254822 0.277246,-1.1739397 0,-0.4572454 -0.09241,-0.8485586 -0.277246,-1.1738941 C 22.332266,6.7350133 22.08587,6.4800268 21.769024,6.3041317 21.452223,6.1282821 21.095822,6.0403572 20.699776,6.0403572 c -0.404796,0 -0.765617,0.087925 -1.082418,0.2637745 -0.308051,0.1758951 -0.554446,0.4308816 -0.739277,0.7650506 -0.184786,0.3253355 -0.277201,0.7166487 -0.277201,1.1738941 0,0.4484575 0.09241,0.8397708 0.277201,1.1739397 0.184831,0.3341234 0.431226,0.5891549 0.739277,0.7650049 0.316801,0.17585 0.673201,0.263821 1.069248,0.263821 z",
+ "fill": "#3a3a3a",
+ "id": "path2",
+ "style": "stroke-width:0.0455515"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m 29.934026,11.857146 c -0.571992,0 -1.095634,-0.131865 -1.57088,-0.395684 -0.466407,-0.26382 -0.840442,-0.659504 -1.122018,-1.1871 -0.272826,-0.5364272 -0.409217,-1.2135074 -0.409217,-2.0312856 0,-0.826566 0.131971,-1.5036463 0.396002,-2.0312862 0.272826,-0.5275944 0.642442,-0.9189077 1.108848,-1.1738942 0.466406,-0.26382 0.998843,-0.3956845 1.597265,-0.3956845 0.695257,0 1.306893,0.1494859 1.83491,0.4484576 0.536811,0.2989717 0.959243,0.7166486 1.267248,1.253031 0.316801,0.5364279 0.475202,1.169523 0.475202,1.8993763 0,0.7298534 -0.158401,1.3673652 -0.475202,1.9125806 -0.308005,0.536383 -0.730437,0.95406 -1.267248,1.253031 -0.528017,0.298972 -1.139653,0.448458 -1.83491,0.448458 z m -3.142079,2.466539 c -0.422659,0 -0.765298,-0.342319 -0.765298,-0.764641 V 5.4859892 c 0,-0.4223213 0.342639,-0.7646408 0.765298,-0.7646408 h 0.04028 c 0.42266,0 0.765299,0.3423195 0.765299,0.7646408 v 0.8972793 l -0.05281,1.8730126 0.132016,1.8729669 v 3.429796 c 0,0.422322 -0.342639,0.764641 -0.765298,0.764641 z m 2.957293,-3.877843 c 0.396001,0 0.748027,-0.08797 1.056033,-0.263821 0.316801,-0.17585 0.567616,-0.4308815 0.752447,-0.7650049 0.184786,-0.3341689 0.277201,-0.7254822 0.277201,-1.1739397 0,-0.4572454 -0.09241,-0.8485586 -0.277201,-1.1738941 C 31.372889,6.7350133 31.122074,6.4800268 30.805273,6.3041317 30.497267,6.1282821 30.145241,6.0403572 29.74924,6.0403572 c -0.396046,0 -0.752447,0.087925 -1.069248,0.2637745 -0.316846,0.1758951 -0.567662,0.4308816 -0.752447,0.7650506 -0.184831,0.3253355 -0.277201,0.7166487 -0.277201,1.1738941 0,0.4484575 0.09237,0.8397708 0.277201,1.1739397 0.184785,0.3341234 0.435601,0.5891549 0.752447,0.7650049 0.316801,0.17585 0.673202,0.263821 1.069248,0.263821 z",
+ "fill": "#3a3a3a",
+ "id": "path3",
+ "style": "stroke-width:0.0455515"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m 35.841594,11.76485 c -0.422659,0 -0.765298,-0.342365 -0.765298,-0.764686 V 5.4859892 c 0,-0.4223213 0.342639,-0.7646408 0.765298,-0.7646408 h 0.119484 c 0.422659,0 0.765298,0.3423195 0.765298,0.7646408 v 5.5141748 c 0,0.422321 -0.342639,0.764686 -0.765298,0.764686 z m 0.06635,-8.2042457 c -0.308006,0 -0.563241,-0.096726 -0.765662,-0.2901837 -0.19358,-0.1934528 -0.290371,-0.4264787 -0.290371,-0.6990729 0,-0.2813867 0.0968,-0.5144125 0.290371,-0.6990728 0.202421,-0.1934528 0.457656,-0.2901838 0.765662,-0.2901838 0.308006,0 0.558822,0.092332 0.752448,0.2769928 0.202375,0.1758678 0.303585,0.4001011 0.303585,0.6726954 0,0.2901792 -0.0968,0.536396 -0.290415,0.7386413 -0.19358,0.1934573 -0.448817,0.2901837 -0.765618,0.2901837 z",
+ "fill": "#3a3a3a",
+ "id": "path4",
+ "style": "stroke-width:0.0455515"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m 40.238571,10.195226 0.0396,-2.0708549 3.479613,-3.2151067 c 0.130739,-0.1208454 0.302264,-0.187916 0.480351,-0.187916 v 0 c 0.629636,0 0.945662,0.7599964 0.501357,1.2058131 l -1.926779,1.9333896 -0.871247,0.7254822 z m -0.581195,1.569624 c -0.42266,0 -0.765253,-0.342365 -0.765253,-0.764686 V 2.7424664 c 0,-0.4223168 0.342593,-0.7646726 0.765253,-0.7646726 h 0.119528 c 0.42266,0 0.765298,0.3423558 0.765298,0.7646726 v 8.2576976 c 0,0.422321 -0.342638,0.764686 -0.765298,0.764686 z m 4.919799,0 c -0.230994,0 -0.449637,-0.104271 -0.594959,-0.283718 l -2.34438,-2.8950987 1.042863,-1.3190088 2.564664,3.2606405 c 0.394542,0.501685 0.03692,1.237185 -0.601702,1.237185 z",
+ "fill": "#3a3a3a",
+ "id": "path5",
+ "style": "stroke-width:0.0455515"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {
+ "id": "defs6"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_3874_31725",
+ "x1": "258.13101",
+ "y1": "269.78299",
+ "x2": "88.645203",
+ "y2": "75.4571",
+ "gradientUnits": "userSpaceOnUse",
+ "gradientTransform": "scale(0.04556973,0.04553331)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#FB9341",
+ "id": "stop5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#E30D3E",
+ "id": "stop6"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "OpikIcon"
+}
diff --git a/app/components/base/icons/src/public/tracing/OpikIcon.tsx b/app/components/base/icons/src/public/tracing/OpikIcon.tsx
new file mode 100644
index 0000000..9f114fb
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/OpikIcon.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './OpikIcon.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'OpikIcon'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/tracing/OpikIconBig.json b/app/components/base/icons/src/public/tracing/OpikIconBig.json
new file mode 100644
index 0000000..44e1e2c
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/OpikIconBig.json
@@ -0,0 +1,162 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "70.700851",
+ "height": "24",
+ "viewBox": "0 0 70.700851 24",
+ "fill": "none",
+ "version": "1.1",
+ "id": "svg6",
+ "sodipodi:docname": "opik-icon-big.svg",
+ "inkscape:version": "1.3.2 (091e20ef0f, 2023-11-25)",
+ "xmlns:inkscape": "http://www.inkscape.org/namespaces/inkscape",
+ "xmlns:sodipodi": "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd",
+ "xmlns": "http://www.w3.org/2000/svg",
+ "xmlns:svg": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "sodipodi:namedview",
+ "attributes": {
+ "id": "namedview6",
+ "pagecolor": "#ffffff",
+ "bordercolor": "#666666",
+ "borderopacity": "1.0",
+ "inkscape:showpageshadow": "2",
+ "inkscape:pageopacity": "0.0",
+ "inkscape:pagecheckerboard": "0",
+ "inkscape:deskcolor": "#d1d1d1",
+ "inkscape:zoom": "18.615088",
+ "inkscape:cx": "36.314629",
+ "inkscape:cy": "18.989972",
+ "inkscape:window-width": "2560",
+ "inkscape:window-height": "1371",
+ "inkscape:window-x": "0",
+ "inkscape:window-y": "0",
+ "inkscape:window-maximized": "1",
+ "inkscape:current-layer": "svg6"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "70.700851",
+ "height": "24",
+ "fill": "#ffffff",
+ "id": "rect1",
+ "x": "0",
+ "y": "0",
+ "style": "stroke-width:0.0683761;fill:none"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M 14.463316,5.8949744 C 11.191179,4.456547 7.3065299,5.9932444 5.8118769,9.3932308 4.3172308,12.793231 5.8113846,16.694496 9.0834872,18.132923 c 1.3197948,0.580171 2.7316238,0.676855 4.0492308,0.364923 0.567179,-0.13429 1.135863,0.216684 1.270085,0.783863 0.134291,0.56718 -0.216615,1.135864 -0.783863,1.270154 C 11.873983,20.964923 9.9916581,20.83788 8.2340513,20.065231 3.8540444,18.139761 1.9338872,12.969778 3.8795692,8.5437949 5.8252581,4.1177778 10.932786,2.0372103 15.312752,3.9626667 c 2.672342,1.1747624 4.432069,3.564376 4.952137,6.2470423 0.110974,0.57224 -0.262974,1.126017 -0.835214,1.236992 -0.572171,0.110906 -1.126017,-0.263043 -1.236923,-0.835282 C 17.796308,8.5668376 16.46359,6.7742906 14.463316,5.8949744 Z M 18.01388,17.557812 c 0.20424,0.856752 -0.324786,1.716786 -1.181538,1.921026 -0.856752,0.204171 -1.716855,-0.324787 -1.921026,-1.181539 -0.204239,-0.856752 0.324787,-1.716855 1.181539,-1.921025 0.856752,-0.20424 1.716854,0.324786 1.921025,1.181538 z m 1.329368,-1.216547 c 1.144615,-0.272821 1.85135,-1.42188 1.57853,-2.566427 -0.272821,-1.144616 -1.421881,-1.851351 -2.566428,-1.57853 -1.144615,0.27282 -1.85135,1.421812 -1.578529,2.566427 0.27282,1.144615 1.42188,1.85135 2.566427,1.57853 z",
+ "fill": "url(#paint0_linear_3874_31725)",
+ "id": "path1",
+ "style": "fill:url(#paint0_linear_3874_31725);stroke-width:0.0683761"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m 31.039658,17.805538 c -1.082803,0 -2.046769,-0.231042 -2.891897,-0.693196 -0.84506,-0.475419 -1.511932,-1.122462 -2.000479,-1.941128 -0.488615,-0.818667 -0.732855,-1.749607 -0.732855,-2.792821 0,-1.056342 0.24424,-1.987282 0.732855,-2.7928204 0.488547,-0.8186666 1.155419,-1.4590769 2.000479,-1.9212991 0.845128,-0.4621538 1.809094,-0.6931966 2.891897,-0.6931966 1.096,0 2.06653,0.2310428 2.911658,0.6931966 0.858257,0.4622222 1.525128,1.096 2.000479,1.9015385 0.488615,0.80547 0.732855,1.742974 0.732855,2.812581 0,1.043214 -0.24424,1.974154 -0.732855,2.792821 -0.475351,0.818666 -1.142222,1.465709 -2.000479,1.941128 -0.845128,0.462154 -1.815658,0.693196 -2.911658,0.693196 z m 0,-2.119316 c 0.607385,0 1.148786,-0.132102 1.624137,-0.396171 0.475419,-0.264068 0.845128,-0.647042 1.109196,-1.148786 0.277334,-0.501812 0.416,-1.089436 0.416,-1.762872 0,-0.686632 -0.138666,-1.274256 -0.416,-1.762803 -0.264068,-0.501812 -0.633777,-0.8847182 -1.109196,-1.148855 -0.475351,-0.2640683 -1.01012,-0.3961025 -1.604376,-0.3961025 -0.607385,0 -1.148787,0.1320342 -1.624137,0.3961025 -0.462222,0.2641368 -0.831932,0.647043 -1.109265,1.148855 -0.277265,0.488547 -0.415932,1.076171 -0.415932,1.762803 0,0.673436 0.138667,1.26106 0.415932,1.762872 0.277333,0.501744 0.647043,0.884718 1.109265,1.148786 0.47535,0.264069 1.01012,0.396171 1.604376,0.396171 z",
+ "fill": "#3a3a3a",
+ "id": "path2",
+ "style": "stroke-width:0.0683761"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m 44.915145,17.805538 c -0.858256,0 -1.643966,-0.198017 -2.35706,-0.594188 -0.699829,-0.396171 -1.261059,-0.990359 -1.683555,-1.782632 -0.409368,-0.805539 -0.614017,-1.822291 -0.614017,-3.050325 0,-1.241231 0.198017,-2.257983 0.594188,-3.0503246 0.409367,-0.7922735 0.963966,-1.3798975 1.663795,-1.7628034 0.699829,-0.396171 1.498735,-0.5941881 2.396649,-0.5941881 1.043214,0 1.960958,0.2244787 2.753231,0.6734359 0.80547,0.4489573 1.439316,1.076171 1.90147,1.881641 0.475351,0.8055382 0.713026,1.7562392 0.713026,2.8522392 0,1.096 -0.237675,2.053333 -0.713026,2.872069 -0.462154,0.80547 -1.096,1.432683 -1.90147,1.881641 -0.792273,0.448957 -1.710017,0.673435 -2.753231,0.673435 z m -4.714598,3.703932 c -0.634188,0 -1.148308,-0.514051 -1.148308,-1.148239 V 8.2381538 c 0,-0.634188 0.51412,-1.1482393 1.148308,-1.1482393 h 0.06044 c 0.634188,0 1.148308,0.5140513 1.148308,1.1482393 v 1.3474188 l -0.07925,2.8126494 0.198086,2.812581 v 5.150428 c 0,0.634188 -0.51412,1.148239 -1.148308,1.148239 z m 4.437333,-5.823248 c 0.594188,0 1.122394,-0.132102 1.584547,-0.396171 0.475351,-0.264068 0.851693,-0.647042 1.129026,-1.148786 0.277265,-0.501812 0.415932,-1.089436 0.415932,-1.762872 0,-0.686632 -0.138667,-1.274256 -0.415932,-1.762803 C 47.07412,10.113778 46.697778,9.7308718 46.222427,9.466735 45.760274,9.2026667 45.232068,9.0706325 44.63788,9.0706325 c -0.594256,0 -1.129025,0.1320342 -1.604376,0.3961025 -0.475419,0.2641368 -0.85176,0.647043 -1.129025,1.148855 -0.277334,0.488547 -0.415932,1.076171 -0.415932,1.762803 0,0.673436 0.138598,1.26106 0.415932,1.762872 0.277265,0.501744 0.653606,0.884718 1.129025,1.148786 0.475351,0.264069 1.01012,0.396171 1.604376,0.396171 z",
+ "fill": "#3a3a3a",
+ "id": "path3",
+ "style": "stroke-width:0.0683761"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m 53.779282,17.66694 c -0.634188,0 -1.148308,-0.514119 -1.148308,-1.148308 V 8.2381538 c 0,-0.634188 0.51412,-1.1482393 1.148308,-1.1482393 h 0.179282 c 0.634188,0 1.148308,0.5140513 1.148308,1.1482393 v 8.2804782 c 0,0.634189 -0.51412,1.148308 -1.148308,1.148308 z m 0.09956,-12.3200819 c -0.462154,0 -0.845129,-0.1452513 -1.148855,-0.4357607 -0.290462,-0.2905025 -0.435692,-0.6404307 -0.435692,-1.0497777 0,-0.4225505 0.14523,-0.7724787 0.435692,-1.0497778 0.303726,-0.2905026 0.686701,-0.4357607 1.148855,-0.4357607 0.462153,0 0.838495,0.138653 1.129025,0.4159521 0.303658,0.2640958 0.455522,0.6008205 0.455522,1.0101676 0,0.4357538 -0.145231,0.8054906 -0.435761,1.1091965 -0.290462,0.2905094 -0.673436,0.4357607 -1.148786,0.4357607 z",
+ "fill": "#3a3a3a",
+ "id": "path4",
+ "style": "stroke-width:0.0683761"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "m 60.376821,15.30988 0.05942,-3.109743 5.22106,-4.8280344 c 0.196169,-0.1814701 0.453537,-0.2821881 0.72075,-0.2821881 v 0 c 0.944752,0 1.41894,1.141265 0.752274,1.8107351 l -2.891077,2.9033164 -1.307282,1.089436 z m -0.872069,2.35706 c -0.634188,0 -1.148239,-0.514119 -1.148239,-1.148308 V 4.1182838 c 0,-0.6341812 0.514051,-1.1482872 1.148239,-1.1482872 h 0.179351 c 0.634188,0 1.148307,0.514106 1.148307,1.1482872 V 16.518632 c 0,0.634189 -0.514119,1.148308 -1.148307,1.148308 z m 7.382017,0 c -0.346598,0 -0.674666,-0.156581 -0.892718,-0.426051 l -3.517675,-4.347487 1.564786,-1.980718 3.848206,4.89641 c 0.592,0.753368 0.05538,1.857846 -0.902838,1.857846 z",
+ "fill": "#3a3a3a",
+ "id": "path5",
+ "style": "stroke-width:0.0683761"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {
+ "id": "defs6"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "linearGradient",
+ "attributes": {
+ "id": "paint0_linear_3874_31725",
+ "x1": "258.13101",
+ "y1": "269.78299",
+ "x2": "88.645203",
+ "y2": "75.4571",
+ "gradientUnits": "userSpaceOnUse",
+ "gradientTransform": "scale(0.06837607)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "stop-color": "#FB9341",
+ "id": "stop5"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "stop",
+ "attributes": {
+ "offset": "1",
+ "stop-color": "#E30D3E",
+ "id": "stop6"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "OpikIconBig"
+}
diff --git a/app/components/base/icons/src/public/tracing/OpikIconBig.tsx b/app/components/base/icons/src/public/tracing/OpikIconBig.tsx
new file mode 100644
index 0000000..643312b
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/OpikIconBig.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './OpikIconBig.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'OpikIconBig'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/tracing/TracingIcon.json b/app/components/base/icons/src/public/tracing/TracingIcon.json
new file mode 100644
index 0000000..2157a08
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/TracingIcon.json
@@ -0,0 +1,47 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "viewBox": "0 0 20 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "analytics-fill"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "opacity": "0.6",
+ "d": "M5 2.5C3.61929 2.5 2.5 3.61929 2.5 5V9.16667H6.15164C6.78293 9.16667 7.36003 9.52333 7.64235 10.088L8.33333 11.4699L10.9213 6.29399C11.0625 6.01167 11.351 5.83333 11.6667 5.83333C11.9823 5.83333 12.2708 6.01167 12.412 6.29399L13.8483 9.16667H17.5V5C17.5 3.61929 16.3807 2.5 15 2.5H5Z",
+ "fill": "white"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M2.5 14.9999C2.5 16.3807 3.61929 17.4999 5 17.4999H15C16.3807 17.4999 17.5 16.3807 17.5 14.9999V10.8333H13.8483C13.2171 10.8333 12.64 10.4766 12.3577 9.91195L11.6667 8.53003L9.07867 13.7059C8.9375 13.9883 8.649 14.1666 8.33333 14.1666C8.01769 14.1666 7.72913 13.9883 7.58798 13.7059L6.15164 10.8333H2.5V14.9999Z",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "TracingIcon"
+}
diff --git a/app/components/base/icons/src/public/tracing/TracingIcon.tsx b/app/components/base/icons/src/public/tracing/TracingIcon.tsx
new file mode 100644
index 0000000..1f1e8d3
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/TracingIcon.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './TracingIcon.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'TracingIcon'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/tracing/WeaveIcon.json b/app/components/base/icons/src/public/tracing/WeaveIcon.json
new file mode 100644
index 0000000..1a96e70
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/WeaveIcon.json
@@ -0,0 +1,279 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "xmlns": "http://www.w3.org/2000/svg",
+ "xmlns:xlink": "http://www.w3.org/1999/xlink",
+ "width": "120px",
+ "height": "16px",
+ "viewBox": "0 0 120 16",
+ "version": "1.1"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "surface1"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 20.847656 3.292969 C 20.875 3.292969 20.902344 3.292969 20.933594 3.292969 C 20.949219 3.292969 20.964844 3.292969 20.980469 3.292969 C 21.035156 3.292969 21.089844 3.292969 21.140625 3.292969 C 21.179688 3.292969 21.21875 3.292969 21.253906 3.292969 C 21.359375 3.292969 21.464844 3.292969 21.566406 3.292969 C 21.675781 3.292969 21.78125 3.292969 21.890625 3.292969 C 22.097656 3.292969 22.300781 3.292969 22.507812 3.292969 C 22.738281 3.292969 22.972656 3.292969 23.207031 3.296875 C 23.6875 3.296875 24.167969 3.296875 24.648438 3.296875 C 24.648438 3.519531 24.648438 3.742188 24.648438 3.96875 C 24.113281 4.042969 24.113281 4.042969 23.566406 4.113281 C 23.667969 4.496094 23.769531 4.882812 23.867188 5.265625 C 23.878906 5.308594 23.878906 5.308594 23.890625 5.351562 C 24.128906 6.269531 24.371094 7.183594 24.609375 8.097656 C 24.675781 8.339844 24.738281 8.582031 24.800781 8.824219 C 24.816406 8.878906 24.832031 8.933594 24.84375 8.992188 C 24.867188 9.078125 24.890625 9.167969 24.914062 9.257812 C 24.921875 9.289062 24.933594 9.320312 24.941406 9.355469 C 24.953125 9.398438 24.964844 9.441406 24.976562 9.484375 C 24.984375 9.523438 24.984375 9.523438 24.996094 9.558594 C 25.007812 9.625 25.007812 9.625 25.007812 9.71875 C 25.023438 9.71875 25.039062 9.71875 25.054688 9.71875 C 25.058594 9.707031 25.058594 9.695312 25.0625 9.679688 C 25.097656 9.492188 25.152344 9.3125 25.210938 9.128906 C 25.222656 9.097656 25.234375 9.0625 25.246094 9.027344 C 25.269531 8.953125 25.292969 8.882812 25.316406 8.808594 C 25.355469 8.691406 25.390625 8.574219 25.429688 8.457031 C 25.464844 8.339844 25.503906 8.21875 25.542969 8.097656 C 25.660156 7.738281 25.773438 7.375 25.890625 7.011719 C 25.902344 6.96875 25.917969 6.921875 25.933594 6.875 C 26.226562 5.945312 26.519531 5.019531 26.808594 4.089844 C 26.785156 4.089844 26.765625 4.089844 26.742188 4.085938 C 26.507812 4.074219 26.273438 4.046875 26.042969 4.015625 C 26.007812 4.011719 25.972656 4.007812 25.933594 4.003906 C 25.851562 3.992188 25.765625 3.980469 25.679688 3.96875 C 25.679688 3.746094 25.679688 3.523438 25.679688 3.296875 C 26.175781 3.296875 26.667969 3.296875 27.160156 3.296875 C 27.390625 3.292969 27.621094 3.292969 27.851562 3.292969 C 28.050781 3.292969 28.25 3.292969 28.449219 3.292969 C 28.554688 3.292969 28.660156 3.292969 28.765625 3.292969 C 28.867188 3.292969 28.964844 3.292969 29.066406 3.292969 C 29.101562 3.292969 29.140625 3.292969 29.175781 3.292969 C 29.226562 3.292969 29.273438 3.292969 29.324219 3.292969 C 29.367188 3.292969 29.367188 3.292969 29.410156 3.292969 C 29.472656 3.296875 29.472656 3.296875 29.496094 3.320312 C 29.5 3.367188 29.5 3.417969 29.5 3.464844 C 29.5 3.492188 29.5 3.515625 29.5 3.542969 C 29.496094 3.59375 29.496094 3.59375 29.496094 3.648438 C 29.496094 3.753906 29.496094 3.859375 29.496094 3.96875 C 29.09375 4.015625 28.6875 4.066406 28.273438 4.113281 C 28.679688 5.460938 28.679688 5.460938 29.089844 6.808594 C 29.105469 6.859375 29.121094 6.910156 29.136719 6.960938 C 29.234375 7.292969 29.335938 7.625 29.4375 7.960938 C 29.484375 8.113281 29.53125 8.265625 29.578125 8.417969 C 29.605469 8.507812 29.632812 8.597656 29.660156 8.691406 C 29.878906 9.40625 29.878906 9.40625 29.976562 9.746094 C 30.027344 9.664062 30.046875 9.601562 30.070312 9.507812 C 30.078125 9.484375 30.078125 9.484375 30.085938 9.457031 C 30.101562 9.402344 30.117188 9.34375 30.132812 9.289062 C 30.144531 9.25 30.152344 9.207031 30.164062 9.167969 C 30.1875 9.082031 30.214844 8.992188 30.238281 8.90625 C 30.292969 8.691406 30.351562 8.480469 30.410156 8.269531 C 30.433594 8.191406 30.453125 8.117188 30.472656 8.042969 C 30.621094 7.5 30.769531 6.960938 30.921875 6.421875 C 30.949219 6.324219 30.976562 6.226562 31 6.128906 C 31.066406 5.902344 31.128906 5.675781 31.191406 5.449219 C 31.230469 5.308594 31.269531 5.164062 31.308594 5.023438 C 31.335938 4.925781 31.363281 4.828125 31.390625 4.734375 C 31.402344 4.6875 31.414062 4.640625 31.429688 4.59375 C 31.445312 4.53125 31.464844 4.46875 31.480469 4.40625 C 31.488281 4.386719 31.492188 4.367188 31.496094 4.347656 C 31.515625 4.277344 31.535156 4.207031 31.558594 4.136719 C 31.210938 4.074219 30.855469 4.023438 30.503906 3.96875 C 30.503906 3.746094 30.503906 3.523438 30.503906 3.296875 C 30.878906 3.296875 31.253906 3.296875 31.628906 3.296875 C 31.804688 3.292969 31.976562 3.292969 32.152344 3.292969 C 32.304688 3.292969 32.457031 3.292969 32.605469 3.292969 C 32.6875 3.292969 32.769531 3.292969 32.847656 3.292969 C 32.9375 3.292969 33.027344 3.292969 33.117188 3.292969 C 33.144531 3.292969 33.171875 3.292969 33.199219 3.292969 C 33.222656 3.292969 33.246094 3.292969 33.273438 3.292969 C 33.304688 3.292969 33.304688 3.292969 33.335938 3.292969 C 33.382812 3.296875 33.382812 3.296875 33.40625 3.320312 C 33.410156 3.367188 33.410156 3.414062 33.410156 3.460938 C 33.410156 3.488281 33.410156 3.515625 33.410156 3.542969 C 33.410156 3.574219 33.410156 3.605469 33.410156 3.632812 C 33.410156 3.664062 33.410156 3.695312 33.410156 3.726562 C 33.410156 3.796875 33.410156 3.871094 33.40625 3.945312 C 33.292969 3.964844 33.175781 3.984375 33.0625 4.007812 C 33.023438 4.011719 32.984375 4.019531 32.945312 4.027344 C 32.738281 4.0625 32.535156 4.097656 32.328125 4.113281 C 32.320312 4.144531 32.320312 4.144531 32.3125 4.179688 C 32.238281 4.480469 32.15625 4.78125 32.070312 5.082031 C 32.058594 5.128906 32.042969 5.171875 32.03125 5.21875 C 31.875 5.78125 31.714844 6.347656 31.550781 6.910156 C 31.375 7.535156 31.195312 8.160156 31.019531 8.785156 C 30.992188 8.871094 30.96875 8.957031 30.945312 9.042969 C 30.835938 9.433594 30.722656 9.820312 30.613281 10.210938 C 30.566406 10.378906 30.519531 10.542969 30.472656 10.707031 C 30.445312 10.804688 30.417969 10.902344 30.390625 11 C 30.277344 11.390625 30.167969 11.785156 30.046875 12.175781 C 29.730469 12.175781 29.414062 12.175781 29.089844 12.175781 C 29.03125 12.003906 29.03125 12.003906 28.976562 11.832031 C 28.925781 11.675781 28.878906 11.523438 28.828125 11.367188 C 28.820312 11.347656 28.8125 11.328125 28.808594 11.304688 C 28.632812 10.769531 28.460938 10.230469 28.285156 9.695312 C 28.144531 9.273438 28.007812 8.847656 27.875 8.425781 C 27.695312 7.867188 27.515625 7.308594 27.332031 6.753906 C 27.304688 6.679688 27.28125 6.605469 27.257812 6.53125 C 27.238281 6.476562 27.222656 6.425781 27.207031 6.375 C 27.046875 5.894531 27.046875 5.894531 27.046875 5.796875 C 27.03125 5.796875 27.015625 5.796875 27 5.796875 C 26.996094 5.8125 26.996094 5.828125 26.992188 5.84375 C 26.964844 5.988281 26.925781 6.132812 26.882812 6.273438 C 26.875 6.296875 26.867188 6.316406 26.859375 6.339844 C 26.84375 6.390625 26.828125 6.4375 26.8125 6.488281 C 26.769531 6.625 26.726562 6.761719 26.683594 6.898438 C 26.675781 6.929688 26.664062 6.957031 26.65625 6.988281 C 26.546875 7.328125 26.445312 7.667969 26.339844 8.007812 C 26.316406 8.078125 26.296875 8.144531 26.273438 8.214844 C 26.230469 8.355469 26.1875 8.496094 26.144531 8.636719 C 26.074219 8.863281 26.007812 9.089844 25.9375 9.3125 C 25.933594 9.328125 25.925781 9.347656 25.921875 9.363281 C 25.894531 9.449219 25.871094 9.535156 25.84375 9.617188 C 25.796875 9.769531 25.75 9.921875 25.703125 10.074219 C 25.675781 10.15625 25.652344 10.242188 25.625 10.328125 C 25.613281 10.363281 25.605469 10.394531 25.59375 10.429688 C 25.414062 11.011719 25.234375 11.59375 25.054688 12.175781 C 24.738281 12.175781 24.421875 12.175781 24.097656 12.175781 C 23.816406 11.230469 23.535156 10.285156 23.261719 9.339844 C 23.253906 9.320312 23.25 9.304688 23.246094 9.285156 C 23.195312 9.117188 23.144531 8.949219 23.097656 8.78125 C 22.960938 8.3125 22.824219 7.84375 22.6875 7.375 C 22.664062 7.304688 22.644531 7.234375 22.625 7.164062 C 22.414062 6.449219 22.207031 5.738281 22 5.027344 C 21.976562 4.953125 21.953125 4.878906 21.933594 4.804688 C 21.898438 4.683594 21.859375 4.5625 21.824219 4.441406 C 21.820312 4.421875 21.8125 4.402344 21.808594 4.382812 C 21.796875 4.347656 21.785156 4.3125 21.777344 4.28125 C 21.753906 4.203125 21.742188 4.148438 21.742188 4.066406 C 21.726562 4.066406 21.710938 4.0625 21.691406 4.0625 C 21.382812 4.042969 21.070312 4.003906 20.761719 3.96875 C 20.757812 3.863281 20.757812 3.753906 20.757812 3.648438 C 20.757812 3.617188 20.757812 3.585938 20.757812 3.554688 C 20.757812 3.523438 20.757812 3.496094 20.757812 3.464844 C 20.757812 3.4375 20.757812 3.410156 20.757812 3.382812 C 20.761719 3.296875 20.761719 3.296875 20.847656 3.292969 Z M 20.847656 3.292969 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 82.488281 3.25 C 83.046875 3.246094 83.605469 3.246094 84.167969 3.246094 C 84.425781 3.246094 84.6875 3.246094 84.945312 3.246094 C 85.171875 3.242188 85.398438 3.242188 85.625 3.242188 C 85.746094 3.242188 85.867188 3.242188 85.984375 3.242188 C 88.15625 3.238281 88.15625 3.238281 88.894531 3.898438 C 88.914062 3.914062 88.9375 3.929688 88.957031 3.945312 C 89.191406 4.144531 89.363281 4.402344 89.472656 4.691406 C 89.480469 4.714844 89.492188 4.742188 89.5 4.765625 C 89.65625 5.25 89.601562 5.785156 89.382812 6.234375 C 89.117188 6.753906 88.695312 7.078125 88.152344 7.265625 C 87.984375 7.320312 87.816406 7.367188 87.648438 7.410156 C 87.664062 7.414062 87.679688 7.417969 87.699219 7.421875 C 88.523438 7.605469 89.300781 7.851562 89.78125 8.597656 C 90.0625 9.0625 90.125 9.636719 90.003906 10.164062 C 89.808594 10.804688 89.363281 11.304688 88.78125 11.621094 C 88.324219 11.863281 87.820312 11.988281 87.3125 12.054688 C 87.28125 12.058594 87.253906 12.0625 87.222656 12.066406 C 86.777344 12.121094 86.332031 12.109375 85.882812 12.105469 C 85.765625 12.105469 85.644531 12.105469 85.523438 12.105469 C 85.300781 12.105469 85.074219 12.105469 84.847656 12.105469 C 84.589844 12.105469 84.332031 12.105469 84.074219 12.105469 C 83.546875 12.105469 83.015625 12.101562 82.488281 12.101562 C 82.488281 11.878906 82.488281 11.65625 82.488281 11.429688 C 82.859375 11.390625 83.234375 11.347656 83.617188 11.308594 C 83.617188 8.910156 83.617188 6.511719 83.617188 4.042969 C 83.488281 4.035156 83.363281 4.027344 83.230469 4.019531 C 83.117188 4.007812 83.003906 3.996094 82.890625 3.980469 C 82.863281 3.980469 82.832031 3.976562 82.804688 3.972656 C 82.695312 3.960938 82.59375 3.949219 82.488281 3.921875 C 82.488281 3.699219 82.488281 3.476562 82.488281 3.25 Z M 85.390625 3.96875 C 85.390625 4.242188 85.386719 4.515625 85.382812 4.785156 C 85.382812 4.914062 85.378906 5.039062 85.378906 5.164062 C 85.371094 5.824219 85.367188 6.484375 85.367188 7.144531 C 86.488281 7.183594 86.488281 7.183594 87.457031 6.691406 C 87.796875 6.320312 87.859375 5.832031 87.847656 5.351562 C 87.832031 4.992188 87.71875 4.644531 87.460938 4.378906 C 87 3.96875 86.363281 3.964844 85.78125 3.96875 C 85.742188 3.96875 85.703125 3.96875 85.667969 3.96875 C 85.574219 3.96875 85.484375 3.96875 85.390625 3.96875 Z M 85.390625 7.84375 C 85.390625 9.003906 85.390625 10.160156 85.390625 11.355469 C 86.28125 11.386719 86.28125 11.386719 87.152344 11.21875 C 87.171875 11.214844 87.1875 11.207031 87.207031 11.199219 C 87.578125 11.066406 87.886719 10.824219 88.066406 10.46875 C 88.28125 9.988281 88.289062 9.417969 88.125 8.921875 C 87.960938 8.492188 87.664062 8.234375 87.257812 8.046875 C 86.664062 7.804688 86.023438 7.84375 85.390625 7.84375 Z M 85.390625 7.84375 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 76.167969 3.476562 C 76.367188 3.671875 76.507812 3.917969 76.585938 4.1875 C 76.589844 4.203125 76.59375 4.222656 76.601562 4.242188 C 76.707031 4.675781 76.621094 5.144531 76.414062 5.53125 C 76.34375 5.644531 76.265625 5.746094 76.175781 5.847656 C 76.15625 5.867188 76.136719 5.886719 76.117188 5.910156 C 75.71875 6.332031 75.199219 6.617188 74.6875 6.882812 C 74.707031 6.902344 74.726562 6.921875 74.746094 6.941406 C 74.972656 7.191406 74.972656 7.191406 75.066406 7.296875 C 75.140625 7.382812 75.21875 7.464844 75.300781 7.542969 C 75.351562 7.59375 75.394531 7.640625 75.4375 7.695312 C 75.527344 7.796875 75.621094 7.894531 75.714844 7.992188 C 76.089844 8.394531 76.089844 8.394531 76.253906 8.585938 C 76.351562 8.695312 76.449219 8.800781 76.546875 8.90625 C 76.621094 8.980469 76.691406 9.058594 76.761719 9.136719 C 76.773438 9.152344 76.789062 9.164062 76.800781 9.179688 C 76.824219 9.207031 76.851562 9.234375 76.875 9.261719 C 76.933594 9.324219 76.992188 9.382812 77.0625 9.429688 C 77.070312 9.410156 77.070312 9.410156 77.082031 9.386719 C 77.113281 9.304688 77.152344 9.230469 77.195312 9.15625 C 77.5625 8.476562 77.800781 7.753906 77.976562 7 C 77.953125 7 77.933594 6.996094 77.910156 6.996094 C 77.707031 6.96875 77.5 6.9375 77.296875 6.902344 C 77.273438 6.898438 77.25 6.894531 77.222656 6.890625 C 77.050781 6.859375 77.050781 6.859375 76.96875 6.832031 C 76.960938 6.328125 76.960938 6.328125 77.015625 6.160156 C 77.949219 6.160156 78.886719 6.160156 79.847656 6.160156 C 79.847656 6.367188 79.847656 6.574219 79.847656 6.785156 C 79.53125 6.839844 79.214844 6.894531 78.886719 6.953125 C 78.859375 7.046875 78.832031 7.140625 78.804688 7.234375 C 78.539062 8.09375 78.164062 9.035156 77.601562 9.746094 C 77.5625 9.792969 77.5625 9.792969 77.566406 9.851562 C 77.601562 9.933594 77.648438 9.980469 77.714844 10.039062 C 77.792969 10.113281 77.867188 10.1875 77.9375 10.269531 C 78.027344 10.375 78.125 10.46875 78.222656 10.566406 C 78.308594 10.65625 78.390625 10.742188 78.472656 10.839844 C 78.539062 10.914062 78.601562 10.933594 78.695312 10.949219 C 78.71875 10.953125 78.746094 10.957031 78.769531 10.960938 C 78.796875 10.964844 78.824219 10.96875 78.851562 10.972656 C 78.875 10.980469 78.902344 10.984375 78.933594 10.988281 C 79.019531 11.003906 79.105469 11.019531 79.191406 11.03125 C 79.277344 11.046875 79.363281 11.0625 79.449219 11.078125 C 79.503906 11.085938 79.558594 11.097656 79.613281 11.105469 C 79.648438 11.113281 79.648438 11.113281 79.6875 11.117188 C 79.707031 11.121094 79.730469 11.125 79.75 11.128906 C 79.800781 11.140625 79.800781 11.140625 79.824219 11.164062 C 79.820312 11.421875 79.785156 11.679688 79.753906 11.933594 C 79.691406 11.949219 79.632812 11.964844 79.570312 11.980469 C 79.546875 11.984375 79.546875 11.984375 79.519531 11.992188 C 79.214844 12.066406 78.910156 12.085938 78.597656 12.085938 C 78.539062 12.085938 78.484375 12.085938 78.425781 12.085938 C 77.847656 12.089844 77.332031 11.917969 76.894531 11.523438 C 76.855469 11.484375 76.816406 11.445312 76.777344 11.40625 C 76.71875 11.347656 76.660156 11.296875 76.601562 11.242188 C 76.578125 11.21875 76.578125 11.21875 76.554688 11.195312 C 76.515625 11.160156 76.476562 11.125 76.441406 11.089844 C 76.429688 11.101562 76.417969 11.109375 76.410156 11.117188 C 76.140625 11.351562 75.859375 11.554688 75.542969 11.71875 C 75.511719 11.738281 75.476562 11.757812 75.445312 11.777344 C 75.3125 11.847656 75.179688 11.894531 75.039062 11.9375 C 75.011719 11.945312 75.011719 11.945312 74.984375 11.953125 C 74.632812 12.058594 74.269531 12.089844 73.90625 12.085938 C 73.84375 12.085938 73.785156 12.085938 73.722656 12.089844 C 72.941406 12.089844 72.222656 11.824219 71.652344 11.28125 C 71.203125 10.820312 71.023438 10.246094 71.03125 9.609375 C 71.042969 9.058594 71.230469 8.546875 71.59375 8.132812 C 71.609375 8.113281 71.625 8.09375 71.644531 8.070312 C 71.980469 7.683594 72.398438 7.421875 72.839844 7.171875 C 72.871094 7.152344 72.902344 7.132812 72.9375 7.113281 C 72.960938 7.101562 72.984375 7.085938 73.007812 7.074219 C 72.996094 7.0625 72.988281 7.050781 72.976562 7.042969 C 72.398438 6.425781 72.09375 5.613281 72.113281 4.773438 C 72.128906 4.371094 72.257812 3.988281 72.527344 3.679688 C 72.542969 3.660156 72.558594 3.644531 72.570312 3.625 C 72.917969 3.210938 73.496094 2.996094 74.015625 2.933594 C 74.050781 2.929688 74.050781 2.929688 74.082031 2.925781 C 74.804688 2.847656 75.621094 2.964844 76.167969 3.476562 Z M 73.671875 3.796875 C 73.433594 4.113281 73.414062 4.4375 73.457031 4.820312 C 73.550781 5.460938 73.921875 5.9375 74.328125 6.425781 C 74.398438 6.390625 74.449219 6.355469 74.503906 6.300781 C 74.527344 6.28125 74.527344 6.28125 74.550781 6.257812 C 74.566406 6.242188 74.582031 6.226562 74.597656 6.210938 C 74.613281 6.191406 74.628906 6.175781 74.644531 6.160156 C 74.773438 6.03125 74.890625 5.894531 75 5.75 C 75.019531 5.726562 75.035156 5.699219 75.054688 5.675781 C 75.335938 5.292969 75.5 4.859375 75.457031 4.378906 C 75.40625 4.078125 75.289062 3.820312 75.035156 3.636719 C 74.59375 3.363281 74.03125 3.410156 73.671875 3.796875 Z M 73.046875 7.828125 C 72.664062 8.226562 72.519531 8.789062 72.519531 9.332031 C 72.53125 9.800781 72.71875 10.257812 73.039062 10.601562 C 73.46875 10.996094 73.980469 11.140625 74.550781 11.125 C 74.960938 11.105469 75.339844 11.003906 75.703125 10.8125 C 75.71875 10.804688 75.738281 10.796875 75.753906 10.785156 C 75.84375 10.738281 75.90625 10.699219 75.960938 10.609375 C 75.949219 10.601562 75.941406 10.589844 75.933594 10.582031 C 75.460938 10.074219 75.460938 10.074219 75.25 9.8125 C 75.1875 9.738281 75.125 9.664062 75.0625 9.59375 C 74.972656 9.484375 74.882812 9.375 74.796875 9.265625 C 74.695312 9.132812 74.589844 9.003906 74.480469 8.878906 C 74.390625 8.773438 74.304688 8.667969 74.214844 8.5625 C 74.152344 8.484375 74.085938 8.40625 74.019531 8.328125 C 73.921875 8.214844 73.828125 8.101562 73.734375 7.984375 C 73.726562 7.96875 73.714844 7.957031 73.703125 7.941406 C 73.683594 7.914062 73.660156 7.886719 73.640625 7.859375 C 73.589844 7.792969 73.539062 7.730469 73.488281 7.667969 C 73.460938 7.632812 73.460938 7.632812 73.433594 7.601562 C 73.414062 7.578125 73.414062 7.578125 73.390625 7.554688 C 73.265625 7.554688 73.132812 7.742188 73.046875 7.828125 Z M 73.046875 7.828125 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 49.992188 5.535156 C 50.101562 5.609375 50.101562 5.609375 50.136719 5.679688 C 50.136719 5.746094 50.140625 5.8125 50.140625 5.882812 C 50.140625 5.914062 50.140625 5.914062 50.140625 5.941406 C 50.140625 5.984375 50.140625 6.027344 50.140625 6.070312 C 50.140625 6.136719 50.140625 6.203125 50.140625 6.269531 C 50.140625 6.308594 50.140625 6.351562 50.140625 6.390625 C 50.140625 6.410156 50.140625 6.429688 50.140625 6.453125 C 50.140625 6.589844 50.140625 6.589844 50.113281 6.617188 C 50.074219 6.617188 50.035156 6.621094 49.996094 6.621094 C 49.972656 6.621094 49.949219 6.621094 49.921875 6.621094 C 49.894531 6.621094 49.871094 6.617188 49.84375 6.617188 C 49.816406 6.617188 49.789062 6.617188 49.757812 6.617188 C 49.671875 6.617188 49.585938 6.617188 49.5 6.617188 C 49.441406 6.617188 49.378906 6.617188 49.320312 6.617188 C 49.175781 6.617188 49.03125 6.617188 48.886719 6.617188 C 48.898438 6.640625 48.90625 6.660156 48.917969 6.683594 C 48.929688 6.714844 48.945312 6.746094 48.957031 6.773438 C 48.964844 6.789062 48.96875 6.804688 48.976562 6.820312 C 49.203125 7.339844 49.195312 8 48.988281 8.523438 C 48.75 9.0625 48.355469 9.457031 47.804688 9.671875 C 47.066406 9.941406 46.210938 9.941406 45.457031 9.746094 C 45.277344 10.003906 45.214844 10.273438 45.238281 10.585938 C 45.269531 10.699219 45.316406 10.761719 45.402344 10.835938 C 45.617188 10.945312 45.851562 10.949219 46.089844 10.949219 C 46.113281 10.953125 46.132812 10.953125 46.15625 10.953125 C 46.203125 10.953125 46.25 10.953125 46.292969 10.953125 C 46.367188 10.953125 46.441406 10.953125 46.515625 10.953125 C 46.726562 10.953125 46.9375 10.957031 47.144531 10.957031 C 47.273438 10.957031 47.402344 10.957031 47.53125 10.960938 C 47.582031 10.960938 47.628906 10.960938 47.675781 10.960938 C 48.324219 10.960938 49.039062 11.019531 49.53125 11.492188 C 49.546875 11.511719 49.566406 11.53125 49.585938 11.550781 C 49.601562 11.566406 49.617188 11.582031 49.636719 11.597656 C 49.957031 11.929688 50.0625 12.394531 50.066406 12.84375 C 50.054688 13.351562 49.847656 13.800781 49.511719 14.171875 C 49.496094 14.191406 49.480469 14.207031 49.460938 14.226562 C 48.8125 14.921875 47.769531 15.179688 46.855469 15.210938 C 45.890625 15.234375 44.761719 15.230469 44.015625 14.523438 C 43.738281 14.222656 43.660156 13.886719 43.671875 13.488281 C 43.679688 13.363281 43.699219 13.253906 43.753906 13.136719 C 43.761719 13.117188 43.769531 13.09375 43.78125 13.074219 C 43.996094 12.644531 44.386719 12.410156 44.785156 12.175781 C 44.765625 12.167969 44.746094 12.160156 44.730469 12.152344 C 44.398438 11.996094 44.222656 11.808594 44.089844 11.476562 C 43.988281 11.136719 44.070312 10.757812 44.222656 10.453125 C 44.421875 10.109375 44.695312 9.824219 44.976562 9.550781 C 44.960938 9.542969 44.945312 9.53125 44.925781 9.523438 C 44.757812 9.417969 44.613281 9.304688 44.472656 9.167969 C 44.457031 9.152344 44.441406 9.136719 44.425781 9.121094 C 44.214844 8.902344 44.085938 8.597656 44.015625 8.300781 C 44.011719 8.28125 44.003906 8.257812 44 8.238281 C 43.882812 7.675781 43.964844 7.042969 44.277344 6.558594 C 44.621094 6.070312 45.09375 5.773438 45.671875 5.628906 C 45.6875 5.625 45.703125 5.621094 45.71875 5.617188 C 46.25 5.492188 46.917969 5.496094 47.449219 5.628906 C 47.464844 5.632812 47.480469 5.636719 47.496094 5.640625 C 47.6875 5.691406 47.867188 5.761719 48.046875 5.84375 C 48.0625 5.851562 48.078125 5.859375 48.09375 5.867188 C 48.164062 5.902344 48.226562 5.933594 48.289062 5.980469 C 48.390625 6.066406 48.390625 6.066406 48.515625 6.082031 C 48.582031 6.0625 48.644531 6.035156 48.707031 6.003906 C 48.730469 5.996094 48.753906 5.984375 48.78125 5.976562 C 48.855469 5.941406 48.929688 5.910156 49.003906 5.875 C 49.054688 5.851562 49.101562 5.832031 49.152344 5.808594 C 49.320312 5.738281 49.488281 5.664062 49.652344 5.585938 C 49.679688 5.574219 49.703125 5.566406 49.730469 5.554688 C 49.75 5.542969 49.769531 5.535156 49.789062 5.523438 C 49.867188 5.503906 49.917969 5.515625 49.992188 5.535156 Z M 45.835938 6.507812 C 45.472656 6.984375 45.421875 7.597656 45.492188 8.175781 C 45.550781 8.542969 45.6875 8.890625 45.980469 9.132812 C 46.207031 9.285156 46.46875 9.3125 46.734375 9.277344 C 47.015625 9.21875 47.210938 9.089844 47.375 8.855469 C 47.683594 8.375 47.742188 7.746094 47.640625 7.191406 C 47.5625 6.859375 47.402344 6.507812 47.117188 6.308594 C 46.703125 6.074219 46.152344 6.148438 45.835938 6.507812 Z M 45.238281 12.367188 C 44.957031 12.734375 44.867188 13.113281 44.902344 13.570312 C 44.957031 13.84375 45.09375 14.058594 45.316406 14.226562 C 45.613281 14.417969 46.015625 14.496094 46.367188 14.507812 C 46.394531 14.507812 46.394531 14.507812 46.417969 14.507812 C 47.132812 14.527344 47.90625 14.457031 48.453125 13.945312 C 48.652344 13.738281 48.710938 13.515625 48.703125 13.230469 C 48.683594 12.992188 48.570312 12.800781 48.394531 12.644531 C 48.113281 12.441406 47.726562 12.449219 47.398438 12.449219 C 47.355469 12.449219 47.3125 12.449219 47.269531 12.449219 C 47.15625 12.449219 47.046875 12.449219 46.933594 12.449219 C 46.753906 12.449219 46.574219 12.445312 46.394531 12.445312 C 46.332031 12.445312 46.269531 12.445312 46.210938 12.445312 C 45.882812 12.445312 45.5625 12.414062 45.238281 12.367188 Z M 45.238281 12.367188 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 53.039062 2.382812 C 53.0625 2.390625 53.0625 2.390625 53.085938 2.398438 C 53.140625 2.429688 53.171875 2.453125 53.207031 2.503906 C 53.230469 2.617188 53.21875 2.730469 53.214844 2.84375 C 53.210938 2.878906 53.210938 2.914062 53.210938 2.953125 C 53.207031 3.027344 53.203125 3.105469 53.199219 3.183594 C 53.191406 3.371094 53.183594 3.558594 53.179688 3.746094 C 53.175781 3.792969 53.175781 3.835938 53.175781 3.882812 C 53.15625 4.441406 53.15625 5 53.15625 5.5625 C 53.15625 5.640625 53.15625 5.71875 53.15625 5.792969 C 53.15625 6.085938 53.160156 6.375 53.160156 6.664062 C 53.179688 6.644531 53.195312 6.625 53.214844 6.605469 C 53.238281 6.578125 53.261719 6.550781 53.285156 6.523438 C 53.296875 6.511719 53.3125 6.5 53.324219 6.484375 C 53.78125 5.984375 54.445312 5.601562 55.128906 5.550781 C 55.640625 5.535156 56.128906 5.578125 56.527344 5.929688 C 56.566406 5.964844 56.601562 6 56.640625 6.039062 C 56.664062 6.0625 56.664062 6.0625 56.691406 6.089844 C 57.246094 6.660156 57.203125 7.570312 57.203125 8.304688 C 57.203125 8.414062 57.203125 8.523438 57.207031 8.632812 C 57.207031 8.839844 57.207031 9.042969 57.207031 9.25 C 57.207031 9.484375 57.210938 9.722656 57.210938 9.957031 C 57.210938 10.4375 57.214844 10.921875 57.214844 11.40625 C 57.246094 11.410156 57.246094 11.410156 57.28125 11.414062 C 57.308594 11.417969 57.335938 11.421875 57.363281 11.425781 C 57.40625 11.433594 57.40625 11.433594 57.445312 11.441406 C 57.558594 11.457031 57.671875 11.480469 57.785156 11.503906 C 57.808594 11.507812 57.828125 11.511719 57.851562 11.515625 C 57.878906 11.519531 57.878906 11.519531 57.910156 11.527344 C 57.929688 11.53125 57.949219 11.535156 57.964844 11.539062 C 58.007812 11.550781 58.007812 11.550781 58.03125 11.574219 C 58.035156 11.613281 58.035156 11.65625 58.035156 11.695312 C 58.035156 11.71875 58.035156 11.746094 58.035156 11.769531 C 58.035156 11.796875 58.035156 11.824219 58.035156 11.851562 C 58.035156 11.875 58.035156 11.902344 58.035156 11.929688 C 58.035156 11.964844 58.035156 11.964844 58.035156 12.003906 C 58.035156 12.027344 58.035156 12.050781 58.035156 12.074219 C 58.03125 12.125 58.03125 12.125 58.007812 12.148438 C 57.964844 12.152344 57.921875 12.152344 57.882812 12.152344 C 57.839844 12.152344 57.839844 12.152344 57.796875 12.152344 C 57.769531 12.152344 57.738281 12.152344 57.707031 12.152344 C 57.675781 12.152344 57.640625 12.152344 57.609375 12.152344 C 57.523438 12.152344 57.433594 12.152344 57.347656 12.152344 C 57.257812 12.152344 57.164062 12.152344 57.074219 12.152344 C 56.917969 12.152344 56.765625 12.152344 56.613281 12.152344 C 56.433594 12.152344 56.257812 12.152344 56.082031 12.152344 C 55.929688 12.152344 55.777344 12.152344 55.625 12.152344 C 55.53125 12.152344 55.441406 12.152344 55.351562 12.152344 C 55.265625 12.152344 55.179688 12.152344 55.09375 12.152344 C 55.046875 12.152344 55 12.152344 54.953125 12.152344 C 54.925781 12.152344 54.898438 12.152344 54.871094 12.152344 C 54.847656 12.152344 54.824219 12.152344 54.796875 12.152344 C 54.742188 12.148438 54.742188 12.148438 54.71875 12.125 C 54.71875 12.085938 54.71875 12.042969 54.71875 12.003906 C 54.71875 11.976562 54.71875 11.953125 54.71875 11.925781 C 54.71875 11.902344 54.71875 11.875 54.71875 11.847656 C 54.71875 11.820312 54.71875 11.796875 54.71875 11.769531 C 54.71875 11.703125 54.71875 11.636719 54.71875 11.574219 C 54.8125 11.53125 54.902344 11.507812 55.003906 11.488281 C 55.03125 11.480469 55.0625 11.476562 55.09375 11.46875 C 55.113281 11.464844 55.128906 11.460938 55.144531 11.460938 C 55.191406 11.449219 55.242188 11.441406 55.289062 11.429688 C 55.527344 11.378906 55.527344 11.378906 55.585938 11.378906 C 55.582031 10.90625 55.582031 10.433594 55.578125 9.960938 C 55.578125 9.742188 55.578125 9.523438 55.574219 9.304688 C 55.574219 9.109375 55.574219 8.917969 55.574219 8.726562 C 55.574219 8.625 55.570312 8.527344 55.570312 8.425781 C 55.570312 8.328125 55.570312 8.234375 55.570312 8.136719 C 55.570312 8.101562 55.570312 8.066406 55.570312 8.03125 C 55.570312 7.664062 55.554688 7.199219 55.289062 6.917969 C 55.054688 6.722656 54.742188 6.746094 54.457031 6.761719 C 54.101562 6.800781 53.738281 7.007812 53.464844 7.234375 C 53.425781 7.265625 53.425781 7.265625 53.371094 7.300781 C 53.273438 7.371094 53.214844 7.421875 53.1875 7.539062 C 53.179688 7.640625 53.179688 7.742188 53.183594 7.84375 C 53.183594 7.882812 53.183594 7.921875 53.183594 7.960938 C 53.183594 8.066406 53.183594 8.167969 53.1875 8.273438 C 53.1875 8.386719 53.1875 8.496094 53.1875 8.605469 C 53.1875 8.8125 53.191406 9.023438 53.191406 9.230469 C 53.195312 9.46875 53.195312 9.703125 53.195312 9.941406 C 53.199219 10.429688 53.203125 10.917969 53.207031 11.40625 C 53.238281 11.410156 53.238281 11.410156 53.265625 11.414062 C 53.351562 11.429688 53.4375 11.445312 53.523438 11.464844 C 53.554688 11.46875 53.585938 11.472656 53.613281 11.480469 C 53.644531 11.484375 53.671875 11.492188 53.703125 11.496094 C 53.730469 11.5 53.753906 11.507812 53.78125 11.511719 C 53.847656 11.523438 53.910156 11.535156 53.976562 11.550781 C 53.976562 11.746094 53.976562 11.945312 53.976562 12.148438 C 52.890625 12.148438 51.804688 12.148438 50.6875 12.148438 C 50.6875 11.953125 50.6875 11.753906 50.6875 11.550781 C 50.964844 11.492188 51.242188 11.4375 51.527344 11.378906 C 51.542969 11.160156 51.554688 10.945312 51.554688 10.722656 C 51.554688 10.691406 51.554688 10.660156 51.554688 10.628906 C 51.554688 10.546875 51.558594 10.464844 51.558594 10.378906 C 51.558594 10.289062 51.558594 10.199219 51.558594 10.109375 C 51.558594 9.953125 51.558594 9.796875 51.558594 9.640625 C 51.558594 9.414062 51.558594 9.1875 51.5625 8.960938 C 51.5625 8.59375 51.5625 8.230469 51.5625 7.863281 C 51.566406 7.507812 51.566406 7.152344 51.566406 6.792969 C 51.566406 6.773438 51.566406 6.75 51.566406 6.726562 C 51.566406 6.617188 51.566406 6.507812 51.566406 6.398438 C 51.570312 5.484375 51.574219 4.570312 51.574219 3.65625 C 51.554688 3.65625 51.535156 3.652344 51.515625 3.652344 C 51.476562 3.648438 51.476562 3.648438 51.4375 3.644531 C 51.414062 3.644531 51.386719 3.640625 51.359375 3.640625 C 51.277344 3.632812 51.195312 3.621094 51.113281 3.609375 C 51.082031 3.605469 51.054688 3.601562 51.023438 3.597656 C 50.996094 3.59375 50.964844 3.589844 50.933594 3.582031 C 50.902344 3.578125 50.871094 3.574219 50.839844 3.570312 C 50.765625 3.558594 50.691406 3.546875 50.617188 3.535156 C 50.617188 3.347656 50.617188 3.15625 50.617188 2.960938 C 50.910156 2.875 51.207031 2.796875 51.5 2.722656 C 51.523438 2.714844 51.542969 2.710938 51.5625 2.707031 C 51.671875 2.679688 51.777344 2.652344 51.886719 2.625 C 51.972656 2.601562 52.0625 2.578125 52.152344 2.554688 C 52.257812 2.527344 52.367188 2.5 52.472656 2.472656 C 52.515625 2.460938 52.554688 2.453125 52.597656 2.441406 C 52.652344 2.425781 52.710938 2.410156 52.765625 2.398438 C 52.78125 2.394531 52.800781 2.386719 52.816406 2.382812 C 52.898438 2.363281 52.960938 2.351562 53.039062 2.382812 Z M 53.039062 2.382812 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 99.691406 6.011719 C 100.109375 6.40625 100.234375 7.003906 100.273438 7.554688 C 100.277344 7.667969 100.277344 7.785156 100.277344 7.898438 C 100.277344 7.933594 100.277344 7.964844 100.277344 8 C 100.277344 8.074219 100.277344 8.144531 100.277344 8.21875 C 100.277344 8.332031 100.277344 8.445312 100.277344 8.558594 C 100.28125 8.886719 100.28125 9.210938 100.28125 9.535156 C 100.28125 9.714844 100.28125 9.894531 100.285156 10.074219 C 100.285156 10.171875 100.285156 10.265625 100.285156 10.359375 C 100.285156 10.449219 100.285156 10.539062 100.285156 10.628906 C 100.285156 10.675781 100.285156 10.726562 100.285156 10.773438 C 100.289062 10.964844 100.292969 11.167969 100.417969 11.320312 C 100.53125 11.378906 100.636719 11.398438 100.757812 11.367188 C 100.898438 11.308594 101.003906 11.21875 101.113281 11.117188 C 101.226562 11.199219 101.339844 11.289062 101.449219 11.378906 C 101.394531 11.527344 101.300781 11.640625 101.207031 11.765625 C 101.179688 11.804688 101.179688 11.804688 101.152344 11.84375 C 100.859375 12.152344 100.476562 12.265625 100.058594 12.277344 C 99.699219 12.269531 99.332031 12.164062 99.066406 11.910156 C 98.933594 11.757812 98.761719 11.519531 98.761719 11.308594 C 98.582031 11.449219 98.582031 11.449219 98.417969 11.605469 C 98.289062 11.738281 98.140625 11.847656 97.992188 11.957031 C 97.96875 11.972656 97.949219 11.992188 97.925781 12.007812 C 97.488281 12.3125 96.855469 12.339844 96.34375 12.25 C 95.917969 12.15625 95.527344 11.929688 95.28125 11.558594 C 95.035156 11.136719 94.964844 10.617188 95.082031 10.140625 C 95.289062 9.527344 95.746094 9.175781 96.300781 8.894531 C 96.941406 8.582031 97.644531 8.375 98.328125 8.179688 C 98.34375 8.175781 98.359375 8.171875 98.375 8.167969 C 98.472656 8.140625 98.566406 8.113281 98.664062 8.085938 C 98.695312 7.195312 98.695312 7.195312 98.328125 6.425781 C 98.121094 6.230469 97.828125 6.203125 97.558594 6.203125 C 97.53125 6.203125 97.53125 6.203125 97.503906 6.203125 C 97.339844 6.207031 97.171875 6.21875 97.007812 6.230469 C 97.003906 6.257812 97.003906 6.289062 97 6.316406 C 96.984375 6.46875 96.957031 6.617188 96.925781 6.765625 C 96.917969 6.816406 96.910156 6.863281 96.902344 6.910156 C 96.832031 7.273438 96.738281 7.585938 96.425781 7.808594 C 96.191406 7.933594 95.945312 7.933594 95.6875 7.867188 C 95.515625 7.808594 95.40625 7.707031 95.320312 7.546875 C 95.234375 7.347656 95.238281 7.183594 95.308594 6.980469 C 95.316406 6.957031 95.316406 6.957031 95.324219 6.929688 C 95.421875 6.644531 95.574219 6.441406 95.785156 6.230469 C 95.800781 6.214844 95.816406 6.195312 95.835938 6.179688 C 96.734375 5.308594 98.742188 5.21875 99.691406 6.011719 Z M 98.394531 8.742188 C 98.292969 8.777344 98.1875 8.8125 98.082031 8.847656 C 97.574219 9.007812 97.011719 9.230469 96.746094 9.722656 C 96.582031 10.042969 96.554688 10.355469 96.648438 10.703125 C 96.71875 10.914062 96.816406 11.042969 97.011719 11.152344 C 97.296875 11.292969 97.609375 11.304688 97.910156 11.199219 C 98.058594 11.132812 98.207031 11.050781 98.34375 10.960938 C 98.398438 10.921875 98.398438 10.921875 98.46875 10.890625 C 98.558594 10.839844 98.644531 10.789062 98.679688 10.683594 C 98.703125 10.542969 98.695312 10.402344 98.691406 10.257812 C 98.6875 10.214844 98.6875 10.167969 98.6875 10.121094 C 98.6875 10 98.683594 9.878906 98.683594 9.757812 C 98.679688 9.636719 98.679688 9.511719 98.675781 9.386719 C 98.675781 9.144531 98.667969 8.902344 98.664062 8.660156 C 98.578125 8.660156 98.476562 8.714844 98.394531 8.742188 Z M 98.394531 8.742188 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 38.035156 6.242188 C 38.207031 6.40625 38.332031 6.578125 38.449219 6.785156 C 38.460938 6.808594 38.460938 6.808594 38.472656 6.832031 C 38.835938 7.472656 38.875 8.257812 38.761719 8.972656 C 38.734375 9 38.734375 9 38.671875 9 C 38.625 9 38.625 9 38.578125 9 C 38.5625 9 38.546875 9 38.53125 9 C 38.472656 9 38.417969 9 38.363281 9 C 38.324219 9 38.285156 9 38.242188 9 C 38.136719 9 38.027344 9 37.917969 9 C 37.804688 9 37.695312 9 37.582031 9 C 37.367188 9 37.152344 9 36.9375 9 C 36.695312 9 36.453125 9 36.207031 9 C 35.707031 9 35.207031 9 34.703125 9 C 34.714844 9.089844 34.726562 9.183594 34.738281 9.273438 C 34.742188 9.300781 34.742188 9.328125 34.746094 9.351562 C 34.8125 9.898438 35.007812 10.441406 35.4375 10.808594 C 35.933594 11.1875 36.476562 11.269531 37.089844 11.203125 C 37.539062 11.128906 37.90625 10.847656 38.222656 10.535156 C 38.347656 10.417969 38.347656 10.417969 38.425781 10.417969 C 38.464844 10.445312 38.464844 10.445312 38.503906 10.488281 C 38.589844 10.585938 38.683594 10.671875 38.785156 10.753906 C 38.679688 11.046875 38.46875 11.28125 38.257812 11.5 C 38.242188 11.519531 38.222656 11.535156 38.207031 11.554688 C 37.792969 12 37.171875 12.246094 36.574219 12.320312 C 36.554688 12.320312 36.535156 12.324219 36.515625 12.328125 C 35.640625 12.425781 34.773438 12.210938 34.074219 11.671875 C 33.421875 11.125 33.078125 10.363281 32.976562 9.527344 C 32.972656 9.496094 32.972656 9.496094 32.96875 9.460938 C 32.871094 8.5 33.074219 7.515625 33.675781 6.746094 C 33.707031 6.710938 33.738281 6.675781 33.769531 6.640625 C 33.78125 6.621094 33.796875 6.605469 33.8125 6.585938 C 34.316406 5.988281 35.136719 5.640625 35.902344 5.566406 C 36.699219 5.511719 37.429688 5.699219 38.035156 6.242188 Z M 35.226562 6.652344 C 34.949219 7.007812 34.820312 7.386719 34.746094 7.824219 C 34.742188 7.851562 34.738281 7.875 34.734375 7.898438 C 34.730469 7.921875 34.726562 7.949219 34.722656 7.972656 C 34.71875 7.992188 34.714844 8.015625 34.710938 8.035156 C 34.703125 8.097656 34.703125 8.15625 34.703125 8.222656 C 34.703125 8.242188 34.703125 8.261719 34.703125 8.28125 C 34.703125 8.292969 34.703125 8.308594 34.703125 8.324219 C 34.972656 8.328125 35.242188 8.328125 35.507812 8.328125 C 35.632812 8.328125 35.757812 8.328125 35.882812 8.332031 C 36.003906 8.332031 36.125 8.332031 36.246094 8.332031 C 36.289062 8.332031 36.335938 8.332031 36.382812 8.332031 C 36.445312 8.332031 36.511719 8.332031 36.574219 8.332031 C 36.59375 8.332031 36.613281 8.332031 36.632812 8.332031 C 36.800781 8.332031 36.964844 8.304688 37.085938 8.183594 C 37.273438 7.9375 37.277344 7.609375 37.246094 7.3125 C 37.195312 6.96875 37.015625 6.636719 36.730469 6.425781 C 36.226562 6.113281 35.617188 6.195312 35.226562 6.652344 Z M 35.226562 6.652344 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 112.726562 6.085938 C 112.90625 6.242188 113.058594 6.414062 113.183594 6.617188 C 113.199219 6.636719 113.210938 6.65625 113.226562 6.679688 C 113.628906 7.320312 113.699219 8.167969 113.566406 8.902344 C 113.523438 8.945312 113.449219 8.929688 113.386719 8.929688 C 113.371094 8.929688 113.355469 8.929688 113.339844 8.929688 C 113.28125 8.929688 113.226562 8.929688 113.171875 8.929688 C 113.132812 8.929688 113.089844 8.933594 113.050781 8.933594 C 112.945312 8.933594 112.835938 8.933594 112.726562 8.933594 C 112.613281 8.933594 112.5 8.933594 112.386719 8.933594 C 112.175781 8.9375 111.960938 8.9375 111.746094 8.9375 C 111.503906 8.941406 111.257812 8.941406 111.015625 8.941406 C 110.515625 8.945312 110.011719 8.949219 109.511719 8.949219 C 109.519531 9.023438 109.527344 9.097656 109.535156 9.171875 C 109.535156 9.191406 109.539062 9.210938 109.539062 9.230469 C 109.554688 9.378906 109.578125 9.523438 109.613281 9.667969 C 109.621094 9.6875 109.625 9.710938 109.628906 9.730469 C 109.703125 10.011719 109.808594 10.261719 109.992188 10.488281 C 110.003906 10.507812 110.019531 10.527344 110.035156 10.542969 C 110.320312 10.898438 110.765625 11.117188 111.214844 11.164062 C 111.839844 11.203125 112.339844 11.078125 112.820312 10.671875 C 112.9375 10.570312 113.050781 10.457031 113.160156 10.347656 C 113.230469 10.378906 113.28125 10.414062 113.339844 10.46875 C 113.355469 10.480469 113.367188 10.496094 113.382812 10.507812 C 113.398438 10.523438 113.414062 10.539062 113.429688 10.554688 C 113.445312 10.566406 113.460938 10.582031 113.476562 10.597656 C 113.515625 10.632812 113.554688 10.671875 113.59375 10.707031 C 113.324219 11.316406 112.769531 11.816406 112.15625 12.066406 C 112.054688 12.105469 111.953125 12.136719 111.847656 12.171875 C 111.832031 12.175781 111.816406 12.179688 111.800781 12.183594 C 111.507812 12.265625 111.214844 12.28125 110.914062 12.28125 C 110.898438 12.28125 110.878906 12.28125 110.859375 12.28125 C 110.554688 12.277344 110.261719 12.257812 109.96875 12.175781 C 109.941406 12.167969 109.941406 12.167969 109.914062 12.160156 C 109.203125 11.953125 108.628906 11.503906 108.238281 10.875 C 108.230469 10.859375 108.222656 10.847656 108.210938 10.832031 C 107.699219 9.980469 107.648438 8.855469 107.878906 7.90625 C 108.074219 7.136719 108.570312 6.417969 109.253906 6 C 110.304688 5.378906 111.75 5.261719 112.726562 6.085938 Z M 110.105469 6.496094 C 109.710938 6.9375 109.507812 7.546875 109.511719 8.136719 C 109.511719 8.160156 109.511719 8.179688 109.511719 8.203125 C 109.511719 8.21875 109.511719 8.234375 109.511719 8.253906 C 109.78125 8.253906 110.050781 8.253906 110.316406 8.257812 C 110.441406 8.257812 110.566406 8.257812 110.691406 8.257812 C 110.8125 8.257812 110.933594 8.257812 111.054688 8.257812 C 111.097656 8.257812 111.144531 8.261719 111.191406 8.261719 C 111.253906 8.261719 111.320312 8.261719 111.382812 8.261719 C 111.402344 8.261719 111.421875 8.261719 111.441406 8.261719 C 111.59375 8.261719 111.746094 8.234375 111.871094 8.140625 C 112.082031 7.886719 112.078125 7.605469 112.054688 7.289062 C 112.011719 6.949219 111.867188 6.6875 111.625 6.449219 C 111.609375 6.433594 111.59375 6.417969 111.582031 6.40625 C 111.164062 6.015625 110.496094 6.121094 110.105469 6.496094 Z M 110.105469 6.496094 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 119.207031 6.039062 C 119.210938 6.308594 119.203125 6.578125 119.1875 6.847656 C 119.183594 6.910156 119.183594 6.972656 119.179688 7.035156 C 119.175781 7.078125 119.175781 7.117188 119.171875 7.160156 C 119.171875 7.175781 119.171875 7.195312 119.171875 7.214844 C 119.164062 7.308594 119.152344 7.390625 119.136719 7.484375 C 118.835938 7.484375 118.535156 7.484375 118.222656 7.484375 C 118.207031 7.40625 118.191406 7.328125 118.171875 7.246094 C 118.15625 7.171875 118.140625 7.097656 118.121094 7.023438 C 118.109375 6.96875 118.101562 6.917969 118.089844 6.867188 C 118.070312 6.792969 118.054688 6.714844 118.039062 6.640625 C 118.035156 6.617188 118.027344 6.59375 118.023438 6.570312 C 118.019531 6.550781 118.015625 6.527344 118.007812 6.503906 C 118.003906 6.484375 118 6.464844 117.996094 6.445312 C 117.984375 6.398438 117.984375 6.398438 117.960938 6.351562 C 117.902344 6.332031 117.847656 6.316406 117.789062 6.300781 C 117.765625 6.296875 117.765625 6.296875 117.738281 6.289062 C 117.339844 6.1875 116.835938 6.167969 116.464844 6.375 C 116.296875 6.480469 116.203125 6.609375 116.128906 6.789062 C 116.082031 7.042969 116.105469 7.261719 116.234375 7.484375 C 116.496094 7.828125 117.082031 7.953125 117.46875 8.070312 C 118.183594 8.289062 118.960938 8.597656 119.359375 9.277344 C 119.578125 9.714844 119.621094 10.257812 119.496094 10.734375 C 119.316406 11.277344 118.957031 11.703125 118.449219 11.964844 C 117.460938 12.445312 116.246094 12.394531 115.222656 12.054688 C 115.007812 11.972656 114.804688 11.867188 114.601562 11.765625 C 114.570312 11.234375 114.574219 10.707031 114.574219 10.175781 C 114.886719 10.175781 115.195312 10.175781 115.511719 10.175781 C 115.539062 10.304688 115.539062 10.304688 115.5625 10.433594 C 115.582031 10.515625 115.597656 10.597656 115.613281 10.679688 C 115.625 10.734375 115.636719 10.792969 115.648438 10.847656 C 115.664062 10.929688 115.679688 11.011719 115.695312 11.09375 C 115.703125 11.121094 115.707031 11.144531 115.710938 11.171875 C 115.71875 11.195312 115.722656 11.21875 115.726562 11.242188 C 115.730469 11.261719 115.734375 11.285156 115.738281 11.304688 C 115.75 11.355469 115.75 11.355469 115.777344 11.40625 C 116.324219 11.617188 117.03125 11.667969 117.578125 11.4375 C 117.800781 11.332031 117.949219 11.207031 118.039062 10.972656 C 118.089844 10.761719 118.082031 10.527344 117.992188 10.328125 C 117.910156 10.191406 117.820312 10.105469 117.6875 10.023438 C 117.664062 10.003906 117.636719 9.988281 117.609375 9.972656 C 117.265625 9.769531 116.875 9.65625 116.496094 9.527344 C 116.066406 9.386719 115.683594 9.222656 115.320312 8.949219 C 115.296875 8.933594 115.273438 8.917969 115.25 8.898438 C 115.226562 8.875 115.226562 8.875 115.199219 8.855469 C 115.199219 8.839844 115.199219 8.824219 115.199219 8.804688 C 115.1875 8.800781 115.171875 8.796875 115.160156 8.789062 C 114.933594 8.65625 114.792969 8.285156 114.726562 8.046875 C 114.605469 7.507812 114.6875 6.964844 114.984375 6.496094 C 115.347656 5.957031 115.902344 5.671875 116.523438 5.542969 C 117.460938 5.367188 118.386719 5.574219 119.207031 6.039062 Z M 119.207031 6.039062 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 67.945312 6.109375 C 67.96875 6.136719 67.96875 6.136719 67.96875 6.1875 C 67.96875 6.210938 67.96875 6.234375 67.964844 6.257812 C 67.964844 6.285156 67.964844 6.3125 67.964844 6.339844 C 67.960938 6.367188 67.960938 6.398438 67.960938 6.425781 C 67.960938 6.457031 67.957031 6.484375 67.957031 6.515625 C 67.941406 6.863281 67.917969 7.207031 67.894531 7.554688 C 67.59375 7.554688 67.292969 7.554688 66.984375 7.554688 C 66.921875 7.3125 66.863281 7.070312 66.808594 6.828125 C 66.804688 6.796875 66.796875 6.769531 66.789062 6.742188 C 66.785156 6.714844 66.777344 6.6875 66.773438 6.660156 C 66.765625 6.632812 66.761719 6.609375 66.753906 6.585938 C 66.742188 6.519531 66.742188 6.519531 66.742188 6.425781 C 66.707031 6.414062 66.667969 6.402344 66.628906 6.390625 C 66.605469 6.386719 66.585938 6.378906 66.5625 6.371094 C 66.355469 6.320312 66.15625 6.296875 65.941406 6.296875 C 65.917969 6.296875 65.894531 6.296875 65.871094 6.296875 C 65.5625 6.300781 65.296875 6.351562 65.0625 6.566406 C 64.894531 6.742188 64.859375 6.90625 64.863281 7.148438 C 64.867188 7.285156 64.890625 7.390625 64.96875 7.507812 C 64.976562 7.519531 64.984375 7.535156 64.996094 7.550781 C 65.261719 7.921875 65.914062 8.0625 66.328125 8.179688 C 67.054688 8.390625 67.703125 8.726562 68.089844 9.40625 C 68.214844 9.648438 68.289062 9.90625 68.304688 10.175781 C 68.304688 10.199219 68.304688 10.21875 68.308594 10.242188 C 68.324219 10.753906 68.15625 11.1875 67.824219 11.574219 C 67.808594 11.589844 67.796875 11.605469 67.78125 11.621094 C 67.28125 12.164062 66.515625 12.347656 65.808594 12.390625 C 65.144531 12.414062 64.535156 12.34375 63.910156 12.117188 C 63.886719 12.109375 63.886719 12.109375 63.859375 12.097656 C 63.675781 12.03125 63.507812 11.929688 63.335938 11.835938 C 63.335938 11.632812 63.335938 11.429688 63.335938 11.226562 C 63.335938 11.132812 63.335938 11.039062 63.335938 10.945312 C 63.332031 10.851562 63.332031 10.761719 63.332031 10.671875 C 63.332031 10.636719 63.332031 10.601562 63.332031 10.566406 C 63.332031 10.515625 63.332031 10.46875 63.332031 10.421875 C 63.332031 10.390625 63.332031 10.363281 63.332031 10.335938 C 63.335938 10.273438 63.335938 10.273438 63.359375 10.25 C 63.421875 10.246094 63.484375 10.246094 63.550781 10.246094 C 63.570312 10.246094 63.585938 10.246094 63.605469 10.246094 C 63.648438 10.246094 63.6875 10.246094 63.726562 10.246094 C 63.789062 10.246094 63.851562 10.246094 63.914062 10.246094 C 63.953125 10.246094 63.992188 10.246094 64.03125 10.246094 C 64.050781 10.246094 64.066406 10.246094 64.085938 10.246094 C 64.21875 10.246094 64.21875 10.246094 64.273438 10.273438 C 64.285156 10.316406 64.285156 10.316406 64.296875 10.375 C 64.300781 10.394531 64.304688 10.414062 64.308594 10.4375 C 64.316406 10.460938 64.320312 10.484375 64.324219 10.507812 C 64.328125 10.53125 64.332031 10.554688 64.339844 10.578125 C 64.347656 10.628906 64.359375 10.679688 64.367188 10.730469 C 64.382812 10.808594 64.398438 10.882812 64.414062 10.960938 C 64.421875 11.007812 64.433594 11.058594 64.441406 11.105469 C 64.445312 11.128906 64.453125 11.152344 64.457031 11.175781 C 64.476562 11.285156 64.492188 11.386719 64.488281 11.5 C 64.53125 11.511719 64.53125 11.511719 64.578125 11.519531 C 64.691406 11.546875 64.804688 11.574219 64.921875 11.605469 C 65.117188 11.648438 65.308594 11.648438 65.507812 11.652344 C 65.539062 11.652344 65.570312 11.652344 65.601562 11.652344 C 65.964844 11.652344 66.320312 11.59375 66.605469 11.359375 C 66.761719 11.199219 66.820312 11.003906 66.828125 10.789062 C 66.820312 10.566406 66.761719 10.382812 66.601562 10.226562 C 66.214844 9.933594 65.765625 9.789062 65.3125 9.640625 C 64.621094 9.414062 63.949219 9.125 63.59375 8.445312 C 63.378906 8 63.375 7.464844 63.53125 6.996094 C 63.761719 6.410156 64.183594 6.027344 64.753906 5.773438 C 65.792969 5.351562 66.988281 5.59375 67.945312 6.109375 Z M 67.945312 6.109375 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 105.941406 5.769531 C 105.960938 5.777344 105.976562 5.785156 105.996094 5.792969 C 106.1875 5.867188 106.351562 5.964844 106.535156 6.0625 C 106.511719 6.539062 106.488281 7.015625 106.464844 7.507812 C 106.164062 7.507812 105.863281 7.507812 105.550781 7.507812 C 105.445312 7.101562 105.445312 7.101562 105.410156 6.941406 C 105.40625 6.925781 105.402344 6.910156 105.398438 6.890625 C 105.386719 6.839844 105.375 6.789062 105.367188 6.738281 C 105.359375 6.703125 105.351562 6.667969 105.34375 6.632812 C 105.324219 6.546875 105.304688 6.460938 105.289062 6.375 C 105.234375 6.359375 105.183594 6.34375 105.128906 6.328125 C 105.097656 6.320312 105.070312 6.3125 105.039062 6.304688 C 104.859375 6.253906 104.6875 6.25 104.503906 6.25 C 104.464844 6.25 104.464844 6.25 104.421875 6.25 C 104.136719 6.246094 103.90625 6.3125 103.664062 6.464844 C 103.507812 6.621094 103.417969 6.816406 103.414062 7.042969 C 103.425781 7.25 103.492188 7.433594 103.632812 7.585938 C 103.976562 7.886719 104.484375 8.003906 104.910156 8.132812 C 105.628906 8.351562 106.285156 8.667969 106.667969 9.355469 C 106.878906 9.800781 106.9375 10.371094 106.785156 10.84375 C 106.554688 11.417969 106.144531 11.8125 105.585938 12.070312 C 104.601562 12.488281 103.335938 12.402344 102.359375 12.007812 C 102.203125 11.9375 102.046875 11.859375 101.902344 11.765625 C 101.894531 11.699219 101.894531 11.699219 101.894531 11.617188 C 101.894531 11.585938 101.894531 11.554688 101.890625 11.523438 C 101.890625 11.488281 101.890625 11.453125 101.890625 11.417969 C 101.890625 11.382812 101.890625 11.347656 101.890625 11.3125 C 101.890625 11.222656 101.886719 11.128906 101.886719 11.039062 C 101.886719 10.925781 101.886719 10.816406 101.882812 10.707031 C 101.882812 10.539062 101.882812 10.371094 101.878906 10.203125 C 102.1875 10.203125 102.496094 10.203125 102.816406 10.203125 C 102.871094 10.363281 102.871094 10.363281 102.886719 10.449219 C 102.890625 10.46875 102.894531 10.488281 102.898438 10.507812 C 102.902344 10.527344 102.90625 10.546875 102.910156 10.566406 C 102.914062 10.585938 102.917969 10.609375 102.921875 10.628906 C 102.933594 10.671875 102.941406 10.71875 102.949219 10.761719 C 102.964844 10.828125 102.976562 10.894531 102.988281 10.960938 C 103 11.003906 103.007812 11.046875 103.015625 11.089844 C 103.019531 11.109375 103.023438 11.132812 103.027344 11.152344 C 103.046875 11.246094 103.0625 11.332031 103.054688 11.429688 C 103.699219 11.59375 104.421875 11.726562 105.03125 11.386719 C 105.21875 11.265625 105.316406 11.125 105.375 10.914062 C 105.402344 10.691406 105.378906 10.496094 105.273438 10.292969 C 104.921875 9.867188 104.363281 9.730469 103.859375 9.5625 C 103.1875 9.339844 102.511719 9.058594 102.167969 8.398438 C 101.949219 7.929688 101.9375 7.414062 102.097656 6.929688 C 102.101562 6.90625 102.109375 6.886719 102.117188 6.863281 C 102.269531 6.417969 102.628906 6.066406 103.03125 5.847656 C 103.054688 5.832031 103.078125 5.820312 103.101562 5.808594 C 103.382812 5.65625 103.699219 5.574219 104.015625 5.535156 C 104.035156 5.53125 104.054688 5.527344 104.074219 5.527344 C 104.714844 5.449219 105.34375 5.535156 105.941406 5.769531 Z M 105.941406 5.769531 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 59.953125 3.921875 C 60.316406 3.921875 60.679688 3.921875 61.054688 3.921875 C 61.058594 4.292969 61.054688 4.667969 61.046875 5.039062 C 61.042969 5.066406 61.042969 5.066406 61.042969 5.09375 C 61.042969 5.144531 61.042969 5.195312 61.039062 5.246094 C 61.039062 5.277344 61.039062 5.304688 61.035156 5.335938 C 61.03125 5.472656 61.019531 5.613281 61.007812 5.75 C 61.53125 5.75 62.054688 5.75 62.59375 5.75 C 62.59375 6.035156 62.59375 6.320312 62.59375 6.617188 C 62.0625 6.617188 61.53125 6.617188 60.984375 6.617188 C 60.984375 7.128906 60.988281 7.644531 60.988281 8.160156 C 60.992188 8.398438 60.992188 8.636719 60.992188 8.875 C 60.992188 9.082031 60.992188 9.292969 60.996094 9.5 C 60.996094 9.609375 60.996094 9.71875 60.996094 9.832031 C 60.996094 9.933594 60.996094 10.039062 60.996094 10.140625 C 60.996094 10.179688 60.996094 10.21875 60.996094 10.253906 C 60.992188 10.765625 60.992188 10.765625 61.199219 11.210938 C 61.34375 11.347656 61.507812 11.40625 61.703125 11.40625 C 61.941406 11.371094 62.144531 11.289062 62.355469 11.175781 C 62.457031 11.125 62.457031 11.125 62.519531 11.117188 C 62.558594 11.140625 62.558594 11.140625 62.597656 11.183594 C 62.613281 11.195312 62.625 11.210938 62.640625 11.226562 C 62.652344 11.238281 62.667969 11.253906 62.683594 11.269531 C 62.695312 11.285156 62.710938 11.300781 62.726562 11.316406 C 62.761719 11.351562 62.796875 11.390625 62.832031 11.429688 C 62.785156 11.5625 62.707031 11.65625 62.617188 11.765625 C 62.605469 11.78125 62.59375 11.792969 62.578125 11.808594 C 62.375 12.03125 62.085938 12.183594 61.800781 12.269531 C 61.777344 12.277344 61.75 12.285156 61.726562 12.292969 C 61.511719 12.347656 61.296875 12.351562 61.078125 12.351562 C 61.046875 12.351562 61.019531 12.351562 60.988281 12.351562 C 60.523438 12.351562 60.085938 12.210938 59.730469 11.898438 C 59.542969 11.699219 59.425781 11.40625 59.375 11.140625 C 59.371094 11.117188 59.367188 11.097656 59.363281 11.074219 C 59.351562 10.988281 59.347656 10.902344 59.347656 10.8125 C 59.347656 10.792969 59.347656 10.777344 59.347656 10.757812 C 59.347656 10.695312 59.347656 10.636719 59.347656 10.578125 C 59.347656 10.535156 59.347656 10.492188 59.347656 10.449219 C 59.347656 10.332031 59.347656 10.214844 59.347656 10.097656 C 59.351562 9.972656 59.351562 9.851562 59.351562 9.730469 C 59.351562 9.496094 59.351562 9.265625 59.351562 9.035156 C 59.351562 8.769531 59.351562 8.507812 59.351562 8.242188 C 59.351562 7.703125 59.351562 7.160156 59.351562 6.617188 C 59.035156 6.617188 58.71875 6.617188 58.390625 6.617188 C 58.390625 6.371094 58.390625 6.125 58.390625 5.871094 C 58.914062 5.800781 58.914062 5.800781 59.449219 5.726562 C 59.480469 5.601562 59.515625 5.476562 59.550781 5.351562 C 59.574219 5.269531 59.59375 5.191406 59.617188 5.113281 C 59.652344 4.988281 59.6875 4.863281 59.722656 4.738281 C 59.75 4.640625 59.777344 4.539062 59.804688 4.4375 C 59.816406 4.398438 59.824219 4.359375 59.835938 4.324219 C 59.851562 4.269531 59.867188 4.214844 59.882812 4.160156 C 59.886719 4.144531 59.890625 4.128906 59.894531 4.113281 C 59.914062 4.046875 59.929688 3.984375 59.953125 3.921875 Z M 59.953125 3.921875 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 93.351562 5.554688 C 93.40625 5.59375 93.429688 5.617188 93.445312 5.679688 C 93.449219 5.75 93.445312 5.8125 93.441406 5.878906 C 93.441406 5.90625 93.441406 5.929688 93.441406 5.957031 C 93.4375 6.015625 93.4375 6.070312 93.433594 6.128906 C 93.429688 6.273438 93.425781 6.417969 93.421875 6.5625 C 93.417969 6.617188 93.417969 6.671875 93.417969 6.726562 C 93.402344 7.175781 93.40625 7.625 93.40625 8.074219 C 93.40625 8.195312 93.40625 8.3125 93.40625 8.429688 C 93.40625 8.644531 93.40625 8.859375 93.40625 9.074219 C 93.40625 9.320312 93.40625 9.570312 93.40625 9.816406 C 93.40625 10.320312 93.40625 10.828125 93.40625 11.332031 C 93.425781 11.335938 93.449219 11.339844 93.46875 11.34375 C 93.542969 11.355469 93.613281 11.371094 93.6875 11.382812 C 93.734375 11.390625 93.785156 11.398438 93.832031 11.40625 C 93.859375 11.414062 93.890625 11.417969 93.921875 11.425781 C 93.949219 11.429688 93.976562 11.433594 94.003906 11.4375 C 94.070312 11.449219 94.136719 11.464844 94.199219 11.476562 C 94.199219 11.675781 94.199219 11.875 94.199219 12.078125 C 93.105469 12.078125 92.015625 12.078125 90.886719 12.078125 C 90.886719 11.878906 90.886719 11.679688 90.886719 11.476562 C 90.988281 11.457031 91.085938 11.433594 91.1875 11.414062 C 91.222656 11.40625 91.253906 11.402344 91.289062 11.394531 C 91.339844 11.382812 91.386719 11.375 91.4375 11.363281 C 91.480469 11.355469 91.480469 11.355469 91.527344 11.34375 C 91.601562 11.332031 91.675781 11.332031 91.753906 11.332031 C 91.753906 10.894531 91.753906 10.457031 91.753906 10.023438 C 91.753906 9.820312 91.753906 9.617188 91.753906 9.414062 C 91.753906 9.234375 91.753906 9.058594 91.753906 8.882812 C 91.753906 8.789062 91.753906 8.695312 91.753906 8.601562 C 91.753906 8.066406 91.746094 7.535156 91.726562 7 C 91.683594 6.996094 91.683594 6.996094 91.636719 6.988281 C 91.539062 6.976562 91.4375 6.964844 91.339844 6.953125 C 91.296875 6.945312 91.25 6.941406 91.207031 6.933594 C 91.144531 6.925781 91.082031 6.917969 91.019531 6.910156 C 90.988281 6.90625 90.988281 6.90625 90.957031 6.902344 C 90.820312 6.882812 90.820312 6.882812 90.792969 6.855469 C 90.789062 6.816406 90.789062 6.777344 90.789062 6.738281 C 90.789062 6.714844 90.789062 6.691406 90.789062 6.667969 C 90.789062 6.640625 90.789062 6.617188 90.789062 6.589844 C 90.789062 6.566406 90.789062 6.539062 90.789062 6.515625 C 90.792969 6.453125 90.792969 6.390625 90.792969 6.328125 C 90.96875 6.253906 91.148438 6.1875 91.328125 6.125 C 91.355469 6.117188 91.382812 6.105469 91.414062 6.097656 C 91.503906 6.066406 91.59375 6.03125 91.683594 6 C 91.808594 5.957031 91.929688 5.914062 92.054688 5.871094 C 92.070312 5.867188 92.085938 5.859375 92.101562 5.855469 C 92.285156 5.792969 92.46875 5.726562 92.652344 5.660156 C 92.667969 5.652344 92.6875 5.644531 92.703125 5.640625 C 92.78125 5.609375 92.859375 5.582031 92.9375 5.554688 C 92.976562 5.539062 92.976562 5.539062 93.019531 5.523438 C 93.050781 5.511719 93.050781 5.511719 93.082031 5.5 C 93.1875 5.476562 93.261719 5.503906 93.351562 5.554688 Z M 93.351562 5.554688 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 42.214844 5.652344 C 42.214844 7.542969 42.214844 9.433594 42.214844 11.378906 C 42.535156 11.441406 42.535156 11.441406 42.863281 11.5 C 42.917969 11.515625 42.976562 11.53125 43.03125 11.550781 C 43.03125 11.738281 43.03125 11.929688 43.03125 12.125 C 41.929688 12.125 40.832031 12.125 39.695312 12.125 C 39.695312 11.9375 39.695312 11.746094 39.695312 11.550781 C 39.875 11.5 40.054688 11.460938 40.234375 11.425781 C 40.265625 11.417969 40.265625 11.417969 40.296875 11.410156 C 40.316406 11.40625 40.335938 11.402344 40.355469 11.398438 C 40.375 11.394531 40.394531 11.390625 40.410156 11.386719 C 40.46875 11.378906 40.523438 11.378906 40.585938 11.378906 C 40.582031 10.886719 40.578125 10.390625 40.574219 9.898438 C 40.574219 9.667969 40.574219 9.4375 40.570312 9.207031 C 40.570312 9.007812 40.570312 8.808594 40.570312 8.605469 C 40.566406 8.5 40.566406 8.394531 40.566406 8.289062 C 40.566406 8.191406 40.566406 8.089844 40.566406 7.988281 C 40.566406 7.953125 40.566406 7.917969 40.566406 7.878906 C 40.5625 7.683594 40.558594 7.488281 40.550781 7.292969 C 40.546875 7.273438 40.546875 7.253906 40.546875 7.234375 C 40.542969 7.140625 40.542969 7.140625 40.511719 7.050781 C 40.445312 7.035156 40.378906 7.027344 40.308594 7.019531 C 40.289062 7.015625 40.269531 7.011719 40.25 7.011719 C 40.183594 7.003906 40.121094 6.996094 40.054688 6.988281 C 40.011719 6.980469 39.96875 6.976562 39.921875 6.96875 C 39.816406 6.957031 39.707031 6.941406 39.601562 6.929688 C 39.601562 6.746094 39.601562 6.5625 39.601562 6.375 C 39.964844 6.242188 40.328125 6.109375 40.695312 5.980469 C 40.777344 5.953125 40.859375 5.921875 40.945312 5.894531 C 41 5.875 41.054688 5.855469 41.109375 5.835938 C 41.246094 5.789062 41.386719 5.738281 41.523438 5.6875 C 41.550781 5.675781 41.578125 5.667969 41.605469 5.65625 C 41.660156 5.636719 41.710938 5.617188 41.761719 5.597656 C 41.785156 5.589844 41.808594 5.578125 41.835938 5.570312 C 41.863281 5.558594 41.863281 5.558594 41.894531 5.546875 C 42.027344 5.515625 42.09375 5.585938 42.214844 5.652344 Z M 42.214844 5.652344 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 8.640625 9.261719 C 8.972656 9.519531 9.191406 9.859375 9.277344 10.273438 C 9.328125 10.675781 9.265625 11.089844 9.019531 11.421875 C 8.734375 11.769531 8.371094 12.007812 7.917969 12.058594 C 7.476562 12.09375 7.078125 11.957031 6.742188 11.667969 C 6.71875 11.648438 6.71875 11.648438 6.695312 11.628906 C 6.421875 11.378906 6.261719 10.992188 6.234375 10.628906 C 6.226562 10.179688 6.355469 9.789062 6.664062 9.457031 C 7.191406 8.921875 8.019531 8.84375 8.640625 9.261719 Z M 8.640625 9.261719 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 2.855469 4.089844 C 2.941406 4.15625 3.019531 4.230469 3.097656 4.308594 C 3.113281 4.324219 3.128906 4.339844 3.148438 4.359375 C 3.414062 4.640625 3.542969 5.027344 3.539062 5.410156 C 3.519531 5.851562 3.332031 6.21875 3.015625 6.527344 C 2.707031 6.792969 2.304688 6.921875 1.898438 6.898438 C 1.578125 6.871094 1.308594 6.769531 1.054688 6.570312 C 1.03125 6.546875 1.03125 6.546875 1.003906 6.527344 C 0.699219 6.277344 0.527344 5.898438 0.484375 5.511719 C 0.453125 5.121094 0.558594 4.730469 0.804688 4.425781 C 1.003906 4.191406 1.226562 4.03125 1.511719 3.921875 C 1.53125 3.914062 1.550781 3.90625 1.570312 3.898438 C 1.988281 3.757812 2.496094 3.84375 2.855469 4.089844 Z M 2.855469 4.089844 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 2.960938 11.683594 C 3.269531 11.949219 3.492188 12.316406 3.53125 12.726562 C 3.558594 13.152344 3.449219 13.550781 3.171875 13.878906 C 2.875 14.203125 2.519531 14.375 2.082031 14.417969 C 1.671875 14.433594 1.28125 14.28125 0.972656 14.011719 C 0.660156 13.714844 0.488281 13.324219 0.476562 12.890625 C 0.480469 12.53125 0.59375 12.214844 0.816406 11.933594 C 0.828125 11.917969 0.839844 11.902344 0.851562 11.882812 C 1.078125 11.597656 1.433594 11.421875 1.785156 11.363281 C 2.207031 11.316406 2.628906 11.417969 2.960938 11.683594 Z M 2.960938 11.683594 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 14.449219 4.167969 C 14.507812 4.222656 14.5625 4.273438 14.617188 4.332031 C 14.628906 4.34375 14.640625 4.355469 14.65625 4.367188 C 14.914062 4.632812 15.015625 5.023438 15.03125 5.378906 C 15.019531 5.734375 14.902344 6.046875 14.6875 6.328125 C 14.675781 6.34375 14.664062 6.359375 14.652344 6.378906 C 14.410156 6.679688 14.042969 6.851562 13.664062 6.898438 C 13.242188 6.925781 12.84375 6.816406 12.523438 6.535156 C 12.484375 6.5 12.445312 6.460938 12.40625 6.425781 C 12.394531 6.410156 12.378906 6.394531 12.363281 6.378906 C 12.085938 6.089844 11.988281 5.707031 11.992188 5.316406 C 12.003906 4.914062 12.167969 4.53125 12.457031 4.25 C 13.023438 3.75 13.847656 3.714844 14.449219 4.167969 Z M 14.449219 4.167969 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 42.046875 2.648438 C 42.253906 2.816406 42.375 3.03125 42.40625 3.296875 C 42.433594 3.558594 42.351562 3.808594 42.191406 4.019531 C 42.007812 4.214844 41.785156 4.351562 41.507812 4.363281 C 41.46875 4.363281 41.429688 4.363281 41.390625 4.363281 C 41.371094 4.363281 41.351562 4.363281 41.332031 4.363281 C 41.058594 4.355469 40.832031 4.273438 40.625 4.089844 C 40.476562 3.933594 40.359375 3.734375 40.34375 3.511719 C 40.34375 3.496094 40.339844 3.480469 40.339844 3.460938 C 40.328125 3.230469 40.390625 2.992188 40.542969 2.8125 C 40.554688 2.796875 40.570312 2.78125 40.585938 2.765625 C 40.597656 2.75 40.613281 2.734375 40.632812 2.714844 C 41.019531 2.339844 41.621094 2.332031 42.046875 2.648438 Z M 42.046875 2.648438 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 93.210938 2.566406 C 93.453125 2.757812 93.570312 2.96875 93.609375 3.273438 C 93.621094 3.53125 93.550781 3.773438 93.378906 3.972656 C 93.367188 3.988281 93.351562 4.003906 93.335938 4.019531 C 93.316406 4.039062 93.316406 4.039062 93.296875 4.058594 C 93.066406 4.28125 92.78125 4.316406 92.476562 4.3125 C 92.355469 4.308594 92.25 4.285156 92.136719 4.234375 C 92.117188 4.226562 92.101562 4.21875 92.082031 4.210938 C 91.871094 4.105469 91.703125 3.9375 91.605469 3.722656 C 91.515625 3.449219 91.515625 3.171875 91.632812 2.90625 C 91.773438 2.652344 92 2.484375 92.277344 2.402344 C 92.605469 2.324219 92.933594 2.375 93.210938 2.566406 Z M 93.210938 2.566406 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 8.320312 5.960938 C 8.539062 6.117188 8.664062 6.320312 8.726562 6.582031 C 8.769531 6.839844 8.710938 7.089844 8.574219 7.3125 C 8.410156 7.535156 8.207031 7.65625 7.945312 7.722656 C 7.621094 7.753906 7.355469 7.6875 7.105469 7.484375 C 6.921875 7.3125 6.8125 7.078125 6.792969 6.832031 C 6.789062 6.535156 6.871094 6.28125 7.078125 6.0625 C 7.4375 5.738281 7.914062 5.710938 8.320312 5.960938 Z M 8.320312 5.960938 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.431373%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 14.09375 0.820312 C 14.289062 0.96875 14.421875 1.179688 14.472656 1.417969 C 14.5 1.714844 14.464844 1.980469 14.273438 2.214844 C 14.082031 2.421875 13.890625 2.558594 13.605469 2.582031 C 13.320312 2.585938 13.078125 2.535156 12.863281 2.332031 C 12.660156 2.128906 12.550781 1.910156 12.542969 1.621094 C 12.546875 1.332031 12.644531 1.117188 12.839844 0.910156 C 13.199219 0.574219 13.6875 0.5625 14.09375 0.820312 Z M 14.09375 0.820312 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 2.574219 0.808594 C 2.769531 0.972656 2.925781 1.164062 2.976562 1.417969 C 2.996094 1.71875 2.972656 1.976562 2.777344 2.214844 C 2.585938 2.421875 2.394531 2.558594 2.109375 2.582031 C 1.824219 2.585938 1.582031 2.53125 1.367188 2.332031 C 1.226562 2.195312 1.136719 2.066406 1.078125 1.875 C 1.074219 1.863281 1.070312 1.847656 1.066406 1.832031 C 1.015625 1.570312 1.054688 1.3125 1.195312 1.089844 C 1.515625 0.644531 2.101562 0.484375 2.574219 0.808594 Z M 2.574219 0.808594 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 2.550781 8.316406 C 2.582031 8.34375 2.609375 8.371094 2.640625 8.398438 C 2.65625 8.414062 2.671875 8.429688 2.691406 8.445312 C 2.878906 8.640625 2.960938 8.847656 2.964844 9.121094 C 2.960938 9.398438 2.882812 9.613281 2.6875 9.816406 C 2.5 9.996094 2.257812 10.109375 1.992188 10.105469 C 1.695312 10.085938 1.449219 9.972656 1.246094 9.753906 C 1.074219 9.535156 1.003906 9.277344 1.03125 9 C 1.089844 8.710938 1.214844 8.484375 1.453125 8.3125 C 1.789062 8.105469 2.222656 8.085938 2.550781 8.316406 Z M 2.550781 8.316406 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 14.058594 8.34375 C 14.269531 8.496094 14.425781 8.714844 14.472656 8.972656 C 14.496094 9.300781 14.441406 9.542969 14.238281 9.804688 C 14.148438 9.90625 14.042969 9.972656 13.921875 10.03125 C 13.894531 10.046875 13.894531 10.046875 13.867188 10.058594 C 13.660156 10.144531 13.386719 10.136719 13.175781 10.066406 C 12.929688 9.960938 12.714844 9.769531 12.613281 9.519531 C 12.601562 9.484375 12.585938 9.445312 12.574219 9.40625 C 12.570312 9.390625 12.566406 9.378906 12.5625 9.363281 C 12.511719 9.109375 12.550781 8.855469 12.679688 8.632812 C 12.824219 8.421875 13.003906 8.277344 13.246094 8.203125 C 13.261719 8.199219 13.277344 8.195312 13.292969 8.191406 C 13.570312 8.136719 13.820312 8.195312 14.058594 8.34375 Z M 14.058594 8.34375 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 8.375 13.523438 C 8.605469 13.730469 8.71875 13.984375 8.742188 14.289062 C 8.734375 14.554688 8.621094 14.789062 8.445312 14.984375 C 8.25 15.164062 7.996094 15.25 7.734375 15.253906 C 7.46875 15.242188 7.25 15.136719 7.0625 14.953125 C 6.863281 14.730469 6.789062 14.488281 6.792969 14.195312 C 6.832031 13.894531 6.964844 13.664062 7.199219 13.472656 C 7.582031 13.230469 8.015625 13.25 8.375 13.523438 Z M 8.375 13.523438 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 14.027344 12.066406 C 14.25 12.234375 14.421875 12.449219 14.472656 12.726562 C 14.492188 13.019531 14.464844 13.269531 14.273438 13.5 C 14.089844 13.699219 13.886719 13.84375 13.609375 13.863281 C 13.3125 13.867188 13.058594 13.800781 12.832031 13.589844 C 12.730469 13.480469 12.65625 13.371094 12.601562 13.234375 C 12.589844 13.207031 12.582031 13.183594 12.570312 13.15625 C 12.519531 12.886719 12.539062 12.625 12.679688 12.386719 C 12.984375 11.945312 13.558594 11.765625 14.027344 12.066406 Z M 14.027344 12.066406 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 8.269531 2.203125 C 8.492188 2.371094 8.652344 2.574219 8.703125 2.855469 C 8.738281 3.113281 8.695312 3.371094 8.535156 3.582031 C 8.355469 3.796875 8.136719 3.949219 7.851562 3.976562 C 7.539062 3.988281 7.289062 3.894531 7.054688 3.679688 C 6.851562 3.449219 6.796875 3.222656 6.808594 2.914062 C 6.824219 2.671875 6.929688 2.480469 7.105469 2.308594 C 7.445312 2.039062 7.886719 1.964844 8.269531 2.203125 Z M 8.269531 2.203125 "
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "WeaveIcon"
+}
diff --git a/app/components/base/icons/src/public/tracing/WeaveIcon.tsx b/app/components/base/icons/src/public/tracing/WeaveIcon.tsx
new file mode 100644
index 0000000..fd66bd7
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/WeaveIcon.tsx
@@ -0,0 +1,16 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './WeaveIcon.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
+ props,
+ ref,
+) => <IconBase {...props} ref={ref} data={data as IconData} />)
+
+Icon.displayName = 'WeaveIcon'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/tracing/WeaveIconBig.json b/app/components/base/icons/src/public/tracing/WeaveIconBig.json
new file mode 100644
index 0000000..5557e23
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/WeaveIconBig.json
@@ -0,0 +1,279 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "xmlns": "http://www.w3.org/2000/svg",
+ "xmlns:xlink": "http://www.w3.org/1999/xlink",
+ "width": "124px",
+ "height": "16px",
+ "viewBox": "0 0 120 16",
+ "version": "1.1"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "surface1"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 20.847656 3.292969 C 20.875 3.292969 20.902344 3.292969 20.933594 3.292969 C 20.949219 3.292969 20.964844 3.292969 20.980469 3.292969 C 21.035156 3.292969 21.089844 3.292969 21.140625 3.292969 C 21.179688 3.292969 21.21875 3.292969 21.253906 3.292969 C 21.359375 3.292969 21.464844 3.292969 21.566406 3.292969 C 21.675781 3.292969 21.78125 3.292969 21.890625 3.292969 C 22.097656 3.292969 22.300781 3.292969 22.507812 3.292969 C 22.738281 3.292969 22.972656 3.292969 23.207031 3.296875 C 23.6875 3.296875 24.167969 3.296875 24.648438 3.296875 C 24.648438 3.519531 24.648438 3.742188 24.648438 3.96875 C 24.113281 4.042969 24.113281 4.042969 23.566406 4.113281 C 23.667969 4.496094 23.769531 4.882812 23.867188 5.265625 C 23.878906 5.308594 23.878906 5.308594 23.890625 5.351562 C 24.128906 6.269531 24.371094 7.183594 24.609375 8.097656 C 24.675781 8.339844 24.738281 8.582031 24.800781 8.824219 C 24.816406 8.878906 24.832031 8.933594 24.84375 8.992188 C 24.867188 9.078125 24.890625 9.167969 24.914062 9.257812 C 24.921875 9.289062 24.933594 9.320312 24.941406 9.355469 C 24.953125 9.398438 24.964844 9.441406 24.976562 9.484375 C 24.984375 9.523438 24.984375 9.523438 24.996094 9.558594 C 25.007812 9.625 25.007812 9.625 25.007812 9.71875 C 25.023438 9.71875 25.039062 9.71875 25.054688 9.71875 C 25.058594 9.707031 25.058594 9.695312 25.0625 9.679688 C 25.097656 9.492188 25.152344 9.3125 25.210938 9.128906 C 25.222656 9.097656 25.234375 9.0625 25.246094 9.027344 C 25.269531 8.953125 25.292969 8.882812 25.316406 8.808594 C 25.355469 8.691406 25.390625 8.574219 25.429688 8.457031 C 25.464844 8.339844 25.503906 8.21875 25.542969 8.097656 C 25.660156 7.738281 25.773438 7.375 25.890625 7.011719 C 25.902344 6.96875 25.917969 6.921875 25.933594 6.875 C 26.226562 5.945312 26.519531 5.019531 26.808594 4.089844 C 26.785156 4.089844 26.765625 4.089844 26.742188 4.085938 C 26.507812 4.074219 26.273438 4.046875 26.042969 4.015625 C 26.007812 4.011719 25.972656 4.007812 25.933594 4.003906 C 25.851562 3.992188 25.765625 3.980469 25.679688 3.96875 C 25.679688 3.746094 25.679688 3.523438 25.679688 3.296875 C 26.175781 3.296875 26.667969 3.296875 27.160156 3.296875 C 27.390625 3.292969 27.621094 3.292969 27.851562 3.292969 C 28.050781 3.292969 28.25 3.292969 28.449219 3.292969 C 28.554688 3.292969 28.660156 3.292969 28.765625 3.292969 C 28.867188 3.292969 28.964844 3.292969 29.066406 3.292969 C 29.101562 3.292969 29.140625 3.292969 29.175781 3.292969 C 29.226562 3.292969 29.273438 3.292969 29.324219 3.292969 C 29.367188 3.292969 29.367188 3.292969 29.410156 3.292969 C 29.472656 3.296875 29.472656 3.296875 29.496094 3.320312 C 29.5 3.367188 29.5 3.417969 29.5 3.464844 C 29.5 3.492188 29.5 3.515625 29.5 3.542969 C 29.496094 3.59375 29.496094 3.59375 29.496094 3.648438 C 29.496094 3.753906 29.496094 3.859375 29.496094 3.96875 C 29.09375 4.015625 28.6875 4.066406 28.273438 4.113281 C 28.679688 5.460938 28.679688 5.460938 29.089844 6.808594 C 29.105469 6.859375 29.121094 6.910156 29.136719 6.960938 C 29.234375 7.292969 29.335938 7.625 29.4375 7.960938 C 29.484375 8.113281 29.53125 8.265625 29.578125 8.417969 C 29.605469 8.507812 29.632812 8.597656 29.660156 8.691406 C 29.878906 9.40625 29.878906 9.40625 29.976562 9.746094 C 30.027344 9.664062 30.046875 9.601562 30.070312 9.507812 C 30.078125 9.484375 30.078125 9.484375 30.085938 9.457031 C 30.101562 9.402344 30.117188 9.34375 30.132812 9.289062 C 30.144531 9.25 30.152344 9.207031 30.164062 9.167969 C 30.1875 9.082031 30.214844 8.992188 30.238281 8.90625 C 30.292969 8.691406 30.351562 8.480469 30.410156 8.269531 C 30.433594 8.191406 30.453125 8.117188 30.472656 8.042969 C 30.621094 7.5 30.769531 6.960938 30.921875 6.421875 C 30.949219 6.324219 30.976562 6.226562 31 6.128906 C 31.066406 5.902344 31.128906 5.675781 31.191406 5.449219 C 31.230469 5.308594 31.269531 5.164062 31.308594 5.023438 C 31.335938 4.925781 31.363281 4.828125 31.390625 4.734375 C 31.402344 4.6875 31.414062 4.640625 31.429688 4.59375 C 31.445312 4.53125 31.464844 4.46875 31.480469 4.40625 C 31.488281 4.386719 31.492188 4.367188 31.496094 4.347656 C 31.515625 4.277344 31.535156 4.207031 31.558594 4.136719 C 31.210938 4.074219 30.855469 4.023438 30.503906 3.96875 C 30.503906 3.746094 30.503906 3.523438 30.503906 3.296875 C 30.878906 3.296875 31.253906 3.296875 31.628906 3.296875 C 31.804688 3.292969 31.976562 3.292969 32.152344 3.292969 C 32.304688 3.292969 32.457031 3.292969 32.605469 3.292969 C 32.6875 3.292969 32.769531 3.292969 32.847656 3.292969 C 32.9375 3.292969 33.027344 3.292969 33.117188 3.292969 C 33.144531 3.292969 33.171875 3.292969 33.199219 3.292969 C 33.222656 3.292969 33.246094 3.292969 33.273438 3.292969 C 33.304688 3.292969 33.304688 3.292969 33.335938 3.292969 C 33.382812 3.296875 33.382812 3.296875 33.40625 3.320312 C 33.410156 3.367188 33.410156 3.414062 33.410156 3.460938 C 33.410156 3.488281 33.410156 3.515625 33.410156 3.542969 C 33.410156 3.574219 33.410156 3.605469 33.410156 3.632812 C 33.410156 3.664062 33.410156 3.695312 33.410156 3.726562 C 33.410156 3.796875 33.410156 3.871094 33.40625 3.945312 C 33.292969 3.964844 33.175781 3.984375 33.0625 4.007812 C 33.023438 4.011719 32.984375 4.019531 32.945312 4.027344 C 32.738281 4.0625 32.535156 4.097656 32.328125 4.113281 C 32.320312 4.144531 32.320312 4.144531 32.3125 4.179688 C 32.238281 4.480469 32.15625 4.78125 32.070312 5.082031 C 32.058594 5.128906 32.042969 5.171875 32.03125 5.21875 C 31.875 5.78125 31.714844 6.347656 31.550781 6.910156 C 31.375 7.535156 31.195312 8.160156 31.019531 8.785156 C 30.992188 8.871094 30.96875 8.957031 30.945312 9.042969 C 30.835938 9.433594 30.722656 9.820312 30.613281 10.210938 C 30.566406 10.378906 30.519531 10.542969 30.472656 10.707031 C 30.445312 10.804688 30.417969 10.902344 30.390625 11 C 30.277344 11.390625 30.167969 11.785156 30.046875 12.175781 C 29.730469 12.175781 29.414062 12.175781 29.089844 12.175781 C 29.03125 12.003906 29.03125 12.003906 28.976562 11.832031 C 28.925781 11.675781 28.878906 11.523438 28.828125 11.367188 C 28.820312 11.347656 28.8125 11.328125 28.808594 11.304688 C 28.632812 10.769531 28.460938 10.230469 28.285156 9.695312 C 28.144531 9.273438 28.007812 8.847656 27.875 8.425781 C 27.695312 7.867188 27.515625 7.308594 27.332031 6.753906 C 27.304688 6.679688 27.28125 6.605469 27.257812 6.53125 C 27.238281 6.476562 27.222656 6.425781 27.207031 6.375 C 27.046875 5.894531 27.046875 5.894531 27.046875 5.796875 C 27.03125 5.796875 27.015625 5.796875 27 5.796875 C 26.996094 5.8125 26.996094 5.828125 26.992188 5.84375 C 26.964844 5.988281 26.925781 6.132812 26.882812 6.273438 C 26.875 6.296875 26.867188 6.316406 26.859375 6.339844 C 26.84375 6.390625 26.828125 6.4375 26.8125 6.488281 C 26.769531 6.625 26.726562 6.761719 26.683594 6.898438 C 26.675781 6.929688 26.664062 6.957031 26.65625 6.988281 C 26.546875 7.328125 26.445312 7.667969 26.339844 8.007812 C 26.316406 8.078125 26.296875 8.144531 26.273438 8.214844 C 26.230469 8.355469 26.1875 8.496094 26.144531 8.636719 C 26.074219 8.863281 26.007812 9.089844 25.9375 9.3125 C 25.933594 9.328125 25.925781 9.347656 25.921875 9.363281 C 25.894531 9.449219 25.871094 9.535156 25.84375 9.617188 C 25.796875 9.769531 25.75 9.921875 25.703125 10.074219 C 25.675781 10.15625 25.652344 10.242188 25.625 10.328125 C 25.613281 10.363281 25.605469 10.394531 25.59375 10.429688 C 25.414062 11.011719 25.234375 11.59375 25.054688 12.175781 C 24.738281 12.175781 24.421875 12.175781 24.097656 12.175781 C 23.816406 11.230469 23.535156 10.285156 23.261719 9.339844 C 23.253906 9.320312 23.25 9.304688 23.246094 9.285156 C 23.195312 9.117188 23.144531 8.949219 23.097656 8.78125 C 22.960938 8.3125 22.824219 7.84375 22.6875 7.375 C 22.664062 7.304688 22.644531 7.234375 22.625 7.164062 C 22.414062 6.449219 22.207031 5.738281 22 5.027344 C 21.976562 4.953125 21.953125 4.878906 21.933594 4.804688 C 21.898438 4.683594 21.859375 4.5625 21.824219 4.441406 C 21.820312 4.421875 21.8125 4.402344 21.808594 4.382812 C 21.796875 4.347656 21.785156 4.3125 21.777344 4.28125 C 21.753906 4.203125 21.742188 4.148438 21.742188 4.066406 C 21.726562 4.066406 21.710938 4.0625 21.691406 4.0625 C 21.382812 4.042969 21.070312 4.003906 20.761719 3.96875 C 20.757812 3.863281 20.757812 3.753906 20.757812 3.648438 C 20.757812 3.617188 20.757812 3.585938 20.757812 3.554688 C 20.757812 3.523438 20.757812 3.496094 20.757812 3.464844 C 20.757812 3.4375 20.757812 3.410156 20.757812 3.382812 C 20.761719 3.296875 20.761719 3.296875 20.847656 3.292969 Z M 20.847656 3.292969 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 82.488281 3.25 C 83.046875 3.246094 83.605469 3.246094 84.167969 3.246094 C 84.425781 3.246094 84.6875 3.246094 84.945312 3.246094 C 85.171875 3.242188 85.398438 3.242188 85.625 3.242188 C 85.746094 3.242188 85.867188 3.242188 85.984375 3.242188 C 88.15625 3.238281 88.15625 3.238281 88.894531 3.898438 C 88.914062 3.914062 88.9375 3.929688 88.957031 3.945312 C 89.191406 4.144531 89.363281 4.402344 89.472656 4.691406 C 89.480469 4.714844 89.492188 4.742188 89.5 4.765625 C 89.65625 5.25 89.601562 5.785156 89.382812 6.234375 C 89.117188 6.753906 88.695312 7.078125 88.152344 7.265625 C 87.984375 7.320312 87.816406 7.367188 87.648438 7.410156 C 87.664062 7.414062 87.679688 7.417969 87.699219 7.421875 C 88.523438 7.605469 89.300781 7.851562 89.78125 8.597656 C 90.0625 9.0625 90.125 9.636719 90.003906 10.164062 C 89.808594 10.804688 89.363281 11.304688 88.78125 11.621094 C 88.324219 11.863281 87.820312 11.988281 87.3125 12.054688 C 87.28125 12.058594 87.253906 12.0625 87.222656 12.066406 C 86.777344 12.121094 86.332031 12.109375 85.882812 12.105469 C 85.765625 12.105469 85.644531 12.105469 85.523438 12.105469 C 85.300781 12.105469 85.074219 12.105469 84.847656 12.105469 C 84.589844 12.105469 84.332031 12.105469 84.074219 12.105469 C 83.546875 12.105469 83.015625 12.101562 82.488281 12.101562 C 82.488281 11.878906 82.488281 11.65625 82.488281 11.429688 C 82.859375 11.390625 83.234375 11.347656 83.617188 11.308594 C 83.617188 8.910156 83.617188 6.511719 83.617188 4.042969 C 83.488281 4.035156 83.363281 4.027344 83.230469 4.019531 C 83.117188 4.007812 83.003906 3.996094 82.890625 3.980469 C 82.863281 3.980469 82.832031 3.976562 82.804688 3.972656 C 82.695312 3.960938 82.59375 3.949219 82.488281 3.921875 C 82.488281 3.699219 82.488281 3.476562 82.488281 3.25 Z M 85.390625 3.96875 C 85.390625 4.242188 85.386719 4.515625 85.382812 4.785156 C 85.382812 4.914062 85.378906 5.039062 85.378906 5.164062 C 85.371094 5.824219 85.367188 6.484375 85.367188 7.144531 C 86.488281 7.183594 86.488281 7.183594 87.457031 6.691406 C 87.796875 6.320312 87.859375 5.832031 87.847656 5.351562 C 87.832031 4.992188 87.71875 4.644531 87.460938 4.378906 C 87 3.96875 86.363281 3.964844 85.78125 3.96875 C 85.742188 3.96875 85.703125 3.96875 85.667969 3.96875 C 85.574219 3.96875 85.484375 3.96875 85.390625 3.96875 Z M 85.390625 7.84375 C 85.390625 9.003906 85.390625 10.160156 85.390625 11.355469 C 86.28125 11.386719 86.28125 11.386719 87.152344 11.21875 C 87.171875 11.214844 87.1875 11.207031 87.207031 11.199219 C 87.578125 11.066406 87.886719 10.824219 88.066406 10.46875 C 88.28125 9.988281 88.289062 9.417969 88.125 8.921875 C 87.960938 8.492188 87.664062 8.234375 87.257812 8.046875 C 86.664062 7.804688 86.023438 7.84375 85.390625 7.84375 Z M 85.390625 7.84375 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 76.167969 3.476562 C 76.367188 3.671875 76.507812 3.917969 76.585938 4.1875 C 76.589844 4.203125 76.59375 4.222656 76.601562 4.242188 C 76.707031 4.675781 76.621094 5.144531 76.414062 5.53125 C 76.34375 5.644531 76.265625 5.746094 76.175781 5.847656 C 76.15625 5.867188 76.136719 5.886719 76.117188 5.910156 C 75.71875 6.332031 75.199219 6.617188 74.6875 6.882812 C 74.707031 6.902344 74.726562 6.921875 74.746094 6.941406 C 74.972656 7.191406 74.972656 7.191406 75.066406 7.296875 C 75.140625 7.382812 75.21875 7.464844 75.300781 7.542969 C 75.351562 7.59375 75.394531 7.640625 75.4375 7.695312 C 75.527344 7.796875 75.621094 7.894531 75.714844 7.992188 C 76.089844 8.394531 76.089844 8.394531 76.253906 8.585938 C 76.351562 8.695312 76.449219 8.800781 76.546875 8.90625 C 76.621094 8.980469 76.691406 9.058594 76.761719 9.136719 C 76.773438 9.152344 76.789062 9.164062 76.800781 9.179688 C 76.824219 9.207031 76.851562 9.234375 76.875 9.261719 C 76.933594 9.324219 76.992188 9.382812 77.0625 9.429688 C 77.070312 9.410156 77.070312 9.410156 77.082031 9.386719 C 77.113281 9.304688 77.152344 9.230469 77.195312 9.15625 C 77.5625 8.476562 77.800781 7.753906 77.976562 7 C 77.953125 7 77.933594 6.996094 77.910156 6.996094 C 77.707031 6.96875 77.5 6.9375 77.296875 6.902344 C 77.273438 6.898438 77.25 6.894531 77.222656 6.890625 C 77.050781 6.859375 77.050781 6.859375 76.96875 6.832031 C 76.960938 6.328125 76.960938 6.328125 77.015625 6.160156 C 77.949219 6.160156 78.886719 6.160156 79.847656 6.160156 C 79.847656 6.367188 79.847656 6.574219 79.847656 6.785156 C 79.53125 6.839844 79.214844 6.894531 78.886719 6.953125 C 78.859375 7.046875 78.832031 7.140625 78.804688 7.234375 C 78.539062 8.09375 78.164062 9.035156 77.601562 9.746094 C 77.5625 9.792969 77.5625 9.792969 77.566406 9.851562 C 77.601562 9.933594 77.648438 9.980469 77.714844 10.039062 C 77.792969 10.113281 77.867188 10.1875 77.9375 10.269531 C 78.027344 10.375 78.125 10.46875 78.222656 10.566406 C 78.308594 10.65625 78.390625 10.742188 78.472656 10.839844 C 78.539062 10.914062 78.601562 10.933594 78.695312 10.949219 C 78.71875 10.953125 78.746094 10.957031 78.769531 10.960938 C 78.796875 10.964844 78.824219 10.96875 78.851562 10.972656 C 78.875 10.980469 78.902344 10.984375 78.933594 10.988281 C 79.019531 11.003906 79.105469 11.019531 79.191406 11.03125 C 79.277344 11.046875 79.363281 11.0625 79.449219 11.078125 C 79.503906 11.085938 79.558594 11.097656 79.613281 11.105469 C 79.648438 11.113281 79.648438 11.113281 79.6875 11.117188 C 79.707031 11.121094 79.730469 11.125 79.75 11.128906 C 79.800781 11.140625 79.800781 11.140625 79.824219 11.164062 C 79.820312 11.421875 79.785156 11.679688 79.753906 11.933594 C 79.691406 11.949219 79.632812 11.964844 79.570312 11.980469 C 79.546875 11.984375 79.546875 11.984375 79.519531 11.992188 C 79.214844 12.066406 78.910156 12.085938 78.597656 12.085938 C 78.539062 12.085938 78.484375 12.085938 78.425781 12.085938 C 77.847656 12.089844 77.332031 11.917969 76.894531 11.523438 C 76.855469 11.484375 76.816406 11.445312 76.777344 11.40625 C 76.71875 11.347656 76.660156 11.296875 76.601562 11.242188 C 76.578125 11.21875 76.578125 11.21875 76.554688 11.195312 C 76.515625 11.160156 76.476562 11.125 76.441406 11.089844 C 76.429688 11.101562 76.417969 11.109375 76.410156 11.117188 C 76.140625 11.351562 75.859375 11.554688 75.542969 11.71875 C 75.511719 11.738281 75.476562 11.757812 75.445312 11.777344 C 75.3125 11.847656 75.179688 11.894531 75.039062 11.9375 C 75.011719 11.945312 75.011719 11.945312 74.984375 11.953125 C 74.632812 12.058594 74.269531 12.089844 73.90625 12.085938 C 73.84375 12.085938 73.785156 12.085938 73.722656 12.089844 C 72.941406 12.089844 72.222656 11.824219 71.652344 11.28125 C 71.203125 10.820312 71.023438 10.246094 71.03125 9.609375 C 71.042969 9.058594 71.230469 8.546875 71.59375 8.132812 C 71.609375 8.113281 71.625 8.09375 71.644531 8.070312 C 71.980469 7.683594 72.398438 7.421875 72.839844 7.171875 C 72.871094 7.152344 72.902344 7.132812 72.9375 7.113281 C 72.960938 7.101562 72.984375 7.085938 73.007812 7.074219 C 72.996094 7.0625 72.988281 7.050781 72.976562 7.042969 C 72.398438 6.425781 72.09375 5.613281 72.113281 4.773438 C 72.128906 4.371094 72.257812 3.988281 72.527344 3.679688 C 72.542969 3.660156 72.558594 3.644531 72.570312 3.625 C 72.917969 3.210938 73.496094 2.996094 74.015625 2.933594 C 74.050781 2.929688 74.050781 2.929688 74.082031 2.925781 C 74.804688 2.847656 75.621094 2.964844 76.167969 3.476562 Z M 73.671875 3.796875 C 73.433594 4.113281 73.414062 4.4375 73.457031 4.820312 C 73.550781 5.460938 73.921875 5.9375 74.328125 6.425781 C 74.398438 6.390625 74.449219 6.355469 74.503906 6.300781 C 74.527344 6.28125 74.527344 6.28125 74.550781 6.257812 C 74.566406 6.242188 74.582031 6.226562 74.597656 6.210938 C 74.613281 6.191406 74.628906 6.175781 74.644531 6.160156 C 74.773438 6.03125 74.890625 5.894531 75 5.75 C 75.019531 5.726562 75.035156 5.699219 75.054688 5.675781 C 75.335938 5.292969 75.5 4.859375 75.457031 4.378906 C 75.40625 4.078125 75.289062 3.820312 75.035156 3.636719 C 74.59375 3.363281 74.03125 3.410156 73.671875 3.796875 Z M 73.046875 7.828125 C 72.664062 8.226562 72.519531 8.789062 72.519531 9.332031 C 72.53125 9.800781 72.71875 10.257812 73.039062 10.601562 C 73.46875 10.996094 73.980469 11.140625 74.550781 11.125 C 74.960938 11.105469 75.339844 11.003906 75.703125 10.8125 C 75.71875 10.804688 75.738281 10.796875 75.753906 10.785156 C 75.84375 10.738281 75.90625 10.699219 75.960938 10.609375 C 75.949219 10.601562 75.941406 10.589844 75.933594 10.582031 C 75.460938 10.074219 75.460938 10.074219 75.25 9.8125 C 75.1875 9.738281 75.125 9.664062 75.0625 9.59375 C 74.972656 9.484375 74.882812 9.375 74.796875 9.265625 C 74.695312 9.132812 74.589844 9.003906 74.480469 8.878906 C 74.390625 8.773438 74.304688 8.667969 74.214844 8.5625 C 74.152344 8.484375 74.085938 8.40625 74.019531 8.328125 C 73.921875 8.214844 73.828125 8.101562 73.734375 7.984375 C 73.726562 7.96875 73.714844 7.957031 73.703125 7.941406 C 73.683594 7.914062 73.660156 7.886719 73.640625 7.859375 C 73.589844 7.792969 73.539062 7.730469 73.488281 7.667969 C 73.460938 7.632812 73.460938 7.632812 73.433594 7.601562 C 73.414062 7.578125 73.414062 7.578125 73.390625 7.554688 C 73.265625 7.554688 73.132812 7.742188 73.046875 7.828125 Z M 73.046875 7.828125 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 49.992188 5.535156 C 50.101562 5.609375 50.101562 5.609375 50.136719 5.679688 C 50.136719 5.746094 50.140625 5.8125 50.140625 5.882812 C 50.140625 5.914062 50.140625 5.914062 50.140625 5.941406 C 50.140625 5.984375 50.140625 6.027344 50.140625 6.070312 C 50.140625 6.136719 50.140625 6.203125 50.140625 6.269531 C 50.140625 6.308594 50.140625 6.351562 50.140625 6.390625 C 50.140625 6.410156 50.140625 6.429688 50.140625 6.453125 C 50.140625 6.589844 50.140625 6.589844 50.113281 6.617188 C 50.074219 6.617188 50.035156 6.621094 49.996094 6.621094 C 49.972656 6.621094 49.949219 6.621094 49.921875 6.621094 C 49.894531 6.621094 49.871094 6.617188 49.84375 6.617188 C 49.816406 6.617188 49.789062 6.617188 49.757812 6.617188 C 49.671875 6.617188 49.585938 6.617188 49.5 6.617188 C 49.441406 6.617188 49.378906 6.617188 49.320312 6.617188 C 49.175781 6.617188 49.03125 6.617188 48.886719 6.617188 C 48.898438 6.640625 48.90625 6.660156 48.917969 6.683594 C 48.929688 6.714844 48.945312 6.746094 48.957031 6.773438 C 48.964844 6.789062 48.96875 6.804688 48.976562 6.820312 C 49.203125 7.339844 49.195312 8 48.988281 8.523438 C 48.75 9.0625 48.355469 9.457031 47.804688 9.671875 C 47.066406 9.941406 46.210938 9.941406 45.457031 9.746094 C 45.277344 10.003906 45.214844 10.273438 45.238281 10.585938 C 45.269531 10.699219 45.316406 10.761719 45.402344 10.835938 C 45.617188 10.945312 45.851562 10.949219 46.089844 10.949219 C 46.113281 10.953125 46.132812 10.953125 46.15625 10.953125 C 46.203125 10.953125 46.25 10.953125 46.292969 10.953125 C 46.367188 10.953125 46.441406 10.953125 46.515625 10.953125 C 46.726562 10.953125 46.9375 10.957031 47.144531 10.957031 C 47.273438 10.957031 47.402344 10.957031 47.53125 10.960938 C 47.582031 10.960938 47.628906 10.960938 47.675781 10.960938 C 48.324219 10.960938 49.039062 11.019531 49.53125 11.492188 C 49.546875 11.511719 49.566406 11.53125 49.585938 11.550781 C 49.601562 11.566406 49.617188 11.582031 49.636719 11.597656 C 49.957031 11.929688 50.0625 12.394531 50.066406 12.84375 C 50.054688 13.351562 49.847656 13.800781 49.511719 14.171875 C 49.496094 14.191406 49.480469 14.207031 49.460938 14.226562 C 48.8125 14.921875 47.769531 15.179688 46.855469 15.210938 C 45.890625 15.234375 44.761719 15.230469 44.015625 14.523438 C 43.738281 14.222656 43.660156 13.886719 43.671875 13.488281 C 43.679688 13.363281 43.699219 13.253906 43.753906 13.136719 C 43.761719 13.117188 43.769531 13.09375 43.78125 13.074219 C 43.996094 12.644531 44.386719 12.410156 44.785156 12.175781 C 44.765625 12.167969 44.746094 12.160156 44.730469 12.152344 C 44.398438 11.996094 44.222656 11.808594 44.089844 11.476562 C 43.988281 11.136719 44.070312 10.757812 44.222656 10.453125 C 44.421875 10.109375 44.695312 9.824219 44.976562 9.550781 C 44.960938 9.542969 44.945312 9.53125 44.925781 9.523438 C 44.757812 9.417969 44.613281 9.304688 44.472656 9.167969 C 44.457031 9.152344 44.441406 9.136719 44.425781 9.121094 C 44.214844 8.902344 44.085938 8.597656 44.015625 8.300781 C 44.011719 8.28125 44.003906 8.257812 44 8.238281 C 43.882812 7.675781 43.964844 7.042969 44.277344 6.558594 C 44.621094 6.070312 45.09375 5.773438 45.671875 5.628906 C 45.6875 5.625 45.703125 5.621094 45.71875 5.617188 C 46.25 5.492188 46.917969 5.496094 47.449219 5.628906 C 47.464844 5.632812 47.480469 5.636719 47.496094 5.640625 C 47.6875 5.691406 47.867188 5.761719 48.046875 5.84375 C 48.0625 5.851562 48.078125 5.859375 48.09375 5.867188 C 48.164062 5.902344 48.226562 5.933594 48.289062 5.980469 C 48.390625 6.066406 48.390625 6.066406 48.515625 6.082031 C 48.582031 6.0625 48.644531 6.035156 48.707031 6.003906 C 48.730469 5.996094 48.753906 5.984375 48.78125 5.976562 C 48.855469 5.941406 48.929688 5.910156 49.003906 5.875 C 49.054688 5.851562 49.101562 5.832031 49.152344 5.808594 C 49.320312 5.738281 49.488281 5.664062 49.652344 5.585938 C 49.679688 5.574219 49.703125 5.566406 49.730469 5.554688 C 49.75 5.542969 49.769531 5.535156 49.789062 5.523438 C 49.867188 5.503906 49.917969 5.515625 49.992188 5.535156 Z M 45.835938 6.507812 C 45.472656 6.984375 45.421875 7.597656 45.492188 8.175781 C 45.550781 8.542969 45.6875 8.890625 45.980469 9.132812 C 46.207031 9.285156 46.46875 9.3125 46.734375 9.277344 C 47.015625 9.21875 47.210938 9.089844 47.375 8.855469 C 47.683594 8.375 47.742188 7.746094 47.640625 7.191406 C 47.5625 6.859375 47.402344 6.507812 47.117188 6.308594 C 46.703125 6.074219 46.152344 6.148438 45.835938 6.507812 Z M 45.238281 12.367188 C 44.957031 12.734375 44.867188 13.113281 44.902344 13.570312 C 44.957031 13.84375 45.09375 14.058594 45.316406 14.226562 C 45.613281 14.417969 46.015625 14.496094 46.367188 14.507812 C 46.394531 14.507812 46.394531 14.507812 46.417969 14.507812 C 47.132812 14.527344 47.90625 14.457031 48.453125 13.945312 C 48.652344 13.738281 48.710938 13.515625 48.703125 13.230469 C 48.683594 12.992188 48.570312 12.800781 48.394531 12.644531 C 48.113281 12.441406 47.726562 12.449219 47.398438 12.449219 C 47.355469 12.449219 47.3125 12.449219 47.269531 12.449219 C 47.15625 12.449219 47.046875 12.449219 46.933594 12.449219 C 46.753906 12.449219 46.574219 12.445312 46.394531 12.445312 C 46.332031 12.445312 46.269531 12.445312 46.210938 12.445312 C 45.882812 12.445312 45.5625 12.414062 45.238281 12.367188 Z M 45.238281 12.367188 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 53.039062 2.382812 C 53.0625 2.390625 53.0625 2.390625 53.085938 2.398438 C 53.140625 2.429688 53.171875 2.453125 53.207031 2.503906 C 53.230469 2.617188 53.21875 2.730469 53.214844 2.84375 C 53.210938 2.878906 53.210938 2.914062 53.210938 2.953125 C 53.207031 3.027344 53.203125 3.105469 53.199219 3.183594 C 53.191406 3.371094 53.183594 3.558594 53.179688 3.746094 C 53.175781 3.792969 53.175781 3.835938 53.175781 3.882812 C 53.15625 4.441406 53.15625 5 53.15625 5.5625 C 53.15625 5.640625 53.15625 5.71875 53.15625 5.792969 C 53.15625 6.085938 53.160156 6.375 53.160156 6.664062 C 53.179688 6.644531 53.195312 6.625 53.214844 6.605469 C 53.238281 6.578125 53.261719 6.550781 53.285156 6.523438 C 53.296875 6.511719 53.3125 6.5 53.324219 6.484375 C 53.78125 5.984375 54.445312 5.601562 55.128906 5.550781 C 55.640625 5.535156 56.128906 5.578125 56.527344 5.929688 C 56.566406 5.964844 56.601562 6 56.640625 6.039062 C 56.664062 6.0625 56.664062 6.0625 56.691406 6.089844 C 57.246094 6.660156 57.203125 7.570312 57.203125 8.304688 C 57.203125 8.414062 57.203125 8.523438 57.207031 8.632812 C 57.207031 8.839844 57.207031 9.042969 57.207031 9.25 C 57.207031 9.484375 57.210938 9.722656 57.210938 9.957031 C 57.210938 10.4375 57.214844 10.921875 57.214844 11.40625 C 57.246094 11.410156 57.246094 11.410156 57.28125 11.414062 C 57.308594 11.417969 57.335938 11.421875 57.363281 11.425781 C 57.40625 11.433594 57.40625 11.433594 57.445312 11.441406 C 57.558594 11.457031 57.671875 11.480469 57.785156 11.503906 C 57.808594 11.507812 57.828125 11.511719 57.851562 11.515625 C 57.878906 11.519531 57.878906 11.519531 57.910156 11.527344 C 57.929688 11.53125 57.949219 11.535156 57.964844 11.539062 C 58.007812 11.550781 58.007812 11.550781 58.03125 11.574219 C 58.035156 11.613281 58.035156 11.65625 58.035156 11.695312 C 58.035156 11.71875 58.035156 11.746094 58.035156 11.769531 C 58.035156 11.796875 58.035156 11.824219 58.035156 11.851562 C 58.035156 11.875 58.035156 11.902344 58.035156 11.929688 C 58.035156 11.964844 58.035156 11.964844 58.035156 12.003906 C 58.035156 12.027344 58.035156 12.050781 58.035156 12.074219 C 58.03125 12.125 58.03125 12.125 58.007812 12.148438 C 57.964844 12.152344 57.921875 12.152344 57.882812 12.152344 C 57.839844 12.152344 57.839844 12.152344 57.796875 12.152344 C 57.769531 12.152344 57.738281 12.152344 57.707031 12.152344 C 57.675781 12.152344 57.640625 12.152344 57.609375 12.152344 C 57.523438 12.152344 57.433594 12.152344 57.347656 12.152344 C 57.257812 12.152344 57.164062 12.152344 57.074219 12.152344 C 56.917969 12.152344 56.765625 12.152344 56.613281 12.152344 C 56.433594 12.152344 56.257812 12.152344 56.082031 12.152344 C 55.929688 12.152344 55.777344 12.152344 55.625 12.152344 C 55.53125 12.152344 55.441406 12.152344 55.351562 12.152344 C 55.265625 12.152344 55.179688 12.152344 55.09375 12.152344 C 55.046875 12.152344 55 12.152344 54.953125 12.152344 C 54.925781 12.152344 54.898438 12.152344 54.871094 12.152344 C 54.847656 12.152344 54.824219 12.152344 54.796875 12.152344 C 54.742188 12.148438 54.742188 12.148438 54.71875 12.125 C 54.71875 12.085938 54.71875 12.042969 54.71875 12.003906 C 54.71875 11.976562 54.71875 11.953125 54.71875 11.925781 C 54.71875 11.902344 54.71875 11.875 54.71875 11.847656 C 54.71875 11.820312 54.71875 11.796875 54.71875 11.769531 C 54.71875 11.703125 54.71875 11.636719 54.71875 11.574219 C 54.8125 11.53125 54.902344 11.507812 55.003906 11.488281 C 55.03125 11.480469 55.0625 11.476562 55.09375 11.46875 C 55.113281 11.464844 55.128906 11.460938 55.144531 11.460938 C 55.191406 11.449219 55.242188 11.441406 55.289062 11.429688 C 55.527344 11.378906 55.527344 11.378906 55.585938 11.378906 C 55.582031 10.90625 55.582031 10.433594 55.578125 9.960938 C 55.578125 9.742188 55.578125 9.523438 55.574219 9.304688 C 55.574219 9.109375 55.574219 8.917969 55.574219 8.726562 C 55.574219 8.625 55.570312 8.527344 55.570312 8.425781 C 55.570312 8.328125 55.570312 8.234375 55.570312 8.136719 C 55.570312 8.101562 55.570312 8.066406 55.570312 8.03125 C 55.570312 7.664062 55.554688 7.199219 55.289062 6.917969 C 55.054688 6.722656 54.742188 6.746094 54.457031 6.761719 C 54.101562 6.800781 53.738281 7.007812 53.464844 7.234375 C 53.425781 7.265625 53.425781 7.265625 53.371094 7.300781 C 53.273438 7.371094 53.214844 7.421875 53.1875 7.539062 C 53.179688 7.640625 53.179688 7.742188 53.183594 7.84375 C 53.183594 7.882812 53.183594 7.921875 53.183594 7.960938 C 53.183594 8.066406 53.183594 8.167969 53.1875 8.273438 C 53.1875 8.386719 53.1875 8.496094 53.1875 8.605469 C 53.1875 8.8125 53.191406 9.023438 53.191406 9.230469 C 53.195312 9.46875 53.195312 9.703125 53.195312 9.941406 C 53.199219 10.429688 53.203125 10.917969 53.207031 11.40625 C 53.238281 11.410156 53.238281 11.410156 53.265625 11.414062 C 53.351562 11.429688 53.4375 11.445312 53.523438 11.464844 C 53.554688 11.46875 53.585938 11.472656 53.613281 11.480469 C 53.644531 11.484375 53.671875 11.492188 53.703125 11.496094 C 53.730469 11.5 53.753906 11.507812 53.78125 11.511719 C 53.847656 11.523438 53.910156 11.535156 53.976562 11.550781 C 53.976562 11.746094 53.976562 11.945312 53.976562 12.148438 C 52.890625 12.148438 51.804688 12.148438 50.6875 12.148438 C 50.6875 11.953125 50.6875 11.753906 50.6875 11.550781 C 50.964844 11.492188 51.242188 11.4375 51.527344 11.378906 C 51.542969 11.160156 51.554688 10.945312 51.554688 10.722656 C 51.554688 10.691406 51.554688 10.660156 51.554688 10.628906 C 51.554688 10.546875 51.558594 10.464844 51.558594 10.378906 C 51.558594 10.289062 51.558594 10.199219 51.558594 10.109375 C 51.558594 9.953125 51.558594 9.796875 51.558594 9.640625 C 51.558594 9.414062 51.558594 9.1875 51.5625 8.960938 C 51.5625 8.59375 51.5625 8.230469 51.5625 7.863281 C 51.566406 7.507812 51.566406 7.152344 51.566406 6.792969 C 51.566406 6.773438 51.566406 6.75 51.566406 6.726562 C 51.566406 6.617188 51.566406 6.507812 51.566406 6.398438 C 51.570312 5.484375 51.574219 4.570312 51.574219 3.65625 C 51.554688 3.65625 51.535156 3.652344 51.515625 3.652344 C 51.476562 3.648438 51.476562 3.648438 51.4375 3.644531 C 51.414062 3.644531 51.386719 3.640625 51.359375 3.640625 C 51.277344 3.632812 51.195312 3.621094 51.113281 3.609375 C 51.082031 3.605469 51.054688 3.601562 51.023438 3.597656 C 50.996094 3.59375 50.964844 3.589844 50.933594 3.582031 C 50.902344 3.578125 50.871094 3.574219 50.839844 3.570312 C 50.765625 3.558594 50.691406 3.546875 50.617188 3.535156 C 50.617188 3.347656 50.617188 3.15625 50.617188 2.960938 C 50.910156 2.875 51.207031 2.796875 51.5 2.722656 C 51.523438 2.714844 51.542969 2.710938 51.5625 2.707031 C 51.671875 2.679688 51.777344 2.652344 51.886719 2.625 C 51.972656 2.601562 52.0625 2.578125 52.152344 2.554688 C 52.257812 2.527344 52.367188 2.5 52.472656 2.472656 C 52.515625 2.460938 52.554688 2.453125 52.597656 2.441406 C 52.652344 2.425781 52.710938 2.410156 52.765625 2.398438 C 52.78125 2.394531 52.800781 2.386719 52.816406 2.382812 C 52.898438 2.363281 52.960938 2.351562 53.039062 2.382812 Z M 53.039062 2.382812 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 99.691406 6.011719 C 100.109375 6.40625 100.234375 7.003906 100.273438 7.554688 C 100.277344 7.667969 100.277344 7.785156 100.277344 7.898438 C 100.277344 7.933594 100.277344 7.964844 100.277344 8 C 100.277344 8.074219 100.277344 8.144531 100.277344 8.21875 C 100.277344 8.332031 100.277344 8.445312 100.277344 8.558594 C 100.28125 8.886719 100.28125 9.210938 100.28125 9.535156 C 100.28125 9.714844 100.28125 9.894531 100.285156 10.074219 C 100.285156 10.171875 100.285156 10.265625 100.285156 10.359375 C 100.285156 10.449219 100.285156 10.539062 100.285156 10.628906 C 100.285156 10.675781 100.285156 10.726562 100.285156 10.773438 C 100.289062 10.964844 100.292969 11.167969 100.417969 11.320312 C 100.53125 11.378906 100.636719 11.398438 100.757812 11.367188 C 100.898438 11.308594 101.003906 11.21875 101.113281 11.117188 C 101.226562 11.199219 101.339844 11.289062 101.449219 11.378906 C 101.394531 11.527344 101.300781 11.640625 101.207031 11.765625 C 101.179688 11.804688 101.179688 11.804688 101.152344 11.84375 C 100.859375 12.152344 100.476562 12.265625 100.058594 12.277344 C 99.699219 12.269531 99.332031 12.164062 99.066406 11.910156 C 98.933594 11.757812 98.761719 11.519531 98.761719 11.308594 C 98.582031 11.449219 98.582031 11.449219 98.417969 11.605469 C 98.289062 11.738281 98.140625 11.847656 97.992188 11.957031 C 97.96875 11.972656 97.949219 11.992188 97.925781 12.007812 C 97.488281 12.3125 96.855469 12.339844 96.34375 12.25 C 95.917969 12.15625 95.527344 11.929688 95.28125 11.558594 C 95.035156 11.136719 94.964844 10.617188 95.082031 10.140625 C 95.289062 9.527344 95.746094 9.175781 96.300781 8.894531 C 96.941406 8.582031 97.644531 8.375 98.328125 8.179688 C 98.34375 8.175781 98.359375 8.171875 98.375 8.167969 C 98.472656 8.140625 98.566406 8.113281 98.664062 8.085938 C 98.695312 7.195312 98.695312 7.195312 98.328125 6.425781 C 98.121094 6.230469 97.828125 6.203125 97.558594 6.203125 C 97.53125 6.203125 97.53125 6.203125 97.503906 6.203125 C 97.339844 6.207031 97.171875 6.21875 97.007812 6.230469 C 97.003906 6.257812 97.003906 6.289062 97 6.316406 C 96.984375 6.46875 96.957031 6.617188 96.925781 6.765625 C 96.917969 6.816406 96.910156 6.863281 96.902344 6.910156 C 96.832031 7.273438 96.738281 7.585938 96.425781 7.808594 C 96.191406 7.933594 95.945312 7.933594 95.6875 7.867188 C 95.515625 7.808594 95.40625 7.707031 95.320312 7.546875 C 95.234375 7.347656 95.238281 7.183594 95.308594 6.980469 C 95.316406 6.957031 95.316406 6.957031 95.324219 6.929688 C 95.421875 6.644531 95.574219 6.441406 95.785156 6.230469 C 95.800781 6.214844 95.816406 6.195312 95.835938 6.179688 C 96.734375 5.308594 98.742188 5.21875 99.691406 6.011719 Z M 98.394531 8.742188 C 98.292969 8.777344 98.1875 8.8125 98.082031 8.847656 C 97.574219 9.007812 97.011719 9.230469 96.746094 9.722656 C 96.582031 10.042969 96.554688 10.355469 96.648438 10.703125 C 96.71875 10.914062 96.816406 11.042969 97.011719 11.152344 C 97.296875 11.292969 97.609375 11.304688 97.910156 11.199219 C 98.058594 11.132812 98.207031 11.050781 98.34375 10.960938 C 98.398438 10.921875 98.398438 10.921875 98.46875 10.890625 C 98.558594 10.839844 98.644531 10.789062 98.679688 10.683594 C 98.703125 10.542969 98.695312 10.402344 98.691406 10.257812 C 98.6875 10.214844 98.6875 10.167969 98.6875 10.121094 C 98.6875 10 98.683594 9.878906 98.683594 9.757812 C 98.679688 9.636719 98.679688 9.511719 98.675781 9.386719 C 98.675781 9.144531 98.667969 8.902344 98.664062 8.660156 C 98.578125 8.660156 98.476562 8.714844 98.394531 8.742188 Z M 98.394531 8.742188 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 38.035156 6.242188 C 38.207031 6.40625 38.332031 6.578125 38.449219 6.785156 C 38.460938 6.808594 38.460938 6.808594 38.472656 6.832031 C 38.835938 7.472656 38.875 8.257812 38.761719 8.972656 C 38.734375 9 38.734375 9 38.671875 9 C 38.625 9 38.625 9 38.578125 9 C 38.5625 9 38.546875 9 38.53125 9 C 38.472656 9 38.417969 9 38.363281 9 C 38.324219 9 38.285156 9 38.242188 9 C 38.136719 9 38.027344 9 37.917969 9 C 37.804688 9 37.695312 9 37.582031 9 C 37.367188 9 37.152344 9 36.9375 9 C 36.695312 9 36.453125 9 36.207031 9 C 35.707031 9 35.207031 9 34.703125 9 C 34.714844 9.089844 34.726562 9.183594 34.738281 9.273438 C 34.742188 9.300781 34.742188 9.328125 34.746094 9.351562 C 34.8125 9.898438 35.007812 10.441406 35.4375 10.808594 C 35.933594 11.1875 36.476562 11.269531 37.089844 11.203125 C 37.539062 11.128906 37.90625 10.847656 38.222656 10.535156 C 38.347656 10.417969 38.347656 10.417969 38.425781 10.417969 C 38.464844 10.445312 38.464844 10.445312 38.503906 10.488281 C 38.589844 10.585938 38.683594 10.671875 38.785156 10.753906 C 38.679688 11.046875 38.46875 11.28125 38.257812 11.5 C 38.242188 11.519531 38.222656 11.535156 38.207031 11.554688 C 37.792969 12 37.171875 12.246094 36.574219 12.320312 C 36.554688 12.320312 36.535156 12.324219 36.515625 12.328125 C 35.640625 12.425781 34.773438 12.210938 34.074219 11.671875 C 33.421875 11.125 33.078125 10.363281 32.976562 9.527344 C 32.972656 9.496094 32.972656 9.496094 32.96875 9.460938 C 32.871094 8.5 33.074219 7.515625 33.675781 6.746094 C 33.707031 6.710938 33.738281 6.675781 33.769531 6.640625 C 33.78125 6.621094 33.796875 6.605469 33.8125 6.585938 C 34.316406 5.988281 35.136719 5.640625 35.902344 5.566406 C 36.699219 5.511719 37.429688 5.699219 38.035156 6.242188 Z M 35.226562 6.652344 C 34.949219 7.007812 34.820312 7.386719 34.746094 7.824219 C 34.742188 7.851562 34.738281 7.875 34.734375 7.898438 C 34.730469 7.921875 34.726562 7.949219 34.722656 7.972656 C 34.71875 7.992188 34.714844 8.015625 34.710938 8.035156 C 34.703125 8.097656 34.703125 8.15625 34.703125 8.222656 C 34.703125 8.242188 34.703125 8.261719 34.703125 8.28125 C 34.703125 8.292969 34.703125 8.308594 34.703125 8.324219 C 34.972656 8.328125 35.242188 8.328125 35.507812 8.328125 C 35.632812 8.328125 35.757812 8.328125 35.882812 8.332031 C 36.003906 8.332031 36.125 8.332031 36.246094 8.332031 C 36.289062 8.332031 36.335938 8.332031 36.382812 8.332031 C 36.445312 8.332031 36.511719 8.332031 36.574219 8.332031 C 36.59375 8.332031 36.613281 8.332031 36.632812 8.332031 C 36.800781 8.332031 36.964844 8.304688 37.085938 8.183594 C 37.273438 7.9375 37.277344 7.609375 37.246094 7.3125 C 37.195312 6.96875 37.015625 6.636719 36.730469 6.425781 C 36.226562 6.113281 35.617188 6.195312 35.226562 6.652344 Z M 35.226562 6.652344 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 112.726562 6.085938 C 112.90625 6.242188 113.058594 6.414062 113.183594 6.617188 C 113.199219 6.636719 113.210938 6.65625 113.226562 6.679688 C 113.628906 7.320312 113.699219 8.167969 113.566406 8.902344 C 113.523438 8.945312 113.449219 8.929688 113.386719 8.929688 C 113.371094 8.929688 113.355469 8.929688 113.339844 8.929688 C 113.28125 8.929688 113.226562 8.929688 113.171875 8.929688 C 113.132812 8.929688 113.089844 8.933594 113.050781 8.933594 C 112.945312 8.933594 112.835938 8.933594 112.726562 8.933594 C 112.613281 8.933594 112.5 8.933594 112.386719 8.933594 C 112.175781 8.9375 111.960938 8.9375 111.746094 8.9375 C 111.503906 8.941406 111.257812 8.941406 111.015625 8.941406 C 110.515625 8.945312 110.011719 8.949219 109.511719 8.949219 C 109.519531 9.023438 109.527344 9.097656 109.535156 9.171875 C 109.535156 9.191406 109.539062 9.210938 109.539062 9.230469 C 109.554688 9.378906 109.578125 9.523438 109.613281 9.667969 C 109.621094 9.6875 109.625 9.710938 109.628906 9.730469 C 109.703125 10.011719 109.808594 10.261719 109.992188 10.488281 C 110.003906 10.507812 110.019531 10.527344 110.035156 10.542969 C 110.320312 10.898438 110.765625 11.117188 111.214844 11.164062 C 111.839844 11.203125 112.339844 11.078125 112.820312 10.671875 C 112.9375 10.570312 113.050781 10.457031 113.160156 10.347656 C 113.230469 10.378906 113.28125 10.414062 113.339844 10.46875 C 113.355469 10.480469 113.367188 10.496094 113.382812 10.507812 C 113.398438 10.523438 113.414062 10.539062 113.429688 10.554688 C 113.445312 10.566406 113.460938 10.582031 113.476562 10.597656 C 113.515625 10.632812 113.554688 10.671875 113.59375 10.707031 C 113.324219 11.316406 112.769531 11.816406 112.15625 12.066406 C 112.054688 12.105469 111.953125 12.136719 111.847656 12.171875 C 111.832031 12.175781 111.816406 12.179688 111.800781 12.183594 C 111.507812 12.265625 111.214844 12.28125 110.914062 12.28125 C 110.898438 12.28125 110.878906 12.28125 110.859375 12.28125 C 110.554688 12.277344 110.261719 12.257812 109.96875 12.175781 C 109.941406 12.167969 109.941406 12.167969 109.914062 12.160156 C 109.203125 11.953125 108.628906 11.503906 108.238281 10.875 C 108.230469 10.859375 108.222656 10.847656 108.210938 10.832031 C 107.699219 9.980469 107.648438 8.855469 107.878906 7.90625 C 108.074219 7.136719 108.570312 6.417969 109.253906 6 C 110.304688 5.378906 111.75 5.261719 112.726562 6.085938 Z M 110.105469 6.496094 C 109.710938 6.9375 109.507812 7.546875 109.511719 8.136719 C 109.511719 8.160156 109.511719 8.179688 109.511719 8.203125 C 109.511719 8.21875 109.511719 8.234375 109.511719 8.253906 C 109.78125 8.253906 110.050781 8.253906 110.316406 8.257812 C 110.441406 8.257812 110.566406 8.257812 110.691406 8.257812 C 110.8125 8.257812 110.933594 8.257812 111.054688 8.257812 C 111.097656 8.257812 111.144531 8.261719 111.191406 8.261719 C 111.253906 8.261719 111.320312 8.261719 111.382812 8.261719 C 111.402344 8.261719 111.421875 8.261719 111.441406 8.261719 C 111.59375 8.261719 111.746094 8.234375 111.871094 8.140625 C 112.082031 7.886719 112.078125 7.605469 112.054688 7.289062 C 112.011719 6.949219 111.867188 6.6875 111.625 6.449219 C 111.609375 6.433594 111.59375 6.417969 111.582031 6.40625 C 111.164062 6.015625 110.496094 6.121094 110.105469 6.496094 Z M 110.105469 6.496094 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 119.207031 6.039062 C 119.210938 6.308594 119.203125 6.578125 119.1875 6.847656 C 119.183594 6.910156 119.183594 6.972656 119.179688 7.035156 C 119.175781 7.078125 119.175781 7.117188 119.171875 7.160156 C 119.171875 7.175781 119.171875 7.195312 119.171875 7.214844 C 119.164062 7.308594 119.152344 7.390625 119.136719 7.484375 C 118.835938 7.484375 118.535156 7.484375 118.222656 7.484375 C 118.207031 7.40625 118.191406 7.328125 118.171875 7.246094 C 118.15625 7.171875 118.140625 7.097656 118.121094 7.023438 C 118.109375 6.96875 118.101562 6.917969 118.089844 6.867188 C 118.070312 6.792969 118.054688 6.714844 118.039062 6.640625 C 118.035156 6.617188 118.027344 6.59375 118.023438 6.570312 C 118.019531 6.550781 118.015625 6.527344 118.007812 6.503906 C 118.003906 6.484375 118 6.464844 117.996094 6.445312 C 117.984375 6.398438 117.984375 6.398438 117.960938 6.351562 C 117.902344 6.332031 117.847656 6.316406 117.789062 6.300781 C 117.765625 6.296875 117.765625 6.296875 117.738281 6.289062 C 117.339844 6.1875 116.835938 6.167969 116.464844 6.375 C 116.296875 6.480469 116.203125 6.609375 116.128906 6.789062 C 116.082031 7.042969 116.105469 7.261719 116.234375 7.484375 C 116.496094 7.828125 117.082031 7.953125 117.46875 8.070312 C 118.183594 8.289062 118.960938 8.597656 119.359375 9.277344 C 119.578125 9.714844 119.621094 10.257812 119.496094 10.734375 C 119.316406 11.277344 118.957031 11.703125 118.449219 11.964844 C 117.460938 12.445312 116.246094 12.394531 115.222656 12.054688 C 115.007812 11.972656 114.804688 11.867188 114.601562 11.765625 C 114.570312 11.234375 114.574219 10.707031 114.574219 10.175781 C 114.886719 10.175781 115.195312 10.175781 115.511719 10.175781 C 115.539062 10.304688 115.539062 10.304688 115.5625 10.433594 C 115.582031 10.515625 115.597656 10.597656 115.613281 10.679688 C 115.625 10.734375 115.636719 10.792969 115.648438 10.847656 C 115.664062 10.929688 115.679688 11.011719 115.695312 11.09375 C 115.703125 11.121094 115.707031 11.144531 115.710938 11.171875 C 115.71875 11.195312 115.722656 11.21875 115.726562 11.242188 C 115.730469 11.261719 115.734375 11.285156 115.738281 11.304688 C 115.75 11.355469 115.75 11.355469 115.777344 11.40625 C 116.324219 11.617188 117.03125 11.667969 117.578125 11.4375 C 117.800781 11.332031 117.949219 11.207031 118.039062 10.972656 C 118.089844 10.761719 118.082031 10.527344 117.992188 10.328125 C 117.910156 10.191406 117.820312 10.105469 117.6875 10.023438 C 117.664062 10.003906 117.636719 9.988281 117.609375 9.972656 C 117.265625 9.769531 116.875 9.65625 116.496094 9.527344 C 116.066406 9.386719 115.683594 9.222656 115.320312 8.949219 C 115.296875 8.933594 115.273438 8.917969 115.25 8.898438 C 115.226562 8.875 115.226562 8.875 115.199219 8.855469 C 115.199219 8.839844 115.199219 8.824219 115.199219 8.804688 C 115.1875 8.800781 115.171875 8.796875 115.160156 8.789062 C 114.933594 8.65625 114.792969 8.285156 114.726562 8.046875 C 114.605469 7.507812 114.6875 6.964844 114.984375 6.496094 C 115.347656 5.957031 115.902344 5.671875 116.523438 5.542969 C 117.460938 5.367188 118.386719 5.574219 119.207031 6.039062 Z M 119.207031 6.039062 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 67.945312 6.109375 C 67.96875 6.136719 67.96875 6.136719 67.96875 6.1875 C 67.96875 6.210938 67.96875 6.234375 67.964844 6.257812 C 67.964844 6.285156 67.964844 6.3125 67.964844 6.339844 C 67.960938 6.367188 67.960938 6.398438 67.960938 6.425781 C 67.960938 6.457031 67.957031 6.484375 67.957031 6.515625 C 67.941406 6.863281 67.917969 7.207031 67.894531 7.554688 C 67.59375 7.554688 67.292969 7.554688 66.984375 7.554688 C 66.921875 7.3125 66.863281 7.070312 66.808594 6.828125 C 66.804688 6.796875 66.796875 6.769531 66.789062 6.742188 C 66.785156 6.714844 66.777344 6.6875 66.773438 6.660156 C 66.765625 6.632812 66.761719 6.609375 66.753906 6.585938 C 66.742188 6.519531 66.742188 6.519531 66.742188 6.425781 C 66.707031 6.414062 66.667969 6.402344 66.628906 6.390625 C 66.605469 6.386719 66.585938 6.378906 66.5625 6.371094 C 66.355469 6.320312 66.15625 6.296875 65.941406 6.296875 C 65.917969 6.296875 65.894531 6.296875 65.871094 6.296875 C 65.5625 6.300781 65.296875 6.351562 65.0625 6.566406 C 64.894531 6.742188 64.859375 6.90625 64.863281 7.148438 C 64.867188 7.285156 64.890625 7.390625 64.96875 7.507812 C 64.976562 7.519531 64.984375 7.535156 64.996094 7.550781 C 65.261719 7.921875 65.914062 8.0625 66.328125 8.179688 C 67.054688 8.390625 67.703125 8.726562 68.089844 9.40625 C 68.214844 9.648438 68.289062 9.90625 68.304688 10.175781 C 68.304688 10.199219 68.304688 10.21875 68.308594 10.242188 C 68.324219 10.753906 68.15625 11.1875 67.824219 11.574219 C 67.808594 11.589844 67.796875 11.605469 67.78125 11.621094 C 67.28125 12.164062 66.515625 12.347656 65.808594 12.390625 C 65.144531 12.414062 64.535156 12.34375 63.910156 12.117188 C 63.886719 12.109375 63.886719 12.109375 63.859375 12.097656 C 63.675781 12.03125 63.507812 11.929688 63.335938 11.835938 C 63.335938 11.632812 63.335938 11.429688 63.335938 11.226562 C 63.335938 11.132812 63.335938 11.039062 63.335938 10.945312 C 63.332031 10.851562 63.332031 10.761719 63.332031 10.671875 C 63.332031 10.636719 63.332031 10.601562 63.332031 10.566406 C 63.332031 10.515625 63.332031 10.46875 63.332031 10.421875 C 63.332031 10.390625 63.332031 10.363281 63.332031 10.335938 C 63.335938 10.273438 63.335938 10.273438 63.359375 10.25 C 63.421875 10.246094 63.484375 10.246094 63.550781 10.246094 C 63.570312 10.246094 63.585938 10.246094 63.605469 10.246094 C 63.648438 10.246094 63.6875 10.246094 63.726562 10.246094 C 63.789062 10.246094 63.851562 10.246094 63.914062 10.246094 C 63.953125 10.246094 63.992188 10.246094 64.03125 10.246094 C 64.050781 10.246094 64.066406 10.246094 64.085938 10.246094 C 64.21875 10.246094 64.21875 10.246094 64.273438 10.273438 C 64.285156 10.316406 64.285156 10.316406 64.296875 10.375 C 64.300781 10.394531 64.304688 10.414062 64.308594 10.4375 C 64.316406 10.460938 64.320312 10.484375 64.324219 10.507812 C 64.328125 10.53125 64.332031 10.554688 64.339844 10.578125 C 64.347656 10.628906 64.359375 10.679688 64.367188 10.730469 C 64.382812 10.808594 64.398438 10.882812 64.414062 10.960938 C 64.421875 11.007812 64.433594 11.058594 64.441406 11.105469 C 64.445312 11.128906 64.453125 11.152344 64.457031 11.175781 C 64.476562 11.285156 64.492188 11.386719 64.488281 11.5 C 64.53125 11.511719 64.53125 11.511719 64.578125 11.519531 C 64.691406 11.546875 64.804688 11.574219 64.921875 11.605469 C 65.117188 11.648438 65.308594 11.648438 65.507812 11.652344 C 65.539062 11.652344 65.570312 11.652344 65.601562 11.652344 C 65.964844 11.652344 66.320312 11.59375 66.605469 11.359375 C 66.761719 11.199219 66.820312 11.003906 66.828125 10.789062 C 66.820312 10.566406 66.761719 10.382812 66.601562 10.226562 C 66.214844 9.933594 65.765625 9.789062 65.3125 9.640625 C 64.621094 9.414062 63.949219 9.125 63.59375 8.445312 C 63.378906 8 63.375 7.464844 63.53125 6.996094 C 63.761719 6.410156 64.183594 6.027344 64.753906 5.773438 C 65.792969 5.351562 66.988281 5.59375 67.945312 6.109375 Z M 67.945312 6.109375 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 105.941406 5.769531 C 105.960938 5.777344 105.976562 5.785156 105.996094 5.792969 C 106.1875 5.867188 106.351562 5.964844 106.535156 6.0625 C 106.511719 6.539062 106.488281 7.015625 106.464844 7.507812 C 106.164062 7.507812 105.863281 7.507812 105.550781 7.507812 C 105.445312 7.101562 105.445312 7.101562 105.410156 6.941406 C 105.40625 6.925781 105.402344 6.910156 105.398438 6.890625 C 105.386719 6.839844 105.375 6.789062 105.367188 6.738281 C 105.359375 6.703125 105.351562 6.667969 105.34375 6.632812 C 105.324219 6.546875 105.304688 6.460938 105.289062 6.375 C 105.234375 6.359375 105.183594 6.34375 105.128906 6.328125 C 105.097656 6.320312 105.070312 6.3125 105.039062 6.304688 C 104.859375 6.253906 104.6875 6.25 104.503906 6.25 C 104.464844 6.25 104.464844 6.25 104.421875 6.25 C 104.136719 6.246094 103.90625 6.3125 103.664062 6.464844 C 103.507812 6.621094 103.417969 6.816406 103.414062 7.042969 C 103.425781 7.25 103.492188 7.433594 103.632812 7.585938 C 103.976562 7.886719 104.484375 8.003906 104.910156 8.132812 C 105.628906 8.351562 106.285156 8.667969 106.667969 9.355469 C 106.878906 9.800781 106.9375 10.371094 106.785156 10.84375 C 106.554688 11.417969 106.144531 11.8125 105.585938 12.070312 C 104.601562 12.488281 103.335938 12.402344 102.359375 12.007812 C 102.203125 11.9375 102.046875 11.859375 101.902344 11.765625 C 101.894531 11.699219 101.894531 11.699219 101.894531 11.617188 C 101.894531 11.585938 101.894531 11.554688 101.890625 11.523438 C 101.890625 11.488281 101.890625 11.453125 101.890625 11.417969 C 101.890625 11.382812 101.890625 11.347656 101.890625 11.3125 C 101.890625 11.222656 101.886719 11.128906 101.886719 11.039062 C 101.886719 10.925781 101.886719 10.816406 101.882812 10.707031 C 101.882812 10.539062 101.882812 10.371094 101.878906 10.203125 C 102.1875 10.203125 102.496094 10.203125 102.816406 10.203125 C 102.871094 10.363281 102.871094 10.363281 102.886719 10.449219 C 102.890625 10.46875 102.894531 10.488281 102.898438 10.507812 C 102.902344 10.527344 102.90625 10.546875 102.910156 10.566406 C 102.914062 10.585938 102.917969 10.609375 102.921875 10.628906 C 102.933594 10.671875 102.941406 10.71875 102.949219 10.761719 C 102.964844 10.828125 102.976562 10.894531 102.988281 10.960938 C 103 11.003906 103.007812 11.046875 103.015625 11.089844 C 103.019531 11.109375 103.023438 11.132812 103.027344 11.152344 C 103.046875 11.246094 103.0625 11.332031 103.054688 11.429688 C 103.699219 11.59375 104.421875 11.726562 105.03125 11.386719 C 105.21875 11.265625 105.316406 11.125 105.375 10.914062 C 105.402344 10.691406 105.378906 10.496094 105.273438 10.292969 C 104.921875 9.867188 104.363281 9.730469 103.859375 9.5625 C 103.1875 9.339844 102.511719 9.058594 102.167969 8.398438 C 101.949219 7.929688 101.9375 7.414062 102.097656 6.929688 C 102.101562 6.90625 102.109375 6.886719 102.117188 6.863281 C 102.269531 6.417969 102.628906 6.066406 103.03125 5.847656 C 103.054688 5.832031 103.078125 5.820312 103.101562 5.808594 C 103.382812 5.65625 103.699219 5.574219 104.015625 5.535156 C 104.035156 5.53125 104.054688 5.527344 104.074219 5.527344 C 104.714844 5.449219 105.34375 5.535156 105.941406 5.769531 Z M 105.941406 5.769531 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 59.953125 3.921875 C 60.316406 3.921875 60.679688 3.921875 61.054688 3.921875 C 61.058594 4.292969 61.054688 4.667969 61.046875 5.039062 C 61.042969 5.066406 61.042969 5.066406 61.042969 5.09375 C 61.042969 5.144531 61.042969 5.195312 61.039062 5.246094 C 61.039062 5.277344 61.039062 5.304688 61.035156 5.335938 C 61.03125 5.472656 61.019531 5.613281 61.007812 5.75 C 61.53125 5.75 62.054688 5.75 62.59375 5.75 C 62.59375 6.035156 62.59375 6.320312 62.59375 6.617188 C 62.0625 6.617188 61.53125 6.617188 60.984375 6.617188 C 60.984375 7.128906 60.988281 7.644531 60.988281 8.160156 C 60.992188 8.398438 60.992188 8.636719 60.992188 8.875 C 60.992188 9.082031 60.992188 9.292969 60.996094 9.5 C 60.996094 9.609375 60.996094 9.71875 60.996094 9.832031 C 60.996094 9.933594 60.996094 10.039062 60.996094 10.140625 C 60.996094 10.179688 60.996094 10.21875 60.996094 10.253906 C 60.992188 10.765625 60.992188 10.765625 61.199219 11.210938 C 61.34375 11.347656 61.507812 11.40625 61.703125 11.40625 C 61.941406 11.371094 62.144531 11.289062 62.355469 11.175781 C 62.457031 11.125 62.457031 11.125 62.519531 11.117188 C 62.558594 11.140625 62.558594 11.140625 62.597656 11.183594 C 62.613281 11.195312 62.625 11.210938 62.640625 11.226562 C 62.652344 11.238281 62.667969 11.253906 62.683594 11.269531 C 62.695312 11.285156 62.710938 11.300781 62.726562 11.316406 C 62.761719 11.351562 62.796875 11.390625 62.832031 11.429688 C 62.785156 11.5625 62.707031 11.65625 62.617188 11.765625 C 62.605469 11.78125 62.59375 11.792969 62.578125 11.808594 C 62.375 12.03125 62.085938 12.183594 61.800781 12.269531 C 61.777344 12.277344 61.75 12.285156 61.726562 12.292969 C 61.511719 12.347656 61.296875 12.351562 61.078125 12.351562 C 61.046875 12.351562 61.019531 12.351562 60.988281 12.351562 C 60.523438 12.351562 60.085938 12.210938 59.730469 11.898438 C 59.542969 11.699219 59.425781 11.40625 59.375 11.140625 C 59.371094 11.117188 59.367188 11.097656 59.363281 11.074219 C 59.351562 10.988281 59.347656 10.902344 59.347656 10.8125 C 59.347656 10.792969 59.347656 10.777344 59.347656 10.757812 C 59.347656 10.695312 59.347656 10.636719 59.347656 10.578125 C 59.347656 10.535156 59.347656 10.492188 59.347656 10.449219 C 59.347656 10.332031 59.347656 10.214844 59.347656 10.097656 C 59.351562 9.972656 59.351562 9.851562 59.351562 9.730469 C 59.351562 9.496094 59.351562 9.265625 59.351562 9.035156 C 59.351562 8.769531 59.351562 8.507812 59.351562 8.242188 C 59.351562 7.703125 59.351562 7.160156 59.351562 6.617188 C 59.035156 6.617188 58.71875 6.617188 58.390625 6.617188 C 58.390625 6.371094 58.390625 6.125 58.390625 5.871094 C 58.914062 5.800781 58.914062 5.800781 59.449219 5.726562 C 59.480469 5.601562 59.515625 5.476562 59.550781 5.351562 C 59.574219 5.269531 59.59375 5.191406 59.617188 5.113281 C 59.652344 4.988281 59.6875 4.863281 59.722656 4.738281 C 59.75 4.640625 59.777344 4.539062 59.804688 4.4375 C 59.816406 4.398438 59.824219 4.359375 59.835938 4.324219 C 59.851562 4.269531 59.867188 4.214844 59.882812 4.160156 C 59.886719 4.144531 59.890625 4.128906 59.894531 4.113281 C 59.914062 4.046875 59.929688 3.984375 59.953125 3.921875 Z M 59.953125 3.921875 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 93.351562 5.554688 C 93.40625 5.59375 93.429688 5.617188 93.445312 5.679688 C 93.449219 5.75 93.445312 5.8125 93.441406 5.878906 C 93.441406 5.90625 93.441406 5.929688 93.441406 5.957031 C 93.4375 6.015625 93.4375 6.070312 93.433594 6.128906 C 93.429688 6.273438 93.425781 6.417969 93.421875 6.5625 C 93.417969 6.617188 93.417969 6.671875 93.417969 6.726562 C 93.402344 7.175781 93.40625 7.625 93.40625 8.074219 C 93.40625 8.195312 93.40625 8.3125 93.40625 8.429688 C 93.40625 8.644531 93.40625 8.859375 93.40625 9.074219 C 93.40625 9.320312 93.40625 9.570312 93.40625 9.816406 C 93.40625 10.320312 93.40625 10.828125 93.40625 11.332031 C 93.425781 11.335938 93.449219 11.339844 93.46875 11.34375 C 93.542969 11.355469 93.613281 11.371094 93.6875 11.382812 C 93.734375 11.390625 93.785156 11.398438 93.832031 11.40625 C 93.859375 11.414062 93.890625 11.417969 93.921875 11.425781 C 93.949219 11.429688 93.976562 11.433594 94.003906 11.4375 C 94.070312 11.449219 94.136719 11.464844 94.199219 11.476562 C 94.199219 11.675781 94.199219 11.875 94.199219 12.078125 C 93.105469 12.078125 92.015625 12.078125 90.886719 12.078125 C 90.886719 11.878906 90.886719 11.679688 90.886719 11.476562 C 90.988281 11.457031 91.085938 11.433594 91.1875 11.414062 C 91.222656 11.40625 91.253906 11.402344 91.289062 11.394531 C 91.339844 11.382812 91.386719 11.375 91.4375 11.363281 C 91.480469 11.355469 91.480469 11.355469 91.527344 11.34375 C 91.601562 11.332031 91.675781 11.332031 91.753906 11.332031 C 91.753906 10.894531 91.753906 10.457031 91.753906 10.023438 C 91.753906 9.820312 91.753906 9.617188 91.753906 9.414062 C 91.753906 9.234375 91.753906 9.058594 91.753906 8.882812 C 91.753906 8.789062 91.753906 8.695312 91.753906 8.601562 C 91.753906 8.066406 91.746094 7.535156 91.726562 7 C 91.683594 6.996094 91.683594 6.996094 91.636719 6.988281 C 91.539062 6.976562 91.4375 6.964844 91.339844 6.953125 C 91.296875 6.945312 91.25 6.941406 91.207031 6.933594 C 91.144531 6.925781 91.082031 6.917969 91.019531 6.910156 C 90.988281 6.90625 90.988281 6.90625 90.957031 6.902344 C 90.820312 6.882812 90.820312 6.882812 90.792969 6.855469 C 90.789062 6.816406 90.789062 6.777344 90.789062 6.738281 C 90.789062 6.714844 90.789062 6.691406 90.789062 6.667969 C 90.789062 6.640625 90.789062 6.617188 90.789062 6.589844 C 90.789062 6.566406 90.789062 6.539062 90.789062 6.515625 C 90.792969 6.453125 90.792969 6.390625 90.792969 6.328125 C 90.96875 6.253906 91.148438 6.1875 91.328125 6.125 C 91.355469 6.117188 91.382812 6.105469 91.414062 6.097656 C 91.503906 6.066406 91.59375 6.03125 91.683594 6 C 91.808594 5.957031 91.929688 5.914062 92.054688 5.871094 C 92.070312 5.867188 92.085938 5.859375 92.101562 5.855469 C 92.285156 5.792969 92.46875 5.726562 92.652344 5.660156 C 92.667969 5.652344 92.6875 5.644531 92.703125 5.640625 C 92.78125 5.609375 92.859375 5.582031 92.9375 5.554688 C 92.976562 5.539062 92.976562 5.539062 93.019531 5.523438 C 93.050781 5.511719 93.050781 5.511719 93.082031 5.5 C 93.1875 5.476562 93.261719 5.503906 93.351562 5.554688 Z M 93.351562 5.554688 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 42.214844 5.652344 C 42.214844 7.542969 42.214844 9.433594 42.214844 11.378906 C 42.535156 11.441406 42.535156 11.441406 42.863281 11.5 C 42.917969 11.515625 42.976562 11.53125 43.03125 11.550781 C 43.03125 11.738281 43.03125 11.929688 43.03125 12.125 C 41.929688 12.125 40.832031 12.125 39.695312 12.125 C 39.695312 11.9375 39.695312 11.746094 39.695312 11.550781 C 39.875 11.5 40.054688 11.460938 40.234375 11.425781 C 40.265625 11.417969 40.265625 11.417969 40.296875 11.410156 C 40.316406 11.40625 40.335938 11.402344 40.355469 11.398438 C 40.375 11.394531 40.394531 11.390625 40.410156 11.386719 C 40.46875 11.378906 40.523438 11.378906 40.585938 11.378906 C 40.582031 10.886719 40.578125 10.390625 40.574219 9.898438 C 40.574219 9.667969 40.574219 9.4375 40.570312 9.207031 C 40.570312 9.007812 40.570312 8.808594 40.570312 8.605469 C 40.566406 8.5 40.566406 8.394531 40.566406 8.289062 C 40.566406 8.191406 40.566406 8.089844 40.566406 7.988281 C 40.566406 7.953125 40.566406 7.917969 40.566406 7.878906 C 40.5625 7.683594 40.558594 7.488281 40.550781 7.292969 C 40.546875 7.273438 40.546875 7.253906 40.546875 7.234375 C 40.542969 7.140625 40.542969 7.140625 40.511719 7.050781 C 40.445312 7.035156 40.378906 7.027344 40.308594 7.019531 C 40.289062 7.015625 40.269531 7.011719 40.25 7.011719 C 40.183594 7.003906 40.121094 6.996094 40.054688 6.988281 C 40.011719 6.980469 39.96875 6.976562 39.921875 6.96875 C 39.816406 6.957031 39.707031 6.941406 39.601562 6.929688 C 39.601562 6.746094 39.601562 6.5625 39.601562 6.375 C 39.964844 6.242188 40.328125 6.109375 40.695312 5.980469 C 40.777344 5.953125 40.859375 5.921875 40.945312 5.894531 C 41 5.875 41.054688 5.855469 41.109375 5.835938 C 41.246094 5.789062 41.386719 5.738281 41.523438 5.6875 C 41.550781 5.675781 41.578125 5.667969 41.605469 5.65625 C 41.660156 5.636719 41.710938 5.617188 41.761719 5.597656 C 41.785156 5.589844 41.808594 5.578125 41.835938 5.570312 C 41.863281 5.558594 41.863281 5.558594 41.894531 5.546875 C 42.027344 5.515625 42.09375 5.585938 42.214844 5.652344 Z M 42.214844 5.652344 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 8.640625 9.261719 C 8.972656 9.519531 9.191406 9.859375 9.277344 10.273438 C 9.328125 10.675781 9.265625 11.089844 9.019531 11.421875 C 8.734375 11.769531 8.371094 12.007812 7.917969 12.058594 C 7.476562 12.09375 7.078125 11.957031 6.742188 11.667969 C 6.71875 11.648438 6.71875 11.648438 6.695312 11.628906 C 6.421875 11.378906 6.261719 10.992188 6.234375 10.628906 C 6.226562 10.179688 6.355469 9.789062 6.664062 9.457031 C 7.191406 8.921875 8.019531 8.84375 8.640625 9.261719 Z M 8.640625 9.261719 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 2.855469 4.089844 C 2.941406 4.15625 3.019531 4.230469 3.097656 4.308594 C 3.113281 4.324219 3.128906 4.339844 3.148438 4.359375 C 3.414062 4.640625 3.542969 5.027344 3.539062 5.410156 C 3.519531 5.851562 3.332031 6.21875 3.015625 6.527344 C 2.707031 6.792969 2.304688 6.921875 1.898438 6.898438 C 1.578125 6.871094 1.308594 6.769531 1.054688 6.570312 C 1.03125 6.546875 1.03125 6.546875 1.003906 6.527344 C 0.699219 6.277344 0.527344 5.898438 0.484375 5.511719 C 0.453125 5.121094 0.558594 4.730469 0.804688 4.425781 C 1.003906 4.191406 1.226562 4.03125 1.511719 3.921875 C 1.53125 3.914062 1.550781 3.90625 1.570312 3.898438 C 1.988281 3.757812 2.496094 3.84375 2.855469 4.089844 Z M 2.855469 4.089844 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 2.960938 11.683594 C 3.269531 11.949219 3.492188 12.316406 3.53125 12.726562 C 3.558594 13.152344 3.449219 13.550781 3.171875 13.878906 C 2.875 14.203125 2.519531 14.375 2.082031 14.417969 C 1.671875 14.433594 1.28125 14.28125 0.972656 14.011719 C 0.660156 13.714844 0.488281 13.324219 0.476562 12.890625 C 0.480469 12.53125 0.59375 12.214844 0.816406 11.933594 C 0.828125 11.917969 0.839844 11.902344 0.851562 11.882812 C 1.078125 11.597656 1.433594 11.421875 1.785156 11.363281 C 2.207031 11.316406 2.628906 11.417969 2.960938 11.683594 Z M 2.960938 11.683594 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 14.449219 4.167969 C 14.507812 4.222656 14.5625 4.273438 14.617188 4.332031 C 14.628906 4.34375 14.640625 4.355469 14.65625 4.367188 C 14.914062 4.632812 15.015625 5.023438 15.03125 5.378906 C 15.019531 5.734375 14.902344 6.046875 14.6875 6.328125 C 14.675781 6.34375 14.664062 6.359375 14.652344 6.378906 C 14.410156 6.679688 14.042969 6.851562 13.664062 6.898438 C 13.242188 6.925781 12.84375 6.816406 12.523438 6.535156 C 12.484375 6.5 12.445312 6.460938 12.40625 6.425781 C 12.394531 6.410156 12.378906 6.394531 12.363281 6.378906 C 12.085938 6.089844 11.988281 5.707031 11.992188 5.316406 C 12.003906 4.914062 12.167969 4.53125 12.457031 4.25 C 13.023438 3.75 13.847656 3.714844 14.449219 4.167969 Z M 14.449219 4.167969 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 42.046875 2.648438 C 42.253906 2.816406 42.375 3.03125 42.40625 3.296875 C 42.433594 3.558594 42.351562 3.808594 42.191406 4.019531 C 42.007812 4.214844 41.785156 4.351562 41.507812 4.363281 C 41.46875 4.363281 41.429688 4.363281 41.390625 4.363281 C 41.371094 4.363281 41.351562 4.363281 41.332031 4.363281 C 41.058594 4.355469 40.832031 4.273438 40.625 4.089844 C 40.476562 3.933594 40.359375 3.734375 40.34375 3.511719 C 40.34375 3.496094 40.339844 3.480469 40.339844 3.460938 C 40.328125 3.230469 40.390625 2.992188 40.542969 2.8125 C 40.554688 2.796875 40.570312 2.78125 40.585938 2.765625 C 40.597656 2.75 40.613281 2.734375 40.632812 2.714844 C 41.019531 2.339844 41.621094 2.332031 42.046875 2.648438 Z M 42.046875 2.648438 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(10.196079%,11.372549%,14.117648%);fill-opacity:1;",
+ "d": "M 93.210938 2.566406 C 93.453125 2.757812 93.570312 2.96875 93.609375 3.273438 C 93.621094 3.53125 93.550781 3.773438 93.378906 3.972656 C 93.367188 3.988281 93.351562 4.003906 93.335938 4.019531 C 93.316406 4.039062 93.316406 4.039062 93.296875 4.058594 C 93.066406 4.28125 92.78125 4.316406 92.476562 4.3125 C 92.355469 4.308594 92.25 4.285156 92.136719 4.234375 C 92.117188 4.226562 92.101562 4.21875 92.082031 4.210938 C 91.871094 4.105469 91.703125 3.9375 91.605469 3.722656 C 91.515625 3.449219 91.515625 3.171875 91.632812 2.90625 C 91.773438 2.652344 92 2.484375 92.277344 2.402344 C 92.605469 2.324219 92.933594 2.375 93.210938 2.566406 Z M 93.210938 2.566406 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 8.320312 5.960938 C 8.539062 6.117188 8.664062 6.320312 8.726562 6.582031 C 8.769531 6.839844 8.710938 7.089844 8.574219 7.3125 C 8.410156 7.535156 8.207031 7.65625 7.945312 7.722656 C 7.621094 7.753906 7.355469 7.6875 7.105469 7.484375 C 6.921875 7.3125 6.8125 7.078125 6.792969 6.832031 C 6.789062 6.535156 6.871094 6.28125 7.078125 6.0625 C 7.4375 5.738281 7.914062 5.710938 8.320312 5.960938 Z M 8.320312 5.960938 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.431373%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 14.09375 0.820312 C 14.289062 0.96875 14.421875 1.179688 14.472656 1.417969 C 14.5 1.714844 14.464844 1.980469 14.273438 2.214844 C 14.082031 2.421875 13.890625 2.558594 13.605469 2.582031 C 13.320312 2.585938 13.078125 2.535156 12.863281 2.332031 C 12.660156 2.128906 12.550781 1.910156 12.542969 1.621094 C 12.546875 1.332031 12.644531 1.117188 12.839844 0.910156 C 13.199219 0.574219 13.6875 0.5625 14.09375 0.820312 Z M 14.09375 0.820312 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 2.574219 0.808594 C 2.769531 0.972656 2.925781 1.164062 2.976562 1.417969 C 2.996094 1.71875 2.972656 1.976562 2.777344 2.214844 C 2.585938 2.421875 2.394531 2.558594 2.109375 2.582031 C 1.824219 2.585938 1.582031 2.53125 1.367188 2.332031 C 1.226562 2.195312 1.136719 2.066406 1.078125 1.875 C 1.074219 1.863281 1.070312 1.847656 1.066406 1.832031 C 1.015625 1.570312 1.054688 1.3125 1.195312 1.089844 C 1.515625 0.644531 2.101562 0.484375 2.574219 0.808594 Z M 2.574219 0.808594 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 2.550781 8.316406 C 2.582031 8.34375 2.609375 8.371094 2.640625 8.398438 C 2.65625 8.414062 2.671875 8.429688 2.691406 8.445312 C 2.878906 8.640625 2.960938 8.847656 2.964844 9.121094 C 2.960938 9.398438 2.882812 9.613281 2.6875 9.816406 C 2.5 9.996094 2.257812 10.109375 1.992188 10.105469 C 1.695312 10.085938 1.449219 9.972656 1.246094 9.753906 C 1.074219 9.535156 1.003906 9.277344 1.03125 9 C 1.089844 8.710938 1.214844 8.484375 1.453125 8.3125 C 1.789062 8.105469 2.222656 8.085938 2.550781 8.316406 Z M 2.550781 8.316406 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 14.058594 8.34375 C 14.269531 8.496094 14.425781 8.714844 14.472656 8.972656 C 14.496094 9.300781 14.441406 9.542969 14.238281 9.804688 C 14.148438 9.90625 14.042969 9.972656 13.921875 10.03125 C 13.894531 10.046875 13.894531 10.046875 13.867188 10.058594 C 13.660156 10.144531 13.386719 10.136719 13.175781 10.066406 C 12.929688 9.960938 12.714844 9.769531 12.613281 9.519531 C 12.601562 9.484375 12.585938 9.445312 12.574219 9.40625 C 12.570312 9.390625 12.566406 9.378906 12.5625 9.363281 C 12.511719 9.109375 12.550781 8.855469 12.679688 8.632812 C 12.824219 8.421875 13.003906 8.277344 13.246094 8.203125 C 13.261719 8.199219 13.277344 8.195312 13.292969 8.191406 C 13.570312 8.136719 13.820312 8.195312 14.058594 8.34375 Z M 14.058594 8.34375 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 8.375 13.523438 C 8.605469 13.730469 8.71875 13.984375 8.742188 14.289062 C 8.734375 14.554688 8.621094 14.789062 8.445312 14.984375 C 8.25 15.164062 7.996094 15.25 7.734375 15.253906 C 7.46875 15.242188 7.25 15.136719 7.0625 14.953125 C 6.863281 14.730469 6.789062 14.488281 6.792969 14.195312 C 6.832031 13.894531 6.964844 13.664062 7.199219 13.472656 C 7.582031 13.230469 8.015625 13.25 8.375 13.523438 Z M 8.375 13.523438 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 14.027344 12.066406 C 14.25 12.234375 14.421875 12.449219 14.472656 12.726562 C 14.492188 13.019531 14.464844 13.269531 14.273438 13.5 C 14.089844 13.699219 13.886719 13.84375 13.609375 13.863281 C 13.3125 13.867188 13.058594 13.800781 12.832031 13.589844 C 12.730469 13.480469 12.65625 13.371094 12.601562 13.234375 C 12.589844 13.207031 12.582031 13.183594 12.570312 13.15625 C 12.519531 12.886719 12.539062 12.625 12.679688 12.386719 C 12.984375 11.945312 13.558594 11.765625 14.027344 12.066406 Z M 14.027344 12.066406 "
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "style": " stroke:none;fill-rule:nonzero;fill:rgb(98.823529%,73.725492%,19.607843%);fill-opacity:1;",
+ "d": "M 8.269531 2.203125 C 8.492188 2.371094 8.652344 2.574219 8.703125 2.855469 C 8.738281 3.113281 8.695312 3.371094 8.535156 3.582031 C 8.355469 3.796875 8.136719 3.949219 7.851562 3.976562 C 7.539062 3.988281 7.289062 3.894531 7.054688 3.679688 C 6.851562 3.449219 6.796875 3.222656 6.808594 2.914062 C 6.824219 2.671875 6.929688 2.480469 7.105469 2.308594 C 7.445312 2.039062 7.886719 1.964844 8.269531 2.203125 Z M 8.269531 2.203125 "
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "WeaveIconBig"
+}
diff --git a/app/components/base/icons/src/public/tracing/WeaveIconBig.tsx b/app/components/base/icons/src/public/tracing/WeaveIconBig.tsx
new file mode 100644
index 0000000..1d2bb9f
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/WeaveIconBig.tsx
@@ -0,0 +1,16 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './WeaveIconBig.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
+ props,
+ ref,
+) => <IconBase {...props} ref={ref} data={data as IconData} />)
+
+Icon.displayName = 'WeaveIconBig'
+
+export default Icon
diff --git a/app/components/base/icons/src/public/tracing/index.ts b/app/components/base/icons/src/public/tracing/index.ts
new file mode 100644
index 0000000..36b59e4
--- /dev/null
+++ b/app/components/base/icons/src/public/tracing/index.ts
@@ -0,0 +1,9 @@
+export { default as LangfuseIconBig } from './LangfuseIconBig'
+export { default as LangfuseIcon } from './LangfuseIcon'
+export { default as LangsmithIconBig } from './LangsmithIconBig'
+export { default as LangsmithIcon } from './LangsmithIcon'
+export { default as OpikIconBig } from './OpikIconBig'
+export { default as OpikIcon } from './OpikIcon'
+export { default as TracingIcon } from './TracingIcon'
+export { default as WeaveIconBig } from './WeaveIconBig'
+export { default as WeaveIcon } from './WeaveIcon'
diff --git a/app/components/base/icons/src/vender/features/Citations.json b/app/components/base/icons/src/vender/features/Citations.json
new file mode 100644
index 0000000..1b0b625
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/Citations.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12ZM7 11.9702V14.958H11.0356V11.2339H8.8125C8.78418 10.8185 8.85498 10.4173 9.0249 10.0303C9.35531 9.29395 10.002 8.77474 10.9648 8.47266V7C9.67155 7.25488 8.68506 7.79297 8.00537 8.61426C7.33512 9.43555 7 10.5542 7 11.9702ZM15.0391 10.0586C15.3695 9.29395 16.0114 8.7653 16.9648 8.47266V7C15.7093 7.25488 14.7323 7.78825 14.0337 8.6001C13.3446 9.41195 13 10.5353 13 11.9702V14.958H17.0356V11.2339H14.8125C14.7747 10.8563 14.8503 10.4645 15.0391 10.0586Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Citations"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/Citations.tsx b/app/components/base/icons/src/vender/features/Citations.tsx
new file mode 100644
index 0000000..439aab6
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/Citations.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Citations.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Citations'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/ContentModeration.json b/app/components/base/icons/src/vender/features/ContentModeration.json
new file mode 100644
index 0000000..4f5c47a
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/ContentModeration.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M7.16146 3H16.8385C17.3657 2.99998 17.8205 2.99997 18.195 3.03057C18.5904 3.06287 18.9836 3.13419 19.362 3.32698C19.9265 3.6146 20.3854 4.07354 20.673 4.63803C20.8658 5.01641 20.9371 5.40963 20.9694 5.80497C21 6.17954 21 6.6343 21 7.16144V16.8386C21 17.3657 21 17.8205 20.9694 18.195C20.9371 18.5904 20.8658 18.9836 20.673 19.362C20.3854 19.9265 19.9265 20.3854 19.362 20.673C18.9836 20.8658 18.5904 20.9371 18.195 20.9694C17.8205 21 17.3657 21 16.8386 21H7.16144C6.6343 21 6.17954 21 5.80497 20.9694C5.40963 20.9371 5.01641 20.8658 4.63803 20.673C4.07354 20.3854 3.6146 19.9265 3.32698 19.362C3.13419 18.9836 3.06287 18.5904 3.03057 18.195C2.99997 17.8205 2.99998 17.3657 3 16.8386V7.16145C2.99998 6.63432 2.99997 6.17954 3.03057 5.80497C3.06287 5.40963 3.13419 5.01641 3.32698 4.63803C3.6146 4.07354 4.07354 3.6146 4.63803 3.32698C5.01641 3.13419 5.40963 3.06287 5.80497 3.03057C6.17954 2.99997 6.63432 2.99998 7.16146 3ZM17 9C17 8.44772 16.5523 8 16 8C15.4477 8 15 8.44772 15 9V15C15 15.5523 15.4477 16 16 16C16.5523 16 17 15.5523 17 15V9ZM9 12C9 12.5523 8.55229 13 8 13C7.44772 13 7 12.5523 7 12C7 11.4477 7.44772 11 8 11C8.55229 11 9 11.4477 9 12ZM12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ContentModeration"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/ContentModeration.tsx b/app/components/base/icons/src/vender/features/ContentModeration.tsx
new file mode 100644
index 0000000..baf9629
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/ContentModeration.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ContentModeration.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ContentModeration'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/Document.json b/app/components/base/icons/src/vender/features/Document.json
new file mode 100644
index 0000000..fdd08d5
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/Document.json
@@ -0,0 +1,23 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "xmlns": "http://www.w3.org/2000/svg",
+ "viewBox": "0 0 24 24",
+ "fill": "currentColor"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20 22H4C3.44772 22 3 21.5523 3 21V3C3 2.44772 3.44772 2 4 2H20C20.5523 2 21 2.44772 21 3V21C21 21.5523 20.5523 22 20 22ZM7 6V10H11V6H7ZM7 12V14H17V12H7ZM7 16V18H17V16H7ZM13 7V9H17V7H13Z"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Document"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/Document.tsx b/app/components/base/icons/src/vender/features/Document.tsx
new file mode 100644
index 0000000..05c0180
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/Document.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Document.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Document'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/FolderUpload.json b/app/components/base/icons/src/vender/features/FolderUpload.json
new file mode 100644
index 0000000..2180127
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/FolderUpload.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2 6C2 4.34315 3.34315 3 5 3H8.92963C9.93269 3 10.8694 3.5013 11.4258 4.3359L12.5352 6H19C20.6569 6 22 7.34315 22 9V17C22 18.6569 20.6569 20 19 20H13V15.4142L13.7929 16.2071C14.1834 16.5976 14.8166 16.5976 15.2071 16.2071C15.5976 15.8166 15.5976 15.1834 15.2071 14.7929L12.7071 12.2929C12.3166 11.9024 11.6834 11.9024 11.2929 12.2929L8.79289 14.7929C8.40237 15.1834 8.40237 15.8166 8.79289 16.2071C9.18342 16.5976 9.81658 16.5976 10.2071 16.2071L11 15.4142V20H5C3.34315 20 2 18.6569 2 17V6Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "FolderUpload"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/FolderUpload.tsx b/app/components/base/icons/src/vender/features/FolderUpload.tsx
new file mode 100644
index 0000000..27b38ae
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/FolderUpload.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FolderUpload.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FolderUpload'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/LoveMessage.json b/app/components/base/icons/src/vender/features/LoveMessage.json
new file mode 100644
index 0000000..7dbc062
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/LoveMessage.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M22 11.3333C22 6.73833 17.5142 3 12 3C6.48583 3 2 6.73833 2 11.3333C2 15.9283 6.48583 19.6667 11.9825 19.6667C12.8404 19.6814 13.6965 19.5839 14.5292 19.3767L19.1858 21.2725C19.2857 21.3127 19.3924 21.3333 19.5 21.3333C19.6175 21.3334 19.7337 21.3086 19.8409 21.2606C19.9481 21.2126 20.044 21.1425 20.1222 21.0548C20.2004 20.9672 20.2592 20.8639 20.2948 20.7519C20.3303 20.64 20.3417 20.5217 20.3283 20.405L19.8742 16.4733C21.1944 15.0821 21.9518 13.2507 22 11.3333ZM15.3917 12.0533L12.0317 15.47C12.0231 15.4784 12.0116 15.4831 11.9996 15.4831C11.9876 15.4831 11.9761 15.4784 11.9675 15.47L8.60917 12.0533C8.18149 11.6398 7.91983 11.0841 7.87347 10.491C7.82712 9.89789 7.99927 9.30831 8.3575 8.83333C8.57837 8.56064 8.85996 8.3434 9.17978 8.19896C9.49959 8.05451 9.84875 7.98687 10.1994 8.00145C10.55 8.01603 10.8923 8.11241 11.199 8.2829C11.5058 8.45339 11.7684 8.69325 11.9658 8.98333C11.9695 8.98883 11.9744 8.99335 11.9803 8.99647C11.9861 8.99959 11.9926 9.00122 11.9992 9.00122C12.0058 9.00122 12.0123 8.99959 12.0181 8.99647C12.0239 8.99335 12.0289 8.98883 12.0325 8.98333C12.23 8.69325 12.4926 8.45339 12.7993 8.2829C13.106 8.11241 13.4484 8.01603 13.799 8.00145C14.1496 7.98687 14.4987 8.05451 14.8186 8.19896C15.1384 8.3434 15.42 8.56064 15.6408 8.83333C15.9997 9.30788 16.1725 9.89736 16.1266 10.4906C16.0807 11.0838 15.8193 11.6397 15.3917 12.0533Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "LoveMessage"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/LoveMessage.tsx b/app/components/base/icons/src/vender/features/LoveMessage.tsx
new file mode 100644
index 0000000..c4cdcfd
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/LoveMessage.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LoveMessage.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LoveMessage'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/MessageFast.json b/app/components/base/icons/src/vender/features/MessageFast.json
new file mode 100644
index 0000000..4580398
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/MessageFast.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M16.2414 2H7.7588C6.95383 1.99999 6.28946 1.99998 5.74827 2.04419C5.18617 2.09012 4.66947 2.18868 4.18413 2.43598C3.43149 2.81947 2.81956 3.43139 2.43607 4.18404C2.18878 4.66937 2.09022 5.18608 2.04429 5.74818C2.00007 6.28937 2.00008 6.95373 2.0001 7.7587L2.00005 14.1376C1.99962 14.933 1.9993 15.5236 2.13639 16.0353C2.50626 17.4156 3.58445 18.4938 4.96482 18.8637C5.27229 18.9461 5.60829 18.9789 6.0001 18.9918L6.00009 20.371C6.00005 20.6062 6 20.846 6.01785 21.0425C6.03492 21.2305 6.08012 21.5852 6.32778 21.8955C6.61276 22.2525 7.0449 22.4602 7.50172 22.4597C7.8987 22.4593 8.20394 22.273 8.36137 22.1689C8.52597 22.06 8.7132 21.9102 8.89688 21.7632L11.31 19.8327C11.8286 19.4178 11.9826 19.3007 12.1425 19.219C12.303 19.137 12.4738 19.0771 12.6504 19.0408C12.8263 19.0047 13.0197 19 13.6838 19H16.2414C17.0464 19 17.7107 19 18.2519 18.9558C18.814 18.9099 19.3307 18.8113 19.8161 18.564C20.5687 18.1805 21.1806 17.5686 21.5641 16.816C21.8114 16.3306 21.91 15.8139 21.9559 15.2518C22.0001 14.7106 22.0001 14.0463 22.0001 13.2413V7.75868C22.0001 6.95372 22.0001 6.28936 21.9559 5.74818C21.91 5.18608 21.8114 4.66937 21.5641 4.18404C21.1806 3.43139 20.5687 2.81947 19.8161 2.43598C19.3307 2.18868 18.814 2.09012 18.2519 2.04419C17.7107 1.99998 17.0464 1.99999 16.2414 2ZM12.681 5.5349C12.8938 5.61898 13.0218 5.83714 12.9916 6.06386L12.5688 9.23501L14.48 9.23501C14.5899 9.23498 14.7038 9.23496 14.7979 9.24356C14.8905 9.25203 15.0589 9.27446 15.2095 9.39066C15.3851 9.52617 15.4913 9.73269 15.4996 9.95432C15.5066 10.1444 15.427 10.2945 15.38 10.3747C15.3324 10.4563 15.2661 10.549 15.2022 10.6384L11.9072 15.2514C11.7743 15.4375 11.5317 15.5092 11.319 15.4251C11.1063 15.341 10.9782 15.1229 11.0084 14.8961L11.4312 11.725L9.52004 11.725C9.41011 11.725 9.29618 11.725 9.20206 11.7164C9.10948 11.708 8.94106 11.6855 8.79051 11.5693C8.61493 11.4338 8.50866 11.2273 8.50044 11.0057C8.49339 10.8156 8.57303 10.6655 8.61996 10.5853C8.66766 10.5037 8.7339 10.411 8.79781 10.3216L12.0928 5.70858C12.2257 5.52246 12.4683 5.45083 12.681 5.5349Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "MessageFast"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/MessageFast.tsx b/app/components/base/icons/src/vender/features/MessageFast.tsx
new file mode 100644
index 0000000..45a1e77
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/MessageFast.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MessageFast.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MessageFast'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/Microphone01.json b/app/components/base/icons/src/vender/features/Microphone01.json
new file mode 100644
index 0000000..a4ba1bc
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/Microphone01.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12 1C9.79086 1 8 2.79086 8 5V12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12V5C16 2.79086 14.2091 1 12 1Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6 10C6 9.44771 5.55228 9 5 9C4.44772 9 4 9.44771 4 10V12C4 16.0803 7.05466 19.4471 11.0019 19.9383C11.0006 19.9587 11 19.9793 11 20V21H8C7.44772 21 7 21.4477 7 22C7 22.5523 7.44772 23 8 23H16C16.5523 23 17 22.5523 17 22C17 21.4477 16.5523 21 16 21H13V20C13 19.9793 12.9994 19.9587 12.9981 19.9383C16.9453 19.4471 20 16.0803 20 12V10C20 9.44771 19.5523 9 19 9C18.4477 9 18 9.44771 18 10V12C18 15.3137 15.3137 18 12 18C8.68629 18 6 15.3137 6 12V10Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Microphone01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/Microphone01.tsx b/app/components/base/icons/src/vender/features/Microphone01.tsx
new file mode 100644
index 0000000..37fb66a
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/Microphone01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Microphone01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Microphone01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/TextToAudio.json b/app/components/base/icons/src/vender/features/TextToAudio.json
new file mode 100644
index 0000000..1d824f7
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/TextToAudio.json
@@ -0,0 +1,77 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1 5.02263C1 3.90973 1.90219 3.00754 3.01509 3.00754H9.06035C10.1733 3.00754 11.0754 3.90973 11.0754 5.02263C11.0754 5.57908 10.6243 6.03017 10.0679 6.03017C9.51144 6.03017 9.06035 5.57908 9.06035 5.02263H7.04526V12.0754C7.60171 12.0754 8.0528 12.5265 8.0528 13.083C8.0528 13.6394 7.60171 14.0905 7.04526 14.0905H5.03017C4.47372 14.0905 4.02263 13.6394 4.02263 13.083C4.02263 12.5265 4.47372 12.0754 5.03017 12.0754V5.02263H3.01509C3.01509 5.57908 2.56399 6.03017 2.00754 6.03017C1.45109 6.03017 1 5.57908 1 5.02263Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.9883 2.15888C19.8823 1.94704 19.58 1.94704 19.4741 2.15888C18.8148 3.47752 18.6898 3.6025 17.3712 4.26182C17.1593 4.36774 17.1593 4.67004 17.3712 4.77596C18.6898 5.43528 18.8148 5.56026 19.4741 6.8789C19.58 7.09074 19.8823 7.09074 19.9883 6.8789C20.6476 5.56026 20.7726 5.43528 22.0912 4.77596C22.303 4.67004 22.303 4.36774 22.0912 4.26182C20.7726 3.6025 20.6476 3.47752 19.9883 2.15888Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.4561 4.17977C14.3463 3.96019 14.033 3.96019 13.9232 4.17977C13.4339 5.15833 13.3178 5.27443 12.3393 5.76371C12.1197 5.8735 12.1197 6.18685 12.3393 6.29664C13.3178 6.78592 13.4339 6.90202 13.9232 7.88058C14.033 8.10016 14.3463 8.10016 14.4561 7.88058C14.9454 6.90202 15.0615 6.78592 16.0401 6.29664C16.2596 6.18685 16.2596 5.8735 16.0401 5.76371C15.0615 5.27443 14.9454 5.15833 14.4561 4.17977Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.78347 16.2645C4.67755 16.0527 4.37525 16.0526 4.26933 16.2645C3.61002 17.5831 3.48505 17.7081 2.16642 18.3674C1.95458 18.4733 1.95458 18.7756 2.16642 18.8815C3.48505 19.5408 3.61002 19.6658 4.26933 20.9844C4.37525 21.1963 4.67755 21.1963 4.78347 20.9844C5.44278 19.6658 5.56776 19.5408 6.88638 18.8815C7.09822 18.7756 7.09822 18.4733 6.88638 18.3674C5.56776 17.7081 5.44278 17.5831 4.78347 16.2645Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M21.1611 12.97C21.4558 12.7644 21.8613 12.8367 22.0668 13.1313C22.655 13.9746 23 15.0008 23 16.1056C23 17.2105 22.655 18.2367 22.0668 19.0799C21.8613 19.3745 21.4558 19.4468 21.1611 19.2413C20.8664 19.0357 20.7942 18.6302 20.9997 18.3355C21.4405 17.7036 21.699 16.9358 21.699 16.1056C21.699 15.2755 21.4405 14.5076 20.9997 13.8757C20.7942 13.581 20.8664 13.1755 21.1611 12.97Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M18.2666 10.0664C18.578 10.0419 18.8823 10.1679 19.0852 10.4054C19.2668 10.6181 19.2957 10.8739 19.3067 10.9981C19.319 11.1373 19.319 11.3102 19.319 11.4861C19.319 11.4942 19.319 11.5022 19.319 11.5103L19.319 20.7312C19.319 20.9071 19.319 21.0799 19.3067 21.2191C19.2957 21.3433 19.2668 21.5991 19.0852 21.8118C18.8823 22.0493 18.578 22.1754 18.2666 22.1509C17.9878 22.1289 17.7865 21.9684 17.6909 21.8884C17.5838 21.7987 17.4615 21.6764 17.3372 21.552L15.2607 19.4756C15.2004 19.4153 15.1702 19.3853 15.1474 19.3645L15.1457 19.3629L15.1433 19.3628C15.1124 19.3614 15.0699 19.3612 14.9847 19.3612L13.8338 19.3612C13.6696 19.3613 13.5097 19.3613 13.3743 19.3502C13.2256 19.3381 13.0502 19.3094 12.8736 19.2194C12.6288 19.0947 12.4297 18.8957 12.305 18.6509C12.215 18.4743 12.1864 18.2988 12.1742 18.1501C12.1632 18.0147 12.1632 17.8548 12.1632 17.6906L12.1632 14.5474C12.1632 14.5404 12.1632 14.5335 12.1632 14.5266C12.1632 14.3624 12.1632 14.2025 12.1742 14.0671C12.1864 13.9184 12.215 13.743 12.305 13.5664C12.4297 13.3216 12.6288 13.1225 12.8736 12.9978C13.0502 12.9078 13.2256 12.8792 13.3743 12.867C13.5097 12.856 13.6696 12.856 13.8338 12.856C13.8407 12.856 13.8476 12.856 13.8546 12.856H14.9847C15.0699 12.856 15.1124 12.8558 15.1433 12.8544L15.1457 12.8543L15.1474 12.8528C15.1702 12.8319 15.2004 12.8019 15.2607 12.7417L17.32 10.6823C17.3258 10.6766 17.3315 10.6709 17.3372 10.6652C17.4615 10.5408 17.5838 10.4185 17.6909 10.3288C17.7865 10.2488 17.9878 10.0883 18.2666 10.0664Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "TextToAudio"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/TextToAudio.tsx b/app/components/base/icons/src/vender/features/TextToAudio.tsx
new file mode 100644
index 0000000..1f94c10
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/TextToAudio.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './TextToAudio.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'TextToAudio'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/VirtualAssistant.json b/app/components/base/icons/src/vender/features/VirtualAssistant.json
new file mode 100644
index 0000000..b426eb4
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/VirtualAssistant.json
@@ -0,0 +1,35 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.1667 7.16667H18.6667V13C18.6667 13.663 18.4033 14.2989 17.9344 14.7678C17.4656 15.2366 16.8297 15.5 16.1667 15.5H11.5L8.5 18H14.095L17.9792 21.2367C18.0549 21.3004 18.151 21.3347 18.25 21.3333C18.311 21.3332 18.3713 21.3198 18.4267 21.2942C18.4984 21.2606 18.5591 21.2072 18.6016 21.1404C18.6441 21.0735 18.6667 20.9959 18.6667 20.9167V18H21.1667C21.3877 18 21.5996 17.9122 21.7559 17.7559C21.9122 17.5996 22 17.3877 22 17.1667V8C22 7.77899 21.9122 7.56703 21.7559 7.41074C21.5996 7.25446 21.3877 7.16667 21.1667 7.16667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M16.1667 3H2.83333C2.61232 3 2.40036 3.0878 2.24408 3.24408C2.0878 3.40036 2 3.61232 2 3.83333V13C2 13.221 2.0878 13.433 2.24408 13.5893C2.40036 13.7455 2.61232 13.8333 2.83333 13.8333H5.33333V17.5833C5.33331 17.6626 5.35587 17.7402 5.39838 17.807C5.44089 17.8739 5.50158 17.9272 5.57333 17.9608C5.6287 17.9865 5.68897 17.9999 5.75 18C5.84753 18.0004 5.94204 17.9661 6.01667 17.9033L10.9008 13.8333H16.1667C16.3877 13.8333 16.5996 13.7455 16.7559 13.5893C16.9122 13.433 17 13.221 17 13V3.83333C17 3.61232 16.9122 3.40036 16.7559 3.24408C16.5996 3.0878 16.3877 3 16.1667 3Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "VirtualAssistant"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/VirtualAssistant.tsx b/app/components/base/icons/src/vender/features/VirtualAssistant.tsx
new file mode 100644
index 0000000..eeb64a1
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/VirtualAssistant.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './VirtualAssistant.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'VirtualAssistant'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/Vision.json b/app/components/base/icons/src/vender/features/Vision.json
new file mode 100644
index 0000000..e9b5b4d
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/Vision.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M22.357 10.5831C19.7908 6.27233 15.952 3.99997 12.0002 4C8.04853 4.00003 4.20967 6.27243 1.64354 10.5832C1.12403 11.4559 1.12403 12.5442 1.64354 13.4169C4.20968 17.7277 8.04854 20 12.0003 20C15.952 20 19.7908 17.7276 22.357 13.4168C22.8765 12.5441 22.8765 11.4558 22.357 10.5831ZM11.5528 8.89443L10.7412 10.5176C10.6928 10.6144 10.6144 10.6928 10.5176 10.7412L8.89443 11.5528C8.5259 11.737 8.5259 12.263 8.89443 12.4472L10.5176 13.2588C10.6144 13.3072 10.6928 13.3856 10.7412 13.4824L11.5528 15.1056C11.737 15.4741 12.263 15.4741 12.4472 15.1056L13.2588 13.4824C13.3072 13.3856 13.3856 13.3072 13.4824 13.2588L15.1056 12.4472C15.4741 12.263 15.4741 11.737 15.1056 11.5528L13.4824 10.7412C13.3856 10.6928 13.3072 10.6144 13.2588 10.5176L12.4472 8.89443C12.263 8.5259 11.737 8.5259 11.5528 8.89443Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Vision"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/features/Vision.tsx b/app/components/base/icons/src/vender/features/Vision.tsx
new file mode 100644
index 0000000..7b6cbf6
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/Vision.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Vision.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Vision'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/features/index.ts b/app/components/base/icons/src/vender/features/index.ts
new file mode 100644
index 0000000..853cad8
--- /dev/null
+++ b/app/components/base/icons/src/vender/features/index.ts
@@ -0,0 +1,10 @@
+export { default as Citations } from './Citations'
+export { default as ContentModeration } from './ContentModeration'
+export { default as Document } from './Document'
+export { default as FolderUpload } from './FolderUpload'
+export { default as LoveMessage } from './LoveMessage'
+export { default as MessageFast } from './MessageFast'
+export { default as Microphone01 } from './Microphone01'
+export { default as TextToAudio } from './TextToAudio'
+export { default as VirtualAssistant } from './VirtualAssistant'
+export { default as Vision } from './Vision'
diff --git a/app/components/base/icons/src/vender/line/alertsAndFeedback/AlertTriangle.json b/app/components/base/icons/src/vender/line/alertsAndFeedback/AlertTriangle.json
new file mode 100644
index 0000000..a200e60
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/alertsAndFeedback/AlertTriangle.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "alert-triangle"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M7.99977 5.33314V7.99981M7.99977 10.6665H8.00644M6.85977 1.90648L1.2131 11.3331C1.09668 11.5348 1.03508 11.7633 1.03443 11.9962C1.03378 12.229 1.0941 12.4579 1.20939 12.6602C1.32468 12.8624 1.49092 13.031 1.69157 13.149C1.89223 13.2671 2.1203 13.3306 2.3531 13.3331H13.6464C13.8792 13.3306 14.1073 13.2671 14.308 13.149C14.5086 13.031 14.6749 12.8624 14.7902 12.6602C14.9054 12.4579 14.9658 12.229 14.9651 11.9962C14.9645 11.7633 14.9029 11.5348 14.7864 11.3331L9.13977 1.90648C9.02092 1.71055 8.85358 1.54856 8.6539 1.43613C8.45422 1.32371 8.22893 1.26465 7.99977 1.26465C7.77061 1.26465 7.54532 1.32371 7.34564 1.43613C7.14596 1.54856 6.97862 1.71055 6.85977 1.90648Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AlertTriangle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/alertsAndFeedback/AlertTriangle.tsx b/app/components/base/icons/src/vender/line/alertsAndFeedback/AlertTriangle.tsx
new file mode 100644
index 0000000..cceacb9
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/alertsAndFeedback/AlertTriangle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AlertTriangle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AlertTriangle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsDown.json b/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsDown.json
new file mode 100644
index 0000000..b9ccbef
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsDown.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon",
+ "clip-path": "url(#clip0_17340_934)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_2",
+ "d": "M11.3333 1.33398V8.66732M14.6666 6.53398V3.46732C14.6666 2.72058 14.6666 2.34721 14.5213 2.062C14.3935 1.81111 14.1895 1.60714 13.9386 1.47931C13.6534 1.33398 13.28 1.33398 12.5333 1.33398H5.41196C4.43764 1.33398 3.95048 1.33398 3.55701 1.51227C3.21022 1.66941 2.91549 1.92227 2.70745 2.24113C2.4714 2.60291 2.39732 3.08441 2.24917 4.0474L1.90045 6.31407C1.70505 7.58419 1.60735 8.21926 1.79582 8.7134C1.96125 9.14711 2.27239 9.50978 2.6759 9.73923C3.13564 10.0007 3.77818 10.0007 5.06324 10.0007H5.59995C5.97332 10.0007 6.16001 10.0007 6.30261 10.0733C6.42806 10.1372 6.53004 10.2392 6.59396 10.3647C6.66662 10.5073 6.66662 10.6939 6.66662 11.0673V13.0234C6.66662 13.9313 7.40262 14.6673 8.31051 14.6673C8.52706 14.6673 8.7233 14.5398 8.81125 14.3419L11.0518 9.30077C11.1537 9.07148 11.2046 8.95684 11.2852 8.87278C11.3563 8.79847 11.4438 8.74165 11.5406 8.70678C11.6501 8.66732 11.7756 8.66732 12.0265 8.66732H12.5333C13.28 8.66732 13.6534 8.66732 13.9386 8.52199C14.1895 8.39416 14.3935 8.19019 14.5213 7.93931C14.6666 7.65409 14.6666 7.28072 14.6666 6.53398Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_17340_934"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ThumbsDown"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsDown.tsx b/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsDown.tsx
new file mode 100644
index 0000000..f2efee6
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsDown.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ThumbsDown.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ThumbsDown'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsUp.json b/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsUp.json
new file mode 100644
index 0000000..674516b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsUp.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon",
+ "clip-path": "url(#clip0_17340_931)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_2",
+ "d": "M4.66671 14.6673V7.33398M1.33337 8.66732V13.334C1.33337 14.0704 1.93033 14.6673 2.66671 14.6673H11.6175C12.6047 14.6673 13.4442 13.9471 13.5943 12.9714L14.3122 8.30477C14.4986 7.09325 13.5613 6.00065 12.3355 6.00065H10C9.63185 6.00065 9.33337 5.70217 9.33337 5.33398V2.97788C9.33337 2.06998 8.59738 1.33398 7.68948 1.33398C7.47293 1.33398 7.27669 1.46151 7.18875 1.6594L4.84267 6.93808C4.73567 7.17883 4.49692 7.33398 4.23346 7.33398H2.66671C1.93033 7.33398 1.33337 7.93094 1.33337 8.66732Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_17340_931"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ThumbsUp"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsUp.tsx b/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsUp.tsx
new file mode 100644
index 0000000..dadd80c
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/alertsAndFeedback/ThumbsUp.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ThumbsUp.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ThumbsUp'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/alertsAndFeedback/index.ts b/app/components/base/icons/src/vender/line/alertsAndFeedback/index.ts
new file mode 100644
index 0000000..f0a0faf
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/alertsAndFeedback/index.ts
@@ -0,0 +1,3 @@
+export { default as AlertTriangle } from './AlertTriangle'
+export { default as ThumbsDown } from './ThumbsDown'
+export { default as ThumbsUp } from './ThumbsUp'
diff --git a/app/components/base/icons/src/vender/line/arrows/ArrowNarrowLeft.json b/app/components/base/icons/src/vender/line/arrows/ArrowNarrowLeft.json
new file mode 100644
index 0000000..73d6708
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ArrowNarrowLeft.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "17",
+ "height": "16",
+ "viewBox": "0 0 17 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.3625 8H2.6958M2.6958 8L6.6958 12M2.6958 8L6.6958 4",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ArrowNarrowLeft"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/arrows/ArrowNarrowLeft.tsx b/app/components/base/icons/src/vender/line/arrows/ArrowNarrowLeft.tsx
new file mode 100644
index 0000000..1c3b82e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ArrowNarrowLeft.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ArrowNarrowLeft.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ArrowNarrowLeft'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/arrows/ArrowUpRight.json b/app/components/base/icons/src/vender/line/arrows/ArrowUpRight.json
new file mode 100644
index 0000000..9ab1e6e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ArrowUpRight.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "arrow-up-right"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M4.08325 9.91665L9.91659 4.08331M9.91659 4.08331H4.08325M9.91659 4.08331V9.91665",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ArrowUpRight"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/arrows/ArrowUpRight.tsx b/app/components/base/icons/src/vender/line/arrows/ArrowUpRight.tsx
new file mode 100644
index 0000000..6c3293f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ArrowUpRight.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ArrowUpRight.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ArrowUpRight'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/arrows/ChevronDownDouble.json b/app/components/base/icons/src/vender/line/arrows/ChevronDownDouble.json
new file mode 100644
index 0000000..cfae439
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ChevronDownDouble.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "13",
+ "viewBox": "0 0 12 13",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "chevron-down-double"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M3.5 7L6 9.5L8.5 7M3.5 3.5L6 6L8.5 3.5",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ChevronDownDouble"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/arrows/ChevronDownDouble.tsx b/app/components/base/icons/src/vender/line/arrows/ChevronDownDouble.tsx
new file mode 100644
index 0000000..aa134fa
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ChevronDownDouble.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ChevronDownDouble.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ChevronDownDouble'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/arrows/ChevronRight.json b/app/components/base/icons/src/vender/line/arrows/ChevronRight.json
new file mode 100644
index 0000000..c144e67
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ChevronRight.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "chevron-right"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M5.25 10.5L8.75 7L5.25 3.5",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ChevronRight"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/arrows/ChevronRight.tsx b/app/components/base/icons/src/vender/line/arrows/ChevronRight.tsx
new file mode 100644
index 0000000..befecea
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ChevronRight.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ChevronRight.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ChevronRight'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/arrows/ChevronSelectorVertical.json b/app/components/base/icons/src/vender/line/arrows/ChevronSelectorVertical.json
new file mode 100644
index 0000000..84da1f3
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ChevronSelectorVertical.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7 15L12 20L17 15M7 9L12 4L17 9",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ChevronSelectorVertical"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/arrows/ChevronSelectorVertical.tsx b/app/components/base/icons/src/vender/line/arrows/ChevronSelectorVertical.tsx
new file mode 100644
index 0000000..7c19420
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ChevronSelectorVertical.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ChevronSelectorVertical.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ChevronSelectorVertical'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/arrows/RefreshCcw01.json b/app/components/base/icons/src/vender/line/arrows/RefreshCcw01.json
new file mode 100644
index 0000000..30033b4
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/RefreshCcw01.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2 10C2 10 4.00498 7.26822 5.63384 5.63824C7.26269 4.00827 9.5136 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.89691 21 4.43511 18.2543 3.35177 14.5M2 10V4M2 10H8",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "RefreshCcw01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/arrows/RefreshCcw01.tsx b/app/components/base/icons/src/vender/line/arrows/RefreshCcw01.tsx
new file mode 100644
index 0000000..f0caf73
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/RefreshCcw01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './RefreshCcw01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'RefreshCcw01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/arrows/RefreshCw05.json b/app/components/base/icons/src/vender/line/arrows/RefreshCw05.json
new file mode 100644
index 0000000..5468171
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/RefreshCw05.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.69773 13.1783C7.29715 13.8879 9.20212 13.8494 10.8334 12.9075C13.5438 11.3427 14.4724 7.87704 12.9076 5.16672L12.7409 4.87804M3.09233 10.8335C1.52752 8.12314 2.45615 4.65746 5.16647 3.09265C6.7978 2.15081 8.70277 2.11227 10.3022 2.82185M1.66226 10.8892L3.48363 11.3773L3.97166 9.5559M12.0284 6.44393L12.5164 4.62256L14.3378 5.1106",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "RefreshCw05"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/arrows/RefreshCw05.tsx b/app/components/base/icons/src/vender/line/arrows/RefreshCw05.tsx
new file mode 100644
index 0000000..b426871
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/RefreshCw05.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './RefreshCw05.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'RefreshCw05'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/arrows/ReverseLeft.json b/app/components/base/icons/src/vender/line/arrows/ReverseLeft.json
new file mode 100644
index 0000000..48c6d1f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ReverseLeft.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_2",
+ "d": "M2.66699 4.66667H9.33366C11.5428 4.66667 13.3337 6.45753 13.3337 8.66667C13.3337 10.8758 11.5428 12.6667 9.33366 12.6667H2.66699M2.66699 4.66667L5.33366 2M2.66699 4.66667L5.33366 7.33333",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ReverseLeft"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/arrows/ReverseLeft.tsx b/app/components/base/icons/src/vender/line/arrows/ReverseLeft.tsx
new file mode 100644
index 0000000..30a2e3a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/ReverseLeft.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ReverseLeft.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ReverseLeft'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/arrows/index.ts b/app/components/base/icons/src/vender/line/arrows/index.ts
new file mode 100644
index 0000000..c329b36
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/arrows/index.ts
@@ -0,0 +1,8 @@
+export { default as ArrowNarrowLeft } from './ArrowNarrowLeft'
+export { default as ArrowUpRight } from './ArrowUpRight'
+export { default as ChevronDownDouble } from './ChevronDownDouble'
+export { default as ChevronRight } from './ChevronRight'
+export { default as ChevronSelectorVertical } from './ChevronSelectorVertical'
+export { default as RefreshCcw01 } from './RefreshCcw01'
+export { default as RefreshCw05 } from './RefreshCw05'
+export { default as ReverseLeft } from './ReverseLeft'
diff --git a/app/components/base/icons/src/vender/line/communication/AiText.json b/app/components/base/icons/src/vender/line/communication/AiText.json
new file mode 100644
index 0000000..0f5ff57
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/AiText.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "ai-text"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M2.33301 10.5H4.08301M2.33301 7H5.24967M2.33301 3.5H11.6663M9.91634 5.83333L10.7913 7.875L12.833 8.75L10.7913 9.625L9.91634 11.6667L9.04134 9.625L6.99967 8.75L9.04134 7.875L9.91634 5.83333Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AiText"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/communication/AiText.tsx b/app/components/base/icons/src/vender/line/communication/AiText.tsx
new file mode 100644
index 0000000..c1a6a24
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/AiText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AiText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AiText'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/communication/ChatBot.json b/app/components/base/icons/src/vender/line/communication/ChatBot.json
new file mode 100644
index 0000000..69547f9
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/ChatBot.json
@@ -0,0 +1,93 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon",
+ "clip-path": "url(#clip0_3167_27725)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M5.93972 6.47002H2.2276C1.64161 6.47002 1.16699 6.94464 1.16699 7.53063V11.7731C1.16699 12.359 1.64161 12.8337 2.2276 12.8337H9.65184C10.2378 12.8337 10.7124 12.359 10.7124 11.7731V7.53063M3.81851 4.66693V3.2882M3.81851 3.2882C4.11139 3.2882 4.34881 3.05078 4.34881 2.7579C4.34881 2.46502 4.11139 2.2276 3.81851 2.2276C3.52563 2.2276 3.2882 2.46502 3.2882 2.7579C3.2882 3.05078 3.52563 3.2882 3.81851 3.2882ZM8.06093 1.6973C8.06093 1.40457 8.29851 1.16699 8.59123 1.16699H12.3034C12.5961 1.16699 12.8337 1.40457 12.8337 1.6973V4.34881C12.8337 4.64154 12.5961 4.87911 12.3034 4.87911H9.65184L8.06093 5.93972V1.6973Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.08354 9.65146C4.52286 9.65146 4.87899 9.29532 4.87899 8.856C4.87899 8.41668 4.52286 8.06055 4.08354 8.06055C3.64422 8.06055 3.28809 8.41668 3.28809 8.856C3.28809 9.29532 3.64422 9.65146 4.08354 9.65146Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.79566 9.65146C8.23498 9.65146 8.59112 9.29532 8.59112 8.856C8.59112 8.41668 8.23498 8.06055 7.79566 8.06055C7.35634 8.06055 7.00021 8.41668 7.00021 8.856C7.00021 9.29532 7.35634 9.65146 7.79566 9.65146Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_3167_27725"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ChatBot"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/communication/ChatBot.tsx b/app/components/base/icons/src/vender/line/communication/ChatBot.tsx
new file mode 100644
index 0000000..867ae31
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/ChatBot.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ChatBot.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ChatBot'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/communication/ChatBotSlim.json b/app/components/base/icons/src/vender/line/communication/ChatBotSlim.json
new file mode 100644
index 0000000..07f6cda
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/ChatBotSlim.json
@@ -0,0 +1,68 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "48",
+ "height": "48",
+ "viewBox": "0 0 48 48",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "chat-bot"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.0909 11.2727C14.0951 11.2727 14.9091 10.4587 14.9091 9.45455C14.9091 8.45039 14.0951 7.63636 13.0909 7.63636C12.0868 7.63636 11.2727 8.45039 11.2727 9.45455C11.2727 10.4587 12.0868 11.2727 13.0909 11.2727Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.3636 22.1818H7.63636C5.62727 22.1818 4 23.8091 4 25.8182V40.3636C4 42.3727 5.62727 44 7.63636 44H33.0909C35.1 44 36.7273 42.3727 36.7273 40.3636V25.8182M13.0909 15.9998V11.2727M13.0909 11.2727C14.0951 11.2727 14.9091 10.4587 14.9091 9.45455C14.9091 8.45039 14.0951 7.63636 13.0909 7.63636C12.0868 7.63636 11.2727 8.45039 11.2727 9.45455C11.2727 10.4587 12.0868 11.2727 13.0909 11.2727ZM27.6364 5.81818C27.6364 4.81455 28.4509 4 29.4545 4H42.1818C43.1855 4 44 4.81455 44 5.81818V14.9091C44 15.9127 43.1855 16.7273 42.1818 16.7273H33.0909L27.6364 20.3636V5.81818Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M15.7275 30.364C15.7275 31.3179 14.9542 32.0913 14.0002 32.0913C13.0463 32.0913 12.2729 31.3179 12.2729 30.364C12.2729 29.41 13.0463 28.6367 14.0002 28.6367C14.9542 28.6367 15.7275 29.41 15.7275 30.364ZM28.4548 30.364C28.4548 31.3179 27.6814 32.0913 26.7275 32.0913C25.7735 32.0913 25.0002 31.3179 25.0002 30.364C25.0002 29.41 25.7735 28.6367 26.7275 28.6367C27.6814 28.6367 28.4548 29.41 28.4548 30.364Z",
+ "fill": "currentColor",
+ "stroke": "currentColor",
+ "stroke-width": "2"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ChatBotSlim"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/communication/ChatBotSlim.tsx b/app/components/base/icons/src/vender/line/communication/ChatBotSlim.tsx
new file mode 100644
index 0000000..1950a42
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/ChatBotSlim.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ChatBotSlim.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ChatBotSlim'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/communication/CuteRobot.json b/app/components/base/icons/src/vender/line/communication/CuteRobot.json
new file mode 100644
index 0000000..4ae74d2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/CuteRobot.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "cute-robot"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M6.99967 2.33366H4.08301C3.43868 2.33366 2.91634 2.85599 2.91634 3.50033V6.41699C2.91634 7.06134 3.43868 7.58366 4.08301 7.58366H9.91634C10.5607 7.58366 11.083 7.06134 11.083 6.41699V3.50033C11.083 2.85599 10.5607 2.33366 9.91634 2.33366H6.99967ZM6.99967 2.33366V1.16699M3.49967 8.75033L2.33301 9.91699M3.49967 8.75033C3.49967 10.6833 5.06668 12.2503 6.99967 12.2503C8.93267 12.2503 10.4997 10.6833 10.4997 8.75033M3.49967 8.75033V7.58366M10.4997 8.75033L11.6663 9.91699M10.4997 8.75033V7.58366M5.24967 4.66699V5.25033M8.74967 4.66699V5.25033",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "CuteRobot"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/communication/CuteRobot.tsx b/app/components/base/icons/src/vender/line/communication/CuteRobot.tsx
new file mode 100644
index 0000000..526bb77
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/CuteRobot.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './CuteRobot.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'CuteRobot'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/communication/MessageCheckRemove.json b/app/components/base/icons/src/vender/line/communication/MessageCheckRemove.json
new file mode 100644
index 0000000..a536c9f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/MessageCheckRemove.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "message-check-remove"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M15.2 2.99994H7.8C6.11984 2.99994 5.27976 2.99994 4.63803 3.32693C4.07354 3.61455 3.6146 4.07349 3.32698 4.63797C3 5.27971 3 6.11979 3 7.79994V13.9999C3 14.9299 3 15.3949 3.10222 15.7764C3.37962 16.8117 4.18827 17.6203 5.22354 17.8977C5.60504 17.9999 6.07003 17.9999 7 17.9999V20.3354C7 20.8683 7 21.1347 7.10923 21.2716C7.20422 21.3906 7.34827 21.4598 7.50054 21.4596C7.67563 21.4594 7.88367 21.293 8.29976 20.9601L10.6852 19.0518C11.1725 18.6619 11.4162 18.467 11.6875 18.3284C11.9282 18.2054 12.1844 18.1155 12.4492 18.0612C12.7477 17.9999 13.0597 17.9999 13.6837 17.9999H16.2C17.8802 17.9999 18.7202 17.9999 19.362 17.673C19.9265 17.3853 20.3854 16.9264 20.673 16.3619C21 15.7202 21 14.8801 21 13.1999V8.79994M12.3333 13.4999L14 10.4999H10L11.6667 7.49994M19.2322 4.76771L21 2.99994M21 2.99994L22.7678 1.23218M21 2.99994L19.2322 1.23218M21 2.99994L22.7678 4.76771",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "MessageCheckRemove"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/communication/MessageCheckRemove.tsx b/app/components/base/icons/src/vender/line/communication/MessageCheckRemove.tsx
new file mode 100644
index 0000000..fac727b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/MessageCheckRemove.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MessageCheckRemove.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MessageCheckRemove'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/communication/MessageFastPlus.json b/app/components/base/icons/src/vender/line/communication/MessageFastPlus.json
new file mode 100644
index 0000000..7d40cc7
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/MessageFastPlus.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.2 3H7.8C6.11984 3 5.27976 3 4.63803 3.32698C4.07354 3.6146 3.6146 4.07354 3.32698 4.63803C3 5.27976 3 6.11984 3 7.8V14C3 14.93 3 15.395 3.10222 15.7765C3.37962 16.8117 4.18827 17.6204 5.22354 17.8978C5.60504 18 6.07003 18 7 18V20.3355C7 20.8684 7 21.1348 7.10923 21.2716C7.20422 21.3906 7.34827 21.4599 7.50054 21.4597C7.67563 21.4595 7.88367 21.2931 8.29976 20.9602L10.6852 19.0518C11.1725 18.662 11.4162 18.4671 11.6875 18.3285C11.9282 18.2055 12.1844 18.1156 12.4492 18.0613C12.7477 18 13.0597 18 13.6837 18H16.2C17.8802 18 18.7202 18 19.362 17.673C19.9265 17.3854 20.3854 16.9265 20.673 16.362C21 15.7202 21 14.8802 21 13.2V8.8M12.3333 13.5L14 10.5H10L11.6667 7.5M21 5V3M21 3V1M21 3H19M21 3H23",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "MessageFastPlus"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/communication/MessageFastPlus.tsx b/app/components/base/icons/src/vender/line/communication/MessageFastPlus.tsx
new file mode 100644
index 0000000..4446687
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/MessageFastPlus.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MessageFastPlus.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MessageFastPlus'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/communication/index.ts b/app/components/base/icons/src/vender/line/communication/index.ts
new file mode 100644
index 0000000..3ab20e8
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/communication/index.ts
@@ -0,0 +1,6 @@
+export { default as AiText } from './AiText'
+export { default as ChatBotSlim } from './ChatBotSlim'
+export { default as ChatBot } from './ChatBot'
+export { default as CuteRobot } from './CuteRobot'
+export { default as MessageCheckRemove } from './MessageCheckRemove'
+export { default as MessageFastPlus } from './MessageFastPlus'
diff --git a/app/components/base/icons/src/vender/line/development/ArtificialBrain.json b/app/components/base/icons/src/vender/line/development/ArtificialBrain.json
new file mode 100644
index 0000000..7015ee2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/ArtificialBrain.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.4542 11.9996H11.9999V13.8177M17.4542 11.9996C17.4542 13.0037 18.2682 13.8177 19.2724 13.8177C20.2765 13.8177 21.0905 13.0037 21.0905 11.9996C21.0905 10.9955 20.2765 10.1815 19.2724 10.1815C18.2682 10.1815 17.4542 10.9955 17.4542 11.9996ZM6.54554 12.9087C5.318 12.9012 4.14258 12.4115 3.27293 11.5451M6.54554 12.9087C6.53904 13.471 6.71172 14.0207 7.03861 14.4783C7.36549 14.936 7.82958 15.2776 8.36365 15.4539M6.54554 12.9087C6.54223 12.5292 6.62185 12.1534 6.77888 11.808C6.9359 11.4625 7.16652 11.1556 7.45459 10.9086M3.27293 11.5451C2.8848 11.7842 2.56415 12.1184 2.34142 12.5161C2.1187 12.9139 2.00125 13.3619 2.00022 13.8177C1.99583 14.2518 2.10201 14.6799 2.30876 15.0616C2.51552 15.4433 2.81603 15.766 3.182 15.9995C3.00399 16.4639 2.91159 16.9567 2.90928 17.454C2.90333 18.0525 3.01683 18.6463 3.24315 19.2004C3.46946 19.7546 3.80404 20.258 4.2273 20.6813C4.65056 21.1045 5.154 21.4391 5.70815 21.6654C6.2623 21.8917 6.85603 22.0052 7.45458 21.9993C8.05314 22.0052 8.64686 21.8917 9.20101 21.6654C9.75516 21.4391 10.2586 21.1045 10.6819 20.6813C11.1051 20.258 11.4397 19.7546 11.666 19.2004C11.8923 18.6463 12.0058 18.0525 11.9999 17.454V16.5449H14.7271L16.1688 17.9867M3.27293 11.5451C2.44984 10.6912 1.9931 9.54938 2.00022 8.36339C1.99427 7.76484 2.10777 7.17111 2.33409 6.61696C2.5604 6.06281 2.89498 5.55937 3.31824 5.13611C3.7415 4.71285 4.24494 4.37827 4.79909 4.15195C5.35324 3.92564 5.94697 3.81214 6.54552 3.81809H6.72733C6.90356 3.28402 7.24525 2.81993 7.70289 2.49304C8.16052 2.16616 8.71035 1.99346 9.2727 1.99997C9.63267 1.99331 9.99029 2.0593 10.3242 2.19399C10.6581 2.32869 10.9614 2.52933 11.2159 2.78391C11.4705 3.03849 11.6712 3.34179 11.8059 3.67567C11.9406 4.00956 12.0065 4.36718 11.9999 4.72715M16.1688 6.0126L14.7271 7.45437H11.9999V9.27249M19.2724 19.2721C19.2724 20.2762 18.4584 21.0902 17.4542 21.0902C16.4501 21.0902 15.6361 20.2762 15.6361 19.2721C15.6361 18.268 16.4501 17.454 17.4542 17.454C18.4584 17.454 19.2724 18.268 19.2724 19.2721ZM19.2724 4.72714C19.2724 5.73126 18.4584 6.54526 17.4542 6.54526C16.4501 6.54526 15.6361 5.73126 15.6361 4.72714C15.6361 3.72302 16.4501 2.90902 17.4542 2.90902C18.4584 2.90902 19.2724 3.72302 19.2724 4.72714Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ArtificialBrain"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/ArtificialBrain.tsx b/app/components/base/icons/src/vender/line/development/ArtificialBrain.tsx
new file mode 100644
index 0000000..cefb404
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/ArtificialBrain.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ArtificialBrain.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ArtificialBrain'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/BarChartSquare02.json b/app/components/base/icons/src/vender/line/development/BarChartSquare02.json
new file mode 100644
index 0000000..5b695a7
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/BarChartSquare02.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "bar-chart-square-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M5.33333 10V11.3333M8 7.33333V11.3333M10.6667 4.66667V11.3333M5.2 14H10.8C11.9201 14 12.4802 14 12.908 13.782C13.2843 13.5903 13.5903 13.2843 13.782 12.908C14 12.4802 14 11.9201 14 10.8V5.2C14 4.0799 14 3.51984 13.782 3.09202C13.5903 2.71569 13.2843 2.40973 12.908 2.21799C12.4802 2 11.9201 2 10.8 2H5.2C4.0799 2 3.51984 2 3.09202 2.21799C2.71569 2.40973 2.40973 2.71569 2.21799 3.09202C2 3.51984 2 4.0799 2 5.2V10.8C2 11.9201 2 12.4802 2.21799 12.908C2.40973 13.2843 2.71569 13.5903 3.09202 13.782C3.51984 14 4.0799 14 5.2 14Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "BarChartSquare02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/BarChartSquare02.tsx b/app/components/base/icons/src/vender/line/development/BarChartSquare02.tsx
new file mode 100644
index 0000000..c8a3357
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/BarChartSquare02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BarChartSquare02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BarChartSquare02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/BracketsX.json b/app/components/base/icons/src/vender/line/development/BracketsX.json
new file mode 100644
index 0000000..08935cc
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/BracketsX.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.5708 20C19.8328 20 20.8568 18.977 20.8568 17.714V13.143L21.9998 12L20.8568 10.857V6.286C20.8568 5.023 19.8338 4 18.5708 4M5.429 4C4.166 4 3.143 5.023 3.143 6.286V10.857L2 12L3.143 13.143V17.714C3.143 18.977 4.166 20 5.429 20M15 9L9 15M9 9L15 15",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "BracketsX"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/BracketsX.tsx b/app/components/base/icons/src/vender/line/development/BracketsX.tsx
new file mode 100644
index 0000000..84cc1d2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/BracketsX.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BracketsX.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BracketsX'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/CodeBrowser.json b/app/components/base/icons/src/vender/line/development/CodeBrowser.json
new file mode 100644
index 0000000..1d0254d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/CodeBrowser.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "code-browser"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M22 9H2M14 17.5L16.5 15L14 12.5M10 12.5L7.5 15L10 17.5M2 7.8L2 16.2C2 17.8802 2 18.7202 2.32698 19.362C2.6146 19.9265 3.07354 20.3854 3.63803 20.673C4.27976 21 5.11984 21 6.8 21H17.2C18.8802 21 19.7202 21 20.362 20.673C20.9265 20.3854 21.3854 19.9265 21.673 19.362C22 18.7202 22 17.8802 22 16.2V7.8C22 6.11984 22 5.27977 21.673 4.63803C21.3854 4.07354 20.9265 3.6146 20.362 3.32698C19.7202 3 18.8802 3 17.2 3L6.8 3C5.11984 3 4.27976 3 3.63803 3.32698C3.07354 3.6146 2.6146 4.07354 2.32698 4.63803C2 5.27976 2 6.11984 2 7.8Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "CodeBrowser"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/CodeBrowser.tsx b/app/components/base/icons/src/vender/line/development/CodeBrowser.tsx
new file mode 100644
index 0000000..fd402ed
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/CodeBrowser.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './CodeBrowser.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'CodeBrowser'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/Container.json b/app/components/base/icons/src/vender/line/development/Container.json
new file mode 100644
index 0000000..3b15cd8
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Container.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.6666 4.85185L7.99998 8M7.99998 8L2.33331 4.85185M7.99998 8L8 14.3333M14 10.7057V5.29431C14 5.06588 14 4.95167 13.9663 4.8498C13.9366 4.75969 13.8879 4.67696 13.8236 4.60717C13.7509 4.52828 13.651 4.47281 13.4514 4.36188L8.51802 1.62114C8.32895 1.5161 8.23442 1.46358 8.1343 1.44299C8.0457 1.42477 7.95431 1.42477 7.8657 1.44299C7.76559 1.46358 7.67105 1.5161 7.48198 1.62114L2.54865 4.36188C2.34896 4.47281 2.24912 4.52828 2.17642 4.60717C2.11211 4.67697 2.06343 4.75969 2.03366 4.84981C2 4.95167 2 5.06588 2 5.29431V10.7057C2 10.9341 2 11.0484 2.03366 11.1502C2.06343 11.2403 2.11211 11.3231 2.17642 11.3929C2.24912 11.4718 2.34897 11.5272 2.54865 11.6382L7.48198 14.3789C7.67105 14.4839 7.76559 14.5365 7.8657 14.557C7.95431 14.5753 8.0457 14.5753 8.1343 14.557C8.23442 14.5365 8.32895 14.4839 8.51802 14.3789L13.4514 11.6382C13.651 11.5272 13.7509 11.4718 13.8236 11.3929C13.8879 11.3231 13.9366 11.2403 13.9663 11.1502C14 11.0484 14 10.9341 14 10.7057Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Container"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/Container.tsx b/app/components/base/icons/src/vender/line/development/Container.tsx
new file mode 100644
index 0000000..2aa777a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Container.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Container.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Container'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/Database01.json b/app/components/base/icons/src/vender/line/development/Database01.json
new file mode 100644
index 0000000..e25b3e7
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Database01.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "17",
+ "height": "16",
+ "viewBox": "0 0 17 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.5 3.33337C14.5 4.43794 11.8137 5.33337 8.5 5.33337C5.18629 5.33337 2.5 4.43794 2.5 3.33337M14.5 3.33337C14.5 2.2288 11.8137 1.33337 8.5 1.33337C5.18629 1.33337 2.5 2.2288 2.5 3.33337M14.5 3.33337V12.6667C14.5 13.7734 11.8333 14.6667 8.5 14.6667C5.16667 14.6667 2.5 13.7734 2.5 12.6667V3.33337M14.5 8.00004C14.5 9.10671 11.8333 10 8.5 10C5.16667 10 2.5 9.10671 2.5 8.00004",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Database01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/Database01.tsx b/app/components/base/icons/src/vender/line/development/Database01.tsx
new file mode 100644
index 0000000..55a67f8
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Database01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Database01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Database01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/Database03.json b/app/components/base/icons/src/vender/line/development/Database03.json
new file mode 100644
index 0000000..5acf4bf
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Database03.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.33333 13.3333C9.33333 14.0696 8.73638 14.6666 8 14.6666C7.26362 14.6666 6.66667 14.0696 6.66667 13.3333M9.33333 13.3333C9.33333 12.5969 8.73638 11.9999 8 11.9999M9.33333 13.3333H14M6.66667 13.3333C6.66667 12.5969 7.26362 11.9999 8 11.9999M6.66667 13.3333H2M8 11.9999V9.33325M14 3.33325C14 4.43782 11.3137 5.33325 8 5.33325C4.68629 5.33325 2 4.43782 2 3.33325M14 3.33325C14 2.22868 11.3137 1.33325 8 1.33325C4.68629 1.33325 2 2.22868 2 3.33325M14 3.33325V7.33325C14 8.43992 11.3333 9.33325 8 9.33325M2 3.33325V7.33325C2 8.43992 4.66667 9.33325 8 9.33325",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Database03"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/Database03.tsx b/app/components/base/icons/src/vender/line/development/Database03.tsx
new file mode 100644
index 0000000..012294a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Database03.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Database03.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Database03'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/FileHeart02.json b/app/components/base/icons/src/vender/line/development/FileHeart02.json
new file mode 100644
index 0000000..ef9343d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/FileHeart02.json
@@ -0,0 +1,52 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "file-heart-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M13.5709 13.9883C13.5108 14.3786 13.175 14.6666 12.7802 14.6666H9.19984C8.90529 14.6666 8.6665 14.4279 8.6665 14.1333V12.2666C8.6665 11.9721 8.90529 11.7333 9.19984 11.7333H9.82654C9.93192 11.7333 10.0274 11.6713 10.0702 11.5749L11.0087 9.46348C11.0438 9.38432 11.1223 9.33331 11.2089 9.33331C11.5721 9.33331 11.8665 9.62771 11.8665 9.99087V10.9333C11.8665 11.0806 11.9859 11.2 12.1332 11.2H13.0673C13.5577 11.2 13.9326 11.637 13.858 12.1216L13.5709 13.9883Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M13.3332 6.66665V4.53331C13.3332 3.41321 13.3332 2.85316 13.1152 2.42533C12.9234 2.04901 12.6175 1.74305 12.2412 1.5513C11.8133 1.33331 11.2533 1.33331 10.1332 1.33331H5.8665C4.7464 1.33331 4.18635 1.33331 3.75852 1.5513C3.3822 1.74305 3.07624 2.04901 2.88449 2.42533C2.6665 2.85316 2.6665 3.41321 2.6665 4.53331V11.3333C2.6665 11.9533 2.6665 12.2633 2.73465 12.5176C2.91959 13.2078 3.45868 13.7469 4.14887 13.9318C4.4032 14 4.71319 14 5.33317 14M8.33317 7.33331H5.33317M5.99984 9.99998H5.33317M10.6665 4.66665H5.33317",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "FileHeart02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/FileHeart02.tsx b/app/components/base/icons/src/vender/line/development/FileHeart02.tsx
new file mode 100644
index 0000000..e918e5e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/FileHeart02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileHeart02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileHeart02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/GitBranch01.json b/app/components/base/icons/src/vender/line/development/GitBranch01.json
new file mode 100644
index 0000000..04205e5
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/GitBranch01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "git-branch-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M2 2V8.8C2 9.92011 2 10.4802 2.21799 10.908C2.40973 11.2843 2.71569 11.5903 3.09202 11.782C3.51984 12 4.0799 12 5.2 12H10M10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12ZM2 5.33333L10 5.33333M10 5.33333C10 6.4379 10.8954 7.33333 12 7.33333C13.1046 7.33333 14 6.4379 14 5.33333C14 4.22876 13.1046 3.33333 12 3.33333C10.8954 3.33333 10 4.22876 10 5.33333Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "GitBranch01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/GitBranch01.tsx b/app/components/base/icons/src/vender/line/development/GitBranch01.tsx
new file mode 100644
index 0000000..15343eb
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/GitBranch01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './GitBranch01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'GitBranch01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/PromptEngineering.json b/app/components/base/icons/src/vender/line/development/PromptEngineering.json
new file mode 100644
index 0000000..c55bde8
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/PromptEngineering.json
@@ -0,0 +1,65 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "prompt-engineering"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M14 6V5.2C14 4.0799 14 3.51984 13.782 3.09202C13.5903 2.7157 13.2843 2.40974 12.908 2.21799C12.4802 2 11.9201 2 10.8 2H5.2C4.0799 2 3.51984 2 3.09202 2.21799C2.7157 2.40973 2.40973 2.7157 2.21799 3.09202C2 3.51984 2 4.0799 2 5.2V10.8C2 11.9201 2 12.4802 2.21799 12.908C2.40973 13.2843 2.71569 13.5903 3.09202 13.782C3.51984 14 4.07989 14 5.2 14H6",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M4.6665 4.66669H4.67317M6.6665 4.66669H6.67317M8.6665 4.66669H8.67317",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_2",
+ "d": "M11.3333 8L11.5343 8.80399C11.7036 9.48123 11.7883 9.81985 11.9646 10.0954C12.1206 10.3391 12.3275 10.5461 12.5713 10.7021C12.8468 10.8784 13.1854 10.963 13.8627 11.1323L14.6667 11.3333L13.8627 11.5343C13.1854 11.7036 12.8468 11.7883 12.5713 11.9646C12.3275 12.1206 12.1206 12.3275 11.9646 12.5713C11.7883 12.8468 11.7036 13.1854 11.5343 13.8627L11.3333 14.6667L11.1323 13.8627C10.963 13.1854 10.8784 12.8468 10.7021 12.5713C10.5461 12.3275 10.3391 12.1206 10.0954 11.9646C9.81985 11.7883 9.48123 11.7036 8.80399 11.5343L8 11.3333L8.80399 11.1323C9.48123 10.963 9.81985 10.8784 10.0954 10.7021C10.3391 10.5461 10.5461 10.3391 10.7021 10.0954C10.8784 9.81985 10.963 9.48123 11.1323 8.80399L11.3333 8Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "PromptEngineering"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/PromptEngineering.tsx b/app/components/base/icons/src/vender/line/development/PromptEngineering.tsx
new file mode 100644
index 0000000..506e9fe
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/PromptEngineering.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './PromptEngineering.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'PromptEngineering'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/PuzzlePiece01.json b/app/components/base/icons/src/vender/line/development/PuzzlePiece01.json
new file mode 100644
index 0000000..ce06d61
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/PuzzlePiece01.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "puzzle-piece-01",
+ "clip-path": "url(#clip0_6770_9698)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M4.99992 3.00004C4.99992 2.07957 5.74611 1.33337 6.66659 1.33337C7.58706 1.33337 8.33325 2.07957 8.33325 3.00004V4.00004H8.99992C9.9318 4.00004 10.3977 4.00004 10.7653 4.15228C11.2553 4.35527 11.6447 4.74462 11.8477 5.23467C11.9999 5.60222 11.9999 6.06816 11.9999 7.00004H12.9999C13.9204 7.00004 14.6666 7.74623 14.6666 8.66671C14.6666 9.58718 13.9204 10.3334 12.9999 10.3334H11.9999V11.4667C11.9999 12.5868 11.9999 13.1469 11.7819 13.5747C11.5902 13.951 11.2842 14.257 10.9079 14.4487C10.4801 14.6667 9.92002 14.6667 8.79992 14.6667H8.33325V13.5C8.33325 12.6716 7.66168 12 6.83325 12C6.00483 12 5.33325 12.6716 5.33325 13.5V14.6667H4.53325C3.41315 14.6667 2.85309 14.6667 2.42527 14.4487C2.04895 14.257 1.74299 13.951 1.55124 13.5747C1.33325 13.1469 1.33325 12.5868 1.33325 11.4667V10.3334H2.33325C3.25373 10.3334 3.99992 9.58718 3.99992 8.66671C3.99992 7.74623 3.25373 7.00004 2.33325 7.00004H1.33325C1.33325 6.06816 1.33325 5.60222 1.48549 5.23467C1.68848 4.74462 2.07783 4.35527 2.56789 4.15228C2.93543 4.00004 3.40137 4.00004 4.33325 4.00004H4.99992V3.00004Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_6770_9698"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "PuzzlePiece01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/PuzzlePiece01.tsx b/app/components/base/icons/src/vender/line/development/PuzzlePiece01.tsx
new file mode 100644
index 0000000..b62d37d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/PuzzlePiece01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './PuzzlePiece01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'PuzzlePiece01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/TerminalSquare.json b/app/components/base/icons/src/vender/line/development/TerminalSquare.json
new file mode 100644
index 0000000..7a78b7b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/TerminalSquare.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "terminal-square"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M7 15L10 12L7 9M13 15H17M7.8 21H16.2C17.8802 21 18.7202 21 19.362 20.673C19.9265 20.3854 20.3854 19.9265 20.673 19.362C21 18.7202 21 17.8802 21 16.2V7.8C21 6.11984 21 5.27976 20.673 4.63803C20.3854 4.07354 19.9265 3.6146 19.362 3.32698C18.7202 3 17.8802 3 16.2 3H7.8C6.11984 3 5.27976 3 4.63803 3.32698C4.07354 3.6146 3.6146 4.07354 3.32698 4.63803C3 5.27976 3 6.11984 3 7.8V16.2C3 17.8802 3 18.7202 3.32698 19.362C3.6146 19.9265 4.07354 20.3854 4.63803 20.673C5.27976 21 6.11984 21 7.8 21Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "TerminalSquare"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/TerminalSquare.tsx b/app/components/base/icons/src/vender/line/development/TerminalSquare.tsx
new file mode 100644
index 0000000..38575b9
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/TerminalSquare.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './TerminalSquare.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'TerminalSquare'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/Variable.json b/app/components/base/icons/src/vender/line/development/Variable.json
new file mode 100644
index 0000000..b7545fe
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Variable.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "variable"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.8686 1.70487C13.7055 1.37481 13.3056 1.23952 12.9756 1.40268C12.6455 1.56585 12.5102 1.9657 12.6734 2.29576C13.5225 4.01329 14.0003 5.94969 14.0003 8.00031C14.0003 10.0509 13.5225 11.9873 12.6734 13.7049C12.5102 14.0349 12.6455 14.4348 12.9756 14.5979C13.3056 14.7611 13.7055 14.6258 13.8686 14.2958C14.8066 12.3984 15.3336 10.2602 15.3336 8.00031C15.3336 5.74041 14.8066 3.60221 13.8686 1.70487Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.32724 2.29576C3.49041 1.9657 3.35511 1.56585 3.02506 1.40268C2.695 1.23952 2.29515 1.37481 2.13198 1.70487C1.19401 3.60221 0.666992 5.74041 0.666992 8.00031C0.666992 10.2602 1.19401 12.3984 2.13198 14.2958C2.29515 14.6258 2.695 14.7611 3.02506 14.5979C3.35511 14.4348 3.49041 14.0349 3.32724 13.7049C2.47815 11.9873 2.00033 10.0509 2.00033 8.00031C2.00033 5.94969 2.47815 4.01329 3.32724 2.29576Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.33274 5.84142C9.74245 5.36093 10.3415 5.0835 10.973 5.0835H11.0328C11.4009 5.0835 11.6994 5.38197 11.6994 5.75016C11.6994 6.11835 11.4009 6.41683 11.0328 6.41683H10.973C10.7333 6.41683 10.5046 6.52209 10.3473 6.70653L8.78729 8.53612L9.28122 10.2739C9.29182 10.3112 9.32425 10.3335 9.35733 10.3335H10.2867C10.6549 10.3335 10.9534 10.632 10.9534 11.0002C10.9534 11.3684 10.6549 11.6668 10.2867 11.6668H9.35733C8.72419 11.6668 8.17111 11.2451 7.99868 10.6385L7.74768 9.75536L6.7641 10.9089C6.35439 11.3894 5.75537 11.6668 5.12387 11.6668H5.06409C4.6959 11.6668 4.39742 11.3684 4.39742 11.0002C4.39742 10.632 4.6959 10.3335 5.06409 10.3335H5.12387C5.36357 10.3335 5.59225 10.2282 5.74952 10.0438L7.30963 8.21412L6.81573 6.47639C6.80513 6.43909 6.7727 6.41683 6.73962 6.41683H5.81022C5.44203 6.41683 5.14355 6.11835 5.14355 5.75016C5.14355 5.38197 5.44203 5.0835 5.81022 5.0835H6.73962C7.37276 5.0835 7.92584 5.5052 8.09826 6.11186L8.34924 6.99487L9.33274 5.84142Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Variable"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/Variable.tsx b/app/components/base/icons/src/vender/line/development/Variable.tsx
new file mode 100644
index 0000000..3f2844a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Variable.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Variable.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Variable'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/Webhooks.json b/app/components/base/icons/src/vender/line/development/Webhooks.json
new file mode 100644
index 0000000..452194d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Webhooks.json
@@ -0,0 +1,89 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "webhooks"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.0007 11.9999C12.5529 11.9999 13.0007 11.5522 13.0007 10.9999C13.0007 10.4476 12.5529 9.99993 12.0007 9.99993C11.4484 9.99993 11.0007 10.4476 11.0007 10.9999C11.0007 11.5522 11.4484 11.9999 12.0007 11.9999Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.00065 5.49993C8.55294 5.49993 9.00065 5.05222 9.00065 4.49993C9.00065 3.94765 8.55294 3.49993 8.00065 3.49993C7.44837 3.49993 7.00065 3.94765 7.00065 4.49993C7.00065 5.05222 7.44837 5.49993 8.00065 5.49993Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.00065 11.9999C4.55294 11.9999 5.00065 11.5522 5.00065 10.9999C5.00065 10.4476 4.55294 9.99993 4.00065 9.99993C3.44837 9.99993 3.00065 10.4476 3.00065 10.9999C3.00065 11.5522 3.44837 11.9999 4.00065 11.9999Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.40065 8.9666C2.6952 9.18751 2.7549 9.60538 2.53398 9.89993C2.35969 10.1323 2.24311 10.4028 2.19386 10.6891C2.14461 10.9754 2.16409 11.2693 2.25071 11.5466C2.33733 11.8239 2.48859 12.0766 2.69205 12.2839C2.8955 12.4913 3.14531 12.6473 3.4209 12.7392C3.69649 12.831 3.98996 12.8561 4.27713 12.8123C4.56431 12.7685 4.83696 12.6571 5.07262 12.4872C5.30828 12.3174 5.50021 12.0939 5.63258 11.8353C5.76495 11.5768 5.83398 11.2904 5.83398 10.9999C5.83398 10.6317 6.13246 10.3333 6.50065 10.3333H12.0007C12.3688 10.3333 12.6673 10.6317 12.6673 10.9999C12.6673 11.3681 12.3688 11.6666 12.0007 11.6666H7.09635C7.03846 11.9354 6.94561 12.1965 6.81944 12.4429C6.5908 12.8896 6.25929 13.2755 5.85223 13.5689C5.44518 13.8623 4.97424 14.0547 4.47821 14.1304C3.98219 14.2061 3.47528 14.1628 2.99926 14.0041C2.52325 13.8454 2.09175 13.5759 1.74033 13.2178C1.38891 12.8596 1.12763 12.4231 0.978025 11.9441C0.828415 11.4652 0.794759 10.9575 0.879828 10.463C0.964898 9.96855 1.16626 9.50134 1.46732 9.09993C1.68823 8.80538 2.1061 8.74568 2.40065 8.9666Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.22821 1.43134C7.70981 1.31005 8.21318 1.30373 8.69767 1.41291C9.18216 1.52208 9.63418 1.74367 10.0172 2.05979C10.4003 2.37591 10.7036 2.77769 10.9027 3.23268C11.0503 3.56999 10.8965 3.96309 10.5592 4.11069C10.2218 4.25828 9.82874 4.10449 9.68115 3.76718C9.56589 3.50377 9.39028 3.27116 9.16852 3.08814C8.94676 2.90512 8.68507 2.77683 8.40458 2.71363C8.12408 2.65042 7.83265 2.65408 7.55383 2.7243C7.27501 2.79452 7.01662 2.92933 6.79952 3.11785C6.58242 3.30637 6.41271 3.54331 6.30409 3.80953C6.19547 4.07575 6.15099 4.36379 6.17424 4.65038C6.19749 4.93696 6.28782 5.21406 6.43794 5.45929C6.58806 5.70452 6.79375 5.911 7.0384 6.06206C7.35127 6.25524 7.44865 6.66527 7.25605 6.9785L4.56855 11.3491C4.37569 11.6628 3.96509 11.7607 3.65145 11.5678C3.33781 11.375 3.2399 10.9644 3.43276 10.6507L5.80875 6.7867C5.61374 6.59953 5.44284 6.38752 5.30076 6.15541C5.04146 5.73184 4.88544 5.25321 4.84527 4.7582C4.80511 4.26319 4.88194 3.76567 5.06956 3.30584C5.25717 2.846 5.55031 2.43674 5.9253 2.11111C6.30029 1.78549 6.74661 1.55262 7.22821 1.43134Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.65145 3.93204C7.96509 3.73918 8.37569 3.83709 8.56855 4.15073L10.944 8.01384C11.1917 7.9264 11.4501 7.86984 11.7135 7.84608C12.2008 7.80211 12.6917 7.87167 13.1476 8.04931C13.6036 8.22695 14.0121 8.50783 14.3413 8.86991C14.6704 9.23199 14.9111 9.66542 15.0446 10.1362C15.1781 10.6069 15.2006 11.1022 15.1105 11.5832C15.0204 12.0641 14.82 12.5176 14.5252 12.9081C14.2303 13.2986 13.849 13.6155 13.4111 13.8338C12.9732 14.0522 12.4907 14.1661 12.0014 14.1666C11.6332 14.167 11.3344 13.8688 11.334 13.5006C11.3336 13.1324 11.6318 12.8337 12 12.8333C12.2832 12.833 12.5626 12.767 12.8161 12.6406C13.0696 12.5142 13.2904 12.3308 13.4611 12.1047C13.6318 11.8786 13.7478 11.616 13.8 11.3376C13.8522 11.0592 13.8391 10.7724 13.7618 10.4999C13.6846 10.2273 13.5452 9.97639 13.3546 9.76676C13.1641 9.55714 12.9276 9.39452 12.6636 9.29168C12.3996 9.18884 12.1154 9.14856 11.8333 9.17402C11.5511 9.19947 11.2787 9.28996 11.0375 9.43839C10.8868 9.53104 10.7056 9.56006 10.5336 9.51905C10.3616 9.47805 10.2129 9.37039 10.1203 9.21975L7.43276 4.84913C7.2399 4.53549 7.33781 4.12489 7.65145 3.93204Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Webhooks"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/development/Webhooks.tsx b/app/components/base/icons/src/vender/line/development/Webhooks.tsx
new file mode 100644
index 0000000..61dc207
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/Webhooks.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Webhooks.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Webhooks'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/development/index.ts b/app/components/base/icons/src/vender/line/development/index.ts
new file mode 100644
index 0000000..93bb195
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/development/index.ts
@@ -0,0 +1,14 @@
+export { default as ArtificialBrain } from './ArtificialBrain'
+export { default as BarChartSquare02 } from './BarChartSquare02'
+export { default as BracketsX } from './BracketsX'
+export { default as CodeBrowser } from './CodeBrowser'
+export { default as Container } from './Container'
+export { default as Database01 } from './Database01'
+export { default as Database03 } from './Database03'
+export { default as FileHeart02 } from './FileHeart02'
+export { default as GitBranch01 } from './GitBranch01'
+export { default as PromptEngineering } from './PromptEngineering'
+export { default as PuzzlePiece01 } from './PuzzlePiece01'
+export { default as TerminalSquare } from './TerminalSquare'
+export { default as Variable } from './Variable'
+export { default as Webhooks } from './Webhooks'
diff --git a/app/components/base/icons/src/vender/line/editor/AlignLeft.json b/app/components/base/icons/src/vender/line/editor/AlignLeft.json
new file mode 100644
index 0000000..ae8b150
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/AlignLeft.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "align-left"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M16 10H3M20 6H3M20 14H3M16 18H3",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AlignLeft"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/editor/AlignLeft.tsx b/app/components/base/icons/src/vender/line/editor/AlignLeft.tsx
new file mode 100644
index 0000000..6d8c83f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/AlignLeft.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AlignLeft.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AlignLeft'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/editor/BezierCurve03.json b/app/components/base/icons/src/vender/line/editor/BezierCurve03.json
new file mode 100644
index 0000000..bc87f9b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/BezierCurve03.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "bezier-curve-03"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M5.42857 3.5L2.57143 8.5M3 9.5H8.9999M9.42857 8.5L6.57143 3.5M1.8 10.5H2.2C2.48003 10.5 2.62004 10.5 2.727 10.4455C2.82108 10.3976 2.89757 10.3211 2.9455 10.227C3 10.12 3 9.98003 3 9.7V9.3C3 9.01997 3 8.87996 2.9455 8.773C2.89757 8.67892 2.82108 8.60243 2.727 8.5545C2.62004 8.5 2.48003 8.5 2.2 8.5H1.8C1.51997 8.5 1.37996 8.5 1.273 8.5545C1.17892 8.60243 1.10243 8.67892 1.0545 8.773C1 8.87996 1 9.01997 1 9.3V9.7C1 9.98003 1 10.12 1.0545 10.227C1.10243 10.3211 1.17892 10.3976 1.273 10.4455C1.37996 10.5 1.51997 10.5 1.8 10.5ZM9.8 10.5H10.2C10.48 10.5 10.62 10.5 10.727 10.4455C10.8211 10.3976 10.8976 10.3211 10.9455 10.227C11 10.12 11 9.98003 11 9.7V9.3C11 9.01997 11 8.87996 10.9455 8.773C10.8976 8.67892 10.8211 8.60243 10.727 8.5545C10.62 8.5 10.48 8.5 10.2 8.5H9.8C9.51997 8.5 9.37996 8.5 9.273 8.5545C9.17892 8.60243 9.10243 8.67892 9.0545 8.773C9 8.87996 9 9.01997 9 9.3V9.7C9 9.98003 9 10.12 9.0545 10.227C9.10243 10.3211 9.17892 10.3976 9.273 10.4455C9.37996 10.5 9.51997 10.5 9.8 10.5ZM5.8 3.5H6.2C6.48003 3.5 6.62004 3.5 6.727 3.4455C6.82108 3.39757 6.89757 3.32108 6.9455 3.227C7 3.12004 7 2.98003 7 2.7V2.3C7 2.01997 7 1.87996 6.9455 1.773C6.89757 1.67892 6.82108 1.60243 6.727 1.5545C6.62004 1.5 6.48003 1.5 6.2 1.5H5.8C5.51997 1.5 5.37996 1.5 5.273 1.5545C5.17892 1.60243 5.10243 1.67892 5.0545 1.773C5 1.87996 5 2.01997 5 2.3V2.7C5 2.98003 5 3.12004 5.0545 3.227C5.10243 3.32108 5.17892 3.39757 5.273 3.4455C5.37996 3.5 5.51997 3.5 5.8 3.5Z",
+ "stroke": "currentColor",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "BezierCurve03"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/editor/BezierCurve03.tsx b/app/components/base/icons/src/vender/line/editor/BezierCurve03.tsx
new file mode 100644
index 0000000..5bea901
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/BezierCurve03.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BezierCurve03.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BezierCurve03'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/editor/Collapse.json b/app/components/base/icons/src/vender/line/editor/Collapse.json
new file mode 100644
index 0000000..5e3cf08
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/Collapse.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon L"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Collapse"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/editor/Collapse.tsx b/app/components/base/icons/src/vender/line/editor/Collapse.tsx
new file mode 100644
index 0000000..6f43dde
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/Collapse.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Collapse.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Collapse'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/editor/Colors.json b/app/components/base/icons/src/vender/line/editor/Colors.json
new file mode 100644
index 0000000..baee8ee
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/Colors.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "colors"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M12 20.4722C13.0615 21.4223 14.4633 22 16 22C19.3137 22 22 19.3137 22 16C22 13.2331 20.1271 10.9036 17.5798 10.2102M6.42018 10.2102C3.87293 10.9036 2 13.2331 2 16C2 19.3137 4.68629 22 8 22C11.3137 22 14 19.3137 14 16C14 15.2195 13.851 14.4738 13.5798 13.7898M18 8C18 11.3137 15.3137 14 12 14C8.68629 14 6 11.3137 6 8C6 4.68629 8.68629 2 12 2C15.3137 2 18 4.68629 18 8Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Colors"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/editor/Colors.tsx b/app/components/base/icons/src/vender/line/editor/Colors.tsx
new file mode 100644
index 0000000..bdfe6d1
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/Colors.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Colors.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Colors'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/editor/ImageIndentLeft.json b/app/components/base/icons/src/vender/line/editor/ImageIndentLeft.json
new file mode 100644
index 0000000..603696d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/ImageIndentLeft.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "image-indent-left"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M21 9.25H15M21 4H3M21 14.75H15M21 20H3M4.6 16H9.4C9.96005 16 10.2401 16 10.454 15.891C10.6422 15.7951 10.7951 15.6422 10.891 15.454C11 15.2401 11 14.9601 11 14.4V9.6C11 9.03995 11 8.75992 10.891 8.54601C10.7951 8.35785 10.6422 8.20487 10.454 8.10899C10.2401 8 9.96005 8 9.4 8H4.6C4.03995 8 3.75992 8 3.54601 8.10899C3.35785 8.20487 3.20487 8.35785 3.10899 8.54601C3 8.75992 3 9.03995 3 9.6V14.4C3 14.9601 3 15.2401 3.10899 15.454C3.20487 15.6422 3.35785 15.7951 3.54601 15.891C3.75992 16 4.03995 16 4.6 16Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ImageIndentLeft"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/editor/ImageIndentLeft.tsx b/app/components/base/icons/src/vender/line/editor/ImageIndentLeft.tsx
new file mode 100644
index 0000000..957c12c
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/ImageIndentLeft.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ImageIndentLeft.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ImageIndentLeft'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/editor/LeftIndent02.json b/app/components/base/icons/src/vender/line/editor/LeftIndent02.json
new file mode 100644
index 0000000..447ae88
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/LeftIndent02.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21 9.24995H12M21 3.99995L12 3.99995M21 14.75H3M21 20H3M4.28 2.95995L8.14667 5.85995C8.43616 6.07707 8.5809 6.18563 8.63266 6.31872C8.678 6.43529 8.678 6.56462 8.63266 6.68119C8.5809 6.81427 8.43616 6.92283 8.14667 7.13995L4.28 10.04C3.86802 10.3489 3.66203 10.5034 3.48961 10.4998C3.33956 10.4967 3.19885 10.4264 3.10632 10.3082C3 10.1724 3 9.91493 3 9.39995V3.59995C3 3.08498 3 2.82749 3.10632 2.6917C3.19885 2.57354 3.33956 2.50318 3.48961 2.50006C3.66203 2.49648 3.86802 2.65097 4.28 2.95995Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "LeftIndent02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/editor/LeftIndent02.tsx b/app/components/base/icons/src/vender/line/editor/LeftIndent02.tsx
new file mode 100644
index 0000000..96ae01c
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/LeftIndent02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LeftIndent02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LeftIndent02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/editor/LetterSpacing01.json b/app/components/base/icons/src/vender/line/editor/LetterSpacing01.json
new file mode 100644
index 0000000..98b3cd6
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/LetterSpacing01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "letter-spacing-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M9 13L15 13M7 17L11.2717 7.60225C11.5031 7.09323 11.6188 6.83872 11.7791 6.75976C11.9184 6.69115 12.0816 6.69115 12.2209 6.75976C12.3812 6.83872 12.4969 7.09323 12.7283 7.60225L17 17M21 3V21M3 3L3 21",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LetterSpacing01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/editor/LetterSpacing01.tsx b/app/components/base/icons/src/vender/line/editor/LetterSpacing01.tsx
new file mode 100644
index 0000000..e6bc4ce
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/LetterSpacing01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LetterSpacing01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LetterSpacing01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/editor/TypeSquare.json b/app/components/base/icons/src/vender/line/editor/TypeSquare.json
new file mode 100644
index 0000000..195b047
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/TypeSquare.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "type-square"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M4 3.5H8M6 3.5V8.5M3.9 10.5H8.1C8.94008 10.5 9.36012 10.5 9.68099 10.3365C9.96323 10.1927 10.1927 9.96323 10.3365 9.68099C10.5 9.36012 10.5 8.94008 10.5 8.1V3.9C10.5 3.05992 10.5 2.63988 10.3365 2.31901C10.1927 2.03677 9.96323 1.8073 9.68099 1.66349C9.36012 1.5 8.94008 1.5 8.1 1.5H3.9C3.05992 1.5 2.63988 1.5 2.31901 1.66349C2.03677 1.8073 1.8073 2.03677 1.66349 2.31901C1.5 2.63988 1.5 3.05992 1.5 3.9V8.1C1.5 8.94008 1.5 9.36012 1.66349 9.68099C1.8073 9.96323 2.03677 10.1927 2.31901 10.3365C2.63988 10.5 3.05992 10.5 3.9 10.5Z",
+ "stroke": "currentColor",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "TypeSquare"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/editor/TypeSquare.tsx b/app/components/base/icons/src/vender/line/editor/TypeSquare.tsx
new file mode 100644
index 0000000..5149e12
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/TypeSquare.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './TypeSquare.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'TypeSquare'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/editor/index.ts b/app/components/base/icons/src/vender/line/editor/index.ts
new file mode 100644
index 0000000..b31c42e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/editor/index.ts
@@ -0,0 +1,8 @@
+export { default as AlignLeft } from './AlignLeft'
+export { default as BezierCurve03 } from './BezierCurve03'
+export { default as Collapse } from './Collapse'
+export { default as Colors } from './Colors'
+export { default as ImageIndentLeft } from './ImageIndentLeft'
+export { default as LeftIndent02 } from './LeftIndent02'
+export { default as LetterSpacing01 } from './LetterSpacing01'
+export { default as TypeSquare } from './TypeSquare'
diff --git a/app/components/base/icons/src/vender/line/education/BookOpen01.json b/app/components/base/icons/src/vender/line/education/BookOpen01.json
new file mode 100644
index 0000000..bfa7941
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/education/BookOpen01.json
@@ -0,0 +1,49 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "book-open-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Fill",
+ "opacity": "0.12",
+ "d": "M1 3.1C1 2.53995 1 2.25992 1.10899 2.04601C1.20487 1.85785 1.35785 1.70487 1.54601 1.60899C1.75992 1.5 2.03995 1.5 2.6 1.5H2.8C3.9201 1.5 4.48016 1.5 4.90798 1.71799C5.28431 1.90973 5.59027 2.21569 5.78201 2.59202C6 3.01984 6 3.5799 6 4.7V10.5L5.94997 10.425C5.60265 9.90398 5.42899 9.64349 5.19955 9.45491C4.99643 9.28796 4.76238 9.1627 4.5108 9.0863C4.22663 9 3.91355 9 3.28741 9H2.6C2.03995 9 1.75992 9 1.54601 8.89101C1.35785 8.79513 1.20487 8.64215 1.10899 8.45399C1 8.24008 1 7.96005 1 7.4V3.1Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M6 10.5L5.94997 10.425C5.60265 9.90398 5.42899 9.64349 5.19955 9.45491C4.99643 9.28796 4.76238 9.1627 4.5108 9.0863C4.22663 9 3.91355 9 3.28741 9H2.6C2.03995 9 1.75992 9 1.54601 8.89101C1.35785 8.79513 1.20487 8.64215 1.10899 8.45399C1 8.24008 1 7.96005 1 7.4V3.1C1 2.53995 1 2.25992 1.10899 2.04601C1.20487 1.85785 1.35785 1.70487 1.54601 1.60899C1.75992 1.5 2.03995 1.5 2.6 1.5H2.8C3.9201 1.5 4.48016 1.5 4.90798 1.71799C5.28431 1.90973 5.59027 2.21569 5.78201 2.59202C6 3.01984 6 3.5799 6 4.7M6 10.5V4.7M6 10.5L6.05003 10.425C6.39735 9.90398 6.57101 9.64349 6.80045 9.45491C7.00357 9.28796 7.23762 9.1627 7.4892 9.0863C7.77337 9 8.08645 9 8.71259 9H9.4C9.96005 9 10.2401 9 10.454 8.89101C10.6422 8.79513 10.7951 8.64215 10.891 8.45399C11 8.24008 11 7.96005 11 7.4V3.1C11 2.53995 11 2.25992 10.891 2.04601C10.7951 1.85785 10.6422 1.70487 10.454 1.60899C10.2401 1.5 9.96005 1.5 9.4 1.5H9.2C8.07989 1.5 7.51984 1.5 7.09202 1.71799C6.71569 1.90973 6.40973 2.21569 6.21799 2.59202C6 3.01984 6 3.5799 6 4.7",
+ "stroke": "currentColor",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "BookOpen01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/education/BookOpen01.tsx b/app/components/base/icons/src/vender/line/education/BookOpen01.tsx
new file mode 100644
index 0000000..b362119
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/education/BookOpen01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BookOpen01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BookOpen01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/education/index.ts b/app/components/base/icons/src/vender/line/education/index.ts
new file mode 100644
index 0000000..db44daf
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/education/index.ts
@@ -0,0 +1 @@
+export { default as BookOpen01 } from './BookOpen01'
diff --git a/app/components/base/icons/src/vender/line/files/Clipboard.json b/app/components/base/icons/src/vender/line/files/Clipboard.json
new file mode 100644
index 0000000..f256747
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/Clipboard.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M16 4C16.93 4 17.395 4 17.7765 4.10222C18.8117 4.37962 19.6204 5.18827 19.8978 6.22354C20 6.60504 20 7.07003 20 8V17.2C20 18.8802 20 19.7202 19.673 20.362C19.3854 20.9265 18.9265 21.3854 18.362 21.673C17.7202 22 16.8802 22 15.2 22H8.8C7.11984 22 6.27976 22 5.63803 21.673C5.07354 21.3854 4.6146 20.9265 4.32698 20.362C4 19.7202 4 18.8802 4 17.2V8C4 7.07003 4 6.60504 4.10222 6.22354C4.37962 5.18827 5.18827 4.37962 6.22354 4.10222C6.60504 4 7.07003 4 8 4M9.6 6H14.4C14.9601 6 15.2401 6 15.454 5.89101C15.6422 5.79513 15.7951 5.64215 15.891 5.45399C16 5.24008 16 4.96005 16 4.4V3.6C16 3.03995 16 2.75992 15.891 2.54601C15.7951 2.35785 15.6422 2.20487 15.454 2.10899C15.2401 2 14.9601 2 14.4 2H9.6C9.03995 2 8.75992 2 8.54601 2.10899C8.35785 2.20487 8.20487 2.35785 8.10899 2.54601C8 2.75992 8 3.03995 8 3.6V4.4C8 4.96005 8 5.24008 8.10899 5.45399C8.20487 5.64215 8.35785 5.79513 8.54601 5.89101C8.75992 6 9.03995 6 9.6 6Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Clipboard"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/Clipboard.tsx b/app/components/base/icons/src/vender/line/files/Clipboard.tsx
new file mode 100644
index 0000000..c49d15d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/Clipboard.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Clipboard.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Clipboard'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/ClipboardCheck.json b/app/components/base/icons/src/vender/line/files/ClipboardCheck.json
new file mode 100644
index 0000000..273b115
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/ClipboardCheck.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M16 4C16.93 4 17.395 4 17.7765 4.10222C18.8117 4.37962 19.6204 5.18827 19.8978 6.22354C20 6.60504 20 7.07003 20 8V17.2C20 18.8802 20 19.7202 19.673 20.362C19.3854 20.9265 18.9265 21.3854 18.362 21.673C17.7202 22 16.8802 22 15.2 22H8.8C7.11984 22 6.27976 22 5.63803 21.673C5.07354 21.3854 4.6146 20.9265 4.32698 20.362C4 19.7202 4 18.8802 4 17.2V8C4 7.07003 4 6.60504 4.10222 6.22354C4.37962 5.18827 5.18827 4.37962 6.22354 4.10222C6.60504 4 7.07003 4 8 4M9 15L11 17L15.5 12.5M9.6 6H14.4C14.9601 6 15.2401 6 15.454 5.89101C15.6422 5.79513 15.7951 5.64215 15.891 5.45399C16 5.24008 16 4.96005 16 4.4V3.6C16 3.03995 16 2.75992 15.891 2.54601C15.7951 2.35785 15.6422 2.20487 15.454 2.10899C15.2401 2 14.9601 2 14.4 2H9.6C9.03995 2 8.75992 2 8.54601 2.10899C8.35785 2.20487 8.20487 2.35785 8.10899 2.54601C8 2.75992 8 3.03995 8 3.6V4.4C8 4.96005 8 5.24008 8.10899 5.45399C8.20487 5.64215 8.35785 5.79513 8.54601 5.89101C8.75992 6 9.03995 6 9.6 6Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ClipboardCheck"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/ClipboardCheck.tsx b/app/components/base/icons/src/vender/line/files/ClipboardCheck.tsx
new file mode 100644
index 0000000..586b55e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/ClipboardCheck.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ClipboardCheck.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ClipboardCheck'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/File02.json b/app/components/base/icons/src/vender/line/files/File02.json
new file mode 100644
index 0000000..110765a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/File02.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_2",
+ "d": "M9.33366 7.3335H5.33366M6.66699 10.0002H5.33366M10.667 4.66683H5.33366M13.3337 4.5335V11.4668C13.3337 12.5869 13.3337 13.147 13.1157 13.5748C12.9239 13.9511 12.618 14.2571 12.2416 14.4488C11.8138 14.6668 11.2538 14.6668 10.1337 14.6668H5.86699C4.74689 14.6668 4.18683 14.6668 3.75901 14.4488C3.38269 14.2571 3.07673 13.9511 2.88498 13.5748C2.66699 13.147 2.66699 12.5869 2.66699 11.4668V4.5335C2.66699 3.41339 2.66699 2.85334 2.88498 2.42552C3.07673 2.04919 3.38269 1.74323 3.75901 1.55148C4.18683 1.3335 4.74689 1.3335 5.86699 1.3335H10.1337C11.2538 1.3335 11.8138 1.3335 12.2416 1.55148C12.618 1.74323 12.9239 2.04919 13.1157 2.42552C13.3337 2.85334 13.3337 3.41339 13.3337 4.5335Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "File02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/File02.tsx b/app/components/base/icons/src/vender/line/files/File02.tsx
new file mode 100644
index 0000000..8c53308
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/File02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './File02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'File02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/FileArrow01.json b/app/components/base/icons/src/vender/line/files/FileArrow01.json
new file mode 100644
index 0000000..189f081
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileArrow01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "file-arrow-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M3.33333 12.333C3.33333 12.6426 3.33333 12.7974 3.35044 12.9274C3.4686 13.8249 4.17481 14.5311 5.07228 14.6492C5.20225 14.6663 5.35705 14.6663 5.66667 14.6663H10.8C11.9201 14.6663 12.4802 14.6663 12.908 14.4484C13.2843 14.2566 13.5903 13.9506 13.782 13.5743C14 13.1465 14 12.5864 14 11.4663V6.65849C14 6.16931 14 5.92472 13.9447 5.69454C13.8957 5.49047 13.8149 5.29538 13.7053 5.11644C13.5816 4.91461 13.4086 4.74165 13.0627 4.39575L10.9373 2.27027C10.5914 1.92436 10.4184 1.75141 10.2166 1.62773C10.0376 1.51807 9.84254 1.43726 9.63846 1.38827C9.40829 1.33301 9.1637 1.33301 8.67452 1.33301H5.66667C5.35705 1.33301 5.20225 1.33301 5.07228 1.35012C4.17481 1.46827 3.4686 2.17449 3.35044 3.07196M5.33333 5.99967L7.33333 7.99967M7.33333 7.99967L5.33333 9.99967M7.33333 7.99967H2",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "FileArrow01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/FileArrow01.tsx b/app/components/base/icons/src/vender/line/files/FileArrow01.tsx
new file mode 100644
index 0000000..c0f4207
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileArrow01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileArrow01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileArrow01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/FileCheck02.json b/app/components/base/icons/src/vender/line/files/FileCheck02.json
new file mode 100644
index 0000000..9a2e063
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileCheck02.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "file-check-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M13.3337 8.33301V4.53301C13.3337 3.4129 13.3337 2.85285 13.1157 2.42503C12.9239 2.0487 12.618 1.74274 12.2416 1.55099C11.8138 1.33301 11.2538 1.33301 10.1337 1.33301H5.86699C4.74689 1.33301 4.18683 1.33301 3.75901 1.55099C3.38269 1.74274 3.07673 2.0487 2.88498 2.42503C2.66699 2.85285 2.66699 3.4129 2.66699 4.53301V11.4663C2.66699 12.5864 2.66699 13.1465 2.88498 13.5743C3.07673 13.9506 3.38269 14.2566 3.75901 14.4484C4.18683 14.6663 4.74689 14.6663 5.86699 14.6663H8.00033M9.33366 7.33301H5.33366M6.66699 9.99967H5.33366M10.667 4.66634H5.33366M9.66699 12.6663L11.0003 13.9997L14.0003 10.9997",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "FileCheck02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/FileCheck02.tsx b/app/components/base/icons/src/vender/line/files/FileCheck02.tsx
new file mode 100644
index 0000000..0bb51a3
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileCheck02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileCheck02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileCheck02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/FileDownload02.json b/app/components/base/icons/src/vender/line/files/FileDownload02.json
new file mode 100644
index 0000000..a0dccc2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileDownload02.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20 12.5V6.8C20 5.11984 20 4.27976 19.673 3.63803C19.3854 3.07354 18.9265 2.6146 18.362 2.32698C17.7202 2 16.8802 2 15.2 2H8.8C7.11984 2 6.27976 2 5.63803 2.32698C5.07354 2.6146 4.6146 3.07354 4.32698 3.63803C4 4.27976 4 5.11984 4 6.8V17.2C4 18.8802 4 19.7202 4.32698 20.362C4.6146 20.9265 5.07354 21.3854 5.63803 21.673C6.27976 22 7.1198 22 8.79986 22H12.5M14 11H8M10 15H8M16 7H8M15 19L18 22M18 22L21 19M18 22V16",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "FileDownload02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/FileDownload02.tsx b/app/components/base/icons/src/vender/line/files/FileDownload02.tsx
new file mode 100644
index 0000000..5dac794
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileDownload02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileDownload02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileDownload02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/FilePlus01.json b/app/components/base/icons/src/vender/line/files/FilePlus01.json
new file mode 100644
index 0000000..67d8784
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FilePlus01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "file-plus-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M13.3332 6.99967V4.53301C13.3332 3.4129 13.3332 2.85285 13.1152 2.42503C12.9234 2.0487 12.6175 1.74274 12.2412 1.55099C11.8133 1.33301 11.2533 1.33301 10.1332 1.33301H5.8665C4.7464 1.33301 4.18635 1.33301 3.75852 1.55099C3.3822 1.74274 3.07624 2.0487 2.88449 2.42503C2.6665 2.85285 2.6665 3.4129 2.6665 4.53301V11.4663C2.6665 12.5864 2.6665 13.1465 2.88449 13.5743C3.07624 13.9506 3.3822 14.2566 3.75852 14.4484C4.18635 14.6663 4.7464 14.6663 5.8665 14.6663H7.99984M11.9998 13.9997V9.99967M9.99984 11.9997H13.9998",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "FilePlus01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/FilePlus01.tsx b/app/components/base/icons/src/vender/line/files/FilePlus01.tsx
new file mode 100644
index 0000000..d33f4b5
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FilePlus01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FilePlus01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FilePlus01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/FilePlus02.json b/app/components/base/icons/src/vender/line/files/FilePlus02.json
new file mode 100644
index 0000000..447b1e9
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FilePlus02.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.3333 6.99992V4.53325C13.3333 3.41315 13.3333 2.85309 13.1153 2.42527C12.9236 2.04895 12.6176 1.74299 12.2413 1.55124C11.8135 1.33325 11.2534 1.33325 10.1333 1.33325H5.86666C4.74655 1.33325 4.1865 1.33325 3.75868 1.55124C3.38235 1.74299 3.07639 2.04895 2.88464 2.42527C2.66666 2.85309 2.66666 3.41315 2.66666 4.53325V11.4666C2.66666 12.5867 2.66666 13.1467 2.88464 13.5746C3.07639 13.9509 3.38235 14.2569 3.75868 14.4486C4.1865 14.6666 4.74655 14.6666 5.86666 14.6666H7.99999M9.33332 7.33325H5.33332M6.66666 9.99992H5.33332M10.6667 4.66659H5.33332M12 13.9999V9.99992M9.99999 11.9999H14",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "FilePlus02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/FilePlus02.tsx b/app/components/base/icons/src/vender/line/files/FilePlus02.tsx
new file mode 100644
index 0000000..5405325
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FilePlus02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FilePlus02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FilePlus02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/FileText.json b/app/components/base/icons/src/vender/line/files/FileText.json
new file mode 100644
index 0000000..536bc45
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileText.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "file-text"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M14 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579C4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142C4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V8M14 2L20 8M14 2V8H20M16 13H8M16 17H8M10 9H8",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "FileText"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/FileText.tsx b/app/components/base/icons/src/vender/line/files/FileText.tsx
new file mode 100644
index 0000000..9c64082
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileText'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/FileUpload.json b/app/components/base/icons/src/vender/line/files/FileUpload.json
new file mode 100644
index 0000000..5dc2ec1
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileUpload.json
@@ -0,0 +1,52 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "file-upload"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M20 10.5V6.8C20 5.11984 20 4.27976 19.673 3.63803C19.3854 3.07354 18.9265 2.6146 18.362 2.32698C17.7202 2 16.8802 2 15.2 2H8.8C7.11984 2 6.27976 2 5.63803 2.32698C5.07354 2.6146 4.6146 3.07354 4.32698 3.63803C4 4.27976 4 5.11984 4 6.8V17.2C4 18.8802 4 19.7202 4.32698 20.362C4.6146 20.9265 5.07354 21.3854 5.63803 21.673C6.27976 22 7.11984 22 8.8 22H12M14 11H8M10 15H8M16 7H8",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_2",
+ "d": "M15 18L18 15M18 15L21 18M18 15L18 21",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "FileUpload"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/FileUpload.tsx b/app/components/base/icons/src/vender/line/files/FileUpload.tsx
new file mode 100644
index 0000000..2e3143d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/FileUpload.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileUpload.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileUpload'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/Folder.json b/app/components/base/icons/src/vender/line/files/Folder.json
new file mode 100644
index 0000000..6bbc438
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/Folder.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "folder"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M12.8327 11.0833C12.8327 11.3928 12.7098 11.6895 12.491 11.9083C12.2722 12.1271 11.9754 12.25 11.666 12.25H2.33268C2.02326 12.25 1.72652 12.1271 1.50772 11.9083C1.28893 11.6895 1.16602 11.3928 1.16602 11.0833V2.91667C1.16602 2.60725 1.28893 2.3105 1.50772 2.09171C1.72652 1.87292 2.02326 1.75 2.33268 1.75H5.24935L6.41602 3.5H11.666C11.9754 3.5 12.2722 3.62292 12.491 3.84171C12.7098 4.0605 12.8327 4.35725 12.8327 4.66667V11.0833Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Folder"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/files/Folder.tsx b/app/components/base/icons/src/vender/line/files/Folder.tsx
new file mode 100644
index 0000000..e7a3fdf
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/Folder.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Folder.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Folder'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/files/index.ts b/app/components/base/icons/src/vender/line/files/index.ts
new file mode 100644
index 0000000..4c0ddc2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/files/index.ts
@@ -0,0 +1,11 @@
+export { default as ClipboardCheck } from './ClipboardCheck'
+export { default as Clipboard } from './Clipboard'
+export { default as File02 } from './File02'
+export { default as FileArrow01 } from './FileArrow01'
+export { default as FileCheck02 } from './FileCheck02'
+export { default as FileDownload02 } from './FileDownload02'
+export { default as FilePlus01 } from './FilePlus01'
+export { default as FilePlus02 } from './FilePlus02'
+export { default as FileText } from './FileText'
+export { default as FileUpload } from './FileUpload'
+export { default as Folder } from './Folder'
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/Balance.json b/app/components/base/icons/src/vender/line/financeAndECommerce/Balance.json
new file mode 100644
index 0000000..c04fcda
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/Balance.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12 3V20M12 20H6.99999M12 20H17M2.99999 6H7.52785C7.83834 6 8.14457 5.92771 8.42228 5.78885L9.5777 5.21115C9.85541 5.07229 10.1616 5 10.4721 5H13.5279C13.8384 5 14.1446 5.07229 14.4223 5.21115L15.5777 5.78885C15.8554 5.92771 16.1616 6 16.4721 6H21M5.49999 6L3.02043 13.4387C2.71807 14.3458 3.08918 15.3834 4.0053 15.657C5.0117 15.9577 5.98828 15.9577 6.99468 15.657C7.9108 15.3834 8.28191 14.3457 7.97955 13.4387L5.49999 6ZM18.5 6L16.0204 13.4387C15.7181 14.3458 16.0892 15.3834 17.0053 15.657C18.0117 15.9577 18.9883 15.9577 19.9947 15.657C20.9108 15.3834 21.2819 14.3457 20.9796 13.4387L18.5 6Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Balance"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/Balance.tsx b/app/components/base/icons/src/vender/line/financeAndECommerce/Balance.tsx
new file mode 100644
index 0000000..f2d4b1b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/Balance.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Balance.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Balance'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/CoinsStacked01.json b/app/components/base/icons/src/vender/line/financeAndECommerce/CoinsStacked01.json
new file mode 100644
index 0000000..8a97190
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/CoinsStacked01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "coins-stacked-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M12 17C12 19.7614 14.2386 22 17 22C19.7614 22 22 19.7614 22 17C22 14.2386 19.7614 12 17 12C14.2386 12 12 14.2386 12 17ZM12 17C12 15.8742 12.3721 14.8353 13 13.9995V5M12 17C12 17.8254 12.2 18.604 12.5541 19.2901C11.7117 20.0018 9.76584 20.5 7.5 20.5C4.46243 20.5 2 19.6046 2 18.5V5M13 5C13 6.10457 10.5376 7 7.5 7C4.46243 7 2 6.10457 2 5M13 5C13 3.89543 10.5376 3 7.5 3C4.46243 3 2 3.89543 2 5M2 14C2 15.1046 4.46243 16 7.5 16C9.689 16 11.5793 15.535 12.4646 14.8618M13 9.5C13 10.6046 10.5376 11.5 7.5 11.5C4.46243 11.5 2 10.6046 2 9.5",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "CoinsStacked01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/CoinsStacked01.tsx b/app/components/base/icons/src/vender/line/financeAndECommerce/CoinsStacked01.tsx
new file mode 100644
index 0000000..7eb20ed
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/CoinsStacked01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './CoinsStacked01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'CoinsStacked01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/GoldCoin.json b/app/components/base/icons/src/vender/line/financeAndECommerce/GoldCoin.json
new file mode 100644
index 0000000..f10b5fa
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/GoldCoin.json
@@ -0,0 +1,120 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_7056_1808)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.00003 4.82855L8.93639 6.72613L11.0303 7.03037L9.51518 8.50734L9.87276 10.5928L8.00003 9.60795L6.1273 10.5928L6.48488 8.50734L4.96973 7.03037L7.06367 6.72613L8.00003 4.82855Z",
+ "stroke": "currentColor",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.00016 14.6666C11.6821 14.6666 14.6668 11.6819 14.6668 7.99998C14.6668 4.31808 11.6821 1.33331 8.00016 1.33331C4.31826 1.33331 1.3335 4.31808 1.3335 7.99998C1.3335 11.6819 4.31826 14.6666 8.00016 14.6666Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.0001 12.8485C8.33482 12.8485 8.60616 12.5771 8.60616 12.2424C8.60616 11.9077 8.33482 11.6364 8.0001 11.6364C7.66539 11.6364 7.39404 11.9077 7.39404 12.2424C7.39404 12.5771 7.66539 12.8485 8.0001 12.8485Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.0348 9.91702C12.3695 9.91702 12.6408 9.64567 12.6408 9.31096C12.6408 8.97624 12.3695 8.7049 12.0348 8.7049C11.7001 8.7049 11.4287 8.97624 11.4287 9.31096C11.4287 9.64567 11.7001 9.91702 12.0348 9.91702Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.4933 5.17391C10.828 5.17391 11.0993 4.90257 11.0993 4.56785C11.0993 4.23313 10.828 3.96179 10.4933 3.96179C10.1585 3.96179 9.88721 4.23313 9.88721 4.56785C9.88721 4.90257 10.1585 5.17391 10.4933 5.17391Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.50645 5.17391C5.84117 5.17391 6.11251 4.90257 6.11251 4.56785C6.11251 4.23313 5.84117 3.96179 5.50645 3.96179C5.17173 3.96179 4.90039 4.23313 4.90039 4.56785C4.90039 4.90257 5.17173 5.17391 5.50645 5.17391Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.96544 9.91702C4.30015 9.91702 4.5715 9.64567 4.5715 9.31096C4.5715 8.97624 4.30015 8.7049 3.96544 8.7049C3.63072 8.7049 3.35938 8.97624 3.35938 9.31096C3.35938 9.64567 3.63072 9.91702 3.96544 9.91702Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_7056_1808"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "GoldCoin"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/GoldCoin.tsx b/app/components/base/icons/src/vender/line/financeAndECommerce/GoldCoin.tsx
new file mode 100644
index 0000000..d912a6b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/GoldCoin.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './GoldCoin.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'GoldCoin'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/ReceiptList.json b/app/components/base/icons/src/vender/line/financeAndECommerce/ReceiptList.json
new file mode 100644
index 0000000..8e9c070
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/ReceiptList.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.55556 8.33333H12M15.5556 8.33333H16.4444M7.55556 11.8889H12M15.5556 11.8889H16.4444M7.55556 15.4444H12M15.5556 15.4444H16.4444M20 21.6667V5C20 3.89543 19.1046 3 18 3H6C4.89543 3 4 3.89543 4 5V21.6667L6.66667 19.8889L9.33333 21.6667L12 19.8889L14.6667 21.6667L17.3333 19.8889L20 21.6667Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ReceiptList"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/ReceiptList.tsx b/app/components/base/icons/src/vender/line/financeAndECommerce/ReceiptList.tsx
new file mode 100644
index 0000000..e96aced
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/ReceiptList.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ReceiptList.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ReceiptList'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/Tag01.json b/app/components/base/icons/src/vender/line/financeAndECommerce/Tag01.json
new file mode 100644
index 0000000..b6f838d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/Tag01.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon",
+ "clip-path": "url(#clip0_17795_9693)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_2",
+ "d": "M4.66699 4.6665H4.67283M1.16699 3.03317L1.16699 5.6433C1.16699 5.92866 1.16699 6.07134 1.19923 6.20561C1.22781 6.32465 1.27495 6.43845 1.33891 6.54284C1.41106 6.66057 1.51195 6.76146 1.71373 6.96324L6.18709 11.4366C6.88012 12.1296 7.22664 12.4761 7.62621 12.606C7.97769 12.7202 8.35629 12.7202 8.70777 12.606C9.10735 12.4761 9.45386 12.1296 10.1469 11.4366L11.4371 10.1464C12.1301 9.45337 12.4766 9.10686 12.6065 8.70728C12.7207 8.35581 12.7207 7.9772 12.6065 7.62572C12.4766 7.22615 12.1301 6.87963 11.4371 6.1866L6.96372 1.71324C6.76195 1.51146 6.66106 1.41057 6.54332 1.33842C6.43894 1.27446 6.32514 1.22732 6.20609 1.19874C6.07183 1.1665 5.92915 1.1665 5.64379 1.1665L3.03366 1.1665C2.38026 1.1665 2.05357 1.1665 1.804 1.29366C1.58448 1.40552 1.406 1.58399 1.29415 1.80352C1.16699 2.05308 1.16699 2.37978 1.16699 3.03317ZM4.95866 4.6665C4.95866 4.82759 4.82808 4.95817 4.66699 4.95817C4.50591 4.95817 4.37533 4.82759 4.37533 4.6665C4.37533 4.50542 4.50591 4.37484 4.66699 4.37484C4.82808 4.37484 4.95866 4.50542 4.95866 4.6665Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_17795_9693"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Tag01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/Tag01.tsx b/app/components/base/icons/src/vender/line/financeAndECommerce/Tag01.tsx
new file mode 100644
index 0000000..c8b1ce2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/Tag01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Tag01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Tag01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/Tag03.json b/app/components/base/icons/src/vender/line/financeAndECommerce/Tag03.json
new file mode 100644
index 0000000..ef0753b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/Tag03.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "tag-03"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M14 7.3335L8.93726 2.27075C8.59135 1.92485 8.4184 1.7519 8.21657 1.62822C8.03762 1.51856 7.84254 1.43775 7.63846 1.38876C7.40829 1.3335 7.16369 1.3335 6.67452 1.3335L4 1.3335M2 5.80016L2 7.11651C2 7.44263 2 7.60569 2.03684 7.75914C2.0695 7.89519 2.12337 8.02525 2.19648 8.14454C2.27894 8.2791 2.39424 8.3944 2.62484 8.625L7.82484 13.825C8.35286 14.353 8.61687 14.617 8.92131 14.716C9.1891 14.803 9.47757 14.803 9.74536 14.716C10.0498 14.617 10.3138 14.353 10.8418 13.825L12.4915 12.1753C13.0195 11.6473 13.2835 11.3833 13.3825 11.0789C13.4695 10.8111 13.4695 10.5226 13.3825 10.2548C13.2835 9.95037 13.0195 9.68636 12.4915 9.15834L7.62484 4.29167C7.39424 4.06107 7.27894 3.94577 7.14438 3.86331C7.02508 3.7902 6.89502 3.73633 6.75898 3.70367C6.60553 3.66683 6.44247 3.66683 6.11634 3.66683H4.13333C3.3866 3.66683 3.01323 3.66683 2.72801 3.81215C2.47713 3.93999 2.27316 4.14396 2.14532 4.39484C2 4.68006 2 5.05343 2 5.80016Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Tag03"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/Tag03.tsx b/app/components/base/icons/src/vender/line/financeAndECommerce/Tag03.tsx
new file mode 100644
index 0000000..c0ec1bb
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/Tag03.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Tag03.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Tag03'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/financeAndECommerce/index.ts b/app/components/base/icons/src/vender/line/financeAndECommerce/index.ts
new file mode 100644
index 0000000..2223daa
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/financeAndECommerce/index.ts
@@ -0,0 +1,6 @@
+export { default as Balance } from './Balance'
+export { default as CoinsStacked01 } from './CoinsStacked01'
+export { default as GoldCoin } from './GoldCoin'
+export { default as ReceiptList } from './ReceiptList'
+export { default as Tag01 } from './Tag01'
+export { default as Tag03 } from './Tag03'
diff --git a/app/components/base/icons/src/vender/line/general/AtSign.json b/app/components/base/icons/src/vender/line/general/AtSign.json
new file mode 100644
index 0000000..0722d8f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/AtSign.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "at-sign",
+ "clip-path": "url(#clip0_8902_1909)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M10.6666 5.33333V8.66666C10.6666 9.19709 10.8773 9.7058 11.2524 10.0809C11.6275 10.4559 12.1362 10.6667 12.6666 10.6667C13.197 10.6667 13.7057 10.4559 14.0808 10.0809C14.4559 9.7058 14.6666 9.19709 14.6666 8.66666V7.99999C14.6665 6.49535 14.1574 5.03498 13.2221 3.85635C12.2868 2.67772 10.9803 1.85014 9.51502 1.50819C8.04974 1.16624 6.51188 1.33002 5.15149 1.9729C3.7911 2.61579 2.68819 3.69996 2.0221 5.04914C1.356 6.39832 1.1659 7.93315 1.4827 9.40407C1.7995 10.875 2.60458 12.1955 3.76701 13.1508C4.92945 14.1062 6.38088 14.6402 7.8853 14.6661C9.38973 14.692 10.8587 14.2082 12.0533 13.2933M10.6666 7.99999C10.6666 9.47275 9.47269 10.6667 7.99993 10.6667C6.52717 10.6667 5.33326 9.47275 5.33326 7.99999C5.33326 6.52723 6.52717 5.33333 7.99993 5.33333C9.47269 5.33333 10.6666 6.52723 10.6666 7.99999Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_8902_1909"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AtSign"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/AtSign.tsx b/app/components/base/icons/src/vender/line/general/AtSign.tsx
new file mode 100644
index 0000000..44c972b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/AtSign.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AtSign.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AtSign'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Bookmark.json b/app/components/base/icons/src/vender/line/general/Bookmark.json
new file mode 100644
index 0000000..1b6e517
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Bookmark.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5 7.8C5 6.11984 5 5.27976 5.32698 4.63803C5.6146 4.07354 6.07354 3.6146 6.63803 3.32698C7.27976 3 8.11984 3 9.8 3H14.2C15.8802 3 16.7202 3 17.362 3.32698C17.9265 3.6146 18.3854 4.07354 18.673 4.63803C19 5.27976 19 6.11984 19 7.8V21L12 17L5 21V7.8Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Bookmark"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Bookmark.tsx b/app/components/base/icons/src/vender/line/general/Bookmark.tsx
new file mode 100644
index 0000000..6708376
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Bookmark.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Bookmark.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Bookmark'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Check.json b/app/components/base/icons/src/vender/line/general/Check.json
new file mode 100644
index 0000000..eae3438
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Check.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "check"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M13.3334 4L6.00008 11.3333L2.66675 8",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Check"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Check.tsx b/app/components/base/icons/src/vender/line/general/Check.tsx
new file mode 100644
index 0000000..babd202
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Check.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Check.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Check'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/CheckDone01.json b/app/components/base/icons/src/vender/line/general/CheckDone01.json
new file mode 100644
index 0000000..85355f9
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/CheckDone01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "check-done-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M6 15L8 17L12.5 12.5M8 8V5.2C8 4.0799 8 3.51984 8.21799 3.09202C8.40973 2.71569 8.71569 2.40973 9.09202 2.21799C9.51984 2 10.0799 2 11.2 2H18.8C19.9201 2 20.4802 2 20.908 2.21799C21.2843 2.40973 21.5903 2.71569 21.782 3.09202C22 3.51984 22 4.0799 22 5.2V12.8C22 13.9201 22 14.4802 21.782 14.908C21.5903 15.2843 21.2843 15.5903 20.908 15.782C20.4802 16 19.9201 16 18.8 16H16M5.2 22H12.8C13.9201 22 14.4802 22 14.908 21.782C15.2843 21.5903 15.5903 21.2843 15.782 20.908C16 20.4802 16 19.9201 16 18.8V11.2C16 10.0799 16 9.51984 15.782 9.09202C15.5903 8.71569 15.2843 8.40973 14.908 8.21799C14.4802 8 13.9201 8 12.8 8H5.2C4.0799 8 3.51984 8 3.09202 8.21799C2.71569 8.40973 2.40973 8.71569 2.21799 9.09202C2 9.51984 2 10.0799 2 11.2V18.8C2 19.9201 2 20.4802 2.21799 20.908C2.40973 21.2843 2.71569 21.5903 3.09202 21.782C3.51984 22 4.07989 22 5.2 22Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "CheckDone01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/CheckDone01.tsx b/app/components/base/icons/src/vender/line/general/CheckDone01.tsx
new file mode 100644
index 0000000..c7e7d80
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/CheckDone01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './CheckDone01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'CheckDone01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/ChecklistSquare.json b/app/components/base/icons/src/vender/line/general/ChecklistSquare.json
new file mode 100644
index 0000000..737c696
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/ChecklistSquare.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "32",
+ "viewBox": "0 0 32 32",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "checklist-square"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M9.7823 11.9146C9.32278 11.6082 8.70191 11.7324 8.39554 12.1919C8.08918 12.6514 8.21333 13.2723 8.67285 13.5787L9.7823 11.9146ZM10.9151 13.8717L10.3603 14.7037C10.8019 14.9982 11.3966 14.8963 11.7151 14.4717L10.9151 13.8717ZM14.5226 10.7284C14.8539 10.2865 14.7644 9.65973 14.3225 9.32836C13.8807 8.99699 13.2539 9.08653 12.9225 9.52836L14.5226 10.7284ZM19.3333 11C18.781 11 18.3333 11.4477 18.3333 12C18.3333 12.5523 18.781 13 19.3333 13V11ZM22 13C22.5523 13 23 12.5523 23 12C23 11.4477 22.5523 11 22 11V13ZM19.3333 19C18.781 19 18.3333 19.4477 18.3333 20C18.3333 20.5523 18.781 21 19.3333 21V19ZM22 21C22.5523 21 23 20.5523 23 20C23 19.4477 22.5523 19 22 19V21ZM9.86913 19.9163C9.4096 19.6099 8.78873 19.7341 8.48238 20.1937C8.17602 20.6532 8.3002 21.274 8.75973 21.5804L9.86913 19.9163ZM11.0019 21.8734L10.4472 22.7054C10.8888 22.9998 11.4835 22.8979 11.8019 22.4734L11.0019 21.8734ZM14.6094 18.7301C14.9408 18.2883 14.8512 17.6615 14.4094 17.3301C13.9676 16.9987 13.3408 17.0883 13.0094 17.5301L14.6094 18.7301ZM6.18404 27.564L5.73005 28.455H5.73005L6.18404 27.564ZM4.43597 25.816L3.54497 26.27H3.54497L4.43597 25.816ZM27.564 25.816L28.455 26.27L27.564 25.816ZM25.816 27.564L26.27 28.455L25.816 27.564ZM25.816 4.43597L26.27 3.54497V3.54497L25.816 4.43597ZM27.564 6.18404L28.455 5.73005V5.73005L27.564 6.18404ZM6.18404 4.43597L5.73005 3.54497L6.18404 4.43597ZM4.43597 6.18404L3.54497 5.73005L4.43597 6.18404ZM8.67285 13.5787L10.3603 14.7037L11.4698 13.0397L9.7823 11.9146L8.67285 13.5787ZM11.7151 14.4717L14.5226 10.7284L12.9225 9.52836L10.1151 13.2717L11.7151 14.4717ZM19.3333 13H22V11H19.3333V13ZM19.3333 21H22V19H19.3333V21ZM8.75973 21.5804L10.4472 22.7054L11.5566 21.0413L9.86913 19.9163L8.75973 21.5804ZM11.8019 22.4734L14.6094 18.7301L13.0094 17.5301L10.2019 21.2733L11.8019 22.4734ZM10.4 5H21.6V3H10.4V5ZM27 10.4V21.6H29V10.4H27ZM21.6 27H10.4V29H21.6V27ZM5 21.6V10.4H3V21.6H5ZM10.4 27C9.26339 27 8.47108 26.9992 7.85424 26.9488C7.24907 26.8994 6.90138 26.8072 6.63803 26.673L5.73005 28.455C6.32234 28.7568 6.96253 28.8826 7.69138 28.9422C8.40855 29.0008 9.2964 29 10.4 29V27ZM3 21.6C3 22.7036 2.99922 23.5914 3.05782 24.3086C3.11737 25.0375 3.24318 25.6777 3.54497 26.27L5.32698 25.362C5.19279 25.0986 5.10062 24.7509 5.05118 24.1458C5.00078 23.5289 5 22.7366 5 21.6H3ZM6.63803 26.673C6.07354 26.3854 5.6146 25.9265 5.32698 25.362L3.54497 26.27C4.02433 27.2108 4.78924 27.9757 5.73005 28.455L6.63803 26.673ZM27 21.6C27 22.7366 26.9992 23.5289 26.9488 24.1458C26.8994 24.7509 26.8072 25.0986 26.673 25.362L28.455 26.27C28.7568 25.6777 28.8826 25.0375 28.9422 24.3086C29.0008 23.5914 29 22.7036 29 21.6H27ZM21.6 29C22.7036 29 23.5914 29.0008 24.3086 28.9422C25.0375 28.8826 25.6777 28.7568 26.27 28.455L25.362 26.673C25.0986 26.8072 24.7509 26.8994 24.1458 26.9488C23.5289 26.9992 22.7366 27 21.6 27V29ZM26.673 25.362C26.3854 25.9265 25.9265 26.3854 25.362 26.673L26.27 28.455C27.2108 27.9757 27.9757 27.2108 28.455 26.27L26.673 25.362ZM21.6 5C22.7366 5 23.5289 5.00078 24.1458 5.05118C24.7509 5.10062 25.0986 5.19279 25.362 5.32698L26.27 3.54497C25.6777 3.24318 25.0375 3.11737 24.3086 3.05782C23.5914 2.99922 22.7036 3 21.6 3V5ZM29 10.4C29 9.2964 29.0008 8.40855 28.9422 7.69138C28.8826 6.96253 28.7568 6.32234 28.455 5.73005L26.673 6.63803C26.8072 6.90138 26.8994 7.24907 26.9488 7.85424C26.9992 8.47108 27 9.26339 27 10.4H29ZM25.362 5.32698C25.9265 5.6146 26.3854 6.07354 26.673 6.63803L28.455 5.73005C27.9757 4.78924 27.2108 4.02433 26.27 3.54497L25.362 5.32698ZM10.4 3C9.2964 3 8.40855 2.99922 7.69138 3.05782C6.96253 3.11737 6.32234 3.24318 5.73005 3.54497L6.63803 5.32698C6.90138 5.19279 7.24907 5.10062 7.85424 5.05118C8.47108 5.00078 9.26339 5 10.4 5V3ZM5 10.4C5 9.26339 5.00078 8.47108 5.05118 7.85424C5.10062 7.24907 5.19279 6.90138 5.32698 6.63803L3.54497 5.73005C3.24318 6.32234 3.11737 6.96253 3.05782 7.69138C2.99922 8.40855 3 9.2964 3 10.4H5ZM5.73005 3.54497C4.78924 4.02433 4.02433 4.78924 3.54497 5.73005L5.32698 6.63803C5.6146 6.07354 6.07354 5.6146 6.63803 5.32698L5.73005 3.54497Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ChecklistSquare"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/ChecklistSquare.tsx b/app/components/base/icons/src/vender/line/general/ChecklistSquare.tsx
new file mode 100644
index 0000000..8fb72f0
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/ChecklistSquare.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ChecklistSquare.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ChecklistSquare'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/DotsGrid.json b/app/components/base/icons/src/vender/line/general/DotsGrid.json
new file mode 100644
index 0000000..9aafed2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/DotsGrid.json
@@ -0,0 +1,134 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.83333 2.91667C5.83333 2.27233 6.35567 1.75 7 1.75C7.64433 1.75 8.16667 2.27233 8.16667 2.91667C8.16667 3.561 7.64433 4.08333 7 4.08333C6.35567 4.08333 5.83333 3.561 5.83333 2.91667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.83333 7C5.83333 6.35567 6.35567 5.83333 7 5.83333C7.64433 5.83333 8.16667 6.35567 8.16667 7C8.16667 7.64433 7.64433 8.16667 7 8.16667C6.35567 8.16667 5.83333 7.64433 5.83333 7Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.83333 11.0833C5.83333 10.439 6.35567 9.91667 7 9.91667C7.64433 9.91667 8.16667 10.439 8.16667 11.0833C8.16667 11.7277 7.64433 12.25 7 12.25C6.35567 12.25 5.83333 11.7277 5.83333 11.0833Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.91667 2.91667C9.91667 2.27233 10.439 1.75 11.0833 1.75C11.7277 1.75 12.25 2.27233 12.25 2.91667C12.25 3.561 11.7277 4.08333 11.0833 4.08333C10.439 4.08333 9.91667 3.561 9.91667 2.91667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.91667 7C9.91667 6.35567 10.439 5.83333 11.0833 5.83333C11.7277 5.83333 12.25 6.35567 12.25 7C12.25 7.64433 11.7277 8.16667 11.0833 8.16667C10.439 8.16667 9.91667 7.64433 9.91667 7Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.91667 11.0833C9.91667 10.439 10.439 9.91667 11.0833 9.91667C11.7277 9.91667 12.25 10.439 12.25 11.0833C12.25 11.7277 11.7277 12.25 11.0833 12.25C10.439 12.25 9.91667 11.7277 9.91667 11.0833Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1.75 2.91667C1.75 2.27233 2.27233 1.75 2.91667 1.75C3.561 1.75 4.08333 2.27233 4.08333 2.91667C4.08333 3.561 3.561 4.08333 2.91667 4.08333C2.27233 4.08333 1.75 3.561 1.75 2.91667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1.75 7C1.75 6.35567 2.27233 5.83333 2.91667 5.83333C3.561 5.83333 4.08333 6.35567 4.08333 7C4.08333 7.64433 3.561 8.16667 2.91667 8.16667C2.27233 8.16667 1.75 7.64433 1.75 7Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1.75 11.0833C1.75 10.439 2.27233 9.91667 2.91667 9.91667C3.561 9.91667 4.08333 10.439 4.08333 11.0833C4.08333 11.7277 3.561 12.25 2.91667 12.25C2.27233 12.25 1.75 11.7277 1.75 11.0833Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "DotsGrid"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/DotsGrid.tsx b/app/components/base/icons/src/vender/line/general/DotsGrid.tsx
new file mode 100644
index 0000000..fb272fd
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/DotsGrid.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './DotsGrid.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'DotsGrid'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Edit02.json b/app/components/base/icons/src/vender/line/general/Edit02.json
new file mode 100644
index 0000000..38798fe
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Edit02.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Left Icon",
+ "clip-path": "url(#clip0_12284_22440)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M10.5007 5.83319L8.16733 3.49985M1.45898 12.5415L3.4332 12.3222C3.6744 12.2954 3.795 12.282 3.90773 12.2455C4.00774 12.2131 4.10291 12.1673 4.19067 12.1095C4.28958 12.0443 4.37539 11.9585 4.54699 11.7868L12.2507 4.08319C12.895 3.43885 12.895 2.39418 12.2507 1.74985C11.6063 1.10552 10.5617 1.10552 9.91733 1.74985L2.21366 9.45351C2.04205 9.62512 1.95625 9.71092 1.89102 9.80983C1.83315 9.89759 1.78741 9.99277 1.75503 10.0928C1.71854 10.2055 1.70514 10.3261 1.67834 10.5673L1.45898 12.5415Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_12284_22440"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Edit02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Edit02.tsx b/app/components/base/icons/src/vender/line/general/Edit02.tsx
new file mode 100644
index 0000000..10ba0f5
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Edit02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Edit02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Edit02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Edit04.json b/app/components/base/icons/src/vender/line/general/Edit04.json
new file mode 100644
index 0000000..73f275b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Edit04.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21 18L19.9999 19.094C19.4695 19.6741 18.7502 20 18.0002 20C17.2501 20 16.5308 19.6741 16.0004 19.094C15.4693 18.5151 14.75 18.1901 14.0002 18.1901C13.2504 18.1901 12.5312 18.5151 12 19.094M3.00003 20H4.67457C5.16376 20 5.40835 20 5.63852 19.9447C5.84259 19.8957 6.03768 19.8149 6.21663 19.7053C6.41846 19.5816 6.59141 19.4086 6.93732 19.0627L19.5001 6.49998C20.3285 5.67156 20.3285 4.32841 19.5001 3.49998C18.6716 2.67156 17.3285 2.67156 16.5001 3.49998L3.93729 16.0627C3.59139 16.4086 3.41843 16.5816 3.29475 16.7834C3.18509 16.9624 3.10428 17.1574 3.05529 17.3615C3.00003 17.5917 3.00003 17.8363 3.00003 18.3255V20Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Edit04"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Edit04.tsx b/app/components/base/icons/src/vender/line/general/Edit04.tsx
new file mode 100644
index 0000000..5e436c0
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Edit04.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Edit04.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Edit04'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Edit05.json b/app/components/base/icons/src/vender/line/general/Edit05.json
new file mode 100644
index 0000000..321336b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Edit05.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "edit-05",
+ "clip-path": "url(#clip0_17249_52683)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M7.33325 2.66617H4.53325C3.41315 2.66617 2.85309 2.66617 2.42527 2.88415C2.04895 3.0759 1.74299 3.38186 1.55124 3.75819C1.33325 4.18601 1.33325 4.74606 1.33325 5.86617V11.4662C1.33325 12.5863 1.33325 13.1463 1.55124 13.5741C1.74299 13.9505 2.04895 14.2564 2.42527 14.4482C2.85309 14.6662 3.41315 14.6662 4.53325 14.6662H10.1333C11.2534 14.6662 11.8134 14.6662 12.2412 14.4482C12.6176 14.2564 12.9235 13.9505 13.1153 13.5741C13.3333 13.1463 13.3333 12.5863 13.3333 11.4662V8.66617M5.33323 10.6662H6.4496C6.77572 10.6662 6.93878 10.6662 7.09223 10.6293C7.22828 10.5967 7.35834 10.5428 7.47763 10.4697C7.61219 10.3872 7.72749 10.2719 7.95809 10.0413L14.3333 3.66617C14.8855 3.11388 14.8855 2.21845 14.3333 1.66617C13.781 1.11388 12.8855 1.11388 12.3333 1.66617L5.95808 8.04133C5.72747 8.27193 5.61217 8.38723 5.52971 8.52179C5.45661 8.64108 5.40274 8.77114 5.37007 8.90719C5.33323 9.06064 5.33323 9.2237 5.33323 9.54982V10.6662Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_17249_52683"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Edit05"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Edit05.tsx b/app/components/base/icons/src/vender/line/general/Edit05.tsx
new file mode 100644
index 0000000..f6904bb
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Edit05.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Edit05.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Edit05'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Hash02.json b/app/components/base/icons/src/vender/line/general/Hash02.json
new file mode 100644
index 0000000..41b639f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Hash02.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "hash-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M4.74999 1.5L3.24999 10.5M8.74998 1.5L7.24998 10.5M10.25 4H1.75M9.75 8H1.25",
+ "stroke": "currentColor",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Hash02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Hash02.tsx b/app/components/base/icons/src/vender/line/general/Hash02.tsx
new file mode 100644
index 0000000..fa8bdfb
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Hash02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Hash02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Hash02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/InfoCircle.json b/app/components/base/icons/src/vender/line/general/InfoCircle.json
new file mode 100644
index 0000000..4017e85
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/InfoCircle.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "info-circle",
+ "clip-path": "url(#clip0_7880_62014)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M6 8V6M6 4H6.005M11 6C11 8.76142 8.76142 11 6 11C3.23858 11 1 8.76142 1 6C1 3.23858 3.23858 1 6 1C8.76142 1 11 3.23858 11 6Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_7880_62014"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "InfoCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/InfoCircle.tsx b/app/components/base/icons/src/vender/line/general/InfoCircle.tsx
new file mode 100644
index 0000000..3f1d59a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/InfoCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './InfoCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'InfoCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Link03.json b/app/components/base/icons/src/vender/line/general/Link03.json
new file mode 100644
index 0000000..ccd608f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Link03.json
@@ -0,0 +1,57 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "17",
+ "height": "16",
+ "viewBox": "0 0 17 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "link-03"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.01569 1.83378C9.7701 1.10515 10.7805 0.701975 11.8293 0.711089C12.8781 0.720202 13.8813 1.14088 14.623 1.88251C15.3646 2.62414 15.7853 3.62739 15.7944 4.67618C15.8035 5.72497 15.4003 6.73538 14.6717 7.48979L14.6636 7.49805L12.6637 9.49796C12.2581 9.90362 11.7701 10.2173 11.2327 10.4178C10.6953 10.6183 10.1211 10.7008 9.54897 10.6598C8.97686 10.6189 8.42025 10.4553 7.91689 10.1803C7.41354 9.90531 6.97522 9.52527 6.63165 9.06596C6.41112 8.77113 6.47134 8.35334 6.76618 8.1328C7.06101 7.91226 7.4788 7.97249 7.69934 8.26732C7.92838 8.57353 8.2206 8.82689 8.55617 9.01023C8.89174 9.19356 9.26281 9.30259 9.64422 9.3299C10.0256 9.35722 10.4085 9.30219 10.7667 9.16854C11.125 9.0349 11.4503 8.82576 11.7207 8.55532L13.7164 6.55956C14.1998 6.05705 14.4672 5.38513 14.4611 4.68777C14.455 3.98857 14.1746 3.31974 13.6802 2.82532C13.1857 2.3309 12.5169 2.05045 11.8177 2.04437C11.12 2.03831 10.4478 2.30591 9.94526 2.78967L8.80219 3.92609C8.54108 4.18568 8.11898 4.18445 7.85939 3.92334C7.5998 3.66223 7.60103 3.24012 7.86214 2.98053L9.0088 1.84053L9.01569 1.83378Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.76493 5.58217C6.30234 5.3817 6.87657 5.29915 7.44869 5.34012C8.0208 5.3811 8.57741 5.54463 9.08077 5.81964C9.58412 6.09465 10.0224 6.47469 10.366 6.93399C10.5865 7.22882 10.5263 7.64662 10.2315 7.86715C9.93665 8.08769 9.51886 8.02746 9.29832 7.73263C9.06928 7.42643 8.77706 7.17307 8.44149 6.98973C8.10592 6.80639 7.73485 6.69737 7.35344 6.67005C6.97203 6.64274 6.58921 6.69777 6.23094 6.83141C5.87266 6.96506 5.54733 7.17419 5.27699 7.44463L3.28123 9.44039C2.79787 9.94291 2.5305 10.6148 2.53656 11.3122C2.54263 12.0114 2.82309 12.6802 3.31751 13.1746C3.81193 13.6691 4.48076 13.9495 5.17995 13.9556C5.87732 13.9616 6.54923 13.6943 7.05174 13.2109L8.18743 12.0752C8.44777 11.8149 8.86988 11.8149 9.13023 12.0752C9.39058 12.3356 9.39058 12.7577 9.13023 13.018L7.99023 14.158L7.98197 14.1662C7.22756 14.8948 6.21715 15.298 5.16837 15.2889C4.11958 15.2798 3.11633 14.8591 2.3747 14.1174C1.63307 13.3758 1.21239 12.3726 1.20328 11.3238C1.19416 10.275 1.59734 9.26458 2.32597 8.51017L2.33409 8.50191L4.33401 6.50199C4.33398 6.50202 4.33404 6.50196 4.33401 6.50199C4.7395 6.09638 5.22756 5.78262 5.76493 5.58217Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Link03"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Link03.tsx b/app/components/base/icons/src/vender/line/general/Link03.tsx
new file mode 100644
index 0000000..1a0c3e1
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Link03.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Link03.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Link03'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/LinkExternal02.json b/app/components/base/icons/src/vender/line/general/LinkExternal02.json
new file mode 100644
index 0000000..af44559
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/LinkExternal02.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "link-external-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M10.5 4.5L10.5 1.5M10.5 1.5H7.49999M10.5 1.5L6 6M5 1.5H3.9C3.05992 1.5 2.63988 1.5 2.31901 1.66349C2.03677 1.8073 1.8073 2.03677 1.66349 2.31901C1.5 2.63988 1.5 3.05992 1.5 3.9V8.1C1.5 8.94008 1.5 9.36012 1.66349 9.68099C1.8073 9.96323 2.03677 10.1927 2.31901 10.3365C2.63988 10.5 3.05992 10.5 3.9 10.5H8.1C8.94008 10.5 9.36012 10.5 9.68099 10.3365C9.96323 10.1927 10.1927 9.96323 10.3365 9.68099C10.5 9.36012 10.5 8.94008 10.5 8.1V7",
+ "stroke": "currentColor",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LinkExternal02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/LinkExternal02.tsx b/app/components/base/icons/src/vender/line/general/LinkExternal02.tsx
new file mode 100644
index 0000000..58d502d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/LinkExternal02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LinkExternal02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LinkExternal02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/LogIn04.json b/app/components/base/icons/src/vender/line/general/LogIn04.json
new file mode 100644
index 0000000..a8316e9
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/LogIn04.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "log-in-04"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.00016 1.99984C5.78015 1.99984 3.84088 3.20518 2.80244 5.00032C2.61808 5.31903 2.21026 5.42794 1.89155 5.24357C1.57285 5.05921 1.46394 4.65139 1.6483 4.33269C2.91526 2.14249 5.28495 0.666504 8.00016 0.666504C12.0502 0.666504 15.3335 3.94975 15.3335 7.99984C15.3335 12.0499 12.0502 15.3332 8.00016 15.3332C5.28495 15.3332 2.91526 13.8572 1.6483 11.667C1.46394 11.3483 1.57285 10.9405 1.89155 10.7561C2.21026 10.5717 2.61808 10.6806 2.80244 10.9994C3.84088 12.7945 5.78015 13.9998 8.00016 13.9998C11.3139 13.9998 14.0002 11.3135 14.0002 7.99984C14.0002 4.68613 11.3139 1.99984 8.00016 1.99984Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.52876 4.86177C7.78911 4.60142 8.21122 4.60142 8.47157 4.86177L11.1382 7.52843C11.3986 7.78878 11.3986 8.21089 11.1382 8.47124L8.47157 11.1379C8.21122 11.3983 7.78911 11.3983 7.52876 11.1379C7.26841 10.8776 7.26841 10.4554 7.52876 10.1951L9.05735 8.6665H2.00016C1.63197 8.6665 1.3335 8.36803 1.3335 7.99984C1.3335 7.63165 1.63197 7.33317 2.00016 7.33317H9.05735L7.52876 5.80457C7.26841 5.54423 7.26841 5.12212 7.52876 4.86177Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LogIn04"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/LogIn04.tsx b/app/components/base/icons/src/vender/line/general/LogIn04.tsx
new file mode 100644
index 0000000..6d2fbfc
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/LogIn04.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LogIn04.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LogIn04'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/LogOut01.json b/app/components/base/icons/src/vender/line/general/LogOut01.json
new file mode 100644
index 0000000..bd2cb3e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/LogOut01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "log-out-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M9.33333 9.91667L12.25 7M12.25 7L9.33333 4.08333M12.25 7H5.25M5.25 1.75H4.55C3.56991 1.75 3.07986 1.75 2.70552 1.94074C2.37623 2.10852 2.10852 2.37623 1.94074 2.70552C1.75 3.07986 1.75 3.56991 1.75 4.55V9.45C1.75 10.4301 1.75 10.9201 1.94074 11.2945C2.10852 11.6238 2.37623 11.8915 2.70552 12.0593C3.07986 12.25 3.56991 12.25 4.55 12.25H5.25",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LogOut01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/LogOut01.tsx b/app/components/base/icons/src/vender/line/general/LogOut01.tsx
new file mode 100644
index 0000000..12b83b2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/LogOut01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LogOut01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LogOut01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/LogOut04.json b/app/components/base/icons/src/vender/line/general/LogOut04.json
new file mode 100644
index 0000000..a19bedf
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/LogOut04.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "log-out-04"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0.666504 8.00016C0.666504 4.3422 3.52829 1.3335 7.11095 1.3335C8.28872 1.3335 9.3935 1.66091 10.3431 2.23137C10.6588 2.42097 10.7609 2.83053 10.5713 3.14615C10.3817 3.46177 9.97216 3.56394 9.65654 3.37434C8.90651 2.92378 8.03794 2.66683 7.11095 2.66683C4.31165 2.66683 1.99984 5.03071 1.99984 8.00016C1.99984 10.9696 4.31165 13.3335 7.11095 13.3335C8.03794 13.3335 8.90651 13.0765 9.65654 12.626C9.97216 12.4364 10.3817 12.5386 10.5713 12.8542C10.7609 13.1698 10.6588 13.5794 10.3431 13.769C9.3935 14.3394 8.28872 14.6668 7.11095 14.6668C3.52829 14.6668 0.666504 11.6581 0.666504 8.00016Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.5284 4.86209C11.7888 4.60174 12.2109 4.60174 12.4712 4.86209L15.1379 7.52876C15.3983 7.78911 15.3983 8.21122 15.1379 8.47157L12.4712 11.1382C12.2109 11.3986 11.7888 11.3986 11.5284 11.1382C11.2681 10.8779 11.2681 10.4558 11.5284 10.1954L13.057 8.66683H5.99984C5.63165 8.66683 5.33317 8.36835 5.33317 8.00016C5.33317 7.63197 5.63165 7.3335 5.99984 7.3335H13.057L11.5284 5.8049C11.2681 5.54455 11.2681 5.12244 11.5284 4.86209Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LogOut04"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/LogOut04.tsx b/app/components/base/icons/src/vender/line/general/LogOut04.tsx
new file mode 100644
index 0000000..2a73cb4
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/LogOut04.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LogOut04.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LogOut04'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Menu01.json b/app/components/base/icons/src/vender/line/general/Menu01.json
new file mode 100644
index 0000000..5b32928
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Menu01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "menu-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M2 8H14M2 4H14M2 12H14",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Menu01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Menu01.tsx b/app/components/base/icons/src/vender/line/general/Menu01.tsx
new file mode 100644
index 0000000..3ef0904
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Menu01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Menu01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Menu01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Pin01.json b/app/components/base/icons/src/vender/line/general/Pin01.json
new file mode 100644
index 0000000..b0e61a2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Pin01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "pin-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M8.00037 10.0007L8.00037 14.6673M5.3337 4.87274V6.29315C5.3337 6.43183 5.3337 6.50117 5.32009 6.56749C5.30801 6.62633 5.28804 6.68327 5.26071 6.73677C5.22991 6.79706 5.18659 6.8512 5.09996 6.95949L4.05344 8.26764C3.60962 8.82242 3.3877 9.09982 3.38745 9.33326C3.38723 9.53629 3.47954 9.72835 3.63822 9.85501C3.82067 10.0007 4.1759 10.0007 4.88637 10.0007H11.1144C11.8248 10.0007 12.1801 10.0007 12.3625 9.85501C12.5212 9.72835 12.6135 9.53629 12.6133 9.33326C12.613 9.09982 12.3911 8.82242 11.9473 8.26764L10.9008 6.95949C10.8141 6.8512 10.7708 6.79706 10.74 6.73677C10.7127 6.68327 10.6927 6.62633 10.6806 6.56749C10.667 6.50117 10.667 6.43183 10.667 6.29315V4.87274C10.667 4.79599 10.667 4.75761 10.6714 4.71977C10.6752 4.68615 10.6816 4.65287 10.6905 4.62023C10.7006 4.58348 10.7148 4.54785 10.7433 4.47659L11.4152 2.7968C11.6113 2.30674 11.7093 2.06171 11.6684 1.86502C11.6327 1.693 11.5305 1.54206 11.384 1.44499C11.2166 1.33398 10.9527 1.33398 10.4249 1.33398H5.57587C5.04806 1.33398 4.78416 1.33398 4.61671 1.44499C4.47027 1.54206 4.36808 1.693 4.33233 1.86502C4.29146 2.06171 4.38947 2.30674 4.58549 2.7968L5.25741 4.47659C5.28591 4.54785 5.30017 4.58348 5.31019 4.62023C5.3191 4.65287 5.32551 4.68615 5.32936 4.71977C5.3337 4.75761 5.3337 4.79599 5.3337 4.87274Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Pin01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Pin01.tsx b/app/components/base/icons/src/vender/line/general/Pin01.tsx
new file mode 100644
index 0000000..fc0aa4f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Pin01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Pin01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Pin01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Pin02.json b/app/components/base/icons/src/vender/line/general/Pin02.json
new file mode 100644
index 0000000..c5b51a5
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Pin02.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.3767 15.6163L2.71985 21.2732M11.6944 6.64181L10.1335 8.2027C10.0062 8.33003 9.94252 8.39369 9.86999 8.44427C9.80561 8.48917 9.73616 8.52634 9.66309 8.555C9.58077 8.58729 9.49249 8.60495 9.31592 8.64026L5.65145 9.37315C4.69915 9.56361 4.223 9.65884 4.00024 9.9099C3.80617 10.1286 3.71755 10.4213 3.75771 10.7109C3.8038 11.0434 4.14715 11.3867 4.83387 12.0735L11.9196 19.1592C12.6063 19.8459 12.9497 20.1893 13.2821 20.2354C13.5718 20.2755 13.8645 20.1869 14.0832 19.9928C14.3342 19.7701 14.4294 19.2939 14.6199 18.3416L15.3528 14.6771C15.3881 14.5006 15.4058 14.4123 15.4381 14.33C15.4667 14.2569 15.5039 14.1875 15.5488 14.1231C15.5994 14.0505 15.663 13.9869 15.7904 13.8596L17.3512 12.2987C17.4326 12.2173 17.4734 12.1766 17.5181 12.141C17.5578 12.1095 17.5999 12.081 17.644 12.0558C17.6936 12.0274 17.7465 12.0048 17.8523 11.9594L20.3467 10.8904C21.0744 10.5785 21.4383 10.4226 21.6035 10.1706C21.7481 9.95025 21.7998 9.68175 21.7474 9.42348C21.6875 9.12813 21.4076 8.84822 20.8478 8.28839L15.7047 3.14526C15.1448 2.58543 14.8649 2.30552 14.5696 2.24565C14.3113 2.19329 14.0428 2.245 13.8225 2.38953C13.5705 2.55481 13.4145 2.91866 13.1027 3.64636L12.0337 6.14071C11.9883 6.24653 11.9656 6.29944 11.9373 6.34905C11.9121 6.39313 11.8836 6.43522 11.852 6.47496C11.8165 6.51971 11.7758 6.56041 11.6944 6.64181Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Pin02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Pin02.tsx b/app/components/base/icons/src/vender/line/general/Pin02.tsx
new file mode 100644
index 0000000..e1b1853
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Pin02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Pin02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Pin02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Plus02.json b/app/components/base/icons/src/vender/line/general/Plus02.json
new file mode 100644
index 0000000..8a9516f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Plus02.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "10",
+ "height": "10",
+ "viewBox": "0 0 10 10",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "plus"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M5.00004 2.08325V7.91659M2.08337 4.99992H7.91671",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Plus02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Plus02.tsx b/app/components/base/icons/src/vender/line/general/Plus02.tsx
new file mode 100644
index 0000000..6e7920f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Plus02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Plus02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Plus02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Refresh.json b/app/components/base/icons/src/vender/line/general/Refresh.json
new file mode 100644
index 0000000..128dcb7
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Refresh.json
@@ -0,0 +1,23 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "xmlns": "http://www.w3.org/2000/svg",
+ "viewBox": "0 0 24 24",
+ "fill": "currentColor"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.46257 4.43262C7.21556 2.91688 9.5007 2 12 2C17.5228 2 22 6.47715 22 12C22 14.1361 21.3302 16.1158 20.1892 17.7406L17 12H20C20 7.58172 16.4183 4 12 4C9.84982 4 7.89777 4.84827 6.46023 6.22842L5.46257 4.43262ZM18.5374 19.5674C16.7844 21.0831 14.4993 22 12 22C6.47715 22 2 17.5228 2 12C2 9.86386 2.66979 7.88416 3.8108 6.25944L7 12H4C4 16.4183 7.58172 20 12 20C14.1502 20 16.1022 19.1517 17.5398 17.7716L18.5374 19.5674Z"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Refresh"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Refresh.tsx b/app/components/base/icons/src/vender/line/general/Refresh.tsx
new file mode 100644
index 0000000..0d51f21
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Refresh.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Refresh.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Refresh'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Settings01.json b/app/components/base/icons/src/vender/line/general/Settings01.json
new file mode 100644
index 0000000..8734e9f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Settings01.json
@@ -0,0 +1,86 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Left Icon",
+ "clip-path": "url(#clip0_11961_30603)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.99935 8.74984C7.96585 8.74984 8.74935 7.96634 8.74935 6.99984C8.74935 6.03334 7.96585 5.24984 6.99935 5.24984C6.03285 5.24984 5.24935 6.03334 5.24935 6.99984C5.24935 7.96634 6.03285 8.74984 6.99935 8.74984Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.9236 8.59075C10.853 8.75069 10.8319 8.92812 10.8631 9.10015C10.8943 9.27218 10.9763 9.43092 11.0986 9.5559L11.1304 9.58772C11.229 9.68622 11.3073 9.80319 11.3606 9.93195C11.414 10.0607 11.4415 10.1987 11.4415 10.3381C11.4415 10.4775 11.414 10.6155 11.3606 10.7442C11.3073 10.873 11.229 10.99 11.1304 11.0885C11.0319 11.1871 10.9149 11.2653 10.7862 11.3187C10.6574 11.3721 10.5194 11.3995 10.38 11.3995C10.2407 11.3995 10.1026 11.3721 9.97388 11.3187C9.84513 11.2653 9.72815 11.1871 9.62965 11.0885L9.59783 11.0567C9.47285 10.9344 9.31411 10.8524 9.14209 10.8212C8.97006 10.79 8.79263 10.8111 8.63268 10.8817C8.47583 10.9489 8.34207 11.0605 8.24785 11.2028C8.15362 11.345 8.10306 11.5118 8.10238 11.6824V11.7726C8.10238 12.0539 7.99064 12.3236 7.79173 12.5225C7.59283 12.7214 7.32306 12.8332 7.04177 12.8332C6.76048 12.8332 6.49071 12.7214 6.29181 12.5225C6.09291 12.3236 5.98117 12.0539 5.98117 11.7726V11.7248C5.97706 11.5493 5.92025 11.3791 5.8181 11.2363C5.71596 11.0935 5.57322 10.9847 5.40844 10.9241C5.24849 10.8535 5.07106 10.8324 4.89904 10.8636C4.72701 10.8948 4.56827 10.9768 4.44329 11.0991L4.41147 11.1309C4.31297 11.2295 4.196 11.3077 4.06724 11.3611C3.93848 11.4145 3.80047 11.442 3.66109 11.442C3.52171 11.442 3.3837 11.4145 3.25494 11.3611C3.12619 11.3077 3.00921 11.2295 2.91071 11.1309C2.8121 11.0324 2.73387 10.9154 2.6805 10.7867C2.62712 10.6579 2.59965 10.5199 2.59965 10.3805C2.59965 10.2411 2.62712 10.1031 2.6805 9.97437C2.73387 9.84561 2.8121 9.72864 2.91071 9.63014L2.94253 9.59832C3.06479 9.47334 3.1468 9.3146 3.17799 9.14257C3.20918 8.97055 3.18812 8.79312 3.11753 8.63317C3.05031 8.47632 2.93869 8.34256 2.79641 8.24833C2.65414 8.15411 2.48742 8.10355 2.31677 8.10287H2.22662C1.94533 8.10287 1.67556 7.99112 1.47666 7.79222C1.27776 7.59332 1.16602 7.32355 1.16602 7.04226C1.16602 6.76097 1.27776 6.4912 1.47666 6.2923C1.67556 6.0934 1.94533 5.98166 2.22662 5.98166H2.27435C2.44988 5.97755 2.62011 5.92073 2.76292 5.81859C2.90572 5.71645 3.0145 5.57371 3.07511 5.40893C3.1457 5.24898 3.16676 5.07155 3.13556 4.89953C3.10437 4.7275 3.02236 4.56876 2.90011 4.44378L2.86829 4.41196C2.76968 4.31346 2.69145 4.19648 2.63807 4.06773C2.5847 3.93897 2.55723 3.80096 2.55723 3.66158C2.55723 3.5222 2.5847 3.38419 2.63807 3.25543C2.69145 3.12668 2.76968 3.0097 2.86829 2.9112C2.96679 2.81259 3.08376 2.73436 3.21252 2.68099C3.34127 2.62761 3.47929 2.60014 3.61867 2.60014C3.75805 2.60014 3.89606 2.62761 4.02482 2.68099C4.15357 2.73436 4.27054 2.81259 4.36905 2.9112L4.40086 2.94302C4.52585 3.06527 4.68458 3.14728 4.85661 3.17848C5.02864 3.20967 5.20607 3.18861 5.36602 3.11802H5.40844C5.56529 3.0508 5.69906 2.93918 5.79328 2.7969C5.8875 2.65463 5.93806 2.48791 5.93874 2.31726V2.22711C5.93874 1.94582 6.05049 1.67605 6.24939 1.47715C6.44829 1.27825 6.71806 1.1665 6.99935 1.1665C7.28064 1.1665 7.55041 1.27825 7.74931 1.47715C7.94821 1.67605 8.05995 1.94582 8.05995 2.22711V2.27484C8.06064 2.44548 8.1112 2.6122 8.20542 2.75448C8.29964 2.89675 8.43341 3.00837 8.59026 3.07559C8.75021 3.14619 8.92763 3.16724 9.09966 3.13605C9.27169 3.10486 9.43043 3.02285 9.55541 2.90059L9.58723 2.86878C9.68573 2.77017 9.8027 2.69194 9.93146 2.63856C10.0602 2.58519 10.1982 2.55772 10.3376 2.55772C10.477 2.55772 10.615 2.58519 10.7438 2.63856C10.8725 2.69194 10.9895 2.77017 11.088 2.86878C11.1866 2.96728 11.2648 3.08425 11.3182 3.21301C11.3716 3.34176 11.399 3.47978 11.399 3.61916C11.399 3.75854 11.3716 3.89655 11.3182 4.0253C11.2648 4.15406 11.1866 4.27103 11.088 4.36953L11.0562 4.40135C10.9339 4.52633 10.8519 4.68507 10.8207 4.8571C10.7895 5.02913 10.8106 5.20656 10.8812 5.3665V5.40893C10.9484 5.56578 11.06 5.69954 11.2023 5.79377C11.3446 5.88799 11.5113 5.93855 11.6819 5.93923H11.7721C12.0534 5.93923 12.3231 6.05097 12.522 6.24988C12.7209 6.44878 12.8327 6.71855 12.8327 6.99984C12.8327 7.28113 12.7209 7.5509 12.522 7.7498C12.3231 7.9487 12.0534 8.06044 11.7721 8.06044H11.7243C11.5537 8.06112 11.387 8.11169 11.2447 8.20591C11.1024 8.30013 10.9908 8.4339 10.9236 8.59075Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_11961_30603"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Settings01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Settings01.tsx b/app/components/base/icons/src/vender/line/general/Settings01.tsx
new file mode 100644
index 0000000..77d4b7a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Settings01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Settings01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Settings01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Settings04.json b/app/components/base/icons/src/vender/line/general/Settings04.json
new file mode 100644
index 0000000..e46a054
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Settings04.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Left Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M1.75 4.6665L8.75 4.6665M8.75 4.6665C8.75 5.633 9.5335 6.4165 10.5 6.4165C11.4665 6.4165 12.25 5.633 12.25 4.6665C12.25 3.70001 11.4665 2.9165 10.5 2.9165C9.5335 2.9165 8.75 3.70001 8.75 4.6665ZM5.25 9.33317L12.25 9.33317M5.25 9.33317C5.25 10.2997 4.4665 11.0832 3.5 11.0832C2.5335 11.0832 1.75 10.2997 1.75 9.33317C1.75 8.36667 2.5335 7.58317 3.5 7.58317C4.4665 7.58317 5.25 8.36667 5.25 9.33317Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Settings04"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Settings04.tsx b/app/components/base/icons/src/vender/line/general/Settings04.tsx
new file mode 100644
index 0000000..cb475fa
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Settings04.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Settings04.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Settings04'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Target04.json b/app/components/base/icons/src/vender/line/general/Target04.json
new file mode 100644
index 0000000..5c07628
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Target04.json
@@ -0,0 +1,65 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Left Icon",
+ "clip-path": "url(#clip0_10386_42171)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M7.99998 4V2.5L9.49998 1L9.99998 2L11 2.5L9.49998 4H7.99998ZM7.99998 4L5.99999 5.99997M11 6C11 8.76142 8.76142 11 6 11C3.23858 11 1 8.76142 1 6C1 3.23858 3.23858 1 6 1M8.5 6C8.5 7.38071 7.38071 8.5 6 8.5C4.61929 8.5 3.5 7.38071 3.5 6C3.5 4.61929 4.61929 3.5 6 3.5",
+ "stroke": "currentColor",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_10386_42171"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Target04"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Target04.tsx b/app/components/base/icons/src/vender/line/general/Target04.tsx
new file mode 100644
index 0000000..d2d04f9
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Target04.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Target04.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Target04'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/Upload03.json b/app/components/base/icons/src/vender/line/general/Upload03.json
new file mode 100644
index 0000000..c3490f3
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Upload03.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Left Icon",
+ "clip-path": "url(#clip0_12728_40636)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M10.6654 8.00016L7.9987 5.3335M7.9987 5.3335L5.33203 8.00016M7.9987 5.3335V10.6668M14.6654 8.00016C14.6654 11.6821 11.6806 14.6668 7.9987 14.6668C4.3168 14.6668 1.33203 11.6821 1.33203 8.00016C1.33203 4.31826 4.3168 1.3335 7.9987 1.3335C11.6806 1.3335 14.6654 4.31826 14.6654 8.00016Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_12728_40636"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Upload03"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/Upload03.tsx b/app/components/base/icons/src/vender/line/general/Upload03.tsx
new file mode 100644
index 0000000..e62e5d7
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/Upload03.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Upload03.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Upload03'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/UploadCloud01.json b/app/components/base/icons/src/vender/line/general/UploadCloud01.json
new file mode 100644
index 0000000..03e448d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/UploadCloud01.json
@@ -0,0 +1,42 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.4",
+ "d": "M4 16.2422C2.79401 15.435 2 14.0602 2 12.5C2 10.1564 3.79151 8.23129 6.07974 8.01937C6.54781 5.17213 9.02024 3 12 3C14.9798 3 17.4522 5.17213 17.9203 8.01937C20.2085 8.23129 22 10.1564 22 12.5C22 14.0602 21.206 15.435 20 16.2422",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8 16L12 12M12 12L16 16M12 12L12 21",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "UploadCloud01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/UploadCloud01.tsx b/app/components/base/icons/src/vender/line/general/UploadCloud01.tsx
new file mode 100644
index 0000000..413c36e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/UploadCloud01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './UploadCloud01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'UploadCloud01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/X.json b/app/components/base/icons/src/vender/line/general/X.json
new file mode 100644
index 0000000..5c2fde5
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/X.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "x"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M11.3334 4.66663L4.66675 11.3333M4.66675 4.66663L11.3334 11.3333",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "X"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/general/X.tsx b/app/components/base/icons/src/vender/line/general/X.tsx
new file mode 100644
index 0000000..779f4cd
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/X.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './X.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'X'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/general/index.ts b/app/components/base/icons/src/vender/line/general/index.ts
new file mode 100644
index 0000000..b5c7a7b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/general/index.ts
@@ -0,0 +1,27 @@
+export { default as AtSign } from './AtSign'
+export { default as Bookmark } from './Bookmark'
+export { default as CheckDone01 } from './CheckDone01'
+export { default as Check } from './Check'
+export { default as ChecklistSquare } from './ChecklistSquare'
+export { default as DotsGrid } from './DotsGrid'
+export { default as Edit02 } from './Edit02'
+export { default as Edit04 } from './Edit04'
+export { default as Edit05 } from './Edit05'
+export { default as Hash02 } from './Hash02'
+export { default as InfoCircle } from './InfoCircle'
+export { default as Link03 } from './Link03'
+export { default as LinkExternal02 } from './LinkExternal02'
+export { default as LogIn04 } from './LogIn04'
+export { default as LogOut01 } from './LogOut01'
+export { default as LogOut04 } from './LogOut04'
+export { default as Menu01 } from './Menu01'
+export { default as Pin01 } from './Pin01'
+export { default as Pin02 } from './Pin02'
+export { default as Plus02 } from './Plus02'
+export { default as Refresh } from './Refresh'
+export { default as Settings01 } from './Settings01'
+export { default as Settings04 } from './Settings04'
+export { default as Target04 } from './Target04'
+export { default as Upload03 } from './Upload03'
+export { default as UploadCloud01 } from './UploadCloud01'
+export { default as X } from './X'
diff --git a/app/components/base/icons/src/vender/line/images/ImagePlus.json b/app/components/base/icons/src/vender/line/images/ImagePlus.json
new file mode 100644
index 0000000..127b046
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/images/ImagePlus.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "image-plus"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M8.33333 2.00016H5.2C4.0799 2.00016 3.51984 2.00016 3.09202 2.21815C2.71569 2.4099 2.40973 2.71586 2.21799 3.09218C2 3.52001 2 4.08006 2 5.20016V10.8002C2 11.9203 2 12.4803 2.21799 12.9081C2.40973 13.2845 2.71569 13.5904 3.09202 13.7822C3.51984 14.0002 4.07989 14.0002 5.2 14.0002H11.3333C11.9533 14.0002 12.2633 14.0002 12.5176 13.932C13.2078 13.7471 13.7469 13.208 13.9319 12.5178C14 12.2635 14 11.9535 14 11.3335M12.6667 5.3335V1.3335M10.6667 3.3335H14.6667M7 5.66683C7 6.40321 6.40305 7.00016 5.66667 7.00016C4.93029 7.00016 4.33333 6.40321 4.33333 5.66683C4.33333 4.93045 4.93029 4.3335 5.66667 4.3335C6.40305 4.3335 7 4.93045 7 5.66683ZM9.99336 7.94559L4.3541 13.0722C4.03691 13.3605 3.87831 13.5047 3.86429 13.6296C3.85213 13.7379 3.89364 13.8453 3.97546 13.9172C4.06985 14.0002 4.28419 14.0002 4.71286 14.0002H10.9707C11.9301 14.0002 12.4098 14.0002 12.7866 13.839C13.2596 13.6366 13.6365 13.2598 13.8388 12.7868C14 12.41 14 11.9303 14 10.9708C14 10.648 14 10.4866 13.9647 10.3363C13.9204 10.1474 13.8353 9.9704 13.7155 9.81776C13.6202 9.6963 13.4941 9.59546 13.242 9.3938L11.3772 7.90194C11.1249 7.7001 10.9988 7.59919 10.8599 7.56357C10.7374 7.53218 10.6086 7.53624 10.4884 7.57529C10.352 7.61959 10.2324 7.72826 9.99336 7.94559Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ImagePlus"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/images/ImagePlus.tsx b/app/components/base/icons/src/vender/line/images/ImagePlus.tsx
new file mode 100644
index 0000000..bd5a921
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/images/ImagePlus.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ImagePlus.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ImagePlus'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/images/index.ts b/app/components/base/icons/src/vender/line/images/index.ts
new file mode 100644
index 0000000..b61eda9
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/images/index.ts
@@ -0,0 +1 @@
+export { default as ImagePlus } from './ImagePlus'
diff --git a/app/components/base/icons/src/vender/line/layout/AlignLeft01.json b/app/components/base/icons/src/vender/line/layout/AlignLeft01.json
new file mode 100644
index 0000000..5ed5add
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/layout/AlignLeft01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "align-left-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M3 3V21M21 12H7M7 12L14 19M7 12L14 5",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AlignLeft01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/layout/AlignLeft01.tsx b/app/components/base/icons/src/vender/line/layout/AlignLeft01.tsx
new file mode 100644
index 0000000..0aad9be
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/layout/AlignLeft01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AlignLeft01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AlignLeft01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/layout/AlignRight01.json b/app/components/base/icons/src/vender/line/layout/AlignRight01.json
new file mode 100644
index 0000000..6690e6d
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/layout/AlignRight01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "align-right-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M21 21V3M3 12H17M17 12L10 5M17 12L10 19",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AlignRight01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/layout/AlignRight01.tsx b/app/components/base/icons/src/vender/line/layout/AlignRight01.tsx
new file mode 100644
index 0000000..486ba7b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/layout/AlignRight01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AlignRight01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AlignRight01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/layout/Grid01.json b/app/components/base/icons/src/vender/line/layout/Grid01.json
new file mode 100644
index 0000000..43a385c
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/layout/Grid01.json
@@ -0,0 +1,83 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "17",
+ "height": "16",
+ "viewBox": "0 0 17 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "grid-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.1 2H3.56667C3.1933 2 3.00661 2 2.86401 2.07266C2.73856 2.13658 2.63658 2.23856 2.57266 2.36401C2.5 2.50661 2.5 2.6933 2.5 3.06667V5.6C2.5 5.97337 2.5 6.16005 2.57266 6.30266C2.63658 6.4281 2.73856 6.53009 2.86401 6.594C3.00661 6.66667 3.1933 6.66667 3.56667 6.66667H6.1C6.47337 6.66667 6.66005 6.66667 6.80266 6.594C6.9281 6.53009 7.03009 6.4281 7.094 6.30266C7.16667 6.16005 7.16667 5.97337 7.16667 5.6V3.06667C7.16667 2.6933 7.16667 2.50661 7.094 2.36401C7.03009 2.23856 6.9281 2.13658 6.80266 2.07266C6.66005 2 6.47337 2 6.1 2Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.4333 2H10.9C10.5266 2 10.3399 2 10.1973 2.07266C10.0719 2.13658 9.96991 2.23856 9.906 2.36401C9.83333 2.50661 9.83333 2.6933 9.83333 3.06667V5.6C9.83333 5.97337 9.83333 6.16005 9.906 6.30266C9.96991 6.4281 10.0719 6.53009 10.1973 6.594C10.3399 6.66667 10.5266 6.66667 10.9 6.66667H13.4333C13.8067 6.66667 13.9934 6.66667 14.136 6.594C14.2614 6.53009 14.3634 6.4281 14.4273 6.30266C14.5 6.16005 14.5 5.97337 14.5 5.6V3.06667C14.5 2.6933 14.5 2.50661 14.4273 2.36401C14.3634 2.23856 14.2614 2.13658 14.136 2.07266C13.9934 2 13.8067 2 13.4333 2Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.4333 9.33333H10.9C10.5266 9.33333 10.3399 9.33333 10.1973 9.406C10.0719 9.46991 9.96991 9.5719 9.906 9.69734C9.83333 9.83995 9.83333 10.0266 9.83333 10.4V12.9333C9.83333 13.3067 9.83333 13.4934 9.906 13.636C9.96991 13.7614 10.0719 13.8634 10.1973 13.9273C10.3399 14 10.5266 14 10.9 14H13.4333C13.8067 14 13.9934 14 14.136 13.9273C14.2614 13.8634 14.3634 13.7614 14.4273 13.636C14.5 13.4934 14.5 13.3067 14.5 12.9333V10.4C14.5 10.0266 14.5 9.83995 14.4273 9.69734C14.3634 9.5719 14.2614 9.46991 14.136 9.406C13.9934 9.33333 13.8067 9.33333 13.4333 9.33333Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.1 9.33333H3.56667C3.1933 9.33333 3.00661 9.33333 2.86401 9.406C2.73856 9.46991 2.63658 9.5719 2.57266 9.69734C2.5 9.83995 2.5 10.0266 2.5 10.4V12.9333C2.5 13.3067 2.5 13.4934 2.57266 13.636C2.63658 13.7614 2.73856 13.8634 2.86401 13.9273C3.00661 14 3.1933 14 3.56667 14H6.1C6.47337 14 6.66005 14 6.80266 13.9273C6.9281 13.8634 7.03009 13.7614 7.094 13.636C7.16667 13.4934 7.16667 13.3067 7.16667 12.9333V10.4C7.16667 10.0266 7.16667 9.83995 7.094 9.69734C7.03009 9.5719 6.9281 9.46991 6.80266 9.406C6.66005 9.33333 6.47337 9.33333 6.1 9.33333Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Grid01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/layout/Grid01.tsx b/app/components/base/icons/src/vender/line/layout/Grid01.tsx
new file mode 100644
index 0000000..5638f3c
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/layout/Grid01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Grid01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Grid01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/layout/LayoutGrid02.json b/app/components/base/icons/src/vender/line/layout/LayoutGrid02.json
new file mode 100644
index 0000000..d71e981
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/layout/LayoutGrid02.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3 9H21M3 15H21M12 3V21M7.8 3H16.2C17.8802 3 18.7202 3 19.362 3.32698C19.9265 3.6146 20.3854 4.07354 20.673 4.63803C21 5.27976 21 6.11984 21 7.8V16.2C21 17.8802 21 18.7202 20.673 19.362C20.3854 19.9265 19.9265 20.3854 19.362 20.673C18.7202 21 17.8802 21 16.2 21H7.8C6.11984 21 5.27976 21 4.63803 20.673C4.07354 20.3854 3.6146 19.9265 3.32698 19.362C3 18.7202 3 17.8802 3 16.2V7.8C3 6.11984 3 5.27976 3.32698 4.63803C3.6146 4.07354 4.07354 3.6146 4.63803 3.32698C5.27976 3 6.11984 3 7.8 3Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "LayoutGrid02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/layout/LayoutGrid02.tsx b/app/components/base/icons/src/vender/line/layout/LayoutGrid02.tsx
new file mode 100644
index 0000000..f718a66
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/layout/LayoutGrid02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LayoutGrid02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LayoutGrid02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/layout/index.ts b/app/components/base/icons/src/vender/line/layout/index.ts
new file mode 100644
index 0000000..7c12b1f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/layout/index.ts
@@ -0,0 +1,4 @@
+export { default as AlignLeft01 } from './AlignLeft01'
+export { default as AlignRight01 } from './AlignRight01'
+export { default as Grid01 } from './Grid01'
+export { default as LayoutGrid02 } from './LayoutGrid02'
diff --git a/app/components/base/icons/src/vender/line/mapsAndTravel/Globe01.json b/app/components/base/icons/src/vender/line/mapsAndTravel/Globe01.json
new file mode 100644
index 0000000..1e08966
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mapsAndTravel/Globe01.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "globe-01",
+ "clip-path": "url(#clip0_8902_1914)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M1.33325 7.99998H14.6666M1.33325 7.99998C1.33325 11.6819 4.31802 14.6666 7.99992 14.6666M1.33325 7.99998C1.33325 4.31808 4.31802 1.33331 7.99992 1.33331M14.6666 7.99998C14.6666 11.6819 11.6818 14.6666 7.99992 14.6666M14.6666 7.99998C14.6666 4.31808 11.6818 1.33331 7.99992 1.33331M7.99992 1.33331C9.66744 3.15888 10.6151 5.528 10.6666 7.99998C10.6151 10.472 9.66744 12.8411 7.99992 14.6666M7.99992 1.33331C6.3324 3.15888 5.38475 5.528 5.33325 7.99998C5.38475 10.472 6.3324 12.8411 7.99992 14.6666",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_8902_1914"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Globe01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/mapsAndTravel/Globe01.tsx b/app/components/base/icons/src/vender/line/mapsAndTravel/Globe01.tsx
new file mode 100644
index 0000000..445fde6
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mapsAndTravel/Globe01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Globe01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Globe01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/mapsAndTravel/Route.json b/app/components/base/icons/src/vender/line/mapsAndTravel/Route.json
new file mode 100644
index 0000000..19cb837
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mapsAndTravel/Route.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "route",
+ "clip-path": "url(#clip0_3167_28693)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M6.70866 2.91699H6.96206C8.73962 2.91699 9.6284 2.91699 9.96578 3.23624C10.2574 3.51221 10.3867 3.91874 10.3079 4.31245C10.2168 4.76792 9.49122 5.28116 8.03999 6.30763L5.66899 7.98468C4.21777 9.01116 3.49215 9.5244 3.40106 9.97987C3.32233 10.3736 3.45157 10.7801 3.7432 11.0561C4.08059 11.3753 4.96937 11.3753 6.74693 11.3753H7.29199M4.66699 2.91699C4.66699 3.88349 3.88349 4.66699 2.91699 4.66699C1.95049 4.66699 1.16699 3.88349 1.16699 2.91699C1.16699 1.95049 1.95049 1.16699 2.91699 1.16699C3.88349 1.16699 4.66699 1.95049 4.66699 2.91699ZM12.8337 11.0837C12.8337 12.0502 12.0502 12.8337 11.0837 12.8337C10.1172 12.8337 9.33366 12.0502 9.33366 11.0837C9.33366 10.1172 10.1172 9.33366 11.0837 9.33366C12.0502 9.33366 12.8337 10.1172 12.8337 11.0837Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_3167_28693"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Route"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/mapsAndTravel/Route.tsx b/app/components/base/icons/src/vender/line/mapsAndTravel/Route.tsx
new file mode 100644
index 0000000..f81fb61
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mapsAndTravel/Route.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Route.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Route'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/mapsAndTravel/index.ts b/app/components/base/icons/src/vender/line/mapsAndTravel/index.ts
new file mode 100644
index 0000000..8f3cf15
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mapsAndTravel/index.ts
@@ -0,0 +1,2 @@
+export { default as Globe01 } from './Globe01'
+export { default as Route } from './Route'
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.json b/app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.json
new file mode 100644
index 0000000..8f273d0
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "microphone-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M12.6666 6.66732V8.00065C12.6666 10.578 10.5772 12.6673 7.99992 12.6673M3.33325 6.66732V8.00065C3.33325 10.578 5.42259 12.6673 7.99992 12.6673M7.99992 12.6673V14.6673M5.33325 14.6673H10.6666M7.99992 10.0007C6.89535 10.0007 5.99992 9.10522 5.99992 8.00065V3.33398C5.99992 2.22941 6.89535 1.33398 7.99992 1.33398C9.10449 1.33398 9.99992 2.22941 9.99992 3.33398V8.00065C9.99992 9.10522 9.10449 10.0007 7.99992 10.0007Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Microphone01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.tsx b/app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.tsx
new file mode 100644
index 0000000..37fb66a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/Microphone01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Microphone01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Microphone01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/PlayCircle.json b/app/components/base/icons/src/vender/line/mediaAndDevices/PlayCircle.json
new file mode 100644
index 0000000..2785125
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/PlayCircle.json
@@ -0,0 +1,86 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "play-circle",
+ "clip-path": "url(#clip0_3607_26538)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.99992 14.6666C11.6818 14.6666 14.6666 11.6819 14.6666 7.99998C14.6666 4.31808 11.6818 1.33331 7.99992 1.33331C4.31802 1.33331 1.33325 4.31808 1.33325 7.99998C1.33325 11.6819 4.31802 14.6666 7.99992 14.6666Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.66659 5.33331L10.6666 7.99998L6.66659 10.6666V5.33331Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_3607_26538"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "PlayCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/PlayCircle.tsx b/app/components/base/icons/src/vender/line/mediaAndDevices/PlayCircle.tsx
new file mode 100644
index 0000000..3298fe3
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/PlayCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './PlayCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'PlayCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/SlidersH.json b/app/components/base/icons/src/vender/line/mediaAndDevices/SlidersH.json
new file mode 100644
index 0000000..fc138ee
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/SlidersH.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3 5H9M9 5C9 6.10457 9.89543 7 11 7C12.1046 7 13 6.10457 13 5C13 3.89543 12.1046 3 11 3C9.89543 3 9 3.89543 9 5ZM17 5L21 5M3 12H9M17 12H21M17 12C17 10.8954 16.1046 10 15 10C13.8954 10 13 10.8954 13 12C13 13.1046 13.8954 14 15 14C16.1046 14 17 13.1046 17 12ZM3 19H7M7 19C7 20.1046 7.89543 21 9 21C10.1046 21 11 20.1046 11 19C11 17.8954 10.1046 17 9 17C7.89543 17 7 17.8954 7 19ZM15 19H21",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "SlidersH"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/SlidersH.tsx b/app/components/base/icons/src/vender/line/mediaAndDevices/SlidersH.tsx
new file mode 100644
index 0000000..f5649c4
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/SlidersH.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './SlidersH.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'SlidersH'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/Speaker.json b/app/components/base/icons/src/vender/line/mediaAndDevices/Speaker.json
new file mode 100644
index 0000000..3e5cbe1
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/Speaker.json
@@ -0,0 +1,112 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_109_6694)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M0 2.86666C0 2.05664 0.656649 1.39999 1.46667 1.39999H5.86667C6.67668 1.39999 7.33333 2.05664 7.33333 2.86666C7.33333 3.27167 7.00501 3.59999 6.6 3.59999C6.19499 3.59999 5.86667 3.27167 5.86667 2.86666H4.4V7.99999C4.80501 7.99999 5.13333 8.32831 5.13333 8.73332C5.13333 9.13833 4.80501 9.46666 4.4 9.46666H2.93333C2.52832 9.46666 2.2 9.13833 2.2 8.73332C2.2 8.32831 2.52832 7.99999 2.93333 7.99999V2.86666H1.46667C1.46667 3.27167 1.13834 3.59999 0.733333 3.59999C0.328324 3.59999 0 3.27167 0 2.86666Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.8205 0.782296C13.7434 0.62811 13.5233 0.62811 13.4462 0.782296C12.9664 1.74206 12.8754 1.83302 11.9156 2.3129C11.7615 2.39 11.7615 2.61003 11.9156 2.68712C12.8754 3.167 12.9664 3.25797 13.4462 4.21773C13.5233 4.37191 13.7434 4.37191 13.8205 4.21773C14.3003 3.25797 14.3913 3.167 15.3511 2.68712C15.5053 2.61003 15.5053 2.39 15.3511 2.3129C14.3913 1.83302 14.3003 1.74206 13.8205 0.782296Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.79394 2.25319C9.71404 2.09337 9.48596 2.09337 9.40605 2.25319C9.04994 2.96543 8.96544 3.04993 8.2532 3.40605C8.09338 3.48595 8.09338 3.71402 8.2532 3.79393C8.96544 4.15005 9.04994 4.23455 9.40606 4.94679C9.48596 5.10661 9.71404 5.10661 9.79394 4.94679C10.1501 4.23455 10.2346 4.15005 10.9468 3.79393C11.1066 3.71402 11.1066 3.48595 10.9468 3.40605C10.2346 3.04993 10.1501 2.96543 9.79394 2.25319Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.75377 11.049C2.67668 10.8948 2.45665 10.8948 2.37956 11.049C1.89969 12.0087 1.80872 12.0997 0.848971 12.5796C0.694788 12.6566 0.694787 12.8767 0.848971 12.9538C1.80872 13.4336 1.89969 13.5246 2.37956 14.4844C2.45665 14.6385 2.67668 14.6385 2.75377 14.4844C3.23365 13.5246 3.32461 13.4336 4.28436 12.9538C4.43855 12.8767 4.43855 12.6566 4.28436 12.5796C3.32461 12.0997 3.23365 12.0087 2.75377 11.049Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M14.6741 8.65106C14.8886 8.50146 15.1837 8.55405 15.3333 8.76853C15.7614 9.38226 16.0125 10.1292 16.0125 10.9333C16.0125 11.7375 15.7614 12.4844 15.3333 13.0981C15.1837 13.3126 14.8886 13.3652 14.6741 13.2156C14.4596 13.066 14.407 12.7708 14.5567 12.5564C14.8775 12.0964 15.0656 11.5375 15.0656 10.9333C15.0656 10.3291 14.8775 9.77025 14.5567 9.31028C14.407 9.09581 14.4596 8.80066 14.6741 8.65106Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12.5674 6.53771C12.794 6.51987 13.0155 6.61161 13.1632 6.78449C13.2954 6.93929 13.3164 7.12549 13.3244 7.21587C13.3334 7.31718 13.3334 7.44301 13.3333 7.57103C13.3333 7.57691 13.3333 7.58278 13.3333 7.58866L13.3333 14.3C13.3334 14.428 13.3334 14.5539 13.3244 14.6552C13.3164 14.7455 13.2954 14.9317 13.1632 15.0865C13.0155 15.2594 12.794 15.3512 12.5674 15.3333C12.3644 15.3173 12.2179 15.2005 12.1484 15.1423C12.0704 15.077 11.9814 14.988 11.8909 14.8975L10.3795 13.3861C10.3357 13.3423 10.3137 13.3205 10.2971 13.3053L10.2958 13.3041L10.2941 13.3041C10.2716 13.303 10.2407 13.3029 10.1787 13.3029L9.34101 13.3029C9.22151 13.3029 9.10513 13.3029 9.00657 13.2949C8.89833 13.286 8.77062 13.2652 8.6421 13.1997C8.46392 13.1089 8.31906 12.964 8.22827 12.7859C8.16279 12.6574 8.14192 12.5296 8.13308 12.4214C8.12503 12.3228 8.12504 12.2065 8.12505 12.087V9.79916C8.12505 9.79413 8.12505 9.78909 8.12505 9.78406C8.12504 9.66456 8.12503 9.54819 8.13308 9.44963C8.14192 9.34139 8.16279 9.21368 8.22827 9.08517C8.31906 8.90699 8.46392 8.76212 8.6421 8.67133C8.77062 8.60585 8.89833 8.58498 9.00657 8.57614C9.10512 8.56809 9.2215 8.5681 9.341 8.56812C9.34603 8.56812 9.35106 8.56812 9.3561 8.56812H10.1787C10.2407 8.56812 10.2716 8.56801 10.2941 8.56698L10.2958 8.5669L10.2971 8.56575C10.3137 8.55058 10.3357 8.52877 10.3795 8.48491L11.8784 6.98602C11.8826 6.98186 11.8867 6.97771 11.8909 6.97355C11.9814 6.88302 12.0704 6.79403 12.1484 6.72874C12.2179 6.67049 12.3644 6.55368 12.5674 6.53771Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_109_6694"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Speaker"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/Speaker.tsx b/app/components/base/icons/src/vender/line/mediaAndDevices/Speaker.tsx
new file mode 100644
index 0000000..0cf9364
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/Speaker.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Speaker.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Speaker'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/Stop.json b/app/components/base/icons/src/vender/line/mediaAndDevices/Stop.json
new file mode 100644
index 0000000..7d25397
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/Stop.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon",
+ "clip-path": "url(#clip0_467_1645)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_2",
+ "d": "M1.5 3.9C1.5 3.05992 1.5 2.63988 1.66349 2.31901C1.8073 2.03677 2.03677 1.8073 2.31901 1.66349C2.63988 1.5 3.05992 1.5 3.9 1.5H8.1C8.94008 1.5 9.36012 1.5 9.68099 1.66349C9.96323 1.8073 10.1927 2.03677 10.3365 2.31901C10.5 2.63988 10.5 3.05992 10.5 3.9V8.1C10.5 8.94008 10.5 9.36012 10.3365 9.68099C10.1927 9.96323 9.96323 10.1927 9.68099 10.3365C9.36012 10.5 8.94008 10.5 8.1 10.5H3.9C3.05992 10.5 2.63988 10.5 2.31901 10.3365C2.03677 10.1927 1.8073 9.96323 1.66349 9.68099C1.5 9.36012 1.5 8.94008 1.5 8.1V3.9Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_467_1645"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Stop"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/Stop.tsx b/app/components/base/icons/src/vender/line/mediaAndDevices/Stop.tsx
new file mode 100644
index 0000000..3b5d84b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/Stop.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Stop.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Stop'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.json b/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.json
new file mode 100644
index 0000000..2d45601
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.json
@@ -0,0 +1,59 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "17",
+ "height": "16",
+ "viewBox": "0 0 17 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon_2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.49967 14.6663C12.1816 14.6663 15.1663 11.6816 15.1663 7.99967C15.1663 4.31778 12.1816 1.33301 8.49967 1.33301C4.81778 1.33301 1.83301 4.31778 1.83301 7.99967C1.83301 11.6816 4.81778 14.6663 8.49967 14.6663Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.4997 5.99967H6.49967V9.99967H10.4997V5.99967Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "StopCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.tsx b/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.tsx
new file mode 100644
index 0000000..84430c3
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/StopCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './StopCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'StopCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts b/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts
new file mode 100644
index 0000000..662f0fa
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts
@@ -0,0 +1,6 @@
+export { default as Microphone01 } from './Microphone01'
+export { default as PlayCircle } from './PlayCircle'
+export { default as SlidersH } from './SlidersH'
+export { default as Speaker } from './Speaker'
+export { default as StopCircle } from './StopCircle'
+export { default as Stop } from './Stop'
diff --git a/app/components/base/icons/src/vender/line/others/Apps02.json b/app/components/base/icons/src/vender/line/others/Apps02.json
new file mode 100644
index 0000000..2ff128f
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Apps02.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "apps-2-line"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M4.66602 7.6665C3.00916 7.6665 1.66602 6.32336 1.66602 4.6665C1.66602 3.00965 3.00916 1.6665 4.66602 1.6665C6.32287 1.6665 7.66602 3.00965 7.66602 4.6665C7.66602 6.32336 6.32287 7.6665 4.66602 7.6665ZM4.66602 14.3332C3.00916 14.3332 1.66602 12.99 1.66602 11.3332C1.66602 9.6763 3.00916 8.33317 4.66602 8.33317C6.32287 8.33317 7.66602 9.6763 7.66602 11.3332C7.66602 12.99 6.32287 14.3332 4.66602 14.3332ZM11.3327 7.6665C9.67582 7.6665 8.33268 6.32336 8.33268 4.6665C8.33268 3.00965 9.67582 1.6665 11.3327 1.6665C12.9895 1.6665 14.3327 3.00965 14.3327 4.6665C14.3327 6.32336 12.9895 7.6665 11.3327 7.6665ZM11.3327 14.3332C9.67582 14.3332 8.33268 12.99 8.33268 11.3332C8.33268 9.6763 9.67582 8.33317 11.3327 8.33317C12.9895 8.33317 14.3327 9.6763 14.3327 11.3332C14.3327 12.99 12.9895 14.3332 11.3327 14.3332ZM4.66602 6.33317C5.58649 6.33317 6.33268 5.58698 6.33268 4.6665C6.33268 3.74603 5.58649 2.99984 4.66602 2.99984C3.74554 2.99984 2.99935 3.74603 2.99935 4.6665C2.99935 5.58698 3.74554 6.33317 4.66602 6.33317ZM4.66602 12.9998C5.58649 12.9998 6.33268 12.2536 6.33268 11.3332C6.33268 10.4127 5.58649 9.6665 4.66602 9.6665C3.74554 9.6665 2.99935 10.4127 2.99935 11.3332C2.99935 12.2536 3.74554 12.9998 4.66602 12.9998ZM11.3327 6.33317C12.2531 6.33317 12.9993 5.58698 12.9993 4.6665C12.9993 3.74603 12.2531 2.99984 11.3327 2.99984C10.4122 2.99984 9.66602 3.74603 9.66602 4.6665C9.66602 5.58698 10.4122 6.33317 11.3327 6.33317ZM11.3327 12.9998C12.2531 12.9998 12.9993 12.2536 12.9993 11.3332C12.9993 10.4127 12.2531 9.6665 11.3327 9.6665C10.4122 9.6665 9.66602 10.4127 9.66602 11.3332C9.66602 12.2536 10.4122 12.9998 11.3327 12.9998Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Apps02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/Apps02.tsx b/app/components/base/icons/src/vender/line/others/Apps02.tsx
new file mode 100644
index 0000000..070cc28
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Apps02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Apps02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Apps02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/BubbleX.json b/app/components/base/icons/src/vender/line/others/BubbleX.json
new file mode 100644
index 0000000..0cb5702
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/BubbleX.json
@@ -0,0 +1,57 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon L"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3.33463 3.33333C2.96643 3.33333 2.66796 3.63181 2.66796 4V10.6667C2.66796 11.0349 2.96643 11.3333 3.33463 11.3333H4.66796C5.03615 11.3333 5.33463 11.6318 5.33463 12V12.8225L7.65833 11.4283C7.76194 11.3662 7.8805 11.3333 8.00132 11.3333H12.0013C12.3695 11.3333 12.668 11.0349 12.668 10.6667C12.668 10.2985 12.9665 10 13.3347 10C13.7028 10 14.0013 10.2985 14.0013 10.6667C14.0013 11.7713 13.1058 12.6667 12.0013 12.6667H8.18598L5.01095 14.5717C4.805 14.6952 4.5485 14.6985 4.33949 14.5801C4.13049 14.4618 4.00129 14.2402 4.00129 14V12.6667H3.33463C2.23006 12.6667 1.33463 11.7713 1.33463 10.6667V4C1.33463 2.89543 2.23006 2 3.33463 2H6.66798C7.03617 2 7.33464 2.29848 7.33464 2.66667C7.33464 3.03486 7.03617 3.33333 6.66798 3.33333H3.33463Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.74113 2.66667C8.74113 2.29848 9.03961 2 9.4078 2H10.331C10.9721 2 11.5177 2.43571 11.6859 3.04075L11.933 3.93004L12.8986 2.77189C13.3045 2.28508 13.9018 2 14.536 2H14.5954C14.9636 2 15.2621 2.29848 15.2621 2.66667C15.2621 3.03486 14.9636 3.33333 14.5954 3.33333H14.536C14.3048 3.33333 14.08 3.43702 13.9227 3.6257L12.367 5.49165L12.8609 7.2689C12.8746 7.31803 12.9105 7.33333 12.9312 7.33333H13.8543C14.2225 7.33333 14.521 7.63181 14.521 8C14.521 8.36819 14.2225 8.66667 13.8543 8.66667H12.9312C12.29 8.66667 11.7444 8.23095 11.5763 7.62591L11.3291 6.73654L10.3634 7.89478C9.95758 8.38159 9.36022 8.66667 8.72604 8.66667H8.66666C8.29847 8.66667 7.99999 8.36819 7.99999 8C7.99999 7.63181 8.29847 7.33333 8.66666 7.33333H8.72604C8.95723 7.33333 9.18204 7.22965 9.33935 7.04096L10.8951 5.17493L10.4012 3.39777C10.3876 3.34863 10.3516 3.33333 10.331 3.33333H9.4078C9.03961 3.33333 8.74113 3.03486 8.74113 2.66667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "BubbleX"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/BubbleX.tsx b/app/components/base/icons/src/vender/line/others/BubbleX.tsx
new file mode 100644
index 0000000..80d4331
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/BubbleX.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BubbleX.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BubbleX'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/Colors.json b/app/components/base/icons/src/vender/line/others/Colors.json
new file mode 100644
index 0000000..b1832c2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Colors.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "colors",
+ "clip-path": "url(#clip0_18499_53582)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M7.00032 11.9422C7.61954 12.4964 8.43724 12.8334 9.33366 12.8334C11.2667 12.8334 12.8337 11.2664 12.8337 9.33342C12.8337 7.71938 11.7411 6.36051 10.2552 5.95602M3.74543 5.95601C2.25954 6.3605 1.16699 7.71937 1.16699 9.33341C1.16699 11.2664 2.734 12.8334 4.66699 12.8334C6.59999 12.8334 8.16699 11.2664 8.16699 9.33341C8.16699 8.87813 8.08006 8.44314 7.92189 8.04415M10.5003 4.66675C10.5003 6.59974 8.93332 8.16675 7.00033 8.16675C5.06733 8.16675 3.50033 6.59974 3.50033 4.66675C3.50033 2.73375 5.06733 1.16675 7.00033 1.16675C8.93332 1.16675 10.5003 2.73375 10.5003 4.66675Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_18499_53582"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Colors"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/Colors.tsx b/app/components/base/icons/src/vender/line/others/Colors.tsx
new file mode 100644
index 0000000..bdfe6d1
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Colors.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Colors.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Colors'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/DragHandle.json b/app/components/base/icons/src/vender/line/others/DragHandle.json
new file mode 100644
index 0000000..c1364af
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/DragHandle.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Drag Handle"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "drag-handle",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6 5C6.55228 5 7 4.55228 7 4C7 3.44772 6.55228 3 6 3C5.44772 3 5 3.44772 5 4C5 4.55228 5.44772 5 6 5ZM6 9C6.55228 9 7 8.55228 7 8C7 7.44772 6.55228 7 6 7C5.44772 7 5 7.44772 5 8C5 8.55228 5.44772 9 6 9ZM11 4C11 4.55228 10.5523 5 10 5C9.44772 5 9 4.55228 9 4C9 3.44772 9.44772 3 10 3C10.5523 3 11 3.44772 11 4ZM10 9C10.5523 9 11 8.55228 11 8C11 7.44772 10.5523 7 10 7C9.44772 7 9 7.44772 9 8C9 8.55228 9.44772 9 10 9ZM7 12C7 12.5523 6.55228 13 6 13C5.44772 13 5 12.5523 5 12C5 11.4477 5.44772 11 6 11C6.55228 11 7 11.4477 7 12ZM10 13C10.5523 13 11 12.5523 11 12C11 11.4477 10.5523 11 10 11C9.44772 11 9 11.4477 9 12C9 12.5523 9.44772 13 10 13Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "DragHandle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/DragHandle.tsx b/app/components/base/icons/src/vender/line/others/DragHandle.tsx
new file mode 100644
index 0000000..495c29c
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/DragHandle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './DragHandle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'DragHandle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/Env.json b/app/components/base/icons/src/vender/line/others/Env.json
new file mode 100644
index 0000000..87a88ed
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Env.json
@@ -0,0 +1,90 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "env"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1.33325 3.33325C1.33325 2.22868 2.22868 1.33325 3.33325 1.33325H12.6666C13.7712 1.33325 14.6666 2.22869 14.6666 3.33325V3.66659C14.6666 4.03478 14.3681 4.33325 13.9999 4.33325C13.6317 4.33325 13.3333 4.03478 13.3333 3.66659V3.33325C13.3333 2.96506 13.0348 2.66659 12.6666 2.66659H3.33325C2.96506 2.66659 2.66659 2.96506 2.66659 3.33325V3.66659C2.66659 4.03478 2.36811 4.33325 1.99992 4.33325C1.63173 4.33325 1.33325 4.03478 1.33325 3.66659V3.33325Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M14.6666 12.6666C14.6666 13.7712 13.7712 14.6666 12.6666 14.6666L3.33325 14.6666C2.22866 14.6666 1.33325 13.7711 1.33325 12.6666L1.33325 12.3333C1.33325 11.9651 1.63173 11.6666 1.99992 11.6666C2.36811 11.6666 2.66659 11.9651 2.66659 12.3333V12.6666C2.66659 13.0348 2.96505 13.3333 3.33325 13.3333L12.6666 13.3333C13.0348 13.3333 13.3333 13.0348 13.3333 12.6666V12.3333C13.3333 11.9651 13.6317 11.6666 13.9999 11.6666C14.3681 11.6666 14.6666 11.9651 14.6666 12.3333V12.6666Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1.33325 5.99992C1.33325 5.63173 1.63173 5.33325 1.99992 5.33325H4.33325C4.70144 5.33325 4.99992 5.63173 4.99992 5.99992C4.99992 6.36811 4.70144 6.66658 4.33325 6.66658H2.66659V7.33325H3.99992C4.36811 7.33325 4.66659 7.63173 4.66659 7.99992C4.66659 8.36811 4.36811 8.66658 3.99992 8.66658H2.66659V9.33325H4.33325C4.70144 9.33325 4.99992 9.63173 4.99992 9.99992C4.99992 10.3681 4.70144 10.6666 4.33325 10.6666H1.99992C1.63173 10.6666 1.33325 10.3681 1.33325 9.99992V5.99992Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6.4734 5.36186C6.75457 5.27673 7.05833 5.38568 7.22129 5.63012L8.66659 7.79807V5.99992C8.66659 5.63173 8.96506 5.33325 9.33325 5.33325C9.70144 5.33325 9.99992 5.63173 9.99992 5.99992V9.99992C9.99992 10.2937 9.80761 10.5528 9.52644 10.638C9.24527 10.7231 8.94151 10.6142 8.77855 10.3697L7.33325 8.20177V9.99992C7.33325 10.3681 7.03478 10.6666 6.66659 10.6666C6.2984 10.6666 5.99992 10.3681 5.99992 9.99992V5.99992C5.99992 5.70614 6.19222 5.44699 6.4734 5.36186Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M11.0768 5.38453C11.4167 5.24292 11.807 5.40364 11.9486 5.74351L12.9999 8.26658L14.0512 5.74351C14.1928 5.40364 14.5831 5.24292 14.923 5.38453C15.2629 5.52614 15.4236 5.91646 15.282 6.25633L13.6153 10.2563C13.5118 10.5048 13.2691 10.6666 12.9999 10.6666C12.7308 10.6666 12.488 10.5048 12.3845 10.2563L10.7179 6.25633C10.5763 5.91646 10.737 5.52614 11.0768 5.38453Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Env"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/Env.tsx b/app/components/base/icons/src/vender/line/others/Env.tsx
new file mode 100644
index 0000000..fbfc3a7
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Env.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Env.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Env'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/Exchange02.json b/app/components/base/icons/src/vender/line/others/Exchange02.json
new file mode 100644
index 0000000..808a9ff
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Exchange02.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.66602 14.3334C3.00916 14.3334 1.66602 12.9903 1.66602 11.3334C1.66602 9.67655 3.00916 8.33342 4.66602 8.33342C6.32287 8.33342 7.66602 9.67655 7.66602 11.3334C7.66602 12.9903 6.32287 14.3334 4.66602 14.3334ZM11.3327 7.66675C9.67582 7.66675 8.33268 6.3236 8.33268 4.66675C8.33268 3.00989 9.67582 1.66675 11.3327 1.66675C12.9895 1.66675 14.3327 3.00989 14.3327 4.66675C14.3327 6.3236 12.9895 7.66675 11.3327 7.66675ZM4.66602 13.0001C5.58649 13.0001 6.33268 12.2539 6.33268 11.3334C6.33268 10.4129 5.58649 9.66675 4.66602 9.66675C3.74554 9.66675 2.99935 10.4129 2.99935 11.3334C2.99935 12.2539 3.74554 13.0001 4.66602 13.0001ZM11.3327 6.33342C12.2531 6.33342 12.9993 5.58722 12.9993 4.66675C12.9993 3.74627 12.2531 3.00008 11.3327 3.00008C10.4122 3.00008 9.66602 3.74627 9.66602 4.66675C9.66602 5.58722 10.4122 6.33342 11.3327 6.33342ZM1.99935 5.33341C1.99935 3.49247 3.49174 2.00008 5.33268 2.00008H7.33268V3.33341H5.33268C4.22812 3.33341 3.33268 4.22885 3.33268 5.33341V7.33342H1.99935V5.33341ZM13.9993 8.66675H12.666V10.6667C12.666 11.7713 11.7706 12.6667 10.666 12.6667H8.66602V14.0001H10.666C12.5069 14.0001 13.9993 12.5077 13.9993 10.6667V8.66675Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Exchange02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/Exchange02.tsx b/app/components/base/icons/src/vender/line/others/Exchange02.tsx
new file mode 100644
index 0000000..782a3fc
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Exchange02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Exchange02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Exchange02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/FileCode.json b/app/components/base/icons/src/vender/line/others/FileCode.json
new file mode 100644
index 0000000..41050a5
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/FileCode.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10 2.66659H3.33333V13.3333H12.6667V5.33325H10V2.66659ZM2 1.99445C2 1.62929 2.29833 1.33325 2.66567 1.33325H10.6667L13.9998 4.66658L14 13.9949C14 14.3659 13.7034 14.6666 13.3377 14.6666H2.66227C2.29651 14.6666 2 14.3631 2 14.0054V1.99445ZM11.7713 7.99992L9.4142 10.3569L8.4714 9.41412L9.8856 7.99992L8.4714 6.58571L9.4142 5.6429L11.7713 7.99992ZM4.22877 7.99992L6.58579 5.6429L7.5286 6.58571L6.11438 7.99992L7.5286 9.41412L6.58579 10.3569L4.22877 7.99992Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "FileCode"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/FileCode.tsx b/app/components/base/icons/src/vender/line/others/FileCode.tsx
new file mode 100644
index 0000000..10df81b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/FileCode.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileCode.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileCode'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/GlobalVariable.json b/app/components/base/icons/src/vender/line/others/GlobalVariable.json
new file mode 100644
index 0000000..d5fce59
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/GlobalVariable.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6.23814 1.33333H9.76188C10.4844 1.33332 11.0672 1.33332 11.5391 1.37187C12.025 1.41157 12.4518 1.49545 12.8466 1.69664C13.4739 2.01622 13.9838 2.52615 14.3034 3.15336C14.5046 3.54822 14.5884 3.97501 14.6281 4.46091C14.6667 4.93283 14.6667 5.51559 14.6667 6.23811V9.76188C14.6667 10.4844 14.6667 11.0672 14.6281 11.5391C14.5884 12.025 14.5046 12.4518 14.3034 12.8466C13.9838 13.4738 13.4739 13.9838 12.8466 14.3033C12.4518 14.5045 12.025 14.5884 11.5391 14.6281C11.0672 14.6667 10.4844 14.6667 9.7619 14.6667H6.23812C5.51561 14.6667 4.93284 14.6667 4.46093 14.6281C3.97503 14.5884 3.54824 14.5045 3.15338 14.3033C2.52617 13.9838 2.01623 13.4738 1.69666 12.8466C1.49546 12.4518 1.41159 12.025 1.37189 11.5391C1.33333 11.0672 1.33334 10.4844 1.33334 9.76187V6.23812C1.33334 5.5156 1.33333 4.93283 1.37189 4.46091C1.41159 3.97501 1.49546 3.54822 1.69666 3.15336C2.01623 2.52615 2.52617 2.01622 3.15338 1.69664C3.54824 1.49545 3.97503 1.41157 4.46093 1.37187C4.93285 1.33332 5.51561 1.33332 6.23814 1.33333ZM4.5695 2.70078C4.16606 2.73374 3.93427 2.79519 3.7587 2.88465C3.38237 3.0764 3.07641 3.38236 2.88466 3.75868C2.79521 3.93425 2.73376 4.16604 2.70079 4.56949C2.6672 4.98072 2.66668 5.50892 2.66668 6.26666V9.73333C2.66668 10.4911 2.6672 11.0193 2.70079 11.4305C2.73376 11.8339 2.79521 12.0657 2.88466 12.2413C3.07641 12.6176 3.38237 12.9236 3.7587 13.1153C3.93427 13.2048 4.16606 13.2662 4.5695 13.2992C4.98073 13.3328 5.50894 13.3333 6.26668 13.3333H9.73334C10.4911 13.3333 11.0193 13.3328 11.4305 13.2992C11.834 13.2662 12.0658 13.2048 12.2413 13.1153C12.6176 12.9236 12.9236 12.6176 13.1154 12.2413C13.2048 12.0657 13.2663 11.8339 13.2992 11.4305C13.3328 11.0193 13.3333 10.4911 13.3333 9.73333V6.26666C13.3333 5.50892 13.3328 4.98072 13.2992 4.56949C13.2663 4.16604 13.2048 3.93425 13.1154 3.75868C12.9236 3.38236 12.6176 3.0764 12.2413 2.88465C12.0658 2.79519 11.834 2.73374 11.4305 2.70078C11.0193 2.66718 10.4911 2.66666 9.73334 2.66666H6.26668C5.50894 2.66666 4.98073 2.66718 4.5695 2.70078ZM5.08339 5.33333C5.08339 4.96514 5.38187 4.66666 5.75006 4.66666H6.68433C7.324 4.66666 7.87606 5.09677 8.04724 5.70542L8.30138 6.60902L9.2915 5.43554C9.7018 4.94926 10.3035 4.66666 10.9399 4.66666H11C11.3682 4.66666 11.6667 4.96514 11.6667 5.33333C11.6667 5.70152 11.3682 5.99999 11 5.99999H10.9399C10.7005 5.99999 10.4702 6.10616 10.3106 6.29537L8.73751 8.15972L9.23641 9.93357C9.24921 9.97909 9.28574 10 9.31579 10H10.2501C10.6182 10 10.9167 10.2985 10.9167 10.6667C10.9167 11.0349 10.6182 11.3333 10.2501 11.3333H9.31579C8.67612 11.3333 8.12406 10.9032 7.95288 10.2946L7.69871 9.39088L6.70852 10.5644C6.29822 11.0507 5.6965 11.3333 5.06011 11.3333H5.00001C4.63182 11.3333 4.33334 11.0349 4.33334 10.6667C4.33334 10.2985 4.63182 10 5.00001 10H5.06011C5.29949 10 5.52982 9.89383 5.68946 9.70462L7.26258 7.84019L6.76371 6.06642C6.75091 6.0209 6.71438 5.99999 6.68433 5.99999H5.75006C5.38187 5.99999 5.08339 5.70152 5.08339 5.33333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "GlobalVariable"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/GlobalVariable.tsx b/app/components/base/icons/src/vender/line/others/GlobalVariable.tsx
new file mode 100644
index 0000000..7758863
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/GlobalVariable.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './GlobalVariable.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'GlobalVariable'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/Icon3Dots.json b/app/components/base/icons/src/vender/line/others/Icon3Dots.json
new file mode 100644
index 0000000..0942222
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Icon3Dots.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon-3-dots"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Icon3Dots"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/Icon3Dots.tsx b/app/components/base/icons/src/vender/line/others/Icon3Dots.tsx
new file mode 100644
index 0000000..bcc2cee
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Icon3Dots.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Icon3Dots.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Icon3Dots'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/LongArrowLeft.json b/app/components/base/icons/src/vender/line/others/LongArrowLeft.json
new file mode 100644
index 0000000..d2646b1
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/LongArrowLeft.json
@@ -0,0 +1,27 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "21",
+ "height": "8",
+ "viewBox": "0 0 21 8",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0.646446 3.64645C0.451185 3.84171 0.451185 4.15829 0.646446 4.35355L3.82843 7.53553C4.02369 7.7308 4.34027 7.7308 4.53553 7.53553C4.7308 7.34027 4.7308 7.02369 4.53553 6.82843L1.70711 4L4.53553 1.17157C4.7308 0.976311 4.7308 0.659728 4.53553 0.464466C4.34027 0.269204 4.02369 0.269204 3.82843 0.464466L0.646446 3.64645ZM21 3.5L1 3.5V4.5L21 4.5V3.5Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.3"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "LongArrowLeft"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/LongArrowLeft.tsx b/app/components/base/icons/src/vender/line/others/LongArrowLeft.tsx
new file mode 100644
index 0000000..997201b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/LongArrowLeft.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LongArrowLeft.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LongArrowLeft'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/LongArrowRight.json b/app/components/base/icons/src/vender/line/others/LongArrowRight.json
new file mode 100644
index 0000000..7582b81
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/LongArrowRight.json
@@ -0,0 +1,27 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "26",
+ "height": "8",
+ "viewBox": "0 0 26 8",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M25.3536 4.35355C25.5488 4.15829 25.5488 3.84171 25.3536 3.64644L22.1716 0.464465C21.9763 0.269202 21.6597 0.269202 21.4645 0.464465C21.2692 0.659727 21.2692 0.976309 21.4645 1.17157L24.2929 4L21.4645 6.82843C21.2692 7.02369 21.2692 7.34027 21.4645 7.53553C21.6597 7.73079 21.9763 7.73079 22.1716 7.53553L25.3536 4.35355ZM3.59058e-08 4.5L25 4.5L25 3.5L-3.59058e-08 3.5L3.59058e-08 4.5Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.3"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "LongArrowRight"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/LongArrowRight.tsx b/app/components/base/icons/src/vender/line/others/LongArrowRight.tsx
new file mode 100644
index 0000000..42732f9
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/LongArrowRight.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LongArrowRight.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LongArrowRight'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/Tools.json b/app/components/base/icons/src/vender/line/others/Tools.json
new file mode 100644
index 0000000..0ab6857
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Tools.json
@@ -0,0 +1,119 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "17",
+ "viewBox": "0 0 16 17",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Tools",
+ "clip-path": "url(#clip0_5381_39479)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "vector",
+ "d": "M13.4375 14.4375V6.8125H2.5625V14.4375C2.5625 14.9898 3.01022 15.4375 3.5625 15.4375H12.4375C12.9898 15.4375 13.4375 14.9898 13.4375 14.4375Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "vector_2",
+ "d": "M13.6254 2.875L11.1738 6.47327",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "vector_3",
+ "d": "M6.3125 9.8125H9.6875",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "vector_4",
+ "d": "M8.63355 1.88044L8.75 1.64754L8.86645 1.88044C8.97531 2.09816 9.15184 2.27469 9.36956 2.38355L9.60246 2.5L9.36956 2.61645C9.15184 2.72531 8.97531 2.90184 8.86645 3.11956L8.75 3.35246L8.63355 3.11956C8.52469 2.90184 8.34816 2.72531 8.13044 2.61645L7.89754 2.5L8.13044 2.38355C8.34816 2.27469 8.52469 2.09816 8.63355 1.88044Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "square",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "vector_5",
+ "d": "M4.625 3.14754L4.61865 3.16025C4.51946 3.35862 4.35862 3.51946 4.16025 3.61865L4.14754 3.625L4.16025 3.63135C4.35862 3.73054 4.51946 3.89138 4.61865 4.08975L4.625 4.10246L4.63135 4.08975C4.73054 3.89138 4.89138 3.73054 5.08975 3.63135L5.10246 3.625L5.08975 3.61865C4.89138 3.51946 4.73054 3.35862 4.63135 3.16025L4.625 3.14754ZM4.625 3.14754L4.63135 3.16025L4.625 3.14754Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "square",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_5381_39479"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white",
+ "transform": "translate(0 0.5)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Tools"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/others/Tools.tsx b/app/components/base/icons/src/vender/line/others/Tools.tsx
new file mode 100644
index 0000000..6d02329
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/Tools.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Tools.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Tools'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/others/index.ts b/app/components/base/icons/src/vender/line/others/index.ts
new file mode 100644
index 0000000..19d5f1e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/others/index.ts
@@ -0,0 +1,12 @@
+export { default as Apps02 } from './Apps02'
+export { default as BubbleX } from './BubbleX'
+export { default as Colors } from './Colors'
+export { default as DragHandle } from './DragHandle'
+export { default as Env } from './Env'
+export { default as Exchange02 } from './Exchange02'
+export { default as FileCode } from './FileCode'
+export { default as GlobalVariable } from './GlobalVariable'
+export { default as Icon3Dots } from './Icon3Dots'
+export { default as LongArrowLeft } from './LongArrowLeft'
+export { default as LongArrowRight } from './LongArrowRight'
+export { default as Tools } from './Tools'
diff --git a/app/components/base/icons/src/vender/line/shapes/CubeOutline.json b/app/components/base/icons/src/vender/line/shapes/CubeOutline.json
new file mode 100644
index 0000000..4091004
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/shapes/CubeOutline.json
@@ -0,0 +1,98 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "17",
+ "viewBox": "0 0 16 17",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "cube-outline"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.26865 1.29003C8.09143 1.25358 7.90866 1.25358 7.73144 1.29003C7.52659 1.33216 7.3435 1.43471 7.19794 1.51624L7.15826 1.53841L6.17628 2.08395C5.85443 2.26276 5.73846 2.66863 5.91727 2.99049C6.09608 3.31234 6.50195 3.4283 6.82381 3.24949L7.80579 2.70395C7.90681 2.64782 7.95839 2.61946 7.99686 2.60091L8.00004 2.59938L8.00323 2.60091C8.0417 2.61946 8.09327 2.64782 8.1943 2.70395L9.17628 3.24949C9.49814 3.4283 9.90401 3.31234 10.0828 2.99048C10.2616 2.66863 10.1457 2.26276 9.82381 2.08395L8.84183 1.53841L8.80215 1.51624C8.65659 1.43471 8.4735 1.33216 8.26865 1.29003Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.8238 3.75062C12.5019 3.57181 12.0961 3.68777 11.9173 4.00963C11.7385 4.33148 11.8544 4.73735 12.1763 4.91616L12.6272 5.16668L12.1763 5.41719C11.8545 5.596 11.7385 6.00186 11.9173 6.32372C12.0961 6.64558 12.502 6.76154 12.8238 6.58273L13.3334 6.29966V6.83339C13.3334 7.20158 13.6319 7.50006 14 7.50006C14.3682 7.50006 14.6667 7.20158 14.6667 6.83339V5.79435L14.6668 5.74627C14.6673 5.62441 14.6678 5.48084 14.6452 5.33482C14.6869 5.17472 14.6696 4.99892 14.5829 4.84286C14.4904 4.6764 14.3371 4.56501 14.1662 4.52099C14.0496 4.43038 13.9239 4.36116 13.8173 4.3024L13.7752 4.27915L12.8238 3.75062Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.8238 4.91616C4.14566 4.73735 4.26162 4.33148 4.08281 4.00963C3.90401 3.68777 3.49814 3.57181 3.17628 3.75062L2.22493 4.27915L2.18284 4.3024C2.07615 4.36116 1.95045 4.4304 1.83382 4.52102C1.66295 4.56506 1.50977 4.67643 1.41731 4.84286C1.33065 4.99886 1.31323 5.17459 1.35493 5.33464C1.33229 5.48072 1.33281 5.62436 1.33326 5.74627L1.33338 5.79435V6.83339C1.33338 7.20158 1.63185 7.50006 2.00004 7.50006C2.36823 7.50006 2.66671 7.20158 2.66671 6.83339V6.29961L3.17632 6.58273C3.49817 6.76154 3.90404 6.64558 4.08285 6.32372C4.26166 6.00186 4.1457 5.596 3.82384 5.41719L3.3729 5.16666L3.8238 4.91616Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.66671 10.1667C2.66671 9.79853 2.36823 9.50006 2.00004 9.50006C1.63185 9.50006 1.33338 9.79853 1.33338 10.1667V11.2058L1.33326 11.2538C1.33262 11.4298 1.33181 11.6509 1.40069 11.8594C1.46024 12.0397 1.55759 12.2051 1.68622 12.3447C1.835 12.5061 2.02873 12.6128 2.18281 12.6977L2.22493 12.721L3.17628 13.2495C3.49814 13.4283 3.90401 13.3123 4.08281 12.9905C4.26162 12.6686 4.14566 12.2628 3.8238 12.084L2.87245 11.5554C2.76582 11.4962 2.71137 11.4656 2.67318 11.4413L2.66995 11.4392L2.66971 11.4354C2.66699 11.3902 2.66671 11.3277 2.66671 11.2058V10.1667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.6667 10.1667C14.6667 9.79853 14.3682 9.50006 14 9.50006C13.6319 9.50006 13.3334 9.79853 13.3334 10.1667V11.2058C13.3334 11.3277 13.3331 11.3902 13.3304 11.4354L13.3301 11.4392L13.3269 11.4413C13.2887 11.4656 13.2343 11.4962 13.1276 11.5554L12.1763 12.084C11.8544 12.2628 11.7385 12.6686 11.9173 12.9905C12.0961 13.3123 12.5019 13.4283 12.8238 13.2495L13.7752 12.721L13.8172 12.6977C13.9713 12.6128 14.1651 12.5061 14.3139 12.3447C14.4425 12.2051 14.5398 12.0397 14.5994 11.8594C14.6683 11.6509 14.6675 11.4298 14.6668 11.2538L14.6667 11.2058V10.1667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.82381 13.7506C6.50195 13.5718 6.09608 13.6878 5.91727 14.0096C5.73846 14.3315 5.85443 14.7374 6.17628 14.9162L7.15826 15.4617L7.19793 15.4839C7.29819 15.54 7.41625 15.6061 7.54696 15.6556C7.66589 15.7659 7.82512 15.8333 8.00008 15.8333C8.17507 15.8333 8.33431 15.7659 8.45324 15.6556C8.58391 15.6061 8.70193 15.54 8.80215 15.4839L8.84183 15.4617L9.82381 14.9162C10.1457 14.7374 10.2616 14.3315 10.0828 14.0096C9.90401 13.6878 9.49814 13.5718 9.17628 13.7506L8.66675 14.0337V13.5C8.66675 13.1318 8.36827 12.8333 8.00008 12.8333C7.63189 12.8333 7.33341 13.1318 7.33341 13.5V14.0337L6.82381 13.7506Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.82384 7.08385C6.50199 6.90505 6.09612 7.02101 5.91731 7.34286C5.7385 7.66472 5.85446 8.07059 6.17632 8.2494L7.33341 8.89223V10.1666C7.33341 10.5348 7.63189 10.8333 8.00008 10.8333C8.36827 10.8333 8.66675 10.5348 8.66675 10.1666V8.89223L9.82384 8.2494C10.1457 8.07059 10.2617 7.66472 10.0829 7.34286C9.90404 7.02101 9.49817 6.90505 9.17632 7.08385L8.00008 7.73732L6.82384 7.08385Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "CubeOutline"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/shapes/CubeOutline.tsx b/app/components/base/icons/src/vender/line/shapes/CubeOutline.tsx
new file mode 100644
index 0000000..40e0df2
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/shapes/CubeOutline.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './CubeOutline.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'CubeOutline'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/shapes/index.ts b/app/components/base/icons/src/vender/line/shapes/index.ts
new file mode 100644
index 0000000..daf43bc
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/shapes/index.ts
@@ -0,0 +1 @@
+export { default as CubeOutline } from './CubeOutline'
diff --git a/app/components/base/icons/src/vender/line/time/ClockFastForward.json b/app/components/base/icons/src/vender/line/time/ClockFastForward.json
new file mode 100644
index 0000000..26b7208
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/time/ClockFastForward.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M22.7 11.5L20.7005 13.5L18.7 11.5M20.9451 13C20.9814 12.6717 21 12.338 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C14.8273 21 17.35 19.6963 19 17.6573M12 7V12L15 14",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ClockFastForward"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/time/ClockFastForward.tsx b/app/components/base/icons/src/vender/line/time/ClockFastForward.tsx
new file mode 100644
index 0000000..e520c5a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/time/ClockFastForward.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ClockFastForward.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ClockFastForward'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/time/ClockPlay.json b/app/components/base/icons/src/vender/line/time/ClockPlay.json
new file mode 100644
index 0000000..7d3cc48
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/time/ClockPlay.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon",
+ "clip-path": "url(#clip0_635_10941)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M14.6334 8.66683C14.6552 8.44756 14.6663 8.22516 14.6663 8.00016C14.6663 4.31826 11.6816 1.3335 7.99967 1.3335C4.31778 1.3335 1.33301 4.31826 1.33301 8.00016C1.33301 11.6821 4.31778 14.6668 7.99967 14.6668C8.11145 14.6668 8.22258 14.6641 8.33301 14.6586C8.44487 14.6531 8.556 14.6449 8.66634 14.6339M7.99967 4.00016V8.00016L5.42265 9.25534M11.853 9.97346L14.4308 11.9068C14.6238 12.0515 14.7203 12.1239 14.7548 12.2126C14.785 12.2904 14.785 12.3766 14.7548 12.4543C14.7203 12.543 14.6238 12.6154 14.4308 12.7601L11.853 14.6935C11.5784 14.8995 11.441 15.0024 11.3261 15.0001C11.226 14.998 11.1322 14.9511 11.0706 14.8723C10.9997 14.7818 10.9997 14.6101 10.9997 14.2668V10.4001C10.9997 10.0568 10.9997 9.88516 11.0706 9.79463C11.1322 9.71585 11.226 9.66895 11.3261 9.66687C11.441 9.66448 11.5784 9.76747 11.853 9.97346Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.5",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_635_10941"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ClockPlay"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/time/ClockPlay.tsx b/app/components/base/icons/src/vender/line/time/ClockPlay.tsx
new file mode 100644
index 0000000..a86756a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/time/ClockPlay.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ClockPlay.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ClockPlay'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/time/ClockPlaySlim.json b/app/components/base/icons/src/vender/line/time/ClockPlaySlim.json
new file mode 100644
index 0000000..348694e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/time/ClockPlaySlim.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "32",
+ "height": "32",
+ "viewBox": "0 0 32 32",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M29.2673 17.3332C29.3109 16.8946 29.3332 16.4498 29.3332 15.9998C29.3332 8.63604 23.3636 2.6665 15.9998 2.6665C8.63604 2.6665 2.6665 8.63604 2.6665 15.9998C2.6665 23.3636 8.63604 29.3332 15.9998 29.3332C16.2234 29.3332 16.4457 29.3277 16.6665 29.3168C16.8902 29.3058 17.1125 29.2892 17.3332 29.2673M15.9998 7.99984V15.9998L10.8458 18.5102M23.7065 19.9464L28.8621 23.8131C29.2481 24.1026 29.441 24.2473 29.5101 24.4248C29.5705 24.5802 29.5705 24.7527 29.5101 24.9081C29.441 25.0855 29.2481 25.2303 28.8621 25.5198L23.7065 29.3864C23.1572 29.7984 22.8825 30.0044 22.6526 29.9996C22.4526 29.9955 22.265 29.9017 22.1416 29.7441C21.9998 29.5631 21.9998 29.2197 21.9998 28.5331V20.7998C21.9998 20.1131 21.9998 19.7698 22.1416 19.5888C22.265 19.4312 22.4526 19.3374 22.6526 19.3333C22.8825 19.3285 23.1572 19.5345 23.7065 19.9464Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ClockPlaySlim"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/time/ClockPlaySlim.tsx b/app/components/base/icons/src/vender/line/time/ClockPlaySlim.tsx
new file mode 100644
index 0000000..47e917b
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/time/ClockPlaySlim.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ClockPlaySlim.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ClockPlaySlim'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/time/ClockRefresh.json b/app/components/base/icons/src/vender/line/time/ClockRefresh.json
new file mode 100644
index 0000000..925907a
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/time/ClockRefresh.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "clock-refresh"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.76984 2.8375L9.71551 3.04027C8.27602 1.22839 5.68891 0.69459 3.62457 1.88644C2.25681 2.67611 1.43067 4.04369 1.27558 5.50073C1.24636 5.77532 1.44526 6.02161 1.71985 6.05084C1.99444 6.08007 2.24074 5.88116 2.26997 5.60657C2.39268 4.4537 3.04533 3.37556 4.12456 2.75247C5.7025 1.84145 7.66731 2.20754 8.82211 3.53002L8.65016 3.48395C8.38343 3.41248 8.10926 3.57077 8.03779 3.8375C7.96632 4.10424 8.12461 4.37841 8.39134 4.44988L9.75737 4.8159C10.0241 4.88737 10.2983 4.72908 10.3697 4.46235L10.7358 3.09632C10.8072 2.82959 10.6489 2.55542 10.3822 2.48395C10.1155 2.41248 9.84131 2.57077 9.76984 2.8375Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.2792 5.94921C10.5538 5.97844 10.7527 6.22473 10.7235 6.49932C10.5684 7.95635 9.74225 9.32394 8.3745 10.1136C6.31011 11.3055 3.72295 10.7716 2.28347 8.95968L2.22918 9.1623C2.15771 9.42903 1.88354 9.58732 1.61681 9.51585C1.35008 9.44438 1.19178 9.17021 1.26325 8.90348L1.62928 7.53746C1.70075 7.27072 1.97492 7.11243 2.24165 7.1839L3.60768 7.54993C3.87441 7.6214 4.0327 7.89557 3.96123 8.1623C3.88976 8.42903 3.61559 8.58732 3.34886 8.51585L3.17668 8.46972C4.33144 9.79246 6.29644 10.1587 7.8745 9.24758C8.95373 8.62449 9.60638 7.54634 9.72909 6.39348C9.75832 6.11889 10.0046 5.91998 10.2792 5.94921Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.49954 3.74997C6.49954 3.47382 6.27568 3.24997 5.99954 3.24997C5.7234 3.24997 5.49954 3.47382 5.49954 3.74997V5.99997C5.49954 6.1756 5.59169 6.33835 5.74229 6.42871L6.99229 7.17871C7.22908 7.32079 7.53621 7.244 7.67828 7.00721C7.82036 6.77042 7.74358 6.46329 7.50679 6.32122L6.49954 5.71687V3.74997Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ClockRefresh"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/time/ClockRefresh.tsx b/app/components/base/icons/src/vender/line/time/ClockRefresh.tsx
new file mode 100644
index 0000000..31e3a9c
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/time/ClockRefresh.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ClockRefresh.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ClockRefresh'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/time/index.ts b/app/components/base/icons/src/vender/line/time/index.ts
new file mode 100644
index 0000000..8e6509e
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/time/index.ts
@@ -0,0 +1,4 @@
+export { default as ClockFastForward } from './ClockFastForward'
+export { default as ClockPlaySlim } from './ClockPlaySlim'
+export { default as ClockPlay } from './ClockPlay'
+export { default as ClockRefresh } from './ClockRefresh'
diff --git a/app/components/base/icons/src/vender/line/users/User01.json b/app/components/base/icons/src/vender/line/users/User01.json
new file mode 100644
index 0000000..5535303
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/users/User01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "user-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M13.3334 14C13.3334 13.0696 13.3334 12.6044 13.2186 12.2259C12.9601 11.3736 12.2931 10.7067 11.4408 10.4482C11.0623 10.3333 10.5971 10.3333 9.66675 10.3333H6.33342C5.40304 10.3333 4.93785 10.3333 4.55932 10.4482C3.70705 10.7067 3.04011 11.3736 2.78157 12.2259C2.66675 12.6044 2.66675 13.0696 2.66675 14M11.0001 5C11.0001 6.65685 9.65694 8 8.00008 8C6.34323 8 5.00008 6.65685 5.00008 5C5.00008 3.34315 6.34323 2 8.00008 2C9.65694 2 11.0001 3.34315 11.0001 5Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "User01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/users/User01.tsx b/app/components/base/icons/src/vender/line/users/User01.tsx
new file mode 100644
index 0000000..24fd0df
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/users/User01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './User01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'User01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/users/Users01.json b/app/components/base/icons/src/vender/line/users/Users01.json
new file mode 100644
index 0000000..96dbeb3
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/users/Users01.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "users-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M14.6666 14V12.6667C14.6666 11.4241 13.8167 10.38 12.6666 10.084M10.3333 2.19384C11.3105 2.58943 11.9999 3.54754 11.9999 4.66667C11.9999 5.78579 11.3105 6.7439 10.3333 7.13949M11.3333 14C11.3333 12.7575 11.3333 12.1362 11.1303 11.6462C10.8596 10.9928 10.3405 10.4736 9.68707 10.203C9.19702 10 8.57576 10 7.33325 10H5.33325C4.09074 10 3.46949 10 2.97943 10.203C2.32602 10.4736 1.80689 10.9928 1.53624 11.6462C1.33325 12.1362 1.33325 12.7575 1.33325 14M8.99992 4.66667C8.99992 6.13943 7.80601 7.33333 6.33325 7.33333C4.86049 7.33333 3.66659 6.13943 3.66659 4.66667C3.66659 3.19391 4.86049 2 6.33325 2C7.80601 2 8.99992 3.19391 8.99992 4.66667Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Users01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/users/Users01.tsx b/app/components/base/icons/src/vender/line/users/Users01.tsx
new file mode 100644
index 0000000..f26ff03
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/users/Users01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Users01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Users01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/users/index.ts b/app/components/base/icons/src/vender/line/users/index.ts
new file mode 100644
index 0000000..9f8a351
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/users/index.ts
@@ -0,0 +1,2 @@
+export { default as User01 } from './User01'
+export { default as Users01 } from './Users01'
diff --git a/app/components/base/icons/src/vender/line/weather/Stars02.json b/app/components/base/icons/src/vender/line/weather/Stars02.json
new file mode 100644
index 0000000..54f6a42
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/weather/Stars02.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.5 22V17M4.5 7V2M2 4.5H7M2 19.5H7M13 3L11.2658 7.50886C10.9838 8.24209 10.8428 8.60871 10.6235 8.91709C10.4292 9.1904 10.1904 9.42919 9.91709 9.62353C9.60871 9.8428 9.24209 9.98381 8.50886 10.2658L4 12L8.50886 13.7342C9.24209 14.0162 9.60871 14.1572 9.91709 14.3765C10.1904 14.5708 10.4292 14.8096 10.6235 15.0829C10.8428 15.3913 10.9838 15.7579 11.2658 16.4911L13 21L14.7342 16.4911C15.0162 15.7579 15.1572 15.3913 15.3765 15.0829C15.5708 14.8096 15.8096 14.5708 16.0829 14.3765C16.3913 14.1572 16.7579 14.0162 17.4911 13.7342L22 12L17.4911 10.2658C16.7579 9.98381 16.3913 9.8428 16.0829 9.62353C15.8096 9.42919 15.5708 9.1904 15.3765 8.91709C15.1572 8.60871 15.0162 8.24209 14.7342 7.50886L13 3Z",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Stars02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/line/weather/Stars02.tsx b/app/components/base/icons/src/vender/line/weather/Stars02.tsx
new file mode 100644
index 0000000..ad24f6c
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/weather/Stars02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Stars02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Stars02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/line/weather/index.ts b/app/components/base/icons/src/vender/line/weather/index.ts
new file mode 100644
index 0000000..1a68bce
--- /dev/null
+++ b/app/components/base/icons/src/vender/line/weather/index.ts
@@ -0,0 +1 @@
+export { default as Stars02 } from './Stars02'
diff --git a/app/components/base/icons/src/vender/other/AnthropicText.json b/app/components/base/icons/src/vender/other/AnthropicText.json
new file mode 100644
index 0000000..a65ef47
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/AnthropicText.json
@@ -0,0 +1,539 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "90",
+ "height": "20",
+ "viewBox": "0 0 90 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask0_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M89.375 4.99805H0V14.998H89.375V4.99805Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask0_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask1_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99609H89.375V14.9961H0V4.99609Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask1_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask2_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99414H89.375V14.9941H0V4.99414Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask2_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask3_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask3_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.1273 11.9244L13.7773 5.15625H11.4297V14.825H13.4321V8.05688L17.7821 14.825H20.1297V5.15625H18.1273V11.9244Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask4_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask4_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.7969 7.02094H25.0423V14.825H27.1139V7.02094H30.3594V5.15625H21.7969V7.02094Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask5_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask5_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M38.6442 9.00994H34.0871V5.15625H32.0156V14.825H34.0871V10.8746H38.6442V14.825H40.7156V5.15625H38.6442V9.00994Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask6_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask6_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M45.3376 7.02094H47.893C48.9152 7.02094 49.4539 7.39387 49.4539 8.09831C49.4539 8.80275 48.9152 9.17569 47.893 9.17569H45.3376V7.02094ZM51.5259 8.09831C51.5259 6.27506 50.186 5.15625 47.9897 5.15625H43.2656V14.825H45.3376V11.0404H47.6443L49.7164 14.825H52.0094L49.715 10.7521C50.8666 10.3094 51.5259 9.37721 51.5259 8.09831Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask7_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask7_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M57.8732 13.0565C56.2438 13.0565 55.2496 11.8963 55.2496 10.004C55.2496 8.08416 56.2438 6.92394 57.8732 6.92394C59.4887 6.92394 60.4691 8.08416 60.4691 10.004C60.4691 11.8963 59.4887 13.0565 57.8732 13.0565ZM57.8732 4.99023C55.0839 4.99023 53.1094 7.06206 53.1094 10.004C53.1094 12.9184 55.0839 14.9902 57.8732 14.9902C60.6486 14.9902 62.6094 12.9184 62.6094 10.004C62.6094 7.06206 60.6486 4.99023 57.8732 4.99023Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask8_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask8_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M69.1794 9.45194H66.6233V7.02094H69.1794C70.2019 7.02094 70.7407 7.43532 70.7407 8.23644C70.7407 9.03756 70.2019 9.45194 69.1794 9.45194ZM69.2762 5.15625H64.5508V14.825H66.6233V11.3166H69.2762C71.473 11.3166 72.8133 10.1564 72.8133 8.23644C72.8133 6.3165 71.473 5.15625 69.2762 5.15625Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask9_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask9_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M86.8413 11.5786C86.4823 12.5179 85.7642 13.0565 84.7837 13.0565C83.1542 13.0565 82.16 11.8963 82.16 10.004C82.16 8.08416 83.1542 6.92394 84.7837 6.92394C85.7642 6.92394 86.4823 7.46261 86.8413 8.40183H89.0369C88.4984 6.33002 86.8827 4.99023 84.7837 4.99023C81.9942 4.99023 80.0195 7.06206 80.0195 10.004C80.0195 12.9184 81.9942 14.9902 84.7837 14.9902C86.8965 14.9902 88.5122 13.6366 89.0508 11.5786H86.8413Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask10_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask10_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M73.6484 5.15625L77.5033 14.825H79.6172L75.7624 5.15625H73.6484Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "mask",
+ "attributes": {
+ "id": "mask11_8587_60274",
+ "style": "mask-type:luminance",
+ "maskUnits": "userSpaceOnUse",
+ "x": "0",
+ "y": "4",
+ "width": "90",
+ "height": "11"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M0 4.99219H89.375V14.9922H0V4.99219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "mask": "url(#mask11_8587_60274)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.64038 10.9989L4.95938 7.60106L6.27838 10.9989H3.64038ZM3.85422 5.15625L0 14.825H2.15505L2.9433 12.7946H6.97558L7.76371 14.825H9.91875L6.06453 5.15625H3.85422Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.92"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_8587_60274"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "89.375",
+ "height": "10",
+ "fill": "white",
+ "transform": "translate(0 5)"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AnthropicText"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/other/AnthropicText.tsx b/app/components/base/icons/src/vender/other/AnthropicText.tsx
new file mode 100644
index 0000000..be9ebd3
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/AnthropicText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AnthropicText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AnthropicText'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/other/Generator.json b/app/components/base/icons/src/vender/other/Generator.json
new file mode 100644
index 0000000..3f24cfe
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/Generator.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "opacity": "0.5",
+ "d": "M10.5402 2.95679L10.5402 2.95685C10.4455 3.05146 10.3424 3.13459 10.2314 3.2072C10.3429 3.27923 10.4468 3.36165 10.5422 3.45535L10.5402 2.95679ZM10.5402 2.95679C10.6348 2.86217 10.718 2.75907 10.7906 2.64807C10.8626 2.75955 10.945 2.86339 11.0387 2.95881L11.0388 2.95888C11.1304 3.05224 11.2302 3.13482 11.3377 3.20717C11.2297 3.27895 11.1292 3.36081 11.0367 3.45327L11.0366 3.45333C10.9442 3.5458 10.8623 3.64635 10.7905 3.75431M10.5402 2.95679L10.7905 3.75431M10.7905 3.75431C10.7182 3.64686 10.6356 3.54707 10.5422 3.45538L10.7905 3.75431Z",
+ "stroke": "currentColor",
+ "stroke-width": "1.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.99659 2.85105C6.96323 2.55641 6.71414 2.33368 6.41758 2.33337C6.12107 2.33307 5.87146 2.55529 5.83751 2.84987C5.67932 4.2213 5.27205 5.16213 4.6339 5.80028C3.99575 6.43841 3.05492 6.84569 1.68349 7.00389C1.3889 7.03784 1.16669 7.28745 1.16699 7.58396C1.1673 7.88052 1.39002 8.12961 1.68467 8.16297C3.03291 8.31569 3.99517 8.72292 4.64954 9.36546C5.30035 10.0045 5.71535 10.944 5.83593 12.3017C5.86271 12.6029 6.11523 12.8337 6.41763 12.8334C6.72009 12.833 6.97209 12.6016 6.99817 12.3003C7.11367 10.9656 7.52836 10.005 8.18344 9.34982C8.83858 8.69474 9.79922 8.28005 11.1339 8.16455C11.4352 8.13847 11.6666 7.88647 11.667 7.58402C11.6673 7.28162 11.4365 7.02909 11.1353 7.00232C9.77758 6.88174 8.83812 6.46676 8.19908 5.81592C7.55653 5.16155 7.14931 4.19929 6.99659 2.85105Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Generator"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/other/Generator.tsx b/app/components/base/icons/src/vender/other/Generator.tsx
new file mode 100644
index 0000000..cba3904
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/Generator.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Generator.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Generator'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/other/Group.json b/app/components/base/icons/src/vender/other/Group.json
new file mode 100644
index 0000000..078febb
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/Group.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "16",
+ "viewBox": "0 0 14 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M5.6475 8.0115L0.333496 5.05884V11.3335C0.333491 11.4524 0.365258 11.569 0.425506 11.6715C0.485754 11.7739 0.572294 11.8584 0.676163 11.9162L6.3335 15.0588V9.17684C6.33344 8.93907 6.26981 8.70565 6.14919 8.50075C6.02857 8.29586 5.85536 8.12694 5.6475 8.0115Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M7.66699 9.17684V15.0588L13.3243 11.9162C13.4282 11.8584 13.5147 11.7739 13.575 11.6715C13.6352 11.569 13.667 11.4524 13.667 11.3335V5.05884L8.35299 8.0115C8.14513 8.12694 7.97192 8.29586 7.8513 8.50075C7.73068 8.70565 7.66705 8.93907 7.66699 9.17684Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M10.1913 2.34351C9.804 3.33351 8.588 4.00017 7 4.00017C5.412 4.00017 4.196 3.33351 3.80867 2.34351L1 3.90417L6.35267 6.87817C6.5507 6.98815 6.77348 7.04586 7 7.04586C7.22652 7.04586 7.4493 6.98815 7.64733 6.87817L13 3.90417L10.1913 2.34351Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M7 2.66675C8.10457 2.66675 9 2.21903 9 1.66675C9 1.11446 8.10457 0.666748 7 0.666748C5.89543 0.666748 5 1.11446 5 1.66675C5 2.21903 5.89543 2.66675 7 2.66675Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Group"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/other/Group.tsx b/app/components/base/icons/src/vender/other/Group.tsx
new file mode 100644
index 0000000..7b72300
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/Group.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Group.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Group'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/other/Openai.json b/app/components/base/icons/src/vender/other/Openai.json
new file mode 100644
index 0000000..236f66f
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/Openai.json
@@ -0,0 +1,80 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "80",
+ "height": "22",
+ "viewBox": "0 0 80 22",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M25.1152 10.5767C25.1152 14.1738 27.4253 16.6818 30.6264 16.6818C33.8274 16.6818 36.1375 14.1738 36.1375 10.5767C36.1375 6.97961 33.8274 4.47156 30.6264 4.47156C27.4253 4.47156 25.1152 6.97961 25.1152 10.5767ZM34.0254 10.5767C34.0254 13.1507 32.6229 14.8173 30.6264 14.8173C28.6298 14.8173 27.2273 13.1507 27.2273 10.5767C27.2273 8.00263 28.6298 6.3361 30.6264 6.3361C32.6229 6.3361 34.0254 8.00263 34.0254 10.5767Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M42.0868 16.6819C44.5124 16.6819 45.8984 14.6358 45.8984 12.1773C45.8984 9.71871 44.5124 7.67267 42.0868 7.67267C40.9648 7.67267 40.1398 8.11818 39.5953 8.76169V7.83767H37.6152V19.4704H39.5953V15.5928C40.1398 16.2364 40.9648 16.6819 42.0868 16.6819ZM39.5458 11.9298C39.5458 10.2962 40.4698 9.40521 41.6908 9.40521C43.1264 9.40521 43.9019 10.5272 43.9019 12.1773C43.9019 13.8273 43.1264 14.9493 41.6908 14.9493C40.4698 14.9493 39.5458 14.0418 39.5458 12.4413V11.9298Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M51.2545 16.6819C52.987 16.6819 54.3565 15.7743 54.967 14.2563L53.2675 13.6128C53.0035 14.5038 52.228 14.9988 51.2545 14.9988C49.9839 14.9988 49.0929 14.0913 48.9444 12.6063H55.0165V11.9463C55.0165 9.57021 53.68 7.67267 51.172 7.67267C48.6639 7.67267 47.0469 9.63621 47.0469 12.1773C47.0469 14.8503 48.7794 16.6819 51.2545 16.6819ZM51.1555 9.3392C52.4095 9.3392 53.0035 10.1642 53.02 11.1212H49.0434C49.3404 9.94972 50.1324 9.3392 51.1555 9.3392Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M56.5039 16.5004H58.484V11.4182C58.484 10.1807 59.3915 9.52071 60.2825 9.52071C61.3715 9.52071 61.8005 10.2962 61.8005 11.3687V16.5004H63.7806V10.7912C63.7806 8.9267 62.6915 7.67267 60.8765 7.67267C59.7545 7.67267 58.979 8.18418 58.484 8.76169V7.83767H56.5039V16.5004Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M69.5799 4.65308L65.0918 16.5003H67.1873L68.1939 13.7943H73.309L74.332 16.5003H76.4605L71.9724 4.65308H69.5799ZM70.7349 6.99613L72.616 11.9462H68.8869L70.7349 6.99613Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M79.8581 4.6875H77.7461V16.5348H79.8581V4.6875Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20.2769 9.00436C20.776 7.50627 20.6041 5.86517 19.8059 4.50251C18.6055 2.41247 16.1924 1.3372 13.8356 1.84321C12.7871 0.662057 11.2808 -0.00964523 9.70154 -2.00271e-05C7.29248 -0.00552014 5.155 1.54551 4.41386 3.83769C2.86626 4.15463 1.53042 5.12334 0.748717 6.49631C-0.460621 8.58085 -0.184928 11.2085 1.43073 12.9961C0.931596 14.4942 1.10348 16.1353 1.90168 17.4979C3.10208 19.588 5.51526 20.6632 7.87206 20.1572C8.91983 21.3384 10.4269 22.0101 12.0061 21.9998C14.4165 22.006 16.5547 20.4535 17.2958 18.1593C18.8434 17.8424 20.1793 16.8737 20.961 15.5007C22.1689 13.4161 21.8925 10.7905 20.2776 9.00298L20.2769 9.00436ZM12.0075 20.5622C11.0429 20.5635 10.1085 20.226 9.36809 19.6079C9.40178 19.59 9.46022 19.5577 9.49803 19.5343L13.8789 17.0043C14.103 16.8771 14.2405 16.6385 14.2391 16.3807V10.2048L16.0906 11.2738C16.1105 11.2835 16.1236 11.3027 16.1264 11.3247V16.4391C16.1236 18.7134 14.2818 20.5574 12.0075 20.5622ZM3.14952 16.7788C2.6662 15.9441 2.49225 14.9658 2.65795 14.0163C2.69026 14.0356 2.74732 14.0707 2.78789 14.094L7.16873 16.6241C7.3908 16.754 7.6658 16.754 7.88856 16.6241L13.2367 13.5358V15.6739C13.2381 15.6959 13.2278 15.7173 13.2106 15.731L8.78233 18.2879C6.80985 19.4236 4.29079 18.7485 3.15021 16.7788H3.14952ZM1.99656 7.21613C2.47782 6.38012 3.23752 5.74073 4.14229 5.40866C4.14229 5.44647 4.14023 5.51316 4.14023 5.55991V10.6207C4.13885 10.8778 4.27636 11.1164 4.4998 11.2436L9.84798 14.3312L7.9965 15.4003C7.97794 15.4127 7.95456 15.4147 7.93393 15.4058L3.50496 12.8469C1.53661 11.707 0.86147 9.18861 1.99587 7.21682L1.99656 7.21613ZM17.2085 10.7561L11.8603 7.66783L13.7118 6.59943C13.7304 6.58706 13.7537 6.585 13.7744 6.59393L18.2033 9.1508C20.1751 10.29 20.851 12.8125 19.7118 14.7843C19.2298 15.6189 18.4708 16.2583 17.5667 16.5911V11.379C17.5688 11.1219 17.432 10.884 17.2092 10.7561H17.2085ZM19.0511 7.98271C19.0187 7.96278 18.9617 7.9284 18.9211 7.90502L14.5403 5.37497C14.3182 5.24503 14.0432 5.24503 13.8204 5.37497L8.47226 8.46329V6.32512C8.47088 6.30311 8.4812 6.2818 8.49838 6.26805L12.9267 3.71325C14.8991 2.57541 17.4209 3.25261 18.5581 5.22578C19.0387 6.05905 19.2126 7.03463 19.0497 7.98271H19.0511ZM7.46574 11.7936L5.61357 10.7245C5.59363 10.7149 5.58057 10.6956 5.57782 10.6736V5.55922C5.5792 3.28218 7.42655 1.43689 9.7036 1.43826C10.6668 1.43826 11.5991 1.77652 12.3395 2.39253C12.3058 2.41041 12.2481 2.44272 12.2096 2.46609L7.82874 4.99615C7.60461 5.12334 7.46711 5.36122 7.46849 5.61904L7.46574 11.7922V11.7936ZM8.47157 9.62519L10.8538 8.24947L13.236 9.6245V12.3752L10.8538 13.7503L8.47157 12.3752V9.62519Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Openai"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/other/Openai.tsx b/app/components/base/icons/src/vender/other/Openai.tsx
new file mode 100644
index 0000000..bcb7337
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/Openai.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Openai.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Openai'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/other/ReplayLine.json b/app/components/base/icons/src/vender/other/ReplayLine.json
new file mode 100644
index 0000000..0fffbc9
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/ReplayLine.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "viewBox": "0 0 20 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Retry"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M9.99996 1.66669C14.6023 1.66669 18.3333 5.39765 18.3333 10C18.3333 14.6024 14.6023 18.3334 9.99996 18.3334C5.39758 18.3334 1.66663 14.6024 1.66663 10H3.33329C3.33329 13.6819 6.31806 16.6667 9.99996 16.6667C13.6819 16.6667 16.6666 13.6819 16.6666 10C16.6666 6.31812 13.6819 3.33335 9.99996 3.33335C7.70848 3.33335 5.68702 4.48947 4.48705 6.25022L6.66663 6.25002V7.91669H1.66663V2.91669H3.33329L3.3332 4.99934C4.85358 2.97565 7.2739 1.66669 9.99996 1.66669Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ReplayLine"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/other/ReplayLine.tsx b/app/components/base/icons/src/vender/other/ReplayLine.tsx
new file mode 100644
index 0000000..29f7137
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/ReplayLine.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ReplayLine.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ReplayLine'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/other/index.ts b/app/components/base/icons/src/vender/other/index.ts
new file mode 100644
index 0000000..8ddf5e7
--- /dev/null
+++ b/app/components/base/icons/src/vender/other/index.ts
@@ -0,0 +1,5 @@
+export { default as AnthropicText } from './AnthropicText'
+export { default as Generator } from './Generator'
+export { default as Group } from './Group'
+export { default as Openai } from './Openai'
+export { default as ReplayLine } from './ReplayLine'
diff --git a/app/components/base/icons/src/vender/plugin/BoxSparkleFill.json b/app/components/base/icons/src/vender/plugin/BoxSparkleFill.json
new file mode 100644
index 0000000..3733f98
--- /dev/null
+++ b/app/components/base/icons/src/vender/plugin/BoxSparkleFill.json
@@ -0,0 +1,66 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M11.3891 2.41987C11.6635 2.58871 11.749 2.94802 11.5802 3.22239L10.3324 5.25H11.0833C11.4055 5.25 11.6667 5.51117 11.6667 5.83334V11.6667C11.6667 12.311 11.1444 12.8333 10.5 12.8333H3.50001C2.85568 12.8333 2.33334 12.311 2.33334 11.6667V5.83334C2.33334 5.51117 2.59451 5.25 2.91668 5.25H8.96252L10.5865 2.61094C10.7554 2.33657 11.1147 2.25102 11.3891 2.41987ZM5.83334 7.58334C5.51118 7.58334 5.25001 7.84449 5.25001 8.16667C5.25001 8.48884 5.51118 8.75 5.83334 8.75H8.16668C8.48885 8.75 8.75001 8.48884 8.75001 8.16667C8.75001 7.84449 8.48885 7.58334 8.16668 7.58334H5.83334Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector_2",
+ "opacity": "0.5"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.91257 1.79347C6.96898 1.76525 7.01477 1.71948 7.043 1.66303L7.32195 1.10508C7.42946 0.890105 7.73623 0.890105 7.84374 1.10508L8.12269 1.66303C8.15093 1.71948 8.19672 1.76525 8.25313 1.79347L8.81108 2.07245C9.0261 2.17994 9.0261 2.48672 8.81108 2.5942L8.25313 2.87318C8.19672 2.9014 8.15093 2.94717 8.12269 3.00362L7.84374 3.56158C7.73623 3.77655 7.42946 3.77655 7.32195 3.56158L7.043 3.00362C7.01477 2.94717 6.96898 2.9014 6.91257 2.87318L6.35461 2.5942C6.13965 2.48672 6.13965 2.17994 6.35461 2.07245L6.91257 1.79347Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.80145 2.7657C3.85789 2.73748 3.90366 2.69171 3.93189 2.63526L4.11364 2.27174C4.22113 2.05677 4.5279 2.05677 4.63539 2.27174L4.81715 2.63526C4.84537 2.6917 4.89114 2.73748 4.94759 2.7657L5.3111 2.94745C5.52607 3.05494 5.52607 3.36172 5.3111 3.4692L4.94759 3.65096C4.89114 3.67919 4.84537 3.72495 4.81715 3.7814L4.63539 4.14491C4.5279 4.35988 4.22113 4.35988 4.11364 4.14491L3.93189 3.7814C3.90366 3.72495 3.85789 3.67919 3.80145 3.65096L3.43793 3.4692C3.22296 3.36172 3.22296 3.05494 3.43793 2.94745L3.80145 2.7657Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "BoxSparkleFill"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/plugin/BoxSparkleFill.tsx b/app/components/base/icons/src/vender/plugin/BoxSparkleFill.tsx
new file mode 100644
index 0000000..500f3e7
--- /dev/null
+++ b/app/components/base/icons/src/vender/plugin/BoxSparkleFill.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BoxSparkleFill.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BoxSparkleFill'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/plugin/LeftCorner.json b/app/components/base/icons/src/vender/plugin/LeftCorner.json
new file mode 100644
index 0000000..d4cd0cd
--- /dev/null
+++ b/app/components/base/icons/src/vender/plugin/LeftCorner.json
@@ -0,0 +1,27 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "13",
+ "height": "20",
+ "viewBox": "0 0 13 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Shape",
+ "d": "M0 0H13V20C9.98017 20 7.26458 18.1615 6.14305 15.3576L0 0Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "LeftCorner"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/plugin/LeftCorner.tsx b/app/components/base/icons/src/vender/plugin/LeftCorner.tsx
new file mode 100644
index 0000000..93b6827
--- /dev/null
+++ b/app/components/base/icons/src/vender/plugin/LeftCorner.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LeftCorner.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LeftCorner'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/plugin/index.ts b/app/components/base/icons/src/vender/plugin/index.ts
new file mode 100644
index 0000000..943c764
--- /dev/null
+++ b/app/components/base/icons/src/vender/plugin/index.ts
@@ -0,0 +1,2 @@
+export { default as BoxSparkleFill } from './BoxSparkleFill'
+export { default as LeftCorner } from './LeftCorner'
diff --git a/app/components/base/icons/src/vender/solid/FinanceAndECommerce/GoldCoin.json b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/GoldCoin.json
new file mode 100644
index 0000000..dac0e56
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/GoldCoin.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12 1C9.82441 1 7.69767 1.64514 5.88873 2.85383C4.07979 4.06253 2.66989 5.7805 1.83733 7.79048C1.00477 9.80047 0.786929 12.0122 1.21137 14.146C1.6358 16.2798 2.68345 18.2398 4.22183 19.7782C5.76021 21.3166 7.72022 22.3642 9.85401 22.7886C11.9878 23.2131 14.1995 22.9952 16.2095 22.1627C18.2195 21.3301 19.9375 19.9202 21.1462 18.1113C22.3549 16.3023 23 14.1756 23 12C23 9.08262 21.8411 6.28473 19.7782 4.22183C17.7153 2.15893 14.9174 1 12 1ZM15.0296 6.26992L16.1076 4.78675C16.1784 4.6893 16.2677 4.60675 16.3703 4.54381C16.473 4.48087 16.5871 4.43877 16.7061 4.41992C16.825 4.40106 16.9465 4.40582 17.0636 4.43393C17.1807 4.46203 17.2912 4.51293 17.3886 4.58371C17.4861 4.65449 17.5686 4.74377 17.6316 4.84646C17.6945 4.94915 17.7366 5.06322 17.7555 5.18218C17.7743 5.30113 17.7696 5.42264 17.7415 5.53975C17.7134 5.65687 17.6625 5.7673 17.5917 5.86475L16.5137 7.34792C16.3707 7.54472 16.1554 7.67667 15.9152 7.71475C15.675 7.75283 15.4294 7.69391 15.2326 7.55096C15.0358 7.40801 14.9039 7.19273 14.8658 6.95249C14.8277 6.71225 14.8866 6.46672 15.0296 6.26992ZM6.61184 4.58417C6.70931 4.51294 6.81989 4.46167 6.93722 4.4333C7.05456 4.40493 7.17635 4.40002 7.29559 4.41884C7.41484 4.43766 7.52919 4.47985 7.63208 4.54299C7.73497 4.60613 7.82438 4.68897 7.89517 4.78675L8.97501 6.26992C9.11796 6.46733 9.17663 6.71344 9.13813 6.95411C9.09962 7.19478 8.96708 7.4103 8.76967 7.55325C8.57226 7.6962 8.32615 7.75488 8.08548 7.71637C7.84481 7.67786 7.62929 7.54533 7.48634 7.34792L6.40834 5.86475C6.33759 5.76731 6.28673 5.65689 6.25867 5.5398C6.23061 5.4227 6.22589 5.30122 6.24479 5.1823C6.26368 5.06338 6.30583 4.94935 6.36881 4.84672C6.43179 4.74409 6.51437 4.65487 6.61184 4.58417ZM6.18101 14.8508L4.43934 15.4173C4.32353 15.4604 4.2002 15.4797 4.07677 15.4739C3.95333 15.4681 3.83234 15.4375 3.72106 15.3837C3.60978 15.33 3.51051 15.2544 3.42922 15.1613C3.34793 15.0682 3.28629 14.9597 3.24801 14.8422C3.20973 14.7247 3.19561 14.6007 3.20648 14.4776C3.21735 14.3545 3.253 14.2349 3.31128 14.1259C3.36955 14.017 3.44926 13.9209 3.54561 13.8435C3.64195 13.7662 3.75295 13.7091 3.87192 13.6757L5.61359 13.1092C5.72952 13.0656 5.85308 13.046 5.9768 13.0515C6.10053 13.057 6.22185 13.0875 6.33345 13.1412C6.44505 13.1949 6.54461 13.2707 6.62613 13.3639C6.70764 13.4572 6.76941 13.566 6.80772 13.6837C6.84603 13.8015 6.86007 13.9258 6.84901 14.0492C6.83794 14.1725 6.802 14.2923 6.74334 14.4014C6.68468 14.5105 6.60453 14.6065 6.50773 14.6838C6.41092 14.761 6.30038 14.8179 6.18101 14.8508ZM12.9167 20.25C12.9167 20.4931 12.8201 20.7263 12.6482 20.8982C12.4763 21.0701 12.2431 21.1667 12 21.1667C11.7569 21.1667 11.5237 21.0701 11.3518 20.8982C11.1799 20.7263 11.0833 20.4931 11.0833 20.25V18.4167C11.0833 18.1736 11.1799 17.9404 11.3518 17.7685C11.5237 17.5966 11.7569 17.5 12 17.5C12.2431 17.5 12.4763 17.5966 12.6482 17.7685C12.8201 17.9404 12.9167 18.1736 12.9167 18.4167V20.25ZM12 14.9333L8.54967 16.7483L9.20876 12.9066L6.4175 10.1859L10.2748 9.62583L12 6.13333L13.7252 9.62583L17.5825 10.1859L14.7913 12.9066L15.4503 16.7483L12 14.9333ZM19.5625 15.4192L17.8208 14.8527C17.7015 14.8197 17.59 14.7629 17.4932 14.6856C17.3964 14.6084 17.3162 14.5123 17.2576 14.4032C17.1989 14.2942 17.163 14.1743 17.1519 14.051C17.1409 13.9276 17.1549 13.8033 17.1932 13.6856C17.2315 13.5678 17.2933 13.459 17.3748 13.3658C17.4563 13.2725 17.5559 13.1968 17.6675 13.1431C17.7791 13.0894 17.9004 13.0588 18.0241 13.0533C18.1479 13.0478 18.2714 13.0674 18.3873 13.111L20.129 13.6775C20.248 13.7109 20.359 13.768 20.4553 13.8454C20.5517 13.9227 20.6314 14.0188 20.6897 14.1278C20.7479 14.2367 20.7836 14.3563 20.7944 14.4794C20.8053 14.6025 20.7912 14.7265 20.7529 14.844C20.7146 14.9615 20.653 15.0701 20.5717 15.1631C20.4904 15.2562 20.3911 15.3319 20.2799 15.3856C20.1686 15.4393 20.0476 15.47 19.9242 15.4757C19.8007 15.4815 19.6783 15.4623 19.5625 15.4192Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "GoldCoin"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/FinanceAndECommerce/GoldCoin.tsx b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/GoldCoin.tsx
new file mode 100644
index 0000000..d912a6b
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/GoldCoin.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './GoldCoin.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'GoldCoin'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/FinanceAndECommerce/Scales02.json b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/Scales02.json
new file mode 100644
index 0000000..9a781bd
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/Scales02.json
@@ -0,0 +1,48 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.64494 5.5L4 5.50001C3.44772 5.50001 3 5.05229 3 4.50001C3 3.94772 3.44771 3.50001 4 3.50001L8.64494 3.5C9.07521 2.05426 10.4145 1 12 1C13.5855 1 14.9248 2.05426 15.3551 3.5L20 3.5C20.5523 3.5 21 3.94772 21 4.5C21 5.05229 20.5523 5.5 20 5.5L15.3551 5.5C15.0191 6.62889 14.1289 7.51909 13 7.85506V20H20C20.5523 20 21 20.4477 21 21C21 21.5523 20.5523 22 20 22L4 22C3.44772 22 3 21.5523 3 21C3 20.4477 3.44772 20 4 20H11V7.85506C9.87111 7.51909 8.98091 6.62889 8.64494 5.5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.49998 7C5.83892 7 6.15479 7.17168 6.33914 7.4561L9.34294 12.0905C9.5058 12.3416 9.65261 12.5678 9.77323 12.9247C9.82544 13.0792 9.86232 13.2714 9.88454 13.4092C9.90677 13.5471 9.93212 13.7411 9.93109 13.9042C9.9302 14.0459 9.92522 14.1726 9.90862 14.2966C9.89198 14.421 9.86633 14.5189 9.85041 14.5797L9.84797 14.5891C9.33962 16.5355 7.60137 18 5.49998 18C3.3986 18 1.66034 16.5355 1.152 14.5891L1.14959 14.5798C1.13367 14.5191 1.108 14.421 1.09135 14.2966C1.07475 14.1726 1.06977 14.0459 1.06888 13.9042C1.06785 13.7411 1.0932 13.5471 1.11542 13.4092C1.13765 13.2714 1.17453 13.0792 1.22674 12.9247C1.34736 12.5678 1.49417 12.3416 1.65703 12.0905L4.66083 7.4561C4.84518 7.17168 5.16105 7 5.49998 7ZM5.49998 9.83859L4.09907 12H6.9009L5.49998 9.83859Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M19.3391 7.4561C19.1548 7.17168 18.8389 7 18.5 7C18.161 7 17.8452 7.17168 17.6608 7.4561L14.657 12.0905C14.4942 12.3416 14.3474 12.5678 14.2267 12.9247C14.1745 13.0792 14.1376 13.2714 14.1154 13.4092C14.0932 13.5471 14.0679 13.7411 14.0689 13.9042C14.0698 14.0459 14.0748 14.1726 14.0914 14.2966C14.108 14.421 14.1337 14.519 14.1496 14.5798L14.152 14.5891C14.6603 16.5355 16.3986 18 18.5 18C20.6014 18 22.3396 16.5355 22.848 14.5891L22.8504 14.5798C22.8663 14.5191 22.892 14.421 22.9086 14.2966C22.9252 14.1726 22.9302 14.0459 22.9311 13.9042C22.9321 13.7411 22.9068 13.5471 22.8845 13.4092C22.8623 13.2714 22.8254 13.0792 22.7732 12.9247C22.6526 12.5678 22.5058 12.3416 22.3429 12.0905L19.3391 7.4561ZM17.0991 12L18.5 9.83859L19.9009 12H17.0991Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Scales02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/FinanceAndECommerce/Scales02.tsx b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/Scales02.tsx
new file mode 100644
index 0000000..5a4ad8b
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/Scales02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Scales02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Scales02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/FinanceAndECommerce/index.ts b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/index.ts
new file mode 100644
index 0000000..777fe96
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/FinanceAndECommerce/index.ts
@@ -0,0 +1,2 @@
+export { default as GoldCoin } from './GoldCoin'
+export { default as Scales02 } from './Scales02'
diff --git a/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle.json b/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle.json
new file mode 100644
index 0000000..c73fbc5
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "alert-triangle"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6.40616 0.834185C6.14751 0.719172 5.85222 0.719172 5.59356 0.834185C5.3938 0.923011 5.26403 1.07947 5.17373 1.20696C5.08495 1.3323 4.9899 1.49651 4.88536 1.67711L0.751783 8.81693C0.646828 8.99818 0.551451 9.16289 0.486781 9.30268C0.421056 9.44475 0.349754 9.63572 0.372478 9.85369C0.401884 10.1357 0.549654 10.392 0.779012 10.5588C0.956259 10.6877 1.15726 10.7217 1.31314 10.736C1.46651 10.75 1.65684 10.75 1.86628 10.75H10.1334C10.3429 10.75 10.5332 10.75 10.6866 10.736C10.8425 10.7217 11.0435 10.6877 11.2207 10.5588C11.4501 10.392 11.5978 10.1357 11.6272 9.85369C11.65 9.63572 11.5787 9.44475 11.5129 9.30268C11.4483 9.1629 11.3529 8.9982 11.248 8.81697L7.11436 1.67709C7.00983 1.49651 6.91477 1.3323 6.82599 1.20696C6.73569 1.07947 6.60593 0.923011 6.40616 0.834185ZM6.49988 4.5C6.49988 4.22386 6.27602 4 5.99988 4C5.72374 4 5.49988 4.22386 5.49988 4.5V6.5C5.49988 6.77614 5.72374 7 5.99988 7C6.27602 7 6.49988 6.77614 6.49988 6.5V4.5ZM5.99988 8C5.72374 8 5.49988 8.22386 5.49988 8.5C5.49988 8.77614 5.72374 9 5.99988 9H6.00488C6.28102 9 6.50488 8.77614 6.50488 8.5C6.50488 8.22386 6.28102 8 6.00488 8H5.99988Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "AlertTriangle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle.tsx b/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle.tsx
new file mode 100644
index 0000000..cceacb9
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AlertTriangle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AlertTriangle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/alertsAndFeedback/index.ts b/app/components/base/icons/src/vender/solid/alertsAndFeedback/index.ts
new file mode 100644
index 0000000..6ad90c1
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/alertsAndFeedback/index.ts
@@ -0,0 +1 @@
+export { default as AlertTriangle } from './AlertTriangle'
diff --git a/app/components/base/icons/src/vender/solid/arrows/ChevronDown.json b/app/components/base/icons/src/vender/solid/arrows/ChevronDown.json
new file mode 100644
index 0000000..ef9a33d
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/arrows/ChevronDown.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "chevron-down"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M6 9L12 15L18 9",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ChevronDown"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/arrows/ChevronDown.tsx b/app/components/base/icons/src/vender/solid/arrows/ChevronDown.tsx
new file mode 100644
index 0000000..e08b7db
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/arrows/ChevronDown.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ChevronDown.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ChevronDown'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/arrows/HighPriority.json b/app/components/base/icons/src/vender/solid/arrows/HighPriority.json
new file mode 100644
index 0000000..6710fd8
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/arrows/HighPriority.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.01488 2.54553C8.91549 2.45869 8.79321 2.40229 8.66264 2.38306C8.53206 2.36384 8.39872 2.38261 8.27852 2.43712C8.15833 2.49164 8.05636 2.5796 7.98481 2.6905C7.91325 2.8014 7.87513 2.93055 7.875 3.06253V6.50003C6.05164 6.50003 4.30295 7.22436 3.01364 8.51367C1.72433 9.80299 1 11.5517 1 13.375C1 15.1984 1.72433 16.9471 3.01364 18.2364C4.30295 19.5257 6.05164 20.25 7.875 20.25H12C12.3647 20.25 12.7144 20.1052 12.9723 19.8473C13.2301 19.5894 13.375 19.2397 13.375 18.875C13.375 18.5104 13.2301 18.1606 12.9723 17.9028C12.7144 17.6449 12.3647 17.5 12 17.5H7.875C6.78098 17.5 5.73177 17.0654 4.95818 16.2919C4.1846 15.5183 3.75 14.4691 3.75 13.375C3.75 12.281 4.1846 11.2318 4.95818 10.4582C5.73177 9.68463 6.78098 9.25003 7.875 9.25003V12.6875C7.87513 12.8195 7.91325 12.9487 7.98481 13.0596C8.05636 13.1705 8.15833 13.2584 8.27852 13.3129C8.39872 13.3675 8.53206 13.3862 8.66264 13.367C8.79321 13.3478 8.91549 13.2914 9.01488 13.2045L14.5149 8.39203C14.5885 8.32751 14.6475 8.24801 14.6879 8.15885C14.7283 8.06969 14.7492 7.97292 14.7492 7.87503C14.7492 7.77714 14.7283 7.68038 14.6879 7.59122C14.6475 7.50206 14.5885 7.42256 14.5149 7.35803L9.01488 2.54553Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.625 17.5H17.5C17.1353 17.5 16.7856 17.6449 16.5277 17.9028C16.2699 18.1606 16.125 18.5104 16.125 18.875C16.125 19.2397 16.2699 19.5894 16.5277 19.8473C16.7856 20.1052 17.1353 20.25 17.5 20.25H21.625C21.9897 20.25 22.3394 20.1052 22.5973 19.8473C22.8551 19.5894 23 19.2397 23 18.875C23 18.5104 22.8551 18.1606 22.5973 17.9028C22.3394 17.6449 21.9897 17.5 21.625 17.5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.625 12H17.5C17.1353 12 16.7856 12.1449 16.5277 12.4028C16.2699 12.6606 16.125 13.0104 16.125 13.375C16.125 13.7397 16.2699 14.0894 16.5277 14.3473C16.7856 14.6052 17.1353 14.75 17.5 14.75H21.625C21.9897 14.75 22.3394 14.6052 22.5973 14.3473C22.8551 14.0894 23 13.7397 23 13.375C23 13.0104 22.8551 12.6606 22.5973 12.4028C22.3394 12.1449 21.9897 12 21.625 12Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.5 9.25003H21.625C21.9897 9.25003 22.3394 9.10517 22.5973 8.8473C22.8551 8.58944 23 8.23971 23 7.87503C23 7.51036 22.8551 7.16062 22.5973 6.90276C22.3394 6.6449 21.9897 6.50003 21.625 6.50003H17.5C17.1353 6.50003 16.7856 6.6449 16.5277 6.90276C16.2699 7.16062 16.125 7.51036 16.125 7.87503C16.125 8.23971 16.2699 8.58944 16.5277 8.8473C16.7856 9.10517 17.1353 9.25003 17.5 9.25003Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "HighPriority"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/arrows/HighPriority.tsx b/app/components/base/icons/src/vender/solid/arrows/HighPriority.tsx
new file mode 100644
index 0000000..4d25be2
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/arrows/HighPriority.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './HighPriority.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'HighPriority'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/arrows/index.ts b/app/components/base/icons/src/vender/solid/arrows/index.ts
new file mode 100644
index 0000000..468f0e5
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/arrows/index.ts
@@ -0,0 +1,2 @@
+export { default as ChevronDown } from './ChevronDown'
+export { default as HighPriority } from './HighPriority'
diff --git a/app/components/base/icons/src/vender/solid/communication/AiText.json b/app/components/base/icons/src/vender/solid/communication/AiText.json
new file mode 100644
index 0000000..c6e30fb
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/AiText.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 5C3.44772 5 3 5.44772 3 6C3 6.55228 3.44772 7 4 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5H4Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.9191 9.60608C17.7616 9.2384 17.4 9 17 9C16.6 9 16.2384 9.2384 16.0809 9.60608L14.7384 12.7384L11.6061 14.0809C11.2384 14.2384 11 14.6 11 15C11 15.4 11.2384 15.7616 11.6061 15.9191L14.7384 17.2616L16.0809 20.3939C16.2384 20.7616 16.6 21 17 21C17.4 21 17.7616 20.7616 17.9191 20.3939L19.2616 17.2616L22.3939 15.9191C22.7616 15.7616 23 15.4 23 15C23 14.6 22.7616 14.2384 22.3939 14.0809L19.2616 12.7384L17.9191 9.60608Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 11C3.44772 11 3 11.4477 3 12C3 12.5523 3.44772 13 4 13H9C9.55228 13 10 12.5523 10 12C10 11.4477 9.55228 11 9 11H4Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 17C3.44772 17 3 17.4477 3 18C3 18.5523 3.44772 19 4 19H7C7.55228 19 8 18.5523 8 18C8 17.4477 7.55228 17 7 17H4Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "AiText"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/AiText.tsx b/app/components/base/icons/src/vender/solid/communication/AiText.tsx
new file mode 100644
index 0000000..c1a6a24
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/AiText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AiText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AiText'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/BubbleTextMod.json b/app/components/base/icons/src/vender/solid/communication/BubbleTextMod.json
new file mode 100644
index 0000000..fceddcc
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/BubbleTextMod.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M2 9C2 5.68629 4.68629 3 8 3H16C19.3137 3 22 5.68629 22 9V15C22 18.3137 19.3137 21 16 21H3C2.44772 21 2 20.5523 2 20V9ZM9 9C8.44772 9 8 9.44772 8 10C8 10.5523 8.44772 11 9 11H15C15.5523 11 16 10.5523 16 10C16 9.44772 15.5523 9 15 9H9ZM9 13C8.44772 13 8 13.4477 8 14C8 14.5523 8.44772 15 9 15H12C12.5523 15 13 14.5523 13 14C13 13.4477 12.5523 13 12 13H9Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "BubbleTextMod"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/BubbleTextMod.tsx b/app/components/base/icons/src/vender/solid/communication/BubbleTextMod.tsx
new file mode 100644
index 0000000..da3ed73
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/BubbleTextMod.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BubbleTextMod.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BubbleTextMod'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/ChatBot.json b/app/components/base/icons/src/vender/solid/communication/ChatBot.json
new file mode 100644
index 0000000..024b0ed
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/ChatBot.json
@@ -0,0 +1,58 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "13",
+ "height": "12",
+ "viewBox": "0 0 13 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "chat-bot"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M4.20913 2.76912L4.09542 2.83543L3.98172 2.76912C3.90566 2.72476 3.86328 2.64979 3.86328 2.57101C3.86328 2.44347 3.96789 2.33887 4.09542 2.33887C4.22296 2.33887 4.32757 2.44347 4.32757 2.57101C4.32757 2.64979 4.28519 2.72476 4.20913 2.76912Z",
+ "fill": "currentColor",
+ "stroke": "currentColor",
+ "stroke-width": "1.25"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M10.0174 6.00058C10.0123 5.98686 10.0097 5.97229 10.0046 5.95858C9.81684 5.48158 9.35398 5.14258 8.81056 5.14258H8.66784L7.52484 5.99972C7.33713 6.14029 7.11556 6.21444 6.88284 6.21444C6.29184 6.21444 5.81056 5.73358 5.81056 5.14258H2.81013C2.10127 5.14258 1.52441 5.71944 1.52441 6.42829V9.85686C1.52441 10.5657 2.10127 11.1426 2.81013 11.1426H8.81013C9.51899 11.1426 10.0958 10.5657 10.0958 9.85686V6.42829C10.0958 6.34386 10.0868 6.26158 10.071 6.18186C10.0586 6.11886 10.0384 6.05972 10.0174 6.00058ZM3.88156 8.57115C3.52713 8.57115 3.2387 8.28272 3.2387 7.92829C3.2387 7.57386 3.52713 7.28544 3.88156 7.28544C4.23599 7.28544 4.52441 7.57386 4.52441 7.92829C4.52441 8.28272 4.23599 8.57115 3.88156 8.57115ZM7.7387 8.57115C7.38427 8.57115 7.09584 8.28272 7.09584 7.92829C7.09584 7.57386 7.38427 7.28544 7.7387 7.28544C8.09313 7.28544 8.38156 7.57386 8.38156 7.92829C8.38156 8.28272 8.09313 8.57115 7.7387 8.57115Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M6.66699 5.14314V1.71456C6.66699 1.24099 7.05056 0.857422 7.52413 0.857422H10.9527C11.4263 0.857422 11.8098 1.24099 11.8098 1.71456V3.42885C11.8098 3.90242 11.4263 4.28599 10.9527 4.28599H8.38128L7.00985 5.31456C6.86842 5.42042 6.66699 5.31971 6.66699 5.14314Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ChatBot"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/ChatBot.tsx b/app/components/base/icons/src/vender/solid/communication/ChatBot.tsx
new file mode 100644
index 0000000..867ae31
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/ChatBot.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ChatBot.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ChatBot'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/CuteRobot.json b/app/components/base/icons/src/vender/solid/communication/CuteRobot.json
new file mode 100644
index 0000000..5b36575
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/CuteRobot.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "cute-robot"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12 1C12.5523 1 13 1.44772 13 2V3H17C18.6569 3 20 4.34315 20 6V11C20 11.8885 19.6138 12.6868 19 13.2361V14.5858L20.7071 16.2929C21.0976 16.6834 21.0976 17.3166 20.7071 17.7071C20.3166 18.0976 19.6834 18.0976 19.2929 17.7071L18.681 17.0952C17.7905 19.9377 15.1361 22 12 22C8.8639 22 6.20948 19.9377 5.31897 17.0952L4.70711 17.7071C4.31658 18.0976 3.68342 18.0976 3.29289 17.7071C2.90237 17.3166 2.90237 16.6834 3.29289 16.2929L5 14.5858V13.2361C4.38625 12.6868 4 11.8885 4 11V6C4 4.34315 5.34315 3 7 3H11V2C11 1.44772 11.4477 1 12 1ZM7 5C6.44772 5 6 5.44772 6 6V11C6 11.5523 6.44772 12 7 12H17C17.5523 12 18 11.5523 18 11V6C18 5.44772 17.5523 5 17 5H7ZM9 7C9.55228 7 10 7.44772 10 8V9C10 9.55228 9.55228 10 9 10C8.44772 10 8 9.55228 8 9V8C8 7.44772 8.44772 7 9 7ZM15 7C15.5523 7 16 7.44772 16 8V9C16 9.55228 15.5523 10 15 10C14.4477 10 14 9.55228 14 9V8C14 7.44772 14.4477 7 15 7Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "CuteRobot"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/CuteRobot.tsx b/app/components/base/icons/src/vender/solid/communication/CuteRobot.tsx
new file mode 100644
index 0000000..526bb77
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/CuteRobot.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './CuteRobot.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'CuteRobot'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/EditList.json b/app/components/base/icons/src/vender/solid/communication/EditList.json
new file mode 100644
index 0000000..436f0be
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/EditList.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.00195 4C3.00195 3.44772 3.44967 3 4.00195 3H20.002C20.5542 3 21.002 3.44772 21.002 4C21.002 4.55228 20.5542 5 20.002 5H4.00195C3.44967 5 3.00195 4.55228 3.00195 4Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.00195 8C3.00195 7.44772 3.44967 7 4.00195 7H10.502C11.0542 7 11.502 7.44772 11.502 8C11.502 8.55228 11.0542 9 10.502 9H4.00195C3.44967 9 3.00195 8.55228 3.00195 8Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 11C3.44772 11 3 11.4477 3 12C3 12.5523 3.44772 13 4 13H7.0022C7.55448 13 8.0022 12.5523 8.0022 12C8.0022 11.4477 7.55448 11 7.0022 11H4Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.2584 8.70705C18.0868 7.53548 16.1873 7.53547 15.0158 8.70705L7.29485 16.428C7.10731 16.6155 7.00195 16.8699 7.00195 17.1351V20.9999C7.00195 21.5522 7.44967 21.9999 8.00195 21.9999H11.8668C12.132 21.9999 12.3864 21.8946 12.5739 21.7071L20.2948 13.9861C21.4664 12.8146 21.4664 10.9151 20.2948 9.74349L19.2584 8.70705Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "EditList"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/EditList.tsx b/app/components/base/icons/src/vender/solid/communication/EditList.tsx
new file mode 100644
index 0000000..09fce2c
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/EditList.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './EditList.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'EditList'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/ListSparkle.json b/app/components/base/icons/src/vender/solid/communication/ListSparkle.json
new file mode 100644
index 0000000..2e348e4
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/ListSparkle.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 5C3.44772 5 3 5.44772 3 6C3 6.55228 3.44772 7 4 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5H4Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.9191 9.60608C17.7616 9.2384 17.4 9 17 9C16.6 9 16.2384 9.2384 16.0809 9.60608L14.7384 12.7384L11.6061 14.0809C11.2384 14.2384 11 14.6 11 15C11 15.4 11.2384 15.7616 11.6061 15.9191L14.7384 17.2616L16.0809 20.3939C16.2384 20.7616 16.6 21 17 21C17.4 21 17.7616 20.7616 17.9191 20.3939L19.2616 17.2616L22.3939 15.9191C22.7616 15.7616 23 15.4 23 15C23 14.6 22.7616 14.2384 22.3939 14.0809L19.2616 12.7384L17.9191 9.60608Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 11C3.44772 11 3 11.4477 3 12C3 12.5523 3.44772 13 4 13H9C9.55228 13 10 12.5523 10 12C10 11.4477 9.55228 11 9 11H4Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4 17C3.44772 17 3 17.4477 3 18C3 18.5523 3.44772 19 4 19H7C7.55228 19 8 18.5523 8 18C8 17.4477 7.55228 17 7 17H4Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "ListSparkle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/ListSparkle.tsx b/app/components/base/icons/src/vender/solid/communication/ListSparkle.tsx
new file mode 100644
index 0000000..b42b769
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/ListSparkle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ListSparkle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ListSparkle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/Logic.json b/app/components/base/icons/src/vender/solid/communication/Logic.json
new file mode 100644
index 0000000..57f86f4
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/Logic.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "logic"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.9089 11.9999C13.913 11.9999 14.727 11.186 14.727 10.1819C14.727 9.17775 13.913 8.36376 12.9089 8.36376C11.9048 8.36376 11.0908 9.17775 11.0908 10.1819C11.0908 11.186 11.9048 11.9999 12.9089 11.9999Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.2871 1.11229C9.95219 1.3228 7.78275 2.40696 6.21264 4.14796C4.64254 5.88897 3.78749 8.15849 3.81849 10.5027V10.8763L2.09676 14.3207C2.04261 14.4277 2.01016 14.5444 2.00129 14.6639C1.99241 14.7835 2.00729 14.9037 2.04506 15.0175C2.08283 15.1313 2.14275 15.2366 2.22136 15.3271C2.29997 15.4177 2.39573 15.4918 2.50311 15.5452L3.81849 16.1979V18.3632C3.81849 19.0865 4.10581 19.7802 4.61725 20.2916C5.12869 20.803 5.82234 21.0904 6.54562 21.0904H9.27276V22.9084H19.2722V16.6606C20.5995 15.3604 21.496 13.6844 21.8409 11.8588C22.1858 10.0331 21.9625 8.14562 21.2012 6.45084C20.4398 4.75606 19.1769 3.33556 17.583 2.38094C15.989 1.42633 14.1406 0.983541 12.2871 1.11229ZM17.4542 11.0909H16.416C16.3316 11.4163 16.2016 11.7282 16.0297 12.0172L16.7651 12.7526C16.8519 12.8365 16.9212 12.9368 16.9688 13.0477C17.0165 13.1586 17.0415 13.2779 17.0426 13.3986C17.0436 13.5193 17.0206 13.639 16.9749 13.7507C16.9292 13.8624 16.8617 13.9639 16.7764 14.0493C16.691 14.1346 16.5895 14.2021 16.4778 14.2478C16.3661 14.2935 16.2464 14.3165 16.1257 14.3155C16.005 14.3144 15.8857 14.2893 15.7748 14.2417C15.6639 14.1941 15.5636 14.1248 15.4797 14.038L14.7443 13.3026C14.4553 13.4745 14.1434 13.6045 13.818 13.6889V14.727C13.818 14.9681 13.7222 15.1994 13.5517 15.3698C13.3812 15.5403 13.15 15.6361 12.9089 15.6361C12.6678 15.6361 12.4366 15.5403 12.2661 15.3698C12.0957 15.1994 11.9999 14.9681 11.9999 14.727V13.6889C11.6744 13.6045 11.3625 13.4745 11.0736 13.3026L10.3382 14.038C10.1667 14.2036 9.93708 14.2952 9.69873 14.2931C9.46038 14.2911 9.23239 14.1955 9.06384 14.0269C8.8953 13.8584 8.79969 13.6304 8.79762 13.392C8.79555 13.1537 8.88718 12.924 9.05277 12.7526L9.78818 12.0172C9.61629 11.7282 9.48622 11.4163 9.40184 11.0909H8.36371C8.12262 11.0909 7.8914 10.9951 7.72092 10.8246C7.55044 10.6541 7.45467 10.4229 7.45467 10.1818C7.45467 9.94073 7.55044 9.70951 7.72092 9.53903C7.8914 9.36855 8.12262 9.27278 8.36371 9.27278H9.40184C9.48622 8.94731 9.61629 8.63544 9.78818 8.34647L9.05277 7.61105C8.88718 7.4396 8.79555 7.20997 8.79762 6.97163C8.79969 6.73328 8.8953 6.50528 9.06384 6.33673C9.23239 6.16819 9.46038 6.07259 9.69873 6.07052C9.93708 6.06844 10.1667 6.16007 10.3382 6.32566L11.0736 7.06108C11.3625 6.88918 11.6744 6.75911 11.9999 6.67473V5.63661C11.9999 5.39551 12.0957 5.16429 12.2661 4.99381C12.4366 4.82334 12.6678 4.72756 12.9089 4.72756C13.15 4.72756 13.3812 4.82334 13.5517 4.99381C13.7222 5.16429 13.818 5.39551 13.818 5.63661V6.67473C14.1434 6.75911 14.4553 6.88918 14.7443 7.06108L15.4797 6.32566C15.5636 6.23884 15.6639 6.16958 15.7748 6.12194C15.8857 6.0743 16.005 6.04922 16.1257 6.04817C16.2464 6.04713 16.3661 6.07013 16.4778 6.11583C16.5895 6.16154 16.691 6.22904 16.7764 6.31439C16.8617 6.39975 16.9292 6.50124 16.9749 6.61296C17.0206 6.72468 17.0436 6.84438 17.0426 6.96508C17.0415 7.08578 17.0165 7.20507 16.9688 7.31598C16.9212 7.42688 16.8519 7.52719 16.7651 7.61105L16.0297 8.34647C16.2016 8.63544 16.3316 8.94731 16.416 9.27278H17.4542C17.6952 9.27278 17.9265 9.36855 18.0969 9.53903C18.2674 9.70951 18.3632 9.94073 18.3632 10.1818C18.3632 10.4229 18.2674 10.6541 18.0969 10.8246C17.9265 10.9951 17.6952 11.0909 17.4542 11.0909Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Logic"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/Logic.tsx b/app/components/base/icons/src/vender/solid/communication/Logic.tsx
new file mode 100644
index 0000000..695b341
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/Logic.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Logic.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Logic'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/MessageDotsCircle.json b/app/components/base/icons/src/vender/solid/communication/MessageDotsCircle.json
new file mode 100644
index 0000000..dca92bf
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/MessageDotsCircle.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "message-dots-circle"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12 2C6.47715 2 2 6.47715 2 12C2 13.3283 2.25952 14.5985 2.73156 15.7608C2.77419 15.8658 2.79872 15.9264 2.81552 15.9711L2.82063 15.9849L2.82 15.9897C2.815 16.0266 2.80672 16.0769 2.79071 16.173L2.19294 19.7596C2.16612 19.9202 2.13611 20.0999 2.12433 20.256C2.11148 20.4261 2.10701 20.6969 2.22973 20.983C2.38144 21.3367 2.6633 21.6186 3.017 21.7703C3.30312 21.893 3.57386 21.8885 3.74404 21.8757C3.90013 21.8639 4.07985 21.8339 4.24049 21.8071L7.82705 21.2093C7.92309 21.1933 7.97339 21.185 8.0103 21.18L8.01505 21.1794L8.02887 21.1845C8.07362 21.2013 8.13423 21.2258 8.23921 21.2684C9.4015 21.7405 10.6717 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM6 12C6 11.1716 6.67157 10.5 7.5 10.5C8.32843 10.5 9 11.1716 9 12C9 12.8284 8.32843 13.5 7.5 13.5C6.67157 13.5 6 12.8284 6 12ZM10.5 12C10.5 11.1716 11.1716 10.5 12 10.5C12.8284 10.5 13.5 11.1716 13.5 12C13.5 12.8284 12.8284 13.5 12 13.5C11.1716 13.5 10.5 12.8284 10.5 12ZM16.5 10.5C15.6716 10.5 15 11.1716 15 12C15 12.8284 15.6716 13.5 16.5 13.5C17.3284 13.5 18 12.8284 18 12C18 11.1716 17.3284 10.5 16.5 10.5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "MessageDotsCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/MessageDotsCircle.tsx b/app/components/base/icons/src/vender/solid/communication/MessageDotsCircle.tsx
new file mode 100644
index 0000000..08431ea
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/MessageDotsCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MessageDotsCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MessageDotsCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/MessageFast.json b/app/components/base/icons/src/vender/solid/communication/MessageFast.json
new file mode 100644
index 0000000..4580398
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/MessageFast.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M16.2414 2H7.7588C6.95383 1.99999 6.28946 1.99998 5.74827 2.04419C5.18617 2.09012 4.66947 2.18868 4.18413 2.43598C3.43149 2.81947 2.81956 3.43139 2.43607 4.18404C2.18878 4.66937 2.09022 5.18608 2.04429 5.74818C2.00007 6.28937 2.00008 6.95373 2.0001 7.7587L2.00005 14.1376C1.99962 14.933 1.9993 15.5236 2.13639 16.0353C2.50626 17.4156 3.58445 18.4938 4.96482 18.8637C5.27229 18.9461 5.60829 18.9789 6.0001 18.9918L6.00009 20.371C6.00005 20.6062 6 20.846 6.01785 21.0425C6.03492 21.2305 6.08012 21.5852 6.32778 21.8955C6.61276 22.2525 7.0449 22.4602 7.50172 22.4597C7.8987 22.4593 8.20394 22.273 8.36137 22.1689C8.52597 22.06 8.7132 21.9102 8.89688 21.7632L11.31 19.8327C11.8286 19.4178 11.9826 19.3007 12.1425 19.219C12.303 19.137 12.4738 19.0771 12.6504 19.0408C12.8263 19.0047 13.0197 19 13.6838 19H16.2414C17.0464 19 17.7107 19 18.2519 18.9558C18.814 18.9099 19.3307 18.8113 19.8161 18.564C20.5687 18.1805 21.1806 17.5686 21.5641 16.816C21.8114 16.3306 21.91 15.8139 21.9559 15.2518C22.0001 14.7106 22.0001 14.0463 22.0001 13.2413V7.75868C22.0001 6.95372 22.0001 6.28936 21.9559 5.74818C21.91 5.18608 21.8114 4.66937 21.5641 4.18404C21.1806 3.43139 20.5687 2.81947 19.8161 2.43598C19.3307 2.18868 18.814 2.09012 18.2519 2.04419C17.7107 1.99998 17.0464 1.99999 16.2414 2ZM12.681 5.5349C12.8938 5.61898 13.0218 5.83714 12.9916 6.06386L12.5688 9.23501L14.48 9.23501C14.5899 9.23498 14.7038 9.23496 14.7979 9.24356C14.8905 9.25203 15.0589 9.27446 15.2095 9.39066C15.3851 9.52617 15.4913 9.73269 15.4996 9.95432C15.5066 10.1444 15.427 10.2945 15.38 10.3747C15.3324 10.4563 15.2661 10.549 15.2022 10.6384L11.9072 15.2514C11.7743 15.4375 11.5317 15.5092 11.319 15.4251C11.1063 15.341 10.9782 15.1229 11.0084 14.8961L11.4312 11.725L9.52004 11.725C9.41011 11.725 9.29618 11.725 9.20206 11.7164C9.10948 11.708 8.94106 11.6855 8.79051 11.5693C8.61493 11.4338 8.50866 11.2273 8.50044 11.0057C8.49339 10.8156 8.57303 10.6655 8.61996 10.5853C8.66766 10.5037 8.7339 10.411 8.79781 10.3216L12.0928 5.70858C12.2257 5.52246 12.4683 5.45083 12.681 5.5349Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "MessageFast"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/MessageFast.tsx b/app/components/base/icons/src/vender/solid/communication/MessageFast.tsx
new file mode 100644
index 0000000..45a1e77
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/MessageFast.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MessageFast.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MessageFast'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/MessageHeartCircle.json b/app/components/base/icons/src/vender/solid/communication/MessageHeartCircle.json
new file mode 100644
index 0000000..84769ba
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/MessageHeartCircle.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "message-heart-circle"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.33334 1.3335C4.83554 1.3335 2.00001 4.16903 2.00001 7.66683C2.00001 8.3735 2.116 9.05444 2.33051 9.69084C2.36824 9.80278 2.39045 9.86902 2.40488 9.91786L2.40961 9.93431L2.40711 9.93952C2.38997 9.97486 2.36451 10.0223 2.31687 10.1105L1.21562 12.1489C1.14736 12.2751 1.07614 12.4069 1.02717 12.5214C0.978485 12.6353 0.89963 12.8442 0.93843 13.0919C0.983911 13.3822 1.15477 13.6378 1.40562 13.7908C1.61963 13.9213 1.84282 13.9283 1.96665 13.9269C2.09123 13.9254 2.24018 13.91 2.38296 13.8952L5.8196 13.54C5.87464 13.5343 5.90342 13.5314 5.92449 13.5297L5.92721 13.5295L5.93545 13.5325C5.96135 13.5418 5.99648 13.5553 6.05711 13.5786C6.76441 13.8511 7.53226 14.0002 8.33334 14.0002C11.8311 14.0002 14.6667 11.1646 14.6667 7.66683C14.6667 4.16903 11.8311 1.3335 8.33334 1.3335ZM5.97972 5.72165C6.73124 5.08746 7.73145 5.27376 8.33126 5.96633C8.93106 5.27376 9.91836 5.09414 10.6828 5.72165C11.4472 6.34916 11.5401 7.41616 10.9499 8.16621C10.5843 8.63089 9.66661 9.4796 9.02123 10.0581C8.78417 10.2706 8.66564 10.3769 8.52339 10.4197C8.40136 10.4564 8.26116 10.4564 8.13913 10.4197C7.99688 10.3769 7.87835 10.2706 7.64128 10.0581C6.9959 9.4796 6.0782 8.63089 5.71257 8.16621C5.1224 7.41616 5.22821 6.35583 5.97972 5.72165Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "MessageHeartCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/MessageHeartCircle.tsx b/app/components/base/icons/src/vender/solid/communication/MessageHeartCircle.tsx
new file mode 100644
index 0000000..0894581
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/MessageHeartCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MessageHeartCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MessageHeartCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/MessageSmileSquare.json b/app/components/base/icons/src/vender/solid/communication/MessageSmileSquare.json
new file mode 100644
index 0000000..7810d90
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/MessageSmileSquare.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "message-smile-square"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M10.8273 1.33337H5.17221C4.63556 1.33337 4.19265 1.33336 3.83185 1.36284C3.45712 1.39345 3.11265 1.45916 2.7891 1.62402C2.28733 1.87969 1.87938 2.28763 1.62372 2.7894C1.45886 3.11296 1.39315 3.45743 1.36253 3.83216C1.33306 4.19295 1.33306 4.63586 1.33307 5.17251L1.33304 9.42509C1.33275 9.95535 1.33254 10.3491 1.42394 10.6902C1.67052 11.6105 2.38931 12.3293 3.30955 12.5758C3.51453 12.6308 3.73853 12.6526 3.99974 12.6612L3.99974 13.5807C3.99971 13.7375 3.99967 13.8974 4.01157 14.0284C4.02296 14.1537 4.05309 14.3902 4.2182 14.597C4.40818 14.835 4.69628 14.9735 5.00082 14.9732C5.26547 14.9729 5.46897 14.8487 5.57392 14.7793C5.68366 14.7067 5.80847 14.6068 5.93093 14.5088L7.53968 13.2218C7.8854 12.9453 7.98804 12.8672 8.0947 12.8127C8.20168 12.758 8.31556 12.7181 8.43324 12.6939C8.55057 12.6699 8.6795 12.6667 9.12224 12.6667H10.8273C11.3639 12.6667 11.8068 12.6667 12.1676 12.6372C12.5424 12.6066 12.8868 12.5409 13.2104 12.3761C13.7121 12.1204 14.1201 11.7124 14.3758 11.2107C14.5406 10.8871 14.6063 10.5427 14.6369 10.1679C14.6664 9.80713 14.6664 9.36423 14.6664 8.82759V5.17249C14.6664 4.63585 14.6664 4.19295 14.6369 3.83216C14.6063 3.45743 14.5406 3.11296 14.3758 2.7894C14.1201 2.28763 13.7121 1.87969 13.2104 1.62402C12.8868 1.45916 12.5424 1.39345 12.1676 1.36284C11.8068 1.33336 11.3639 1.33337 10.8273 1.33337ZM8.99479 5.00004C8.99479 4.44776 9.44251 4.00004 9.99479 4.00004C10.5471 4.00004 10.9948 4.44776 10.9948 5.00004C10.9948 5.55233 10.5471 6.00004 9.99479 6.00004C9.44251 6.00004 8.99479 5.55233 8.99479 5.00004ZM4.92813 7.80008C5.22175 7.57986 5.63792 7.63849 5.85937 7.93064C5.90047 7.98307 5.94569 8.03241 5.99175 8.08048C6.08995 8.18295 6.23751 8.32196 6.42858 8.46092C6.81329 8.74071 7.34515 9.00008 7.9948 9.00008C8.64444 9.00008 9.17631 8.74071 9.56102 8.46092C9.75209 8.32196 9.89965 8.18295 9.99785 8.08048C10.0439 8.03242 10.0891 7.98306 10.1302 7.93064C10.3517 7.63849 10.7678 7.57986 11.0615 7.80008C11.356 8.02099 11.4157 8.43886 11.1948 8.73341C11.1965 8.73124 11.1925 8.73622 11.1857 8.74479C11.1695 8.76522 11.137 8.8061 11.1259 8.81929C11.0868 8.86587 11.0315 8.92896 10.9605 9.00302C10.8191 9.15055 10.6125 9.34486 10.3452 9.53924C9.81328 9.92612 9.01182 10.3334 7.9948 10.3334C6.97778 10.3334 6.17631 9.92612 5.64435 9.53924C5.37709 9.34486 5.17048 9.15055 5.0291 9.00302C4.95813 8.92896 4.9028 8.86587 4.8637 8.81929C4.84413 8.79597 4.82856 8.77671 4.81707 8.76219C4.58678 8.46467 4.61774 8.03288 4.92813 7.80008ZM5.99479 4.00004C5.44251 4.00004 4.99479 4.44776 4.99479 5.00004C4.99479 5.55233 5.44251 6.00004 5.99479 6.00004C6.54708 6.00004 6.99479 5.55233 6.99479 5.00004C6.99479 4.44776 6.54708 4.00004 5.99479 4.00004Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "MessageSmileSquare"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/MessageSmileSquare.tsx b/app/components/base/icons/src/vender/solid/communication/MessageSmileSquare.tsx
new file mode 100644
index 0000000..ece3080
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/MessageSmileSquare.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MessageSmileSquare.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MessageSmileSquare'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/Send03.json b/app/components/base/icons/src/vender/solid/communication/Send03.json
new file mode 100644
index 0000000..c6ff534
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/Send03.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "viewBox": "0 0 20 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "send-03"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "d": "M18.4385 10.5535C18.6111 10.2043 18.6111 9.79465 18.4385 9.44548C18.2865 9.13803 18.0197 8.97682 17.8815 8.89905C17.7327 8.81532 17.542 8.72955 17.3519 8.64403L3.36539 2.35014C3.17087 2.26257 2.97694 2.17526 2.81335 2.11859C2.66315 2.06656 2.36076 1.97151 2.02596 2.06467C1.64761 2.16994 1.34073 2.4469 1.19734 2.81251C1.07045 3.13604 1.13411 3.44656 1.17051 3.60129C1.21017 3.76983 1.27721 3.9717 1.34445 4.17418L2.69818 8.25278C2.80718 8.58118 2.86168 8.74537 2.96302 8.86678C3.05252 8.97399 3.16752 9.05699 3.29746 9.10816C3.44462 9.1661 3.61762 9.1661 3.96363 9.1661H10.0001C10.4603 9.1661 10.8334 9.53919 10.8334 9.99943C10.8334 10.4597 10.4603 10.8328 10.0001 10.8328H3.97939C3.63425 10.8328 3.46168 10.8328 3.3148 10.8905C3.18508 10.9414 3.07022 11.0241 2.98072 11.1309C2.87937 11.2519 2.82459 11.4155 2.71502 11.7428L1.3504 15.8191C1.28243 16.0221 1.21472 16.2242 1.17455 16.3929C1.13773 16.5476 1.07301 16.8587 1.19956 17.1831C1.34245 17.5493 1.64936 17.827 2.02806 17.9327C2.36342 18.0263 2.6665 17.9309 2.81674 17.8789C2.98066 17.8221 3.17507 17.7346 3.37023 17.6467L17.3518 11.355C17.542 11.2695 17.7327 11.1837 17.8815 11.0999C18.0197 11.0222 18.2865 10.861 18.4385 10.5535Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Send03"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/communication/Send03.tsx b/app/components/base/icons/src/vender/solid/communication/Send03.tsx
new file mode 100644
index 0000000..7e23d70
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/Send03.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Send03.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Send03'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/communication/index.ts b/app/components/base/icons/src/vender/solid/communication/index.ts
new file mode 100644
index 0000000..7d2a3a5
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/communication/index.ts
@@ -0,0 +1,12 @@
+export { default as AiText } from './AiText'
+export { default as BubbleTextMod } from './BubbleTextMod'
+export { default as ChatBot } from './ChatBot'
+export { default as CuteRobot } from './CuteRobot'
+export { default as EditList } from './EditList'
+export { default as ListSparkle } from './ListSparkle'
+export { default as Logic } from './Logic'
+export { default as MessageDotsCircle } from './MessageDotsCircle'
+export { default as MessageFast } from './MessageFast'
+export { default as MessageHeartCircle } from './MessageHeartCircle'
+export { default as MessageSmileSquare } from './MessageSmileSquare'
+export { default as Send03 } from './Send03'
diff --git a/app/components/base/icons/src/vender/solid/development/ApiConnection.json b/app/components/base/icons/src/vender/solid/development/ApiConnection.json
new file mode 100644
index 0000000..6aafba9
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/ApiConnection.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "api-connection"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.36364 11.8182C4.36364 7.60073 7.78255 4.18182 12 4.18182C14.8252 4.18182 17.2934 5.71543 18.6154 8.00079C18.9171 8.52231 19.5844 8.70053 20.106 8.39884C20.6275 8.09716 20.8057 7.42982 20.504 6.9083C18.8081 3.97648 15.6355 2 12 2C6.9463 2 2.78441 5.81824 2.24174 10.7273H1.09091C0.488417 10.7273 0 11.2157 0 11.8182C0 12.4207 0.488417 12.9091 1.09091 12.9091H2.24174C2.78441 17.8181 6.9463 21.6364 12 21.6364C15.6355 21.6364 18.8081 19.6599 20.504 16.7281C20.8057 16.2065 20.6275 15.5392 20.106 15.2375C19.5844 14.9358 18.9171 15.1141 18.6154 15.6356C17.2934 17.9209 14.8252 19.4545 12 19.4545C7.78255 19.4545 4.36364 16.0356 4.36364 11.8182Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12 6.36364C8.98754 6.36364 6.54545 8.80572 6.54545 11.8182C6.54545 14.8306 8.98754 17.2727 12 17.2727C14.6389 17.2727 16.84 15.3988 17.3454 12.9091H22.9091C23.5116 12.9091 24 12.4207 24 11.8182C24 11.2157 23.5116 10.7273 22.9091 10.7273H17.3454C16.84 8.23756 14.6389 6.36364 12 6.36364Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ApiConnection"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/ApiConnection.tsx b/app/components/base/icons/src/vender/solid/development/ApiConnection.tsx
new file mode 100644
index 0000000..7001163
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/ApiConnection.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ApiConnection.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ApiConnection'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/ApiConnectionMod.json b/app/components/base/icons/src/vender/solid/development/ApiConnectionMod.json
new file mode 100644
index 0000000..e8ebcc7
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/ApiConnectionMod.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon L"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M7.99996 3.33333C5.42263 3.33333 3.33329 5.42267 3.33329 8C3.33329 10.5773 5.42263 12.6667 7.99996 12.6667C9.72643 12.6667 11.2348 11.7295 12.0427 10.3329C12.227 10.0141 12.6349 9.90523 12.9536 10.0896C13.2723 10.274 13.3812 10.6818 13.1968 11.0005C12.1604 12.7921 10.2216 14 7.99996 14C4.91159 14 2.36821 11.6666 2.03658 8.66667H1.33329C0.965103 8.66667 0.666626 8.36819 0.666626 8C0.666626 7.63181 0.965103 7.33333 1.33329 7.33333H2.03658C2.36821 4.33337 4.91159 2 7.99996 2C10.2216 2 12.1604 3.20785 13.1968 4.99952C13.3812 5.31823 13.2723 5.72605 12.9536 5.91041C12.6349 6.09477 12.227 5.98585 12.0427 5.66714C11.2348 4.27054 9.72643 3.33333 7.99996 3.33333ZM7.99996 6C6.89539 6 5.99996 6.89543 5.99996 8C5.99996 9.10455 6.89539 10 7.99996 10C9.1045 10 9.99996 9.10454 9.99996 8C9.99996 6.89543 9.10451 6 7.99996 6ZM4.66663 8C4.66663 6.15905 6.15901 4.66667 7.99996 4.66667C9.61257 4.66667 10.9578 5.81184 11.2666 7.33333H14.6666C15.0348 7.33333 15.3333 7.63181 15.3333 8C15.3333 8.36819 15.0348 8.66667 14.6666 8.66667H11.2666C10.9578 10.1881 9.61257 11.3333 7.99996 11.3333C6.159 11.3333 4.66663 9.84092 4.66663 8Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ApiConnectionMod"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/ApiConnectionMod.tsx b/app/components/base/icons/src/vender/solid/development/ApiConnectionMod.tsx
new file mode 100644
index 0000000..fb741f0
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/ApiConnectionMod.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ApiConnectionMod.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ApiConnectionMod'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/BarChartSquare02.json b/app/components/base/icons/src/vender/solid/development/BarChartSquare02.json
new file mode 100644
index 0000000..14b274e
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/BarChartSquare02.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "bar-chart-square-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M11.8925 1.33331H4.1078C3.75638 1.3333 3.45319 1.33329 3.20348 1.35369C2.93992 1.37523 2.67777 1.42277 2.42552 1.5513C2.04919 1.74305 1.74323 2.04901 1.55148 2.42533C1.42296 2.67759 1.37541 2.93973 1.35388 3.2033C1.33348 3.453 1.33349 3.75617 1.3335 4.10759V11.8923C1.33349 12.2438 1.33348 12.547 1.35388 12.7967C1.37541 13.0602 1.42296 13.3224 1.55148 13.5746C1.74323 13.951 2.04919 14.2569 2.42552 14.4487C2.67777 14.5772 2.93992 14.6247 3.20348 14.6463C3.45319 14.6667 3.75636 14.6667 4.10779 14.6666H11.8925C12.244 14.6667 12.5471 14.6667 12.7969 14.6463C13.0604 14.6247 13.3226 14.5772 13.5748 14.4487C13.9511 14.2569 14.2571 13.951 14.4488 13.5746C14.5774 13.3224 14.6249 13.0602 14.6465 12.7967C14.6669 12.547 14.6668 12.2438 14.6668 11.8924V4.1076C14.6668 3.75618 14.6669 3.45301 14.6465 3.2033C14.6249 2.93973 14.5774 2.67759 14.4488 2.42533C14.2571 2.04901 13.9511 1.74305 13.5748 1.5513C13.3226 1.42277 13.0604 1.37523 12.7969 1.35369C12.5471 1.33329 12.2439 1.3333 11.8925 1.33331ZM11.3335 4.66665C11.3335 4.29846 11.035 3.99998 10.6668 3.99998C10.2986 3.99998 10.0002 4.29846 10.0002 4.66665V11.3333C10.0002 11.7015 10.2986 12 10.6668 12C11.035 12 11.3335 11.7015 11.3335 11.3333V4.66665ZM8.00016 6.66665C8.36835 6.66665 8.66683 6.96512 8.66683 7.33331V11.3333C8.66683 11.7015 8.36835 12 8.00016 12C7.63197 12 7.3335 11.7015 7.3335 11.3333V7.33331C7.3335 6.96512 7.63197 6.66665 8.00016 6.66665ZM5.3335 9.33331C5.70169 9.33331 6.00016 9.63179 6.00016 9.99998V11.3333C6.00016 11.7015 5.70169 12 5.3335 12C4.96531 12 4.66683 11.7015 4.66683 11.3333V9.99998C4.66683 9.63179 4.96531 9.33331 5.3335 9.33331Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "BarChartSquare02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/BarChartSquare02.tsx b/app/components/base/icons/src/vender/solid/development/BarChartSquare02.tsx
new file mode 100644
index 0000000..c8a3357
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/BarChartSquare02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BarChartSquare02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BarChartSquare02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/Container.json b/app/components/base/icons/src/vender/solid/development/Container.json
new file mode 100644
index 0000000..c2c3701
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Container.json
@@ -0,0 +1,44 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "17",
+ "height": "16",
+ "viewBox": "0 0 17 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.29782 0.790031C8.12061 0.753584 7.93783 0.753584 7.76062 0.790031C7.55577 0.832161 7.37268 0.934712 7.22712 1.01624L7.18744 1.03841C6.01215 1.69134 4.02394 2.79644 2.90301 3.41952C2.63085 3.5708 2.49477 3.64644 2.44929 3.74641C2.40965 3.83357 2.4094 3.93356 2.4486 4.02091C2.49357 4.12111 2.62938 4.19751 2.90101 4.3503L7.76772 7.08785C7.8631 7.1415 7.91079 7.16832 7.96135 7.17884C8.0061 7.18814 8.05229 7.18814 8.09703 7.17884C8.1476 7.16832 8.19529 7.1415 8.29067 7.08785L13.1574 4.35029C13.429 4.1975 13.5649 4.12111 13.6098 4.02091C13.649 3.93355 13.6488 3.83356 13.6091 3.74641C13.5637 3.64644 13.4276 3.57079 13.1554 3.41951C12.0345 2.79644 10.0463 1.69134 8.871 1.03841L8.83132 1.01624C8.68576 0.934713 8.50267 0.832161 8.29782 0.790031Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.6932 5.92676C14.6929 5.62787 14.6928 5.47842 14.6297 5.39117C14.5748 5.31504 14.4902 5.26564 14.3969 5.25511C14.2899 5.24305 14.1594 5.31646 13.8984 5.46329L8.96774 8.23679C8.86877 8.29246 8.81928 8.3203 8.78326 8.35968C8.75139 8.39452 8.72729 8.43573 8.71254 8.48059C8.69588 8.53129 8.69588 8.58807 8.69588 8.70163V14.1518C8.69588 14.4499 8.69588 14.599 8.75856 14.6862C8.81326 14.7623 8.89744 14.8118 8.9905 14.8227C9.09716 14.8352 9.22706 14.763 9.48688 14.6188C10.5978 14.0019 12.6169 12.8807 13.8043 12.221L13.8464 12.1977C14.0005 12.1128 14.1943 12.0061 14.343 11.8447C14.4717 11.7051 14.569 11.5397 14.6286 11.3594C14.6975 11.1509 14.6966 10.9298 14.696 10.7538L14.6959 10.7058C14.6959 9.39704 14.6942 7.17087 14.6932 5.92676Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.57155 14.6187C6.83137 14.763 6.96128 14.8352 7.06793 14.8227C7.16099 14.8118 7.24518 14.7623 7.29987 14.6862C7.36255 14.599 7.36255 14.4499 7.36255 14.1518V8.70166C7.36255 8.5881 7.36255 8.53132 7.34589 8.48062C7.33114 8.43576 7.30704 8.39455 7.27517 8.35971C7.23915 8.32033 7.18966 8.29249 7.09069 8.23682L2.16004 5.4633C1.89902 5.31648 1.76851 5.24306 1.66154 5.25513C1.56823 5.26565 1.48367 5.31506 1.42869 5.39118C1.36566 5.47844 1.36553 5.62789 1.36528 5.92678C1.36424 7.17088 1.36255 9.39704 1.36255 10.7058L1.36243 10.7538C1.36179 10.9298 1.36099 11.1509 1.42986 11.3594C1.48941 11.5397 1.58676 11.7051 1.71539 11.8447C1.86417 12.0061 2.0579 12.1128 2.21199 12.1977L2.2541 12.221C3.44156 12.8807 5.46065 14.0019 6.57155 14.6187Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Container"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/Container.tsx b/app/components/base/icons/src/vender/solid/development/Container.tsx
new file mode 100644
index 0000000..2aa777a
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Container.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Container.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Container'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/Database02.json b/app/components/base/icons/src/vender/solid/development/Database02.json
new file mode 100644
index 0000000..a1c5230
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Database02.json
@@ -0,0 +1,46 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "17",
+ "height": "16",
+ "viewBox": "0 0 17 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M15.1956 4.66669V3.33335C15.1956 2.76539 14.8497 2.33041 14.4701 2.03126C14.083 1.72618 13.5641 1.48059 12.9824 1.28668C11.812 0.896551 10.2375 0.666687 8.52897 0.666687C6.8204 0.666687 5.24591 0.896551 4.07551 1.28668C3.4938 1.48059 2.97495 1.72618 2.58783 2.03126C2.20823 2.33041 1.8623 2.76539 1.8623 3.33335V4.66669C1.8623 5.23294 2.20443 5.66805 2.58368 5.96857C2.96958 6.27436 3.48705 6.52014 4.06786 6.71405C5.23637 7.10415 6.81113 7.33335 8.52897 7.33335C10.2468 7.33335 11.8216 7.10415 12.9901 6.71405C13.5709 6.52014 14.0884 6.27436 14.4743 5.96857C14.8535 5.66805 15.1956 5.23294 15.1956 4.66669ZM3.19564 3.33353C3.19564 3.33353 3.19576 3.33725 3.19767 3.34355C3.19994 3.35098 3.20552 3.36565 3.21902 3.38764C3.24732 3.43374 3.30502 3.50304 3.41313 3.58824C3.63325 3.76171 3.99308 3.94709 4.49715 4.11511C5.49832 4.44884 6.92383 4.66669 8.52897 4.66669C10.1341 4.66669 11.5596 4.44884 12.5608 4.11511C13.0649 3.94709 13.4247 3.76171 13.6448 3.58824C13.7529 3.50304 13.8106 3.43374 13.8389 3.38764C13.8524 3.36565 13.858 3.35098 13.8603 3.34355C13.8622 3.33716 13.8623 3.33335 13.8623 3.33335C13.8623 3.33335 13.8624 3.33006 13.8603 3.32316C13.858 3.31573 13.8524 3.30105 13.8389 3.27907C13.8106 3.23297 13.7529 3.16367 13.6448 3.07847C13.4247 2.905 13.0649 2.71962 12.5608 2.5516C11.5596 2.21787 10.1341 2.00002 8.52897 2.00002C6.92383 2.00002 5.49832 2.21787 4.49715 2.5516C3.99308 2.71962 3.63325 2.905 3.41313 3.07847C3.30502 3.16367 3.24732 3.23297 3.21902 3.27907C3.20552 3.30105 3.19994 3.31573 3.19767 3.32316C3.19563 3.32988 3.19564 3.33353 3.19564 3.33353Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.9234 7.00002C14.8447 7.00002 14.7705 7.03473 14.7155 7.09102C14.6407 7.16749 14.5613 7.23785 14.4802 7.30206C14.0939 7.60785 13.5759 7.85363 12.9945 8.04753C11.8249 8.43764 10.2485 8.66684 8.52896 8.66684C6.8094 8.66684 5.23307 8.43764 4.06339 8.04753C3.48201 7.85363 2.96401 7.60785 2.57773 7.30206C2.49661 7.23784 2.41719 7.16749 2.34244 7.09101C2.28743 7.03473 2.21322 7.00002 2.13452 7.00002C1.98418 7.00002 1.8623 7.12189 1.8623 7.27223V8.66669C1.8623 9.23294 2.20443 9.66805 2.58368 9.96857C2.96958 10.2744 3.48705 10.5201 4.06786 10.714C5.23637 11.1041 6.81113 11.3334 8.52897 11.3334C10.2468 11.3334 11.8216 11.1041 12.9901 10.714C13.5709 10.5201 14.0884 10.2744 14.4743 9.96857C14.8535 9.66805 15.1956 9.23294 15.1956 8.66669V7.27224C15.1956 7.1219 15.0738 7.00002 14.9234 7.00002Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.9234 11C14.8447 11 14.7705 11.0347 14.7155 11.091C14.6407 11.1675 14.5613 11.2378 14.4802 11.3021C14.0939 11.6079 13.5759 11.8536 12.9945 12.0475C11.8249 12.4376 10.2485 12.6668 8.52896 12.6668C6.8094 12.6668 5.23307 12.4376 4.06339 12.0475C3.48201 11.8536 2.96401 11.6079 2.57773 11.3021C2.49661 11.2378 2.41719 11.1675 2.34244 11.091C2.28743 11.0347 2.21322 11 2.13452 11C1.98418 11 1.8623 11.1219 1.8623 11.2722V12.6667C1.8623 13.2329 2.20443 13.668 2.58368 13.9686C2.96958 14.2744 3.48705 14.5201 4.06786 14.714C5.23637 15.1041 6.81113 15.3334 8.52897 15.3334C10.2468 15.3334 11.8216 15.1041 12.9901 14.714C13.5709 14.5201 14.0884 14.2744 14.4743 13.9686C14.8535 13.668 15.1956 13.2329 15.1956 12.6667V11.2722C15.1956 11.1219 15.0738 11 14.9234 11Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Database02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/Database02.tsx b/app/components/base/icons/src/vender/solid/development/Database02.tsx
new file mode 100644
index 0000000..088a3ae
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Database02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Database02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Database02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/Database03.json b/app/components/base/icons/src/vender/solid/development/Database03.json
new file mode 100644
index 0000000..fa0c7ce
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Database03.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.66659 9.98845C10.1231 9.93732 11.4455 9.71981 12.461 9.38077C13.0418 9.18687 13.5593 8.94109 13.9452 8.6353C14.3245 8.33478 14.6666 7.89967 14.6666 7.33341V3.33341C14.6666 2.76545 14.3207 2.33047 13.9411 2.03132C13.5539 1.72624 13.0351 1.48065 12.4534 1.28675C11.283 0.896612 9.70849 0.666748 7.99992 0.666748C6.29135 0.666748 4.71686 0.896612 3.54646 1.28675C2.96474 1.48065 2.44589 1.72624 2.05878 2.03132C1.67918 2.33047 1.33325 2.76545 1.33325 3.33341V7.33341C1.33325 7.89967 1.67538 8.33478 2.05463 8.6353C2.44053 8.94109 2.958 9.18687 3.53881 9.38077C4.55435 9.71981 5.87675 9.93732 7.33325 9.98845V11.4472C6.76498 11.6481 6.31458 12.0985 6.11372 12.6667H1.99992C1.63173 12.6667 1.33325 12.9652 1.33325 13.3334C1.33325 13.7016 1.63173 14.0001 1.99992 14.0001H6.11372C6.38828 14.7769 7.12911 15.3334 7.99992 15.3334C8.87073 15.3334 9.61156 14.7769 9.88612 14.0001H13.9999C14.3681 14.0001 14.6666 13.7016 14.6666 13.3334C14.6666 12.9652 14.3681 12.6667 13.9999 12.6667H9.88612C9.68526 12.0985 9.23486 11.6481 8.66659 11.4472V9.98845ZM2.66659 3.33337C2.66659 3.33337 2.66657 3.32994 2.66862 3.32322C2.67089 3.31579 2.67647 3.30111 2.68997 3.27913C2.71827 3.23303 2.77597 3.16373 2.88408 3.07853C3.1042 2.90506 3.46403 2.71968 3.9681 2.55166C4.96927 2.21793 6.39478 2.00008 7.99992 2.00008C9.60506 2.00008 11.0306 2.21793 12.0317 2.55166C12.5358 2.71968 12.8956 2.90506 13.1158 3.07853C13.2239 3.16373 13.2816 3.23303 13.3099 3.27913C13.3234 3.30111 13.329 3.31579 13.3312 3.32322C13.3333 3.32994 13.3333 3.33337 13.3333 3.33337C13.3333 3.33337 13.3332 3.33722 13.3312 3.34361C13.329 3.35104 13.3234 3.36572 13.3099 3.3877C13.2816 3.4338 13.2239 3.5031 13.1158 3.5883C12.8956 3.76177 12.5358 3.94715 12.0317 4.11517C11.0306 4.4489 9.60506 4.66675 7.99992 4.66675C6.39478 4.66675 4.96927 4.4489 3.9681 4.11517C3.46403 3.94715 3.1042 3.76177 2.88408 3.5883C2.77597 3.5031 2.71827 3.4338 2.68997 3.3877C2.67647 3.36572 2.67089 3.35104 2.66862 3.34361C2.6667 3.33731 2.66659 3.33337 2.66659 3.33337Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Database03"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/Database03.tsx b/app/components/base/icons/src/vender/solid/development/Database03.tsx
new file mode 100644
index 0000000..012294a
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Database03.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Database03.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Database03'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/FileHeart02.json b/app/components/base/icons/src/vender/solid/development/FileHeart02.json
new file mode 100644
index 0000000..08df0f2
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/FileHeart02.json
@@ -0,0 +1,50 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "file-heart-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Subtract",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.8392 0.666687H10.1609C10.6976 0.666679 11.1405 0.666673 11.5013 0.696151C11.876 0.726767 12.2205 0.792477 12.544 0.957337C13.0458 1.213 13.4538 1.62095 13.7094 2.12271C13.8743 2.44627 13.94 2.79074 13.9706 3.16547C14.0001 3.52626 14.0001 3.96917 14.0001 4.50581V10.0803C13.7558 9.96135 13.4846 9.88753 13.1964 9.87049C13.1342 8.82702 12.2682 8.00002 11.2091 8.00002C10.5956 8.00002 10.0396 8.36134 9.7904 8.922L9.13298 10.4012C8.13309 10.4365 7.33333 11.2582 7.33333 12.2667V14.1334C7.33333 14.3187 7.36034 14.4977 7.41064 14.6667L5.24168 14.6667C4.71142 14.667 4.31765 14.6672 3.97655 14.5758C3.0563 14.3292 2.33751 13.6104 2.09093 12.6902C1.99953 12.3491 1.99974 11.9553 2.00003 11.4251L2.00006 4.50582C2.00006 3.96918 2.00005 3.52627 2.02953 3.16547C2.06014 2.79074 2.12585 2.44627 2.29071 2.12271C2.54638 1.62095 2.95432 1.213 3.45609 0.957337C3.77965 0.792477 4.12412 0.726767 4.49885 0.696151C4.85964 0.666673 5.30256 0.666679 5.8392 0.666687ZM4.66667 4.66669C4.66667 4.2985 4.96514 4.00002 5.33333 4.00002H10.6667C11.0349 4.00002 11.3333 4.2985 11.3333 4.66669C11.3333 5.03488 11.0349 5.33335 10.6667 5.33335H5.33333C4.96514 5.33335 4.66667 5.03488 4.66667 4.66669ZM4.66667 7.33335C4.66667 6.96516 4.96514 6.66669 5.33333 6.66669H8.33333C8.70152 6.66669 9 6.96516 9 7.33335C9 7.70154 8.70152 8.00002 8.33333 8.00002H5.33333C4.96514 8.00002 4.66667 7.70154 4.66667 7.33335ZM4.66667 10C4.66667 9.63183 4.96514 9.33335 5.33333 9.33335H6C6.36819 9.33335 6.66667 9.63183 6.66667 10C6.66667 10.3682 6.36819 10.6667 6 10.6667H5.33333C4.96514 10.6667 4.66667 10.3682 4.66667 10Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M10.7044 9.32812C10.7931 9.12859 10.9909 9 11.2093 9C11.7565 9 12.2002 9.44364 12.2002 9.99089V10.8667H13.0677C13.7623 10.8667 14.2934 11.4858 14.1878 12.1723L13.9006 14.039C13.8156 14.5919 13.3399 15 12.7805 15H9.20016C8.72152 15 8.3335 14.612 8.3335 14.1333V12.2667C8.3335 11.788 8.72152 11.4 9.20016 11.4H9.78354L10.7044 9.32812Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "FileHeart02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/FileHeart02.tsx b/app/components/base/icons/src/vender/solid/development/FileHeart02.tsx
new file mode 100644
index 0000000..e918e5e
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/FileHeart02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileHeart02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileHeart02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/PatternRecognition.json b/app/components/base/icons/src/vender/solid/development/PatternRecognition.json
new file mode 100644
index 0000000..3d13c32
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/PatternRecognition.json
@@ -0,0 +1,98 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.72727 22C4.18787 22 3.66058 21.84 3.21208 21.5404C2.76359 21.2407 2.41402 20.8148 2.2076 20.3164C2.00118 19.8181 1.94717 19.2697 2.05241 18.7407C2.15764 18.2116 2.41739 17.7257 2.7988 17.3443C3.18022 16.9628 3.66617 16.7031 4.19521 16.5979C4.72425 16.4926 5.27261 16.5466 5.77096 16.7531C6.2693 16.9595 6.69524 17.309 6.99492 17.7575C7.2946 18.206 7.45455 18.7333 7.45455 19.2727C7.45455 19.996 7.16721 20.6897 6.65575 21.2012C6.14429 21.7127 5.45059 22 4.72727 22Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12 9.27273C11.4606 9.27273 10.9333 9.43268 10.4848 9.73236C10.0363 10.032 9.68675 10.458 9.48033 10.9563C9.27391 11.4547 9.2199 12.003 9.32513 12.5321C9.43036 13.0611 9.69011 13.5471 10.0715 13.9285C10.4529 14.3099 10.9389 14.5696 11.4679 14.6749C11.997 14.7801 12.5453 14.7261 13.0437 14.5197C13.542 14.3133 13.968 13.9637 14.2676 13.5152C14.5673 13.0667 14.7273 12.5394 14.7273 12C14.7273 11.2767 14.4399 10.583 13.9285 10.0715C13.417 9.56006 12.7233 9.27273 12 9.27273Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.72727 2C4.18787 2 3.66058 2.15995 3.21208 2.45963C2.76358 2.7593 2.41402 3.18525 2.2076 3.68359C2.00118 4.18193 1.94717 4.7303 2.05241 5.25934C2.15764 5.78838 2.41738 6.27433 2.7988 6.65575C3.18022 7.03716 3.66617 7.29691 4.19521 7.40214C4.72425 7.50737 5.27261 7.45336 5.77096 7.24694C6.2693 7.04052 6.69524 6.69096 6.99492 6.24246C7.29459 5.79397 7.45455 5.26668 7.45455 4.72727C7.45455 4.00395 7.16721 3.31026 6.65575 2.7988C6.14428 2.28734 5.45059 2 4.72727 2Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.2727 2C18.7333 2 18.206 2.15995 17.7575 2.45963C17.309 2.75931 16.9595 3.18525 16.7531 3.68359C16.5466 4.18194 16.4926 4.7303 16.5979 5.25934C16.7031 5.78838 16.9628 6.27433 17.3443 6.65575C17.7257 7.03716 18.2116 7.29691 18.7407 7.40214C19.2697 7.50737 19.8181 7.45337 20.3164 7.24694C20.8148 7.04052 21.2407 6.69096 21.5404 6.24247C21.84 5.79397 22 5.26668 22 4.72727C22 4.00396 21.7127 3.31026 21.2012 2.7988C20.6897 2.28734 19.996 2 19.2727 2Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19.2727 16.5455C18.7333 16.5455 18.206 16.7054 17.7575 17.0051C17.309 17.3048 16.9595 17.7307 16.7531 18.229C16.5466 18.7274 16.4926 19.2758 16.5979 19.8048C16.7031 20.3338 16.9628 20.8198 17.3443 21.2012C17.7257 21.5826 18.2116 21.8424 18.7407 21.9476C19.2697 22.0528 19.8181 21.9988 20.3164 21.7924C20.8148 21.586 21.2407 21.2364 21.5404 20.7879C21.84 20.3394 22 19.8121 22 19.2727C22 18.5494 21.7127 17.8557 21.2012 17.3443C20.6897 16.8328 19.996 16.5455 19.2727 16.5455Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.45455 9.27273H2V14.7273H7.45455V9.27273Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M22 9.27273H16.5455V14.7273H22V9.27273Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.7273 2H9.27273V7.45455H14.7273V2Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.7273 16.5455H9.27273V22H14.7273V16.5455Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "PatternRecognition"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/PatternRecognition.tsx b/app/components/base/icons/src/vender/solid/development/PatternRecognition.tsx
new file mode 100644
index 0000000..c1eb6ad
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/PatternRecognition.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './PatternRecognition.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'PatternRecognition'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/PromptEngineering.json b/app/components/base/icons/src/vender/solid/development/PromptEngineering.json
new file mode 100644
index 0000000..01fbac5
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/PromptEngineering.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "prompt-engineering"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.17263 1.33331H10.8277C11.3643 1.33331 11.8073 1.3333 12.168 1.36278C12.5428 1.39339 12.8872 1.4591 13.2108 1.62396C13.7126 1.87963 14.1205 2.28758 14.3762 2.78934C14.541 3.1129 14.6068 3.45737 14.6374 3.8321C14.6668 4.19289 14.6668 4.63579 14.6668 5.17243V9.61535L14.2671 9.51541C13.9093 9.42597 13.7127 9.37607 13.5686 9.33055C13.506 9.31079 13.4738 9.2979 13.4609 9.29232C13.427 9.26909 13.3977 9.23979 13.3745 9.2059C13.3689 9.19304 13.356 9.16081 13.3363 9.09826C13.2907 8.95416 13.2408 8.7575 13.1514 8.39975L12.9504 7.59575C12.7649 6.85381 12.0983 6.33331 11.3335 6.33331C10.5687 6.33331 9.90208 6.85381 9.71659 7.59576L9.51559 8.39975C9.42616 8.7575 9.37626 8.95416 9.33074 9.09826C9.31097 9.16081 9.29808 9.19303 9.29251 9.2059C9.26927 9.23979 9.23997 9.26909 9.20609 9.29232C9.19322 9.2979 9.16099 9.31079 9.09844 9.33055C8.95434 9.37607 8.75769 9.42597 8.39993 9.51541L7.59594 9.71641C6.85399 9.9019 6.3335 10.5685 6.3335 11.3333C6.3335 12.0981 6.85399 12.7647 7.59594 12.9502L8.39993 13.1512C8.75769 13.2407 8.95434 13.2906 9.09844 13.3361C9.16099 13.3558 9.19322 13.3687 9.20609 13.3743C9.23997 13.3975 9.26927 13.4268 9.29251 13.4607C9.29808 13.4736 9.31098 13.5058 9.33074 13.5684C9.37626 13.7125 9.42616 13.9091 9.51559 14.2669L9.61553 14.6666H5.17268C4.63601 14.6667 4.19309 14.6667 3.83228 14.6372C3.45755 14.6066 3.11308 14.5409 2.78952 14.376C2.28776 14.1203 1.87981 13.7124 1.62415 13.2106C1.45929 12.8871 1.39358 12.5426 1.36296 12.1679C1.33348 11.8071 1.33349 11.3642 1.3335 10.8275V5.17245C1.33349 4.63581 1.33348 4.19289 1.36296 3.8321C1.39358 3.45737 1.45929 3.1129 1.62415 2.78934C1.87981 2.28757 2.28776 1.87963 2.78952 1.62396C3.11308 1.4591 3.45755 1.39339 3.83228 1.36278C4.19307 1.3333 4.636 1.33331 5.17263 1.33331ZM4.66683 3.99998C4.29864 3.99998 4.00016 4.29846 4.00016 4.66665C4.00016 5.03484 4.29864 5.33331 4.66683 5.33331H4.6735C5.04169 5.33331 5.34016 5.03484 5.34016 4.66665C5.34016 4.29846 5.04169 3.99998 4.6735 3.99998H4.66683ZM6.66683 3.99998C6.29864 3.99998 6.00016 4.29846 6.00016 4.66665C6.00016 5.03484 6.29864 5.33331 6.66683 5.33331H6.6735C7.04169 5.33331 7.34016 5.03484 7.34016 4.66665C7.34016 4.29846 7.04169 3.99998 6.6735 3.99998H6.66683ZM8.66683 3.99998C8.29864 3.99998 8.00016 4.29846 8.00016 4.66665C8.00016 5.03484 8.29864 5.33331 8.66683 5.33331H8.6735C9.04169 5.33331 9.34016 5.03484 9.34016 4.66665C9.34016 4.29846 9.04169 3.99998 8.6735 3.99998H8.66683Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M11.3335 7.49998C11.5629 7.49998 11.7629 7.65613 11.8186 7.87871L12.0196 8.68271C12.1974 9.39402 12.2642 9.63563 12.3859 9.82588C12.5029 10.0087 12.6581 10.1639 12.8409 10.2809C13.0312 10.4026 13.2728 10.4694 13.9841 10.6472L14.7881 10.8482C15.0107 10.9039 15.1668 11.1039 15.1668 11.3333C15.1668 11.5627 15.0107 11.7627 14.7881 11.8184L13.9841 12.0194C13.2728 12.1972 13.0312 12.264 12.8409 12.3857C12.6581 12.5027 12.5029 12.658 12.3859 12.8407C12.2642 13.031 12.1974 13.2726 12.0196 13.9839L11.8186 14.7879C11.7629 15.0105 11.5629 15.1666 11.3335 15.1666C11.1041 15.1666 10.9041 15.0105 10.8484 14.7879L10.6474 13.9839C10.4696 13.2726 10.4028 13.031 10.2811 12.8407C10.1641 12.658 10.0089 12.5027 9.82606 12.3857C9.63581 12.264 9.39421 12.1972 8.68289 12.0194L7.8789 11.8184C7.65631 11.7627 7.50016 11.5627 7.50016 11.3333C7.50016 11.1039 7.65631 10.9039 7.8789 10.8482L8.68289 10.6472C9.39421 10.4694 9.63581 10.4026 9.82606 10.2809C10.0089 10.1639 10.1641 10.0087 10.2811 9.82588C10.4028 9.63563 10.4696 9.39402 10.6474 8.6827L10.8484 7.87871C10.9041 7.65613 11.1041 7.49998 11.3335 7.49998Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "PromptEngineering"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/PromptEngineering.tsx b/app/components/base/icons/src/vender/solid/development/PromptEngineering.tsx
new file mode 100644
index 0000000..506e9fe
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/PromptEngineering.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './PromptEngineering.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'PromptEngineering'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/PuzzlePiece01.json b/app/components/base/icons/src/vender/solid/development/PuzzlePiece01.json
new file mode 100644
index 0000000..f4008c8
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/PuzzlePiece01.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "17",
+ "height": "16",
+ "viewBox": "0 0 17 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "puzzle-piece-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4.83333 2.99999C4.83333 1.71133 5.878 0.666656 7.16667 0.666656C8.45533 0.666656 9.5 1.71133 9.5 2.99999V3.33332L9.52285 3.33332C9.96938 3.33332 10.338 3.33331 10.6397 3.3539C10.9525 3.37525 11.2419 3.42093 11.5205 3.53631C12.1739 3.80696 12.693 4.32609 12.9637 4.9795C13.0791 5.25804 13.1247 5.54744 13.1461 5.8603C13.1558 6.0027 13.1609 6.15998 13.1636 6.33332H13.5C14.7887 6.33332 15.8333 7.37799 15.8333 8.66666C15.8333 9.95532 14.7887 11 13.5 11H13.1667V11.4942C13.1667 12.0308 13.1667 12.4737 13.1372 12.8345C13.1066 13.2093 13.0409 13.5537 12.876 13.8773C12.6204 14.3791 12.2124 14.787 11.7106 15.0427C11.3871 15.2075 11.0426 15.2732 10.6679 15.3039C10.3071 15.3333 9.86419 15.3333 9.32755 15.3333H8.83333C8.46514 15.3333 8.16667 15.0348 8.16667 14.6667V13.5C8.16667 13.0398 7.79357 12.6667 7.33333 12.6667C6.8731 12.6667 6.5 13.0398 6.5 13.5V14.6667C6.5 15.0348 6.20152 15.3333 5.83333 15.3333H5.00578C4.46914 15.3333 4.02624 15.3333 3.66545 15.3039C3.29072 15.2732 2.94625 15.2075 2.62269 15.0427C2.12093 14.787 1.71298 14.3791 1.45732 13.8773C1.29246 13.5537 1.22675 13.2093 1.19613 12.8345C1.16665 12.4737 1.16666 12.0308 1.16667 11.4942L1.16667 10.3333C1.16667 9.96513 1.46514 9.66666 1.83333 9.66666H2.83333C3.38562 9.66666 3.83333 9.21894 3.83333 8.66666C3.83333 8.11437 3.38562 7.66666 2.83333 7.66666H1.83333C1.46514 7.66666 1.16667 7.36818 1.16667 6.99999L1.16667 6.97715C1.16666 6.53062 1.16666 6.16204 1.18724 5.8603C1.20859 5.54744 1.25428 5.25804 1.36965 4.9795C1.64031 4.32609 2.15944 3.80696 2.81284 3.53631C3.09139 3.42093 3.38078 3.37525 3.69364 3.3539C3.99538 3.33331 4.36396 3.33332 4.81048 3.33332L4.83333 3.33332L4.83333 2.99999Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "PuzzlePiece01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/PuzzlePiece01.tsx b/app/components/base/icons/src/vender/solid/development/PuzzlePiece01.tsx
new file mode 100644
index 0000000..b62d37d
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/PuzzlePiece01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './PuzzlePiece01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'PuzzlePiece01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/Semantic.json b/app/components/base/icons/src/vender/solid/development/Semantic.json
new file mode 100644
index 0000000..333b3fa
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Semantic.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M16.5833 12.945C16.4856 13.3276 16.2038 14.272 15.7382 15.7784H17.4432C17.0038 14.3674 16.7569 13.5692 16.7025 13.3841C16.6493 13.1998 16.609 13.0532 16.5833 12.945Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21.1667 9.33333H12C11.5138 9.33333 11.0475 9.52649 10.7036 9.87031C10.3598 10.2141 10.1667 10.6804 10.1667 11.1667V19.4167C10.1667 19.9029 10.3598 20.3692 10.7036 20.713C11.0475 21.0568 11.5138 21.25 12 21.25H17.5L21.1667 24V21.25C21.6529 21.25 22.1192 21.0568 22.463 20.713C22.8068 20.3692 23 19.9029 23 19.4167V11.1667C23 10.6804 22.8068 10.2141 22.463 9.87031C22.1192 9.52649 21.6529 9.33333 21.1667 9.33333ZM18.2507 18.5L17.775 16.9417H15.3917L14.9159 18.5H13.4208L15.7308 11.9293H17.4267L19.7458 18.5H18.2507Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12 2H2.83333C2.3471 2 1.88079 2.19315 1.53697 2.53697C1.19315 2.88079 1 3.3471 1 3.83333V12.0833C1 12.5696 1.19315 13.0359 1.53697 13.3797C1.88079 13.7235 2.3471 13.9167 2.83333 13.9167V16.6667L6.5 13.9167H9.25V11.1667C9.25381 11.0459 9.26606 10.9255 9.28667 10.8064C8.64229 10.5527 8.0315 10.2208 7.468 9.81825C6.5802 10.4316 5.59355 10.8877 4.55117 11.1667C4.394 10.6965 4.15573 10.2575 3.84717 9.86958C4.76378 9.70375 5.64426 9.37861 6.44867 8.90892C6.07755 8.50417 5.75993 8.05346 5.50358 7.56783C5.29175 7.16889 5.12217 6.74892 4.99758 6.31475C4.56583 6.31475 4.3165 6.32942 3.94983 6.35875V5.03233C4.30266 5.0703 4.65741 5.08744 5.01225 5.08367H6.63292V4.64367C6.63379 4.48979 6.61904 4.33623 6.58892 4.18533H8.05833C8.02877 4.33229 8.01403 4.48185 8.01433 4.63175V5.07908H9.756C10.1108 5.08303 10.4656 5.06589 10.8184 5.02775V6.35875C10.4958 6.32942 10.2098 6.31475 9.778 6.31475C9.67623 6.80565 9.51074 7.28115 9.28575 7.72917C9.06864 8.16083 8.79489 8.56159 8.47175 8.92083C8.89523 9.17057 9.34617 9.37051 9.81558 9.51667C10.0695 9.17655 10.399 8.90012 10.7781 8.70922C11.1573 8.51831 11.5755 8.41816 12 8.41667H13.8333V3.83333C13.8333 3.3471 13.6402 2.88079 13.2964 2.53697C12.9525 2.19315 12.4862 2 12 2Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.43133 8.0885C7.87722 7.58102 8.19195 6.97201 8.348 6.31475H6.40833C6.59708 6.98164 6.94861 7.59116 7.43133 8.0885Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Semantic"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/Semantic.tsx b/app/components/base/icons/src/vender/solid/development/Semantic.tsx
new file mode 100644
index 0000000..df01994
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Semantic.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Semantic.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Semantic'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/TerminalSquare.json b/app/components/base/icons/src/vender/solid/development/TerminalSquare.json
new file mode 100644
index 0000000..7716cfd
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/TerminalSquare.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "terminal-square"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.91927 1H3.08073C2.81716 0.999992 2.58977 0.999984 2.40249 1.01529C2.20481 1.03144 2.00821 1.06709 1.81902 1.16349C1.53677 1.3073 1.3073 1.53677 1.16349 1.81902C1.06709 2.00821 1.03144 2.20481 1.01529 2.40249C0.999984 2.58977 0.999992 2.81714 1 3.08071V8.91927C0.999992 9.18284 0.999984 9.41023 1.01529 9.59752C1.03144 9.79519 1.06709 9.9918 1.16349 10.181C1.3073 10.4632 1.53677 10.6927 1.81902 10.8365C2.00821 10.9329 2.20481 10.9686 2.40249 10.9847C2.58977 11 2.81715 11 3.08072 11H8.91928C9.18285 11 9.41023 11 9.59752 10.9847C9.79519 10.9686 9.9918 10.9329 10.181 10.8365C10.4632 10.6927 10.6927 10.4632 10.8365 10.181C10.9329 9.9918 10.9686 9.79519 10.9847 9.59752C11 9.41023 11 9.18285 11 8.91928V3.08072C11 2.81715 11 2.58977 10.9847 2.40249C10.9686 2.20481 10.9329 2.00821 10.8365 1.81902C10.6927 1.53677 10.4632 1.3073 10.181 1.16349C9.9918 1.06709 9.79519 1.03144 9.59752 1.01529C9.41023 0.999984 9.18284 0.999992 8.91927 1ZM3.85355 4.14645C3.65829 3.95118 3.34171 3.95118 3.14645 4.14645C2.95118 4.34171 2.95118 4.65829 3.14645 4.85355L4.29289 6L3.14645 7.14645C2.95118 7.34171 2.95118 7.65829 3.14645 7.85355C3.34171 8.04882 3.65829 8.04882 3.85355 7.85355L5.35355 6.35355C5.54882 6.15829 5.54882 5.84171 5.35355 5.64645L3.85355 4.14645ZM6.5 7C6.22386 7 6 7.22386 6 7.5C6 7.77614 6.22386 8 6.5 8H8.5C8.77614 8 9 7.77614 9 7.5C9 7.22386 8.77614 7 8.5 7H6.5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "TerminalSquare"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/TerminalSquare.tsx b/app/components/base/icons/src/vender/solid/development/TerminalSquare.tsx
new file mode 100644
index 0000000..38575b9
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/TerminalSquare.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './TerminalSquare.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'TerminalSquare'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/Variable02.json b/app/components/base/icons/src/vender/solid/development/Variable02.json
new file mode 100644
index 0000000..f506afd
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Variable02.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "variable-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.9986 8.76189C14.6132 8.04115 15.5117 7.625 16.459 7.625H16.5486C17.1009 7.625 17.5486 8.07272 17.5486 8.625C17.5486 9.17728 17.1009 9.625 16.5486 9.625H16.459C16.0994 9.625 15.7564 9.78289 15.5205 10.0595L13.1804 12.8039L13.9213 15.4107C13.9372 15.4666 13.9859 15.5 14.0355 15.5H15.4296C15.9819 15.5 16.4296 15.9477 16.4296 16.5C16.4296 17.0523 15.9819 17.5 15.4296 17.5H14.0355C13.0858 17.5 12.2562 16.8674 11.9975 15.9575L11.621 14.6328L10.1457 16.3631C9.5311 17.0839 8.63257 17.5 7.68532 17.5H7.59564C7.04336 17.5 6.59564 17.0523 6.59564 16.5C6.59564 15.9477 7.04336 15.5 7.59564 15.5H7.68532C8.04487 15.5 8.38789 15.3421 8.62379 15.0655L10.964 12.3209L10.2231 9.71433C10.2072 9.65839 10.1586 9.625 10.1089 9.625H8.71484C8.16256 9.625 7.71484 9.17728 7.71484 8.625C7.71484 8.07272 8.16256 7.625 8.71484 7.625H10.1089C11.0586 7.625 11.8883 8.25756 12.1469 9.16754L12.5234 10.4921L13.9986 8.76189Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.429 3C3.61372 3 2.143 4.47071 2.143 6.286V10.4428L1.29289 11.2929C1.10536 11.4804 1 11.7348 1 12C1 12.2652 1.10536 12.5196 1.29289 12.7071L2.143 13.5572V17.714C2.143 19.5293 3.61372 21 5.429 21C5.98128 21 6.429 20.5523 6.429 20C6.429 19.4477 5.98128 19 5.429 19C4.71828 19 4.143 18.4247 4.143 17.714V13.143C4.143 12.8778 4.03764 12.6234 3.85011 12.4359L3.41421 12L3.85011 11.5641C4.03764 11.3766 4.143 11.1222 4.143 10.857V6.286C4.143 5.57528 4.71828 5 5.429 5C5.98128 5 6.429 4.55228 6.429 4C6.429 3.44772 5.98128 3 5.429 3Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.5708 3C18.0185 3 17.5708 3.44772 17.5708 4C17.5708 4.55228 18.0185 5 18.5708 5C19.2815 5 19.8568 5.57529 19.8568 6.286V10.857C19.8568 11.1222 19.9622 11.3766 20.1497 11.5641L20.5856 12L20.1497 12.4359C19.9622 12.6234 19.8568 12.8778 19.8568 13.143V17.714C19.8568 18.4244 19.2808 19 18.5708 19C18.0185 19 17.5708 19.4477 17.5708 20C17.5708 20.5523 18.0185 21 18.5708 21C20.3848 21 21.8568 19.5296 21.8568 17.714V13.5572L22.7069 12.7071C23.0974 12.3166 23.0974 11.6834 22.7069 11.2929L21.8568 10.4428V6.286C21.8568 4.47071 20.3861 3 18.5708 3Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Variable02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/development/Variable02.tsx b/app/components/base/icons/src/vender/solid/development/Variable02.tsx
new file mode 100644
index 0000000..8ffaeaa
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/Variable02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Variable02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Variable02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/development/index.ts b/app/components/base/icons/src/vender/solid/development/index.ts
new file mode 100644
index 0000000..159a1cb
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/development/index.ts
@@ -0,0 +1,13 @@
+export { default as ApiConnectionMod } from './ApiConnectionMod'
+export { default as ApiConnection } from './ApiConnection'
+export { default as BarChartSquare02 } from './BarChartSquare02'
+export { default as Container } from './Container'
+export { default as Database02 } from './Database02'
+export { default as Database03 } from './Database03'
+export { default as FileHeart02 } from './FileHeart02'
+export { default as PatternRecognition } from './PatternRecognition'
+export { default as PromptEngineering } from './PromptEngineering'
+export { default as PuzzlePiece01 } from './PuzzlePiece01'
+export { default as Semantic } from './Semantic'
+export { default as TerminalSquare } from './TerminalSquare'
+export { default as Variable02 } from './Variable02'
diff --git a/app/components/base/icons/src/vender/solid/editor/Brush01.json b/app/components/base/icons/src/vender/solid/editor/Brush01.json
new file mode 100644
index 0000000..049e5f2
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/Brush01.json
@@ -0,0 +1,35 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M17.264 2.20765C18.5274 1.0378 20.4895 1.07552 21.707 2.29307C22.9246 3.51061 22.9623 5.47268 21.7924 6.73612L15.4019 13.638C15.008 14.0634 14.811 14.2761 14.579 14.3585C14.3751 14.4309 14.1531 14.4352 13.9465 14.3707C13.7115 14.2973 13.5065 14.0923 13.0965 13.6823L10.3178 10.9036C9.9078 10.4936 9.7028 10.2886 9.62943 10.0536C9.56493 9.84699 9.5692 9.62504 9.6416 9.42107C9.72395 9.18906 9.93667 8.9921 10.3621 8.59817L17.264 2.20765Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.76212 12.1763C8.35165 11.7659 8.14641 11.5606 7.9013 11.4888C7.7037 11.4308 7.43858 11.4436 7.24747 11.5203C7.01041 11.6154 6.86226 11.7953 6.56595 12.1551C6.46827 12.2737 6.37864 12.398 6.30066 12.53C6.03001 12.9883 5.8908 13.5013 5.88405 14.0163C4.608 13.9077 3.29445 14.3416 2.31799 15.318C1.28682 16.3492 1.34471 17.8002 1.38417 18.7893L1.38921 18.9154C1.43381 20.027 1.46675 20.848 1.11009 21.5439C0.951191 21.8539 0.965076 22.2242 1.14673 22.5215C1.32839 22.8187 1.65165 23 2 23C2.27235 23 2.58299 23.0081 2.91511 23.0167C3.66655 23.0362 4.52805 23.0586 5.30424 22.9968C6.44876 22.9057 7.7418 22.6221 8.68195 21.682C9.65838 20.7056 10.0923 19.3921 9.98366 18.1161C10.4987 18.1093 11.0118 17.9701 11.4701 17.6994C11.6021 17.6215 11.7264 17.5318 11.845 17.4341C12.2048 17.1378 12.3847 16.9897 12.4798 16.7526C12.5565 16.5615 12.5693 16.2964 12.5113 16.0988C12.4395 15.8537 12.2342 15.6484 11.8238 15.238L8.76212 12.1763Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Brush01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/editor/Brush01.tsx b/app/components/base/icons/src/vender/solid/editor/Brush01.tsx
new file mode 100644
index 0000000..d76c5f1
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/Brush01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Brush01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Brush01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/editor/Citations.json b/app/components/base/icons/src/vender/solid/editor/Citations.json
new file mode 100644
index 0000000..79d56b1
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/Citations.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "citations"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Subtract",
+ "d": "M0.666992 7.99996C0.666992 3.94987 3.95024 0.666626 8.00033 0.666626C12.0504 0.666626 15.3337 3.94987 15.3337 7.99996C15.3337 12.05 12.0504 15.3333 8.00033 15.3333C3.95024 15.3333 0.666992 12.05 0.666992 7.99996ZM4.66699 7.9801V9.97196H7.35742V7.48922H5.87533C5.85644 7.21231 5.90365 6.94484 6.01693 6.68681C6.2372 6.19592 6.66829 5.84979 7.31022 5.6484V4.66663C6.44803 4.83655 5.79036 5.19527 5.33724 5.7428C4.89041 6.29032 4.66699 7.03609 4.66699 7.9801ZM10.0264 6.70569C10.2466 6.19592 10.6746 5.84349 11.3102 5.6484V4.66663C10.4732 4.83655 9.82183 5.19212 9.35612 5.73336C8.8967 6.27459 8.66699 7.02351 8.66699 7.9801V9.97196H11.3574V7.48922H9.87533C9.85015 7.23748 9.9005 6.9763 10.0264 6.70569Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Citations"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/editor/Citations.tsx b/app/components/base/icons/src/vender/solid/editor/Citations.tsx
new file mode 100644
index 0000000..439aab6
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/Citations.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Citations.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Citations'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/editor/Colors.json b/app/components/base/icons/src/vender/solid/editor/Colors.json
new file mode 100644
index 0000000..6e5dc69
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/Colors.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "colors"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.4494 13.2298C12.9854 13.3409 12.5002 13.3999 12 13.3999C10.2804 13.3999 8.72326 12.6997 7.59953 11.5677C6.4872 10.4471 5.8 8.90382 5.8 7.20007C5.8 3.77586 8.57584 1 12 1C15.4241 1 18.2 3.77586 18.2 7.20007C18.2 8.44569 17.8327 9.60551 17.2005 10.5771C16.3665 11.8588 15.0715 12.8131 13.5506 13.2047C13.517 13.2133 13.4833 13.2217 13.4494 13.2298Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.1476 14.7743C16.6646 14.1431 17.9513 13.0695 18.8465 11.7146C19.0004 11.4817 19.0773 11.3652 19.1762 11.3066C19.2615 11.2561 19.3659 11.2312 19.4648 11.2379C19.5795 11.2457 19.6773 11.3015 19.8728 11.4133C21.7413 12.4817 23 14.4946 23 16.7999C23 20.2241 20.2242 23 16.8 23C15.9123 23 15.0689 22.8139 14.3059 22.4782C14.0549 22.3678 13.9294 22.3126 13.8502 22.2049C13.7822 22.1126 13.7468 21.9922 13.7539 21.8777C13.7622 21.7444 13.8565 21.6018 14.045 21.3167C14.8373 20.1184 15.3234 18.6997 15.3917 17.1723C15.3969 17.0566 15.3996 16.9402 15.4 16.8233L15.4 16.7999C15.4 16.1888 15.333 15.5926 15.2057 15.0185C15.1876 14.9366 15.1682 14.8552 15.1476 14.7743Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.12723 11.4133C4.32273 11.3015 4.42049 11.2457 4.53516 11.2379C4.63414 11.2312 4.73848 11.2561 4.82382 11.3066C4.92269 11.3652 4.99964 11.4817 5.15355 11.7146C6.62074 13.9352 9.13929 15.4001 12 15.4001C12.4146 15.4001 12.822 15.3694 13.2201 15.31L13.2263 15.3357C13.3398 15.8045 13.4 16.2947 13.4 16.7999L13.4 16.8214C13.3997 16.9056 13.3977 16.9895 13.3941 17.0728C13.2513 20.3704 10.5327 23 7.2 23C3.77584 23 1 20.2241 1 16.7999C1 14.4946 2.25869 12.4817 4.12723 11.4133Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Colors"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/editor/Colors.tsx b/app/components/base/icons/src/vender/solid/editor/Colors.tsx
new file mode 100644
index 0000000..bdfe6d1
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/Colors.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Colors.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Colors'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/editor/Paragraph.json b/app/components/base/icons/src/vender/solid/editor/Paragraph.json
new file mode 100644
index 0000000..a16f076
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/Paragraph.json
@@ -0,0 +1,44 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2 6.5C2 5.67157 2.67157 5 3.5 5H20.5C21.3284 5 22 5.67157 22 6.5C22 7.32843 21.3284 8 20.5 8H3.5C2.67157 8 2 7.32843 2 6.5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2 12.5C2 11.6716 2.67157 11 3.5 11H20.5C21.3284 11 22 11.6716 22 12.5C22 13.3284 21.3284 14 20.5 14H3.5C2.67157 14 2 13.3284 2 12.5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2 18.5C2 17.6716 2.67157 17 3.5 17H12.5C13.3284 17 14 17.6716 14 18.5C14 19.3284 13.3284 20 12.5 20H3.5C2.67157 20 2 19.3284 2 18.5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Paragraph"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/editor/Paragraph.tsx b/app/components/base/icons/src/vender/solid/editor/Paragraph.tsx
new file mode 100644
index 0000000..548b383
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/Paragraph.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Paragraph.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Paragraph'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/editor/TypeSquare.json b/app/components/base/icons/src/vender/solid/editor/TypeSquare.json
new file mode 100644
index 0000000..f901b07
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/TypeSquare.json
@@ -0,0 +1,28 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M7.7587 2H16.2413C17.0463 1.99999 17.7106 1.99998 18.2518 2.0442C18.8139 2.09012 19.3306 2.18868 19.816 2.43598C20.5686 2.81947 21.1805 3.43139 21.564 4.18404C21.8113 4.66938 21.9099 5.18608 21.9558 5.74818C22 6.28937 22 6.95372 22 7.75868V16.2413C22 17.0463 22 17.7106 21.9558 18.2518C21.9099 18.8139 21.8113 19.3306 21.564 19.816C21.1805 20.5686 20.5686 21.1805 19.816 21.564C19.3306 21.8113 18.8139 21.9099 18.2518 21.9558C17.7106 22 17.0463 22 16.2413 22H7.75868C6.95372 22 6.28937 22 5.74818 21.9558C5.18608 21.9099 4.66938 21.8113 4.18404 21.564C3.43139 21.1805 2.81947 20.5686 2.43598 19.816C2.18868 19.3306 2.09012 18.8139 2.0442 18.2518C1.99998 17.7106 1.99999 17.0463 2 16.2413V7.75869C1.99999 6.95373 1.99998 6.28936 2.0442 5.74818C2.09012 5.18608 2.18868 4.66938 2.43598 4.18404C2.81947 3.43139 3.43139 2.81947 4.18404 2.43598C4.66938 2.18868 5.18608 2.09012 5.74818 2.0442C6.28936 1.99998 6.95375 1.99999 7.7587 2ZM7 7C7 6.44772 7.44772 6 8 6H16C16.5523 6 17 6.44772 17 7C17 7.55229 16.5523 8 16 8H13V17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V8H8C7.44772 8 7 7.55229 7 7Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "TypeSquare"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/editor/TypeSquare.tsx b/app/components/base/icons/src/vender/solid/editor/TypeSquare.tsx
new file mode 100644
index 0000000..5149e12
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/TypeSquare.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './TypeSquare.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'TypeSquare'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/editor/index.ts b/app/components/base/icons/src/vender/solid/editor/index.ts
new file mode 100644
index 0000000..6b1a0a1
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/editor/index.ts
@@ -0,0 +1,5 @@
+export { default as Brush01 } from './Brush01'
+export { default as Citations } from './Citations'
+export { default as Colors } from './Colors'
+export { default as Paragraph } from './Paragraph'
+export { default as TypeSquare } from './TypeSquare'
diff --git a/app/components/base/icons/src/vender/solid/education/Beaker02.json b/app/components/base/icons/src/vender/solid/education/Beaker02.json
new file mode 100644
index 0000000..2f78300
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/education/Beaker02.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "beaker-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4.13856 0.500003H7.8617C7.92126 0.49998 7.99238 0.499953 8.05504 0.505073C8.12765 0.511005 8.23165 0.526227 8.34062 0.581751C8.48174 0.653656 8.59648 0.768392 8.66838 0.909513C8.72391 1.01849 8.73913 1.12248 8.74506 1.19509C8.75018 1.25775 8.75015 1.32888 8.75013 1.38844V2.61157C8.75015 2.67113 8.75018 2.74226 8.74506 2.80492C8.73913 2.87753 8.72391 2.98153 8.66838 3.0905C8.59648 3.23162 8.48174 3.34636 8.34062 3.41826C8.23165 3.47379 8.12765 3.48901 8.05504 3.49494C8.03725 3.49639 8.01877 3.49743 8.00006 3.49817V5.2506C8.00006 5.55312 8.00408 5.61265 8.01723 5.66153C8.03245 5.71807 8.05747 5.7715 8.09117 5.81939C8.1203 5.86078 8.16346 5.90197 8.39586 6.09564L10.2807 7.66627C10.4566 7.81255 10.6116 7.94145 10.7267 8.10509C10.8278 8.24875 10.9029 8.40904 10.9486 8.57867C11.0005 8.7719 11.0003 8.97351 11.0001 9.2023C11.0001 9.39886 11.0002 9.59542 11.0002 9.79198C11.0003 9.98232 11.0005 10.1463 10.9713 10.2927C10.853 10.8877 10.3878 11.3529 9.7928 11.4712C9.64637 11.5003 9.48246 11.5002 9.29211 11.5001H2.70822C2.51787 11.5002 2.35396 11.5003 2.20753 11.4712C1.98473 11.4269 1.78014 11.334 1.60515 11.2038C1.42854 11.0725 1.28221 10.9034 1.17753 10.7077C1.10892 10.5796 1.05831 10.4401 1.02899 10.2927C0.999862 10.1463 0.999992 9.98233 1.00014 9.79199C1.00014 9.59542 1.00006 9.39886 1.00003 9.20229C0.999794 8.97351 0.999584 8.7719 1.05157 8.57867C1.09721 8.40904 1.17229 8.24875 1.27338 8.10509C1.38855 7.94145 1.54356 7.81255 1.71947 7.66627L3.60427 6.09564C3.83667 5.90197 3.87983 5.86078 3.90896 5.81939C3.94266 5.7715 3.96768 5.71807 3.9829 5.66153C3.99605 5.61265 4.00006 5.55312 4.00006 5.2506V3.49817C3.9814 3.49743 3.96297 3.49639 3.94521 3.49494C3.8726 3.48901 3.76861 3.47379 3.65964 3.41826C3.51851 3.34636 3.40378 3.23162 3.33187 3.0905C3.27635 2.98153 3.26113 2.87753 3.25519 2.80492C3.25008 2.74226 3.2501 2.67113 3.25013 2.61158V1.38844C3.2501 1.32888 3.25008 1.25775 3.25519 1.19509C3.26113 1.12248 3.27635 1.01849 3.33187 0.909513C3.40378 0.768392 3.51851 0.653656 3.65964 0.581751C3.76861 0.526227 3.8726 0.511005 3.94521 0.505073C4.00787 0.499953 4.079 0.49998 4.13856 0.500003ZM9.11909 8.00004H2.88104L4.28066 6.83373C4.45657 6.68745 4.61158 6.55855 4.72675 6.39491C4.82784 6.25125 4.90292 6.09096 4.94856 5.92133C5.00054 5.7281 5.00033 5.52649 5.0001 5.29771L5.00006 3.50001H7.00006L7.00003 5.29771C6.99979 5.52649 6.99958 5.7281 7.05157 5.92133C7.09721 6.09096 7.17229 6.25125 7.27338 6.39491C7.38855 6.55855 7.54356 6.68745 7.71947 6.83373L9.11909 8.00004Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Beaker02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/education/Beaker02.tsx b/app/components/base/icons/src/vender/solid/education/Beaker02.tsx
new file mode 100644
index 0000000..6fd1a62
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/education/Beaker02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Beaker02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Beaker02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/education/BubbleText.json b/app/components/base/icons/src/vender/solid/education/BubbleText.json
new file mode 100644
index 0000000..999f0db
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/education/BubbleText.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "bubble-text"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "vector",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M2 9C2 5.68629 4.68629 3 8 3H16C19.3137 3 22 5.68629 22 9V15C22 18.3137 19.3137 21 16 21H3C2.44772 21 2 20.5523 2 20V9ZM9 9C8.44772 9 8 9.44772 8 10C8 10.5523 8.44772 11 9 11H15C15.5523 11 16 10.5523 16 10C16 9.44772 15.5523 9 15 9H9ZM9 13C8.44772 13 8 13.4477 8 14C8 14.5523 8.44772 15 9 15H12C12.5523 15 13 14.5523 13 14C13 13.4477 12.5523 13 12 13H9Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "BubbleText"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/education/BubbleText.tsx b/app/components/base/icons/src/vender/solid/education/BubbleText.tsx
new file mode 100644
index 0000000..9be36ec
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/education/BubbleText.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './BubbleText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'BubbleText'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/education/Heart02.json b/app/components/base/icons/src/vender/solid/education/Heart02.json
new file mode 100644
index 0000000..8cecaae
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/education/Heart02.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.5836 3.8721C12.3615 3.99329 12.1665 4.11496 12 4.22818C11.8335 4.11496 11.6385 3.99329 11.4164 3.8721C10.6185 3.4369 9.45449 3 8 3C6.48169 3 4.96498 3.60857 3.83296 4.81606C2.69616 6.02865 2 7.78592 2 10C2 13.3448 4.37277 16.1023 6.58187 17.9272C7.71336 18.8619 8.86688 19.6065 9.7917 20.1203C10.2539 20.377 10.6687 20.5816 11.004 20.7253C11.1707 20.7967 11.3289 20.858 11.4705 20.9033C11.5784 20.9378 11.7841 21 12 21C12.2159 21 12.4216 20.9378 12.5295 20.9033C12.6711 20.858 12.8293 20.7967 12.996 20.7253C13.3313 20.5816 13.7461 20.377 14.2083 20.1203C15.1331 19.6065 16.2866 18.8619 17.4181 17.9272C19.6272 16.1023 22 13.3448 22 10C22 7.78592 21.3038 6.02865 20.167 4.81606C19.035 3.60857 17.5183 3 16 3C14.5455 3 13.3815 3.4369 12.5836 3.8721Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Heart02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/education/Heart02.tsx b/app/components/base/icons/src/vender/solid/education/Heart02.tsx
new file mode 100644
index 0000000..ffe3a07
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/education/Heart02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Heart02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Heart02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/education/Unblur.json b/app/components/base/icons/src/vender/solid/education/Unblur.json
new file mode 100644
index 0000000..13b8bb3
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/education/Unblur.json
@@ -0,0 +1,152 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "unblur"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.5 6.25C9.5 6.80228 9.05228 7.25 8.5 7.25C7.94772 7.25 7.5 6.80228 7.5 6.25C7.5 5.69772 7.94772 5.25 8.5 5.25C9.05228 5.25 9.5 5.69772 9.5 6.25Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6 6.25C6 6.80228 5.55228 7.25 5 7.25C4.44772 7.25 4 6.80228 4 6.25C4 5.69772 4.44772 5.25 5 5.25C5.55228 5.25 6 5.69772 6 6.25Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.5 17.75C9.5 18.3023 9.05228 18.75 8.5 18.75C7.94772 18.75 7.5 18.3023 7.5 17.75C7.5 17.1977 7.94772 16.75 8.5 16.75C9.05228 16.75 9.5 17.1977 9.5 17.75Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.25 3.25C9.25 3.66421 8.91421 4 8.5 4C8.08579 4 7.75 3.66421 7.75 3.25C7.75 2.83579 8.08579 2.5 8.5 2.5C8.91421 2.5 9.25 2.83579 9.25 3.25Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3 10C3 10.4142 2.66421 10.75 2.25 10.75C1.83579 10.75 1.5 10.4142 1.5 10C1.5 9.58579 1.83579 9.25 2.25 9.25C2.66421 9.25 3 9.58579 3 10Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3 14C3 14.4142 2.66421 14.75 2.25 14.75C1.83579 14.75 1.5 14.4142 1.5 14C1.5 13.5858 1.83579 13.25 2.25 13.25C2.66421 13.25 3 13.5858 3 14Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.25 20.75C9.25 21.1642 8.91421 21.5 8.5 21.5C8.08579 21.5 7.75 21.1642 7.75 20.75C7.75 20.3358 8.08579 20 8.5 20C8.91421 20 9.25 20.3358 9.25 20.75Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10 10C10 10.8284 9.32843 11.5 8.5 11.5C7.67157 11.5 7 10.8284 7 10C7 9.17157 7.67157 8.5 8.5 8.5C9.32843 8.5 10 9.17157 10 10Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10 14C10 14.8284 9.32843 15.5 8.5 15.5C7.67157 15.5 7 14.8284 7 14C7 13.1716 7.67157 12.5 8.5 12.5C9.32843 12.5 10 13.1716 10 14Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6 10C6 10.5523 5.55228 11 5 11C4.44772 11 4 10.5523 4 10C4 9.44772 4.44772 9 5 9C5.55228 9 6 9.44772 6 10Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6 14C6 14.5523 5.55228 15 5 15C4.44772 15 4 14.5523 4 14C4 13.4477 4.44772 13 5 13C5.55228 13 6 13.4477 6 14Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6 17.75C6 18.3023 5.55228 18.75 5 18.75C4.44772 18.75 4 18.3023 4 17.75C4 17.1977 4.44772 16.75 5 16.75C5.55228 16.75 6 17.1977 6 17.75Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12 2C11.4477 2 11 2.44772 11 3V21C11 21.5523 11.4477 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Unblur"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/education/Unblur.tsx b/app/components/base/icons/src/vender/solid/education/Unblur.tsx
new file mode 100644
index 0000000..b994171
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/education/Unblur.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Unblur.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Unblur'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/education/index.ts b/app/components/base/icons/src/vender/solid/education/index.ts
new file mode 100644
index 0000000..2c8a3b6
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/education/index.ts
@@ -0,0 +1,4 @@
+export { default as Beaker02 } from './Beaker02'
+export { default as BubbleText } from './BubbleText'
+export { default as Heart02 } from './Heart02'
+export { default as Unblur } from './Unblur'
diff --git a/app/components/base/icons/src/vender/solid/files/File05.json b/app/components/base/icons/src/vender/solid/files/File05.json
new file mode 100644
index 0000000..17b9629
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/files/File05.json
@@ -0,0 +1,55 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "file-05"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.66667 1.34356C8.66667 1.32602 8.66667 1.31725 8.66591 1.30135C8.65018 0.972168 8.3607 0.682824 8.03151 0.667251C8.01562 0.666499 8.0104 0.666501 8.00001 0.666504H5.8391C5.30248 0.666497 4.85957 0.666491 4.49878 0.695968C4.12405 0.726585 3.77958 0.792295 3.45603 0.957155C2.95426 1.21282 2.54631 1.62077 2.29065 2.12253C2.12579 2.44609 2.06008 2.79056 2.02946 3.16529C1.99999 3.52608 1.99999 3.96899 2 4.50562V11.494C1.99999 12.0307 1.99999 12.4736 2.02946 12.8344C2.06008 13.2091 2.12579 13.5536 2.29065 13.8771C2.54631 14.3789 2.95426 14.7869 3.45603 15.0425C3.77958 15.2074 4.12405 15.2731 4.49878 15.3037C4.85958 15.3332 5.30248 15.3332 5.83912 15.3332H10.1609C10.6975 15.3332 11.1404 15.3332 11.5012 15.3037C11.8759 15.2731 12.2204 15.2074 12.544 15.0425C13.0457 14.7869 13.4537 14.3789 13.7093 13.8771C13.8742 13.5536 13.9399 13.2091 13.9705 12.8344C14 12.4736 14 12.0307 14 11.4941V6.66646C14 6.65611 14 6.65093 13.9993 6.63505C13.9837 6.30583 13.6943 6.01631 13.3651 6.0006C13.3492 5.99985 13.3405 5.99985 13.323 5.99985L10.3787 5.99985C10.2105 5.99987 10.0466 5.99989 9.90785 5.98855C9.75545 5.9761 9.57563 5.94672 9.39468 5.85452C9.1438 5.72669 8.93983 5.52272 8.81199 5.27183C8.7198 5.09088 8.69042 4.91106 8.67797 4.75867C8.66663 4.61989 8.66665 4.45603 8.66667 4.28778L8.66667 1.34356ZM5.33333 8.6665C4.96514 8.6665 4.66667 8.96498 4.66667 9.33317C4.66667 9.70136 4.96514 9.99984 5.33333 9.99984H10.6667C11.0349 9.99984 11.3333 9.70136 11.3333 9.33317C11.3333 8.96498 11.0349 8.6665 10.6667 8.6665H5.33333ZM5.33333 11.3332C4.96514 11.3332 4.66667 11.6316 4.66667 11.9998C4.66667 12.368 4.96514 12.6665 5.33333 12.6665H9.33333C9.70152 12.6665 10 12.368 10 11.9998C10 11.6316 9.70152 11.3332 9.33333 11.3332H5.33333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.6053 4.6665C12.8011 4.6665 12.8989 4.6665 12.9791 4.61735C13.0923 4.54794 13.16 4.3844 13.129 4.25526C13.107 4.16382 13.0432 4.10006 12.9155 3.97253L10.694 1.75098C10.5664 1.62333 10.5027 1.5595 10.4112 1.53752C10.2821 1.50648 10.1186 1.57417 10.0492 1.6874C10 1.76757 10 1.86545 10 2.0612L10 4.13315C10 4.31982 10 4.41316 10.0363 4.48446C10.0683 4.54718 10.1193 4.59818 10.182 4.63014C10.2533 4.66647 10.3466 4.66647 10.5333 4.66647L12.6053 4.6665Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "File05"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/files/File05.tsx b/app/components/base/icons/src/vender/solid/files/File05.tsx
new file mode 100644
index 0000000..eda65c0
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/files/File05.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './File05.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'File05'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/files/FileSearch02.json b/app/components/base/icons/src/vender/solid/files/FileSearch02.json
new file mode 100644
index 0000000..7f8b0e8
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/files/FileSearch02.json
@@ -0,0 +1,57 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "file-search-02"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M10.1609 0.666748H5.83913C5.3025 0.66674 4.85958 0.666734 4.49878 0.696212C4.12405 0.726828 3.77958 0.792538 3.45603 0.957399C2.95426 1.21306 2.54631 1.62101 2.29065 2.12277C2.12579 2.44633 2.06008 2.7908 2.02946 3.16553C1.99999 3.52632 1.99999 3.96924 2 4.50587V11.4943C1.99999 12.0309 1.99999 12.4738 2.02946 12.8346C2.06008 13.2094 2.12579 13.5538 2.29065 13.8774C2.54631 14.3792 2.95426 14.7871 3.45603 15.0428C3.77958 15.2076 4.12405 15.2733 4.49878 15.304C4.85958 15.3334 5.30248 15.3334 5.83912 15.3334H7.75554C8.22798 15.3334 8.4642 15.3334 8.55219 15.2689C8.64172 15.2033 8.67645 15.1421 8.68693 15.0316C8.69724 14.9229 8.55693 14.6879 8.27632 14.2177C7.88913 13.5689 7.66667 12.8105 7.66667 12.0001C7.66667 9.60685 9.60677 7.66675 12 7.66675C12.4106 7.66675 12.8078 7.72385 13.1842 7.83055C13.5061 7.92177 13.667 7.96739 13.7581 7.94138C13.847 7.91602 13.9015 7.87486 13.9501 7.79623C14 7.71563 14 7.56892 14 7.27549V4.50587C14 3.96923 14 3.52633 13.9705 3.16553C13.9399 2.7908 13.8742 2.44633 13.7093 2.12277C13.4537 1.62101 13.0457 1.21306 12.544 0.957399C12.2204 0.792538 11.8759 0.726828 11.5012 0.696212C11.1404 0.666734 10.6975 0.66674 10.1609 0.666748ZM4.66667 3.33342C4.29848 3.33342 4 3.63189 4 4.00008C4 4.36827 4.29848 4.66675 4.66667 4.66675H10.6667C11.0349 4.66675 11.3333 4.36827 11.3333 4.00008C11.3333 3.63189 11.0349 3.33342 10.6667 3.33342H4.66667ZM4 6.66675C4 6.29856 4.29848 6.00008 4.66667 6.00008H8.66667C9.03486 6.00008 9.33333 6.29856 9.33333 6.66675C9.33333 7.03494 9.03486 7.33342 8.66667 7.33342H4.66667C4.29848 7.33342 4 7.03494 4 6.66675ZM4 9.33342C4 8.96523 4.29848 8.66675 4.66667 8.66675H6C6.36819 8.66675 6.66667 8.96523 6.66667 9.33342C6.66667 9.7016 6.36819 10.0001 6 10.0001H4.66667C4.29848 10.0001 4 9.7016 4 9.33342Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9 12.0001C9 10.3432 10.3431 9.00008 12 9.00008C13.6569 9.00008 15 10.3432 15 12.0001C15 12.5871 14.8314 13.1348 14.54 13.5972L15.1381 14.1953C15.3984 14.4557 15.3984 14.8778 15.1381 15.1382C14.8777 15.3985 14.4556 15.3985 14.1953 15.1382L13.5972 14.54C13.1347 14.8315 12.587 15.0001 12 15.0001C10.3431 15.0001 9 13.6569 9 12.0001ZM12 10.3334C11.0795 10.3334 10.3333 11.0796 10.3333 12.0001C10.3333 12.9206 11.0795 13.6667 12 13.6667C12.9205 13.6667 13.6667 12.9206 13.6667 12.0001C13.6667 11.0796 12.9205 10.3334 12 10.3334Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "FileSearch02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/files/FileSearch02.tsx b/app/components/base/icons/src/vender/solid/files/FileSearch02.tsx
new file mode 100644
index 0000000..154ad45
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/files/FileSearch02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileSearch02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileSearch02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/files/FileZip.json b/app/components/base/icons/src/vender/solid/files/FileZip.json
new file mode 100644
index 0000000..11fe823
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/files/FileZip.json
@@ -0,0 +1,47 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M3.99999 1.33325H7.99999V5.33325C7.99999 6.06963 8.59692 6.66659 9.33332 6.66659H13.3333V13.3333C13.3333 14.0697 12.7364 14.6666 12 14.6666H6.66666V13.3333H7.99999V11.9999H6.66666V10.6666H7.99999V9.33325H6.66666V7.99992H5.33332V9.33325H6.66666V10.6666H5.33332V11.9999H6.66666V13.3333H5.33332V14.6666H3.99999C3.26361 14.6666 2.66666 14.0697 2.66666 13.3333V2.66659C2.66666 1.93021 3.26361 1.33325 3.99999 1.33325Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "opacity": "0.5",
+ "d": "M12.9428 4.99993C13.0415 5.09868 13.1232 5.21133 13.1859 5.33327H9.33334V1.48071C9.45528 1.54338 9.56794 1.62504 9.66668 1.72379L12.9428 4.99993Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "FileZip"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/files/FileZip.tsx b/app/components/base/icons/src/vender/solid/files/FileZip.tsx
new file mode 100644
index 0000000..fc22a3a
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/files/FileZip.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './FileZip.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'FileZip'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/files/Folder.json b/app/components/base/icons/src/vender/solid/files/Folder.json
new file mode 100644
index 0000000..4fc5e5f
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/files/Folder.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M0.666993 4.10794C0.666981 3.75652 0.666972 3.45333 0.687374 3.20362C0.708908 2.94006 0.756452 2.67791 0.884981 2.42566C1.07673 2.04933 1.38269 1.74337 1.75901 1.55163C2.01127 1.4231 2.27341 1.37555 2.53698 1.35402C2.78669 1.33362 3.08986 1.33363 3.4413 1.33364L6.0981 1.33357C6.4938 1.33304 6.84179 1.33258 7.16176 1.44295C7.44201 1.53961 7.69726 1.69737 7.90905 1.9048C8.15086 2.14164 8.30607 2.45309 8.48257 2.80725L9.07895 4.00016H11.4945C12.0312 4.00015 12.4741 4.00015 12.8349 4.02963C13.2096 4.06024 13.5541 4.12595 13.8776 4.29081C14.3794 4.54648 14.7873 4.95442 15.043 5.45619C15.2079 5.77975 15.2736 6.12421 15.3042 6.49895C15.3337 6.85974 15.3337 7.30264 15.3337 7.83928V10.8277C15.3337 11.3644 15.3337 11.8073 15.3042 12.168C15.2736 12.5428 15.2079 12.8872 15.043 13.2108C14.7873 13.7126 14.3794 14.1205 13.8776 14.3762C13.5541 14.541 13.2096 14.6068 12.8349 14.6374C12.4741 14.6668 12.0312 14.6668 11.4945 14.6668H4.50614C3.9695 14.6668 3.52657 14.6668 3.16578 14.6374C2.79104 14.6068 2.44658 14.541 2.12302 14.3762C1.62125 14.1205 1.2133 13.7126 0.957643 13.2108C0.792782 12.8872 0.727073 12.5428 0.696456 12.168C0.666978 11.8073 0.666985 11.3643 0.666993 10.8277V4.10794ZM6.01519 2.66697C6.54213 2.66697 6.64658 2.67567 6.727 2.70341C6.82041 2.73563 6.9055 2.78822 6.97609 2.85736C7.03687 2.91688 7.09136 3.00642 7.32701 3.47773L7.58823 4.00016L2.00038 4.00016C2.00067 3.69017 2.00271 3.47827 2.01628 3.3122C2.03108 3.13109 2.05619 3.06394 2.07299 3.03098C2.13691 2.90554 2.23889 2.80355 2.36433 2.73964C2.3973 2.72284 2.46444 2.69772 2.64555 2.68292C2.83444 2.66749 3.08263 2.66697 3.46699 2.66697H6.01519Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Folder"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/files/Folder.tsx b/app/components/base/icons/src/vender/solid/files/Folder.tsx
new file mode 100644
index 0000000..e7a3fdf
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/files/Folder.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Folder.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Folder'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/files/index.ts b/app/components/base/icons/src/vender/solid/files/index.ts
new file mode 100644
index 0000000..fa93cd6
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/files/index.ts
@@ -0,0 +1,4 @@
+export { default as File05 } from './File05'
+export { default as FileSearch02 } from './FileSearch02'
+export { default as FileZip } from './FileZip'
+export { default as Folder } from './Folder'
diff --git a/app/components/base/icons/src/vender/solid/general/AnswerTriangle.json b/app/components/base/icons/src/vender/solid/general/AnswerTriangle.json
new file mode 100644
index 0000000..a4b6283
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/AnswerTriangle.json
@@ -0,0 +1,27 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "8",
+ "height": "12",
+ "viewBox": "0 0 8 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Rectangle 1",
+ "d": "M1.03647 1.5547C0.59343 0.890144 1.06982 0 1.86852 0H8V12L1.03647 1.5547Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "AnswerTriangle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/AnswerTriangle.tsx b/app/components/base/icons/src/vender/solid/general/AnswerTriangle.tsx
new file mode 100644
index 0000000..956c328
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/AnswerTriangle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AnswerTriangle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AnswerTriangle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/ArrowDownRoundFill.json b/app/components/base/icons/src/vender/solid/general/ArrowDownRoundFill.json
new file mode 100644
index 0000000..4e7da3c
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/ArrowDownRoundFill.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "arrow-down-round-fill"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M6.02913 6.23572C5.08582 6.23572 4.56482 7.33027 5.15967 8.06239L7.13093 10.4885C7.57922 11.0403 8.42149 11.0403 8.86986 10.4885L10.8411 8.06239C11.4359 7.33027 10.9149 6.23572 9.97158 6.23572H6.02913Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ArrowDownRoundFill"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/ArrowDownRoundFill.tsx b/app/components/base/icons/src/vender/solid/general/ArrowDownRoundFill.tsx
new file mode 100644
index 0000000..c766a72
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/ArrowDownRoundFill.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ArrowDownRoundFill.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ArrowDownRoundFill'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/CheckCircle.json b/app/components/base/icons/src/vender/solid/general/CheckCircle.json
new file mode 100644
index 0000000..1b567e8
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/CheckCircle.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "check-circle"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8 0.666626C3.94992 0.666626 0.666672 3.94987 0.666672 7.99996C0.666672 12.05 3.94992 15.3333 8 15.3333C12.0501 15.3333 15.3333 12.05 15.3333 7.99996C15.3333 3.94987 12.0501 0.666626 8 0.666626ZM11.4714 6.47136C11.7318 6.21101 11.7318 5.7889 11.4714 5.52855C11.2111 5.26821 10.7889 5.26821 10.5286 5.52855L7 9.05715L5.47141 7.52855C5.21106 7.2682 4.78895 7.2682 4.5286 7.52855C4.26825 7.7889 4.26825 8.21101 4.5286 8.47136L6.5286 10.4714C6.78895 10.7317 7.21106 10.7317 7.47141 10.4714L11.4714 6.47136Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "CheckCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/CheckCircle.tsx b/app/components/base/icons/src/vender/solid/general/CheckCircle.tsx
new file mode 100644
index 0000000..2b34cd6
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/CheckCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './CheckCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'CheckCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/CheckDone01.json b/app/components/base/icons/src/vender/solid/general/CheckDone01.json
new file mode 100644
index 0000000..b4d5530
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/CheckDone01.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12.8385 7H5.16146C4.63433 6.99998 4.17954 6.99997 3.80497 7.03057C3.40963 7.06287 3.01641 7.13419 2.63803 7.32698C2.07354 7.6146 1.6146 8.07354 1.32698 8.63803C1.13419 9.01641 1.06287 9.40963 1.03057 9.80497C0.999969 10.1795 0.999984 10.6343 1 11.1614V18.8385C0.999984 19.3657 0.999969 19.8205 1.03057 20.195C1.06287 20.5904 1.13419 20.9836 1.32698 21.362C1.6146 21.9265 2.07354 22.3854 2.63803 22.673C3.01641 22.8658 3.40963 22.9371 3.80497 22.9694C4.17952 23 4.63425 23 5.16136 23H12.8385C13.3656 23 13.8205 23 14.195 22.9694C14.5904 22.9371 14.9836 22.8658 15.362 22.673C15.9265 22.3854 16.3854 21.9265 16.673 21.362C16.8658 20.9836 16.9371 20.5904 16.9694 20.195C17 19.8205 17 19.3657 17 18.8385V11.1615C17 10.6343 17 10.1796 16.9694 9.80497C16.9371 9.40963 16.8658 9.01641 16.673 8.63803C16.3854 8.07354 15.9265 7.6146 15.362 7.32698C14.9836 7.13419 14.5904 7.06287 14.195 7.03057C13.8205 6.99997 13.3657 6.99998 12.8385 7ZM13.2071 13.2071C13.5976 12.8166 13.5976 12.1834 13.2071 11.7929C12.8166 11.4024 12.1834 11.4024 11.7929 11.7929L8 15.5858L6.70711 14.2929C6.31658 13.9024 5.68342 13.9024 5.29289 14.2929C4.90237 14.6834 4.90237 15.3166 5.29289 15.7071L7.29289 17.7071C7.68342 18.0976 8.31658 18.0976 8.70711 17.7071L13.2071 13.2071Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M18.8385 1H11.1615C10.6343 0.999984 10.1795 0.999969 9.80497 1.03057C9.40963 1.06287 9.01641 1.13419 8.63803 1.32698C8.07354 1.6146 7.6146 2.07354 7.32698 2.63803C7.13419 3.01641 7.06287 3.40963 7.03057 3.80497C7.00314 4.14076 7.00031 4.54098 7.00003 5.00003L12.8809 5.00001C13.3695 4.9999 13.8993 4.99977 14.3579 5.03724C14.8769 5.07964 15.5626 5.1846 16.2699 5.54499C17.2108 6.02436 17.9757 6.78926 18.455 7.73007C18.8154 8.43739 18.9204 9.12311 18.9628 9.64213C19.0003 10.1007 19.0001 10.6305 19 11.1192L19 17C19.459 16.9997 19.8593 16.9969 20.195 16.9694C20.5904 16.9371 20.9836 16.8658 21.362 16.673C21.9265 16.3854 22.3854 15.9265 22.673 15.362C22.8658 14.9836 22.9371 14.5904 22.9694 14.195C23 13.8205 23 13.3658 23 12.8386V5.16148C23 4.63437 23 4.17952 22.9694 3.80497C22.9371 3.40963 22.8658 3.01641 22.673 2.63803C22.3854 2.07354 21.9265 1.6146 21.362 1.32698C20.9836 1.13419 20.5904 1.06287 20.195 1.03057C19.8205 0.999969 19.3657 0.999984 18.8385 1Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "CheckDone01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/CheckDone01.tsx b/app/components/base/icons/src/vender/solid/general/CheckDone01.tsx
new file mode 100644
index 0000000..c7e7d80
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/CheckDone01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './CheckDone01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'CheckDone01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/Download02.json b/app/components/base/icons/src/vender/solid/general/Download02.json
new file mode 100644
index 0000000..5854e64
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Download02.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M21 21H3M18 11L12 17M12 17L6 11M12 17V3",
+ "stroke": "currentColor",
+ "stroke-width": "2",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Download02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/Download02.tsx b/app/components/base/icons/src/vender/solid/general/Download02.tsx
new file mode 100644
index 0000000..aee2993
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Download02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Download02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Download02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/Edit03.json b/app/components/base/icons/src/vender/solid/general/Edit03.json
new file mode 100644
index 0000000..f736ef5
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Edit03.json
@@ -0,0 +1,57 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "edit-03"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.50004 10.0001C5.50004 9.72398 5.7239 9.50012 6.00004 9.50012H10.5C10.7762 9.50012 11 9.72398 11 10.0001C11 10.2763 10.7762 10.5001 10.5 10.5001H6.00004C5.7239 10.5001 5.50004 10.2763 5.50004 10.0001Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M7.89651 1.39656C8.50599 0.787085 9.49414 0.787084 10.1036 1.39656C10.7131 2.00604 10.7131 2.99419 10.1036 3.60367L3.82225 9.88504C3.81235 9.89494 3.80254 9.90476 3.79281 9.91451C3.64909 10.0585 3.52237 10.1855 3.3696 10.2791C3.23539 10.3613 3.08907 10.4219 2.93602 10.4587C2.7618 10.5005 2.58242 10.5003 2.37897 10.5001C2.3652 10.5001 2.35132 10.5001 2.33732 10.5001H1.50005C1.22391 10.5001 1.00005 10.2763 1.00005 10.0001V9.16286C1.00005 9.14886 1.00004 9.13497 1.00003 9.1212C0.999836 8.91776 0.999669 8.73838 1.0415 8.56416C1.07824 8.4111 1.13885 8.26479 1.22109 8.13058C1.31471 7.97781 1.44166 7.85109 1.58566 7.70736C1.5954 7.69764 1.60523 7.68783 1.61513 7.67793L7.89651 1.39656Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Edit03"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/Edit03.tsx b/app/components/base/icons/src/vender/solid/general/Edit03.tsx
new file mode 100644
index 0000000..837e597
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Edit03.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Edit03.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Edit03'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/Edit04.json b/app/components/base/icons/src/vender/solid/general/Edit04.json
new file mode 100644
index 0000000..aa923c2
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Edit04.json
@@ -0,0 +1,39 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M21.6747 17.2619C22.0824 17.6345 22.1107 18.2671 21.7381 18.6747L20.738 19.7687C20.0284 20.5448 19.0458 21 18.0002 21C16.9549 21 15.9726 20.5452 15.2631 19.7696C14.9112 19.3863 14.4549 19.1901 14.0002 19.1901C13.5454 19.1901 13.0889 19.3864 12.7369 19.7701C12.3635 20.177 11.7309 20.2043 11.324 19.8309C10.917 19.4575 10.8898 18.8249 11.2632 18.418C11.9735 17.6438 12.9555 17.1901 14.0002 17.1901C15.045 17.1901 16.0269 17.6438 16.7373 18.418L16.7384 18.4192C17.0897 18.8034 17.5458 19 18.0002 19C18.4545 19 18.9106 18.8034 19.2618 18.4193L20.2619 17.3253C20.6346 16.9177 21.2671 16.8893 21.6747 17.2619Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M15.793 2.79287C17.0119 1.57393 18.9882 1.57392 20.2072 2.79287C21.4261 4.01183 21.4261 5.98814 20.2072 7.20709L7.64443 19.7698C7.62463 19.7896 7.60502 19.8093 7.58556 19.8288C7.29811 20.1168 7.04467 20.3707 6.73914 20.5579C6.47072 20.7224 6.17809 20.8436 5.87198 20.9171C5.52353 21.0007 5.16478 21.0004 4.75788 21C4.73034 21 4.70258 21 4.67458 21H3.00004C2.44776 21 2.00004 20.5523 2.00004 20V18.3255C2.00004 18.2975 2.00001 18.2697 1.99999 18.2422C1.99961 17.8353 1.99928 17.4765 2.08293 17.1281C2.15642 16.822 2.27763 16.5293 2.44212 16.2609C2.62936 15.9554 2.88327 15.7019 3.17125 15.4145C3.19075 15.395 3.2104 15.3754 3.23019 15.3556L15.793 2.79287Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Edit04"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/Edit04.tsx b/app/components/base/icons/src/vender/solid/general/Edit04.tsx
new file mode 100644
index 0000000..5e436c0
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Edit04.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Edit04.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Edit04'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/Eye.json b/app/components/base/icons/src/vender/solid/general/Eye.json
new file mode 100644
index 0000000..a7e6348
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Eye.json
@@ -0,0 +1,37 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10 12C10 10.8954 10.8954 10 12 10C13.1046 10 14 10.8954 14 12C14 13.1046 13.1046 14 12 14C10.8954 14 10 13.1046 10 12Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12 4C9.13833 4 6.80535 5.26472 5.07675 6.70743C3.3505 8.14818 2.16697 9.81429 1.57422 10.7528L1.55014 10.7908C1.43252 10.976 1.27981 11.2164 1.2026 11.5532C1.14027 11.8251 1.14027 12.1749 1.2026 12.4468C1.2798 12.7836 1.43252 13.024 1.55014 13.2092L1.57423 13.2472C2.16697 14.1857 3.3505 15.8518 5.07675 17.2926C6.80535 18.7353 9.13833 20 12 20C14.8617 20 17.1947 18.7353 18.9233 17.2926C20.6495 15.8518 21.833 14.1857 22.4258 13.2472L22.4499 13.2092C22.5675 13.024 22.7202 12.7837 22.7974 12.4468C22.8597 12.1749 22.8597 11.8251 22.7974 11.5532C22.7202 11.2163 22.5675 10.976 22.4499 10.7908L22.4258 10.7528C21.833 9.81429 20.6495 8.14818 18.9233 6.70743C17.1947 5.26472 14.8617 4 12 4ZM12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Eye"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/Eye.tsx b/app/components/base/icons/src/vender/solid/general/Eye.tsx
new file mode 100644
index 0000000..29d1ea9
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Eye.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Eye.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Eye'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/Github.json b/app/components/base/icons/src/vender/solid/general/Github.json
new file mode 100644
index 0000000..46e6942
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Github.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M8 1C4.1325 1 1 4.1325 1 8C1 11.0975 3.00375 13.7137 5.78625 14.6413C6.13625 14.7025 6.2675 14.4925 6.2675 14.3088C6.2675 14.1425 6.25875 13.5913 6.25875 13.005C4.5 13.3288 4.045 12.5763 3.905 12.1825C3.82625 11.9812 3.485 11.36 3.1875 11.1937C2.9425 11.0625 2.5925 10.7387 3.17875 10.73C3.73 10.7212 4.12375 11.2375 4.255 11.4475C4.885 12.5062 5.89125 12.2088 6.29375 12.025C6.355 11.57 6.53875 11.2638 6.74 11.0887C5.1825 10.9137 3.555 10.31 3.555 7.6325C3.555 6.87125 3.82625 6.24125 4.2725 5.75125C4.2025 5.57625 3.9575 4.85875 4.3425 3.89625C4.3425 3.89625 4.92875 3.7125 6.2675 4.61375C6.8275 4.45625 7.4225 4.3775 8.0175 4.3775C8.6125 4.3775 9.2075 4.45625 9.7675 4.61375C11.1063 3.70375 11.6925 3.89625 11.6925 3.89625C12.0775 4.85875 11.8325 5.57625 11.7625 5.75125C12.2087 6.24125 12.48 6.8625 12.48 7.6325C12.48 10.3187 10.8438 10.9137 9.28625 11.0887C9.54 11.3075 9.75875 11.7275 9.75875 12.3837C9.75875 13.32 9.75 14.0725 9.75 14.3088C9.75 14.4925 9.88125 14.7113 10.2312 14.6413C11.6209 14.1721 12.8284 13.279 13.6839 12.0877C14.5393 10.8963 14.9996 9.46668 15 8C15 4.1325 11.8675 1 8 1Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Github"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/Github.tsx b/app/components/base/icons/src/vender/solid/general/Github.tsx
new file mode 100644
index 0000000..9c6f418
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Github.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Github.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Github'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/MessageClockCircle.json b/app/components/base/icons/src/vender/solid/general/MessageClockCircle.json
new file mode 100644
index 0000000..4307f82
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/MessageClockCircle.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "message-clock-circle"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "d": "M1.33301 8.00016C1.33301 4.31826 4.31778 1.3335 7.99967 1.3335C11.6816 1.3335 14.6663 4.31826 14.6663 8.00016C14.6663 11.6821 11.6816 14.6668 7.99967 14.6668C7.11413 14.6668 6.26734 14.4938 5.49248 14.1791C5.42249 14.1507 5.38209 14.1344 5.35225 14.1231L5.34304 14.1197L5.33987 14.1202C5.31527 14.1235 5.28173 14.129 5.21771 14.1397L2.82667 14.5382C2.71958 14.5561 2.59976 14.5761 2.4957 14.5839C2.38225 14.5925 2.20175 14.5955 2.01101 14.5137C1.77521 14.4125 1.5873 14.2246 1.48616 13.9888C1.40435 13.7981 1.40733 13.6176 1.41589 13.5041C1.42375 13.4001 1.44375 13.2803 1.46163 13.1732L1.86015 10.7821C1.87082 10.7181 1.87634 10.6846 1.87967 10.66L1.8801 10.6568L1.87669 10.6476C1.86549 10.6178 1.84914 10.5773 1.82071 10.5074C1.50602 9.7325 1.33301 8.88571 1.33301 8.00016ZM7.99967 5.3335C7.99967 4.96531 7.7012 4.66683 7.33301 4.66683C6.96482 4.66683 6.66634 4.96531 6.66634 5.3335V8.66683C6.66634 9.03502 6.96482 9.3335 7.33301 9.3335H10.6663C11.0345 9.3335 11.333 9.03502 11.333 8.66683C11.333 8.29864 11.0345 8.00016 10.6663 8.00016H7.99967V5.3335Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "MessageClockCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/MessageClockCircle.tsx b/app/components/base/icons/src/vender/solid/general/MessageClockCircle.tsx
new file mode 100644
index 0000000..dc1f17e
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/MessageClockCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MessageClockCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MessageClockCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/PlusCircle.json b/app/components/base/icons/src/vender/solid/general/PlusCircle.json
new file mode 100644
index 0000000..005a7ba
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/PlusCircle.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "plus-circle"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1ZM12 7C12.5523 7 13 7.44772 13 8V11H16C16.5523 11 17 11.4477 17 12C17 12.5523 16.5523 13 16 13H13V16C13 16.5523 12.5523 17 12 17C11.4477 17 11 16.5523 11 16V13H8C7.44772 13 7 12.5523 7 12C7 11.4477 7.44772 11 8 11H11V8C11 7.44772 11.4477 7 12 7Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "PlusCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/PlusCircle.tsx b/app/components/base/icons/src/vender/solid/general/PlusCircle.tsx
new file mode 100644
index 0000000..142ad91
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/PlusCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './PlusCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'PlusCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/QuestionTriangle.json b/app/components/base/icons/src/vender/solid/general/QuestionTriangle.json
new file mode 100644
index 0000000..8830ee5
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/QuestionTriangle.json
@@ -0,0 +1,45 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "8",
+ "height": "12",
+ "viewBox": "0 0 8 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Rectangle 2"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.96353 1.5547C7.40657 0.890144 6.93018 0 6.13148 0H0V12L6.96353 1.5547Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M6.96353 1.5547C7.40657 0.890144 6.93018 0 6.13148 0H0V12L6.96353 1.5547Z",
+ "fill": "currentColor",
+ "fill-opacity": "0.5"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "QuestionTriangle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/QuestionTriangle.tsx b/app/components/base/icons/src/vender/solid/general/QuestionTriangle.tsx
new file mode 100644
index 0000000..85cc44f
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/QuestionTriangle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './QuestionTriangle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'QuestionTriangle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/SearchMd.json b/app/components/base/icons/src/vender/solid/general/SearchMd.json
new file mode 100644
index 0000000..808195f
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/SearchMd.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "search-md"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2ZM4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "SearchMd"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/SearchMd.tsx b/app/components/base/icons/src/vender/solid/general/SearchMd.tsx
new file mode 100644
index 0000000..295997c
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/SearchMd.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './SearchMd.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'SearchMd'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/Target04.json b/app/components/base/icons/src/vender/solid/general/Target04.json
new file mode 100644
index 0000000..6b22fab
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Target04.json
@@ -0,0 +1,46 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M19.1601 1.01292C19.4774 1.06441 19.7506 1.26529 19.8944 1.5528L20.7453 3.25466L22.4472 4.10558C22.7347 4.24934 22.9355 4.52254 22.987 4.83983C23.0385 5.15712 22.9343 5.47982 22.707 5.70712L19.707 8.70712C19.5195 8.89466 19.2652 9.00001 18.9999 9.00001H16.4142L12.7071 12.7071C12.3166 13.0976 11.6834 13.0976 11.2929 12.7071C10.9024 12.3166 10.9024 11.6834 11.2929 11.2929L14.9999 7.58585V5.00001C14.9999 4.7348 15.1053 4.48044 15.2928 4.29291L18.2928 1.29291C18.5201 1.06561 18.8428 0.961435 19.1601 1.01292Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3 12C3 7.02944 7.02944 3 12 3C12.5523 3 13 2.55228 13 2C13 1.44772 12.5523 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C18.0751 23 23 18.0751 23 12C23 11.4477 22.5523 11 22 11C21.4477 11 21 11.4477 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8 12C8 9.79086 9.79086 8 12 8C12.5523 8 13 7.55228 13 7C13 6.44772 12.5523 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18C15.3137 18 18 15.3137 18 12C18 11.4477 17.5523 11 17 11C16.4477 11 16 11.4477 16 12C16 14.2091 14.2091 16 12 16C9.79086 16 8 14.2091 8 12Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Target04"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/Target04.tsx b/app/components/base/icons/src/vender/solid/general/Target04.tsx
new file mode 100644
index 0000000..d2d04f9
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Target04.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Target04.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Target04'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/Tool03.json b/app/components/base/icons/src/vender/solid/general/Tool03.json
new file mode 100644
index 0000000..0a7f1ab
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Tool03.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "tool-03"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.10516 6.61092L6.45642 5.41856C6.43816 5.25959 6.43018 5.09961 6.43253 4.93962V4.9285L2.91826 1.41365C2.89245 1.38778 2.86179 1.36725 2.82804 1.35325C2.79429 1.33924 2.75811 1.33203 2.72157 1.33203C2.68503 1.33203 2.64884 1.33924 2.61509 1.35325C2.58134 1.36725 2.55069 1.38778 2.52488 1.41365L1.41365 2.52489C1.38778 2.5507 1.36725 2.58135 1.35325 2.6151C1.33924 2.64885 1.33203 2.68504 1.33203 2.72158C1.33203 2.75812 1.33924 2.7943 1.35325 2.82806C1.36725 2.86181 1.38778 2.89246 1.41365 2.91827L5.10516 6.61092Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M12.5043 9.33348C12.3512 9.3848 12.1956 9.42819 12.0381 9.46349L11.9748 9.47461C11.7112 9.51388 11.4451 9.53375 11.1786 9.53406C10.9848 9.53389 10.7912 9.52314 10.5985 9.50183L8.58942 11.7604L10.8297 14.0007C11.0335 14.2097 11.2767 14.3763 11.5452 14.4907C11.8138 14.6052 12.1024 14.6652 12.3943 14.6674H12.4176C12.8604 14.6643 13.2924 14.5307 13.6596 14.2832C14.0268 14.0356 14.3128 13.6853 14.4818 13.276C14.6508 12.8667 14.6952 12.4167 14.6096 11.9822C14.524 11.5478 14.3122 11.1483 14.0006 10.8337L12.5043 9.33348Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.4606 3.79227C14.4443 3.74889 14.4174 3.71027 14.3823 3.67995C14.3472 3.64963 14.3051 3.62857 14.2599 3.61868C14.2146 3.6088 14.1675 3.6104 14.123 3.62335C14.0785 3.6363 14.0379 3.66018 14.005 3.69282L12.4132 5.27745L10.7224 3.5928L12.3132 2.00929C12.3454 1.97739 12.3692 1.93802 12.3825 1.89468C12.3957 1.85134 12.3981 1.80539 12.3893 1.76092C12.3805 1.7159 12.3606 1.67376 12.3315 1.63828C12.3024 1.60279 12.265 1.57506 12.2226 1.55757C11.7685 1.35982 11.2688 1.29063 10.778 1.35754C9.88338 1.43541 9.05173 1.8501 8.45122 2.51777C7.8507 3.18544 7.52615 4.05624 7.54319 4.95408C7.53907 5.24983 7.58317 5.54428 7.67376 5.82584L2.09204 10.7442C1.64427 11.1439 1.3735 11.7051 1.33923 12.3043C1.30495 12.9036 1.50997 13.4919 1.90924 13.9401L1.95703 13.9924C2.35812 14.411 2.90891 14.6533 3.4885 14.6662C4.06809 14.6791 4.62913 14.4616 5.04848 14.0613C5.11213 14.0008 5.17189 13.9364 5.22739 13.8685L10.1801 8.30058C10.7141 8.43272 11.2688 8.45821 11.8126 8.37559C12.4502 8.24485 13.04 7.9423 13.5182 7.50065C13.9964 7.05899 14.3447 6.49503 14.5256 5.86974C14.7321 5.18882 14.7092 4.45895 14.4606 3.79227Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Tool03"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/Tool03.tsx b/app/components/base/icons/src/vender/solid/general/Tool03.tsx
new file mode 100644
index 0000000..fd60b8e
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/Tool03.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Tool03.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Tool03'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/XCircle.json b/app/components/base/icons/src/vender/solid/general/XCircle.json
new file mode 100644
index 0000000..dd269fa
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/XCircle.json
@@ -0,0 +1,29 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.00008 0.666016C3.94999 0.666016 0.666748 3.94926 0.666748 7.99935C0.666748 12.0494 3.94999 15.3327 8.00008 15.3327C12.0502 15.3327 15.3334 12.0494 15.3334 7.99935C15.3334 3.94926 12.0502 0.666016 8.00008 0.666016ZM10.4715 5.52794C10.7318 5.78829 10.7318 6.2104 10.4715 6.47075L8.94289 7.99935L10.4715 9.52794C10.7318 9.78829 10.7318 10.2104 10.4715 10.4708C10.2111 10.7311 9.78903 10.7311 9.52868 10.4708L8.00008 8.94216L6.47149 10.4708C6.21114 10.7311 5.78903 10.7311 5.52868 10.4708C5.26833 10.2104 5.26833 9.78829 5.52868 9.52794L7.05727 7.99935L5.52868 6.47075C5.26833 6.2104 5.26833 5.78829 5.52868 5.52794C5.78903 5.26759 6.21114 5.26759 6.47149 5.52794L8.00008 7.05654L9.52868 5.52794C9.78903 5.26759 10.2111 5.26759 10.4715 5.52794Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "XCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/XCircle.tsx b/app/components/base/icons/src/vender/solid/general/XCircle.tsx
new file mode 100644
index 0000000..b278a98
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/XCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './XCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'XCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/ZapFast.json b/app/components/base/icons/src/vender/solid/general/ZapFast.json
new file mode 100644
index 0000000..865a48e
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/ZapFast.json
@@ -0,0 +1,79 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "zap-fast"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1.25 8.75004C1.25 8.4739 1.47386 8.25004 1.75 8.25004H4.5C4.77614 8.25004 5 8.4739 5 8.75004C5 9.02618 4.77614 9.25004 4.5 9.25004H1.75C1.47386 9.25004 1.25 9.02618 1.25 8.75004Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M0.5 6.00004C0.5 5.7239 0.723858 5.50004 1 5.50004H3.25C3.52614 5.50004 3.75 5.7239 3.75 6.00004C3.75 6.27618 3.52614 6.50004 3.25 6.50004H1C0.723858 6.50004 0.5 6.27618 0.5 6.00004Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1.5 3.25004C1.5 2.9739 1.72386 2.75004 2 2.75004H4.5C4.77614 2.75004 5 2.9739 5 3.25004C5 3.52618 4.77614 3.75004 4.5 3.75004H2C1.72386 3.75004 1.5 3.52618 1.5 3.25004Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.68379 1.03505C8.89736 1.11946 9.02596 1.33849 8.99561 1.56612L8.57109 4.75004H10.4727C10.4785 4.75004 10.4842 4.75004 10.49 4.75004C10.6003 4.75002 10.7147 4.74999 10.8092 4.75863C10.9022 4.76713 11.0713 4.78965 11.2224 4.90631C11.3987 5.04237 11.5054 5.24972 11.5137 5.47225C11.5208 5.66306 11.4408 5.81376 11.3937 5.89434C11.3458 5.97625 11.2793 6.06932 11.2151 6.15912C11.2118 6.16381 11.2084 6.16849 11.2051 6.17316L7.90687 10.7907C7.77339 10.9775 7.52978 11.0495 7.31621 10.965C7.10264 10.8806 6.97404 10.6616 7.00439 10.434L7.42891 7.25004H5.52728C5.52154 7.25004 5.51579 7.25004 5.51003 7.25004C5.39966 7.25007 5.28526 7.25009 5.19077 7.24145C5.09782 7.23296 4.92871 7.21044 4.77755 7.09377C4.60127 6.95771 4.49456 6.75036 4.48631 6.52783C4.47924 6.33702 4.5592 6.18632 4.60631 6.10575C4.65421 6.02383 4.72072 5.93076 4.78489 5.84097C4.78824 5.83628 4.79158 5.8316 4.79492 5.82693L8.09313 1.20942C8.22661 1.02255 8.47022 0.950633 8.68379 1.03505Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ZapFast"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/ZapFast.tsx b/app/components/base/icons/src/vender/solid/general/ZapFast.tsx
new file mode 100644
index 0000000..af7e8bd
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/ZapFast.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ZapFast.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ZapFast'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/ZapNarrow.json b/app/components/base/icons/src/vender/solid/general/ZapNarrow.json
new file mode 100644
index 0000000..740c823
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/ZapNarrow.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "zap-narrow"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6.69792 1.03505C6.91148 1.11946 7.04009 1.33849 7.00974 1.56612L6.58522 4.75004H8.48685C8.49259 4.75004 8.49834 4.75004 8.5041 4.75004C8.61447 4.75002 8.72887 4.74999 8.82336 4.75863C8.91631 4.76713 9.08541 4.78965 9.23657 4.90631C9.41286 5.04237 9.51956 5.24972 9.52781 5.47225C9.53489 5.66306 9.45493 5.81376 9.40781 5.89434C9.35992 5.97625 9.29341 6.06932 9.22924 6.15912C9.22589 6.16381 9.22255 6.16849 9.21921 6.17316L5.92099 10.7907C5.78752 10.9775 5.54391 11.0495 5.33034 10.965C5.11677 10.8806 4.98816 10.6616 5.01851 10.434L5.44304 7.25004H3.5414C3.53567 7.25004 3.52992 7.25004 3.52416 7.25004C3.41378 7.25007 3.29939 7.25009 3.2049 7.24145C3.11194 7.23296 2.94284 7.21044 2.79168 7.09377C2.6154 6.95771 2.50869 6.75036 2.50044 6.52783C2.49336 6.33702 2.57333 6.18632 2.62044 6.10575C2.66833 6.02383 2.73484 5.93076 2.79901 5.84097C2.80236 5.83628 2.80571 5.8316 2.80904 5.82693L6.10726 1.20942C6.24074 1.02255 6.48435 0.950633 6.69792 1.03505Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ZapNarrow"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/general/ZapNarrow.tsx b/app/components/base/icons/src/vender/solid/general/ZapNarrow.tsx
new file mode 100644
index 0000000..5f2aa62
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/ZapNarrow.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ZapNarrow.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ZapNarrow'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/general/index.ts b/app/components/base/icons/src/vender/solid/general/index.ts
new file mode 100644
index 0000000..4c4dd9a
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/general/index.ts
@@ -0,0 +1,18 @@
+export { default as AnswerTriangle } from './AnswerTriangle'
+export { default as ArrowDownRoundFill } from './ArrowDownRoundFill'
+export { default as CheckCircle } from './CheckCircle'
+export { default as CheckDone01 } from './CheckDone01'
+export { default as Download02 } from './Download02'
+export { default as Edit03 } from './Edit03'
+export { default as Edit04 } from './Edit04'
+export { default as Eye } from './Eye'
+export { default as Github } from './Github'
+export { default as MessageClockCircle } from './MessageClockCircle'
+export { default as PlusCircle } from './PlusCircle'
+export { default as QuestionTriangle } from './QuestionTriangle'
+export { default as SearchMd } from './SearchMd'
+export { default as Target04 } from './Target04'
+export { default as Tool03 } from './Tool03'
+export { default as XCircle } from './XCircle'
+export { default as ZapFast } from './ZapFast'
+export { default as ZapNarrow } from './ZapNarrow'
diff --git a/app/components/base/icons/src/vender/solid/layout/Grid01.json b/app/components/base/icons/src/vender/solid/layout/Grid01.json
new file mode 100644
index 0000000..722cdec
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/layout/Grid01.json
@@ -0,0 +1,79 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "grid-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3.04545 1.33338C3.90407 1.33348 4.76437 1.33348 5.62131 1.33338C5.78956 1.33336 5.95343 1.33334 6.0922 1.34467C6.24459 1.35713 6.42442 1.3865 6.60536 1.4787C6.85625 1.60653 7.06022 1.81051 7.18805 2.06139C7.28025 2.24234 7.30963 2.42216 7.32208 2.57456C7.33342 2.71333 7.3334 2.8772 7.33338 3.04546V5.6213C7.3334 5.78956 7.33342 5.95342 7.32208 6.0922C7.30963 6.24459 7.28025 6.42442 7.18805 6.60536C7.06022 6.85625 6.85625 7.06022 6.60536 7.18805C6.42442 7.28025 6.24459 7.30963 6.0922 7.32208C5.95342 7.33342 5.78956 7.3334 5.6213 7.33338H3.04546C2.8772 7.3334 2.71333 7.33342 2.57456 7.32208C2.42216 7.30963 2.24234 7.28025 2.06139 7.18805C1.81051 7.06022 1.60653 6.85625 1.4787 6.60536C1.3865 6.42442 1.35713 6.24459 1.34467 6.0922C1.33334 5.95343 1.33336 5.78956 1.33338 5.62131C1.33338 5.61423 1.33338 5.60714 1.33338 5.60004V3.06671C1.33338 3.05962 1.33338 3.05253 1.33338 3.04545C1.33336 2.87719 1.33334 2.71333 1.34467 2.57456C1.35713 2.42216 1.3865 2.24234 1.4787 2.06139C1.60653 1.81051 1.81051 1.60653 2.06139 1.4787C2.24234 1.3865 2.42216 1.35713 2.57456 1.34467C2.71333 1.33334 2.87719 1.33336 3.04545 1.33338Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3.04545 8.66671C3.90407 8.66682 4.76437 8.66682 5.62131 8.66671C5.78956 8.66669 5.95343 8.66667 6.0922 8.67801C6.24459 8.69046 6.42442 8.71984 6.60536 8.81204C6.85625 8.93987 7.06022 9.14384 7.18805 9.39472C7.28025 9.57567 7.30963 9.7555 7.32208 9.90789C7.33342 10.0467 7.3334 10.2105 7.33338 10.3788V12.9546C7.3334 13.1229 7.33342 13.2868 7.32208 13.4255C7.30963 13.5779 7.28025 13.7577 7.18805 13.9387C7.06022 14.1896 6.85625 14.3936 6.60536 14.5214C6.42442 14.6136 6.24459 14.643 6.0922 14.6554C5.95342 14.6668 5.78956 14.6667 5.6213 14.6667H3.04546C2.8772 14.6667 2.71333 14.6668 2.57456 14.6554C2.42216 14.643 2.24234 14.6136 2.06139 14.5214C1.81051 14.3936 1.60653 14.1896 1.4787 13.9387C1.3865 13.7577 1.35713 13.5779 1.34467 13.4255C1.33334 13.2868 1.33336 13.1229 1.33338 12.9546C1.33338 12.9476 1.33338 12.9405 1.33338 12.9334V10.4C1.33338 10.3929 1.33338 10.3859 1.33338 10.3788C1.33336 10.2105 1.33334 10.0467 1.34467 9.90789C1.35713 9.7555 1.3865 9.57567 1.4787 9.39472C1.60653 9.14384 1.81051 8.93987 2.06139 8.81204C2.24234 8.71984 2.42216 8.69046 2.57456 8.67801C2.71333 8.66667 2.87719 8.66669 3.04545 8.66671Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M10.3788 1.33338C11.2374 1.33348 12.0977 1.33348 12.9546 1.33338C13.1229 1.33336 13.2868 1.33334 13.4255 1.34467C13.5779 1.35713 13.7577 1.3865 13.9387 1.4787C14.1896 1.60653 14.3936 1.81051 14.5214 2.06139C14.6136 2.24234 14.643 2.42216 14.6554 2.57456C14.6668 2.71333 14.6667 2.8772 14.6667 3.04546V5.6213C14.6667 5.78956 14.6668 5.95342 14.6554 6.0922C14.643 6.24459 14.6136 6.42442 14.5214 6.60536C14.3936 6.85625 14.1896 7.06022 13.9387 7.18805C13.7577 7.28025 13.5779 7.30963 13.4255 7.32208C13.2868 7.33342 13.1229 7.3334 12.9546 7.33338H10.3788C10.2105 7.3334 10.0467 7.33342 9.90789 7.32208C9.7555 7.30963 9.57567 7.28025 9.39472 7.18805C9.14384 7.06022 8.93987 6.85625 8.81204 6.60536C8.71984 6.42442 8.69046 6.24459 8.67801 6.0922C8.66667 5.95343 8.66669 5.78956 8.66671 5.62131C8.66671 5.61423 8.66671 5.60714 8.66671 5.60004V3.06671C8.66671 3.05962 8.66671 3.05253 8.66671 3.04545C8.66669 2.87719 8.66667 2.71333 8.67801 2.57456C8.69046 2.42216 8.71984 2.24234 8.81204 2.06139C8.93987 1.81051 9.14384 1.60653 9.39472 1.4787C9.57567 1.3865 9.7555 1.35713 9.90789 1.34467C10.0467 1.33334 10.2105 1.33336 10.3788 1.33338Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M10.3788 8.66671C11.2374 8.66682 12.0977 8.66682 12.9546 8.66671C13.1229 8.66669 13.2868 8.66667 13.4255 8.67801C13.5779 8.69046 13.7577 8.71984 13.9387 8.81204C14.1896 8.93987 14.3936 9.14384 14.5214 9.39472C14.6136 9.57567 14.643 9.7555 14.6554 9.90789C14.6668 10.0467 14.6667 10.2105 14.6667 10.3788V12.9546C14.6667 13.1229 14.6668 13.2868 14.6554 13.4255C14.643 13.5779 14.6136 13.7577 14.5214 13.9387C14.3936 14.1896 14.1896 14.3936 13.9387 14.5214C13.7577 14.6136 13.5779 14.643 13.4255 14.6554C13.2868 14.6668 13.1229 14.6667 12.9546 14.6667H10.3788C10.2105 14.6667 10.0467 14.6668 9.90789 14.6554C9.7555 14.643 9.57567 14.6136 9.39472 14.5214C9.14384 14.3936 8.93987 14.1896 8.81204 13.9387C8.71984 13.7577 8.69046 13.5779 8.67801 13.4255C8.66667 13.2868 8.66669 13.1229 8.66671 12.9546C8.66671 12.9476 8.66671 12.9405 8.66671 12.9334V10.4C8.66671 10.3929 8.66671 10.3859 8.66671 10.3788C8.66669 10.2105 8.66667 10.0467 8.67801 9.90789C8.69046 9.7555 8.71984 9.57567 8.81204 9.39472C8.93987 9.14384 9.14384 8.93987 9.39472 8.81204C9.57567 8.71984 9.7555 8.69046 9.90789 8.67801C10.0467 8.66667 10.2105 8.66669 10.3788 8.66671Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Grid01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/layout/Grid01.tsx b/app/components/base/icons/src/vender/solid/layout/Grid01.tsx
new file mode 100644
index 0000000..5638f3c
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/layout/Grid01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Grid01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Grid01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/layout/index.ts b/app/components/base/icons/src/vender/solid/layout/index.ts
new file mode 100644
index 0000000..73a2513
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/layout/index.ts
@@ -0,0 +1 @@
+export { default as Grid01 } from './Grid01'
diff --git a/app/components/base/icons/src/vender/solid/mapsAndTravel/Globe06.json b/app/components/base/icons/src/vender/solid/mapsAndTravel/Globe06.json
new file mode 100644
index 0000000..6cc565f
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mapsAndTravel/Globe06.json
@@ -0,0 +1,57 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "17",
+ "viewBox": "0 0 16 17",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6.39498 2.71706C6.90587 2.57557 7.44415 2.49996 8.00008 2.49996C9.30806 2.49996 10.5183 2.91849 11.5041 3.62893C10.9796 3.97562 10.5883 4.35208 10.3171 4.75458C9.90275 5.36959 9.79654 6.00558 9.88236 6.58587C9.96571 7.1494 10.2245 7.63066 10.4965 7.98669C10.7602 8.33189 11.0838 8.6206 11.3688 8.76305C12.0863 9.12177 12.9143 9.30141 13.5334 9.39399C14.0933 9.47774 15.2805 9.75802 15.3244 8.86608C15.3304 8.74474 15.3334 8.62267 15.3334 8.49996C15.3334 4.44987 12.0502 1.16663 8.00008 1.16663C3.94999 1.16663 0.666748 4.44987 0.666748 8.49996C0.666748 12.55 3.94999 15.8333 8.00008 15.8333C8.1228 15.8333 8.24486 15.8303 8.3662 15.8243C8.73395 15.8062 9.01738 15.4934 8.99927 15.1256C8.98117 14.7579 8.66837 14.4745 8.30063 14.4926C8.20111 14.4975 8.10091 14.5 8.00008 14.5C5.6605 14.5 3.63367 13.1609 2.6442 11.2074L3.28991 10.8346L5.67171 11.2804C6.28881 11.3959 6.85846 10.9208 6.85566 10.293L6.84632 8.19093L8.06357 6.10697C8.26079 5.76932 8.24312 5.3477 8.01833 5.02774L6.39498 2.71706Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.29718 8.93736C9.05189 8.84432 8.77484 8.90379 8.58934 9.08929C8.40383 9.27479 8.34437 9.55184 8.43741 9.79713L10.5486 15.363C10.6461 15.6199 10.8912 15.7908 11.166 15.7932C11.4408 15.7956 11.689 15.6292 11.791 15.374L12.6714 13.1714L14.874 12.2909C15.1292 12.1889 15.2957 11.9408 15.2932 11.666C15.2908 11.3912 15.12 11.146 14.863 11.0486L9.29718 8.93736Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Globe06"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mapsAndTravel/Globe06.tsx b/app/components/base/icons/src/vender/solid/mapsAndTravel/Globe06.tsx
new file mode 100644
index 0000000..d961eed
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mapsAndTravel/Globe06.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Globe06.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Globe06'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mapsAndTravel/Route.json b/app/components/base/icons/src/vender/solid/mapsAndTravel/Route.json
new file mode 100644
index 0000000..24d3f35
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mapsAndTravel/Route.json
@@ -0,0 +1,58 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "13",
+ "height": "12",
+ "viewBox": "0 0 13 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "route-sep"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "d": "M6.08303 2.5H6.30023C7.82386 2.5 8.58567 2.5 8.87485 2.77364C9.12483 3.01018 9.23561 3.35864 9.16812 3.69611C9.09004 4.08651 8.46809 4.52643 7.22418 5.40627L5.19189 6.84373C3.94799 7.72357 3.32603 8.16349 3.24795 8.55389C3.18046 8.89136 3.29124 9.23982 3.54122 9.47636C3.8304 9.75 4.59221 9.75 6.11584 9.75H6.58303",
+ "stroke": "currentColor",
+ "stroke-linecap": "round",
+ "stroke-linejoin": "round"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_2",
+ "d": "M2.83301 4C3.66143 4 4.33301 3.32843 4.33301 2.5C4.33301 1.67157 3.66143 1 2.83301 1C2.00458 1 1.33301 1.67157 1.33301 2.5C1.33301 3.32843 2.00458 4 2.83301 4Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon_3",
+ "d": "M9.83301 11C10.6614 11 11.333 10.3284 11.333 9.5C11.333 8.67157 10.6614 8 9.83301 8C9.00458 8 8.33301 8.67157 8.33301 9.5C8.33301 10.3284 9.00458 11 9.83301 11Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Route"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mapsAndTravel/Route.tsx b/app/components/base/icons/src/vender/solid/mapsAndTravel/Route.tsx
new file mode 100644
index 0000000..f81fb61
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mapsAndTravel/Route.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Route.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Route'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mapsAndTravel/index.ts b/app/components/base/icons/src/vender/solid/mapsAndTravel/index.ts
new file mode 100644
index 0000000..0a0abda
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mapsAndTravel/index.ts
@@ -0,0 +1,2 @@
+export { default as Globe06 } from './Globe06'
+export { default as Route } from './Route'
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/AudioSupportIcon.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/AudioSupportIcon.json
new file mode 100644
index 0000000..cd3006b
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/AudioSupportIcon.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "xmlns": "http://www.w3.org/2000/svg",
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.3567 3.56405L10.2334 3.84689C10.1432 4.05396 9.8568 4.05396 9.76655 3.84689L9.6433 3.56405C9.42355 3.05973 9.02775 2.6582 8.53385 2.43854L8.154 2.26961C7.94865 2.17826 7.94865 1.8794 8.154 1.78806L8.5126 1.62857C9.0192 1.40325 9.4221 0.986865 9.63805 0.465414L9.76465 0.159767C9.8529 -0.0532556 10.1471 -0.0532556 10.2353 0.159767L10.3619 0.465414C10.5779 0.986865 10.9808 1.40325 11.4874 1.62857L11.846 1.78806C12.0514 1.8794 12.0514 2.17826 11.846 2.26961L11.4662 2.43854C10.9723 2.6582 10.5764 3.05973 10.3567 3.56405ZM4.25 3H3.25V9H4.25V3ZM2 5H1V7H2V5ZM6.5 1H5.5V11H6.5V1ZM8.75 4H7.75V9H8.75V4ZM11 5H10V7H11V5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "AudioSupportIcon"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/AudioSupportIcon.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/AudioSupportIcon.tsx
new file mode 100644
index 0000000..663866f
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/AudioSupportIcon.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './AudioSupportIcon.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'AudioSupportIcon'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/DocumentSupportIcon.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/DocumentSupportIcon.json
new file mode 100644
index 0000000..49cb6a5
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/DocumentSupportIcon.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "xmlns": "http://www.w3.org/2000/svg",
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.5 4V10.4966C10.5 10.7751 10.2776 11 10.0033 11H1.9967C1.72248 11 1.5 10.778 1.5 10.5041V1.4959C1.5 1.22766 1.72435 1 2.00111 1H7.4984L10.5 4ZM9.5 4.5H7V2H2.5V10H9.5V4.5ZM4 3.5H5.5V4.5H4V3.5ZM4 5.5H8V6.5H4V5.5ZM4 7.5H8V8.5H4V7.5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "DocumentSupportIcon"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/DocumentSupportIcon.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/DocumentSupportIcon.tsx
new file mode 100644
index 0000000..5bad91e
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/DocumentSupportIcon.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './DocumentSupportIcon.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'DocumentSupportIcon'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicBox.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicBox.json
new file mode 100644
index 0000000..4668e9e
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicBox.json
@@ -0,0 +1,64 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "box-sparkle, magic box"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.76205 2.07424C9.99723 2.21897 10.0706 2.52694 9.92583 2.76212L8.85632 4.50007H9.5C9.77614 4.50007 10 4.72393 10 5.00007V9.00007C10 10.1046 9.10457 11.0001 8 11.0001H4C2.89543 11.0001 2 10.1046 2 9.00007V5.00007C2 4.72393 2.22386 4.50007 2.5 4.50007H7.68214L9.07417 2.23802C9.2189 2.00284 9.52687 1.92952 9.76205 2.07424ZM5 6.50007C4.72386 6.50007 4.5 6.72393 4.5 7.00007C4.5 7.27621 4.72386 7.50007 5 7.50007H7C7.27614 7.50007 7.5 7.27621 7.5 7.00007C7.5 6.72393 7.27614 6.50007 7 6.50007H5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.92504 1.53733C5.97342 1.51314 6.01265 1.47391 6.03684 1.42553L6.27597 0.947279C6.3681 0.763016 6.63105 0.763017 6.72318 0.947279L6.96231 1.42553C6.9865 1.47391 7.02573 1.51314 7.07411 1.53733L7.55236 1.77646C7.73663 1.86859 7.73663 2.13154 7.55236 2.22367L7.07411 2.4628C7.02573 2.48699 6.9865 2.52622 6.96231 2.5746L6.72318 3.05285C6.63105 3.23711 6.3681 3.23711 6.27597 3.05285L6.03684 2.5746C6.01265 2.52622 5.97342 2.48699 5.92504 2.4628L5.44679 2.22367C5.26253 2.13154 5.26253 1.86859 5.44679 1.77646L5.92504 1.53733Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.25837 2.37067C3.30676 2.34648 3.34599 2.30724 3.37018 2.25886L3.52597 1.94728C3.6181 1.76302 3.88105 1.76302 3.97318 1.94728L4.12898 2.25886C4.15317 2.30724 4.1924 2.34648 4.24078 2.37067L4.55236 2.52646C4.73662 2.61859 4.73663 2.88154 4.55236 2.97367L4.24078 3.12946C4.1924 3.15365 4.15317 3.19289 4.12898 3.24127L3.97318 3.55285C3.88105 3.73711 3.6181 3.73711 3.52597 3.55285L3.37018 3.24127C3.34599 3.19289 3.30676 3.15365 3.25837 3.12946L2.94679 2.97367C2.76253 2.88154 2.76253 2.61859 2.94679 2.52646L3.25837 2.37067Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "MagicBox"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicBox.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicBox.tsx
new file mode 100644
index 0000000..0c38691
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicBox.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MagicBox.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MagicBox'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicEyes.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicEyes.json
new file mode 100644
index 0000000..00e1696
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicEyes.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "eye-sparkle, magic eyes"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M11.0338 5.05688C9.75366 3.05335 7.90203 1.99999 6.00017 2C4.09831 2.00001 2.24669 3.05341 0.966566 5.05693C0.599687 5.63113 0.599686 6.36892 0.966566 6.94312C2.24669 8.94665 4.09832 10 6.00018 10C7.90204 9.99999 9.75366 8.94659 11.0338 6.94307C11.4007 6.36887 11.4007 5.63108 11.0338 5.05688ZM5.77639 4.44721L5.3706 5.2588C5.34641 5.30718 5.30718 5.34641 5.2588 5.3706L4.44721 5.77639C4.26295 5.86852 4.26295 6.13148 4.44721 6.22361L5.2588 6.6294C5.30718 6.65359 5.34641 6.69282 5.3706 6.7412L5.77639 7.55279C5.86852 7.73705 6.13148 7.73705 6.22361 7.55279L6.6294 6.7412C6.65359 6.69282 6.69282 6.65359 6.7412 6.6294L7.55279 6.22361C7.73705 6.13148 7.73705 5.86852 7.55279 5.77639L6.7412 5.3706C6.69282 5.34641 6.65359 5.30718 6.6294 5.2588L6.22361 4.44721C6.13148 4.26295 5.86852 4.26295 5.77639 4.44721Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "MagicEyes"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicEyes.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicEyes.tsx
new file mode 100644
index 0000000..e7f7335
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicEyes.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MagicEyes.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MagicEyes'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicWand.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicWand.json
new file mode 100644
index 0000000..bf13ab9
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicWand.json
@@ -0,0 +1,73 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "magic-wand-2, magic stick, star"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.27056 1.77151C8.811 1.23107 9.68723 1.23107 10.2277 1.77151C10.7681 2.31195 10.7681 3.18818 10.2277 3.72862L3.72767 10.2286C3.18723 10.7691 2.31101 10.7691 1.77056 10.2286C1.23012 9.68818 1.23012 8.81195 1.77056 8.27151L8.27056 1.77151ZM9.52056 2.47862C9.37065 2.3287 9.12759 2.3287 8.97767 2.47862L8.08122 3.37506L8.62412 3.91796L9.52056 3.02151C9.67048 2.87159 9.67048 2.62853 9.52056 2.47862Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.92504 1.03733C4.97342 1.01314 5.01265 0.973911 5.03684 0.92553L5.27597 0.447279C5.3681 0.263016 5.63105 0.263017 5.72318 0.447279L5.96231 0.92553C5.9865 0.973911 6.02573 1.01314 6.07411 1.03733L6.55236 1.27646C6.73663 1.36859 6.73663 1.63154 6.55236 1.72367L6.07411 1.9628C6.02573 1.98699 5.9865 2.02622 5.96231 2.0746L5.72318 2.55285C5.63105 2.73711 5.3681 2.73711 5.27597 2.55285L5.03684 2.0746C5.01265 2.02622 4.97342 1.98699 4.92504 1.9628L4.44679 1.72367C4.26253 1.63154 4.26253 1.36859 4.44679 1.27646L4.92504 1.03733Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.42504 6.53733C9.47342 6.51314 9.51265 6.47391 9.53684 6.42553L9.77597 5.94728C9.8681 5.76302 10.1311 5.76302 10.2232 5.94728L10.4623 6.42553C10.4865 6.47391 10.5257 6.51314 10.5741 6.53733L11.0524 6.77646C11.2366 6.86859 11.2366 7.13154 11.0524 7.22367L10.5741 7.4628C10.5257 7.48699 10.4865 7.52622 10.4623 7.5746L10.2232 8.05285C10.1311 8.23711 9.8681 8.23711 9.77597 8.05285L9.53684 7.5746C9.51265 7.52622 9.47342 7.48699 9.42504 7.4628L8.94679 7.22367C8.76253 7.13154 8.76253 6.86859 8.94679 6.77646L9.42504 6.53733Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.42504 3.53733C2.47342 3.51314 2.51265 3.47391 2.53684 3.42553L2.77597 2.94728C2.8681 2.76302 3.13105 2.76302 3.22318 2.94728L3.46231 3.42553C3.4865 3.47391 3.52573 3.51314 3.57411 3.53733L4.05236 3.77646C4.23663 3.86859 4.23663 4.13154 4.05236 4.22367L3.57411 4.4628C3.52573 4.48699 3.4865 4.52622 3.46231 4.5746L3.22318 5.05285C3.13105 5.23711 2.8681 5.23711 2.77597 5.05285L2.53684 4.5746C2.51265 4.52622 2.47342 4.48699 2.42504 4.4628L1.94679 4.22367C1.76253 4.13154 1.76253 3.86859 1.94679 3.77646L2.42504 3.53733Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "MagicWand"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicWand.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicWand.tsx
new file mode 100644
index 0000000..3eb6130
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/MagicWand.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './MagicWand.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'MagicWand'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.json
new file mode 100644
index 0000000..36aad43
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.json
@@ -0,0 +1,55 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "microphone-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.00008 0.666016C6.52732 0.666016 5.33341 1.85992 5.33341 3.33268V7.99935C5.33341 9.47211 6.52732 10.666 8.00008 10.666C9.47284 10.666 10.6667 9.47211 10.6667 7.99935V3.33268C10.6667 1.85992 9.47284 0.666016 8.00008 0.666016Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.00008 6.66602C4.00008 6.29783 3.7016 5.99935 3.33341 5.99935C2.96522 5.99935 2.66675 6.29783 2.66675 6.66602V7.99935C2.66675 10.7195 4.70319 12.9641 7.33466 13.2916C7.33384 13.3052 7.33341 13.3189 7.33341 13.3327V13.9993H5.33341C4.96522 13.9993 4.66675 14.2978 4.66675 14.666C4.66675 15.0342 4.96522 15.3327 5.33341 15.3327H10.6667C11.0349 15.3327 11.3334 15.0342 11.3334 14.666C11.3334 14.2978 11.0349 13.9993 10.6667 13.9993H8.66675V13.3327C8.66675 13.3189 8.66633 13.3052 8.6655 13.2916C11.297 12.9641 13.3334 10.7195 13.3334 7.99935V6.66602C13.3334 6.29783 13.0349 5.99935 12.6667 5.99935C12.2986 5.99935 12.0001 6.29783 12.0001 6.66602V7.99935C12.0001 10.2085 10.2092 11.9993 8.00008 11.9993C5.79094 11.9993 4.00008 10.2085 4.00008 7.99935V6.66602Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Microphone01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.tsx
new file mode 100644
index 0000000..37fb66a
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Microphone01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Microphone01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Microphone01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Play.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/Play.json
new file mode 100644
index 0000000..b32d786
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Play.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "play"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4.00312 1.40109C4.0091 1.40508 4.0151 1.40907 4.02111 1.41309L9.29548 4.92933C9.44809 5.03105 9.58959 5.12537 9.69827 5.21301C9.81168 5.30448 9.94538 5.43132 10.0223 5.61687C10.124 5.86212 10.124 6.13775 10.0223 6.38301C9.94538 6.56856 9.81168 6.6954 9.69827 6.78686C9.5896 6.8745 9.44811 6.96881 9.2955 7.07053L4.00314 10.5988C3.8166 10.7232 3.64886 10.835 3.50652 10.9121C3.36409 10.9893 3.16859 11.0775 2.9404 11.0639C2.64852 11.0465 2.3789 10.9022 2.20249 10.669C2.06458 10.4867 2.02952 10.2751 2.01474 10.1138C1.99997 9.95254 1.99999 9.75094 2 9.52674L2 2.49475C2 2.48752 2 2.48031 2 2.47313C1.99999 2.24893 1.99997 2.04733 2.01474 1.88612C2.02952 1.72479 2.06458 1.5132 2.20249 1.33089C2.3789 1.0977 2.64852 0.953401 2.9404 0.935973C3.16859 0.922349 3.36409 1.01055 3.50652 1.08774C3.64885 1.16488 3.81659 1.27672 4.00312 1.40109Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Play"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Play.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/Play.tsx
new file mode 100644
index 0000000..b9e07c5
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Play.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Play.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Play'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Robot.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/Robot.json
new file mode 100644
index 0000000..650ca36
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Robot.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "robot, bot"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6 0.5C6.27614 0.5 6.5 0.723858 6.5 1V1.5H8.5C9.32843 1.5 10 2.17157 10 3V5.5C10 5.94425 9.80688 6.34339 9.5 6.61805V7.29289L10.3536 8.14645C10.5488 8.34171 10.5488 8.65829 10.3536 8.85355C10.1583 9.04882 9.84171 9.04882 9.64645 8.85355L9.34052 8.54762C8.89526 9.96884 7.56805 11 6 11C4.43195 11 3.10474 9.96884 2.65948 8.54762L2.35355 8.85355C2.15829 9.04882 1.84171 9.04882 1.64645 8.85355C1.45118 8.65829 1.45118 8.34171 1.64645 8.14645L2.5 7.29289V6.61805C2.19313 6.34339 2 5.94425 2 5.5V3C2 2.17157 2.67157 1.5 3.5 1.5H5.5V1C5.5 0.723858 5.72386 0.5 6 0.5ZM3.5 2.5C3.22386 2.5 3 2.72386 3 3V5.5C3 5.77614 3.22386 6 3.5 6H8.5C8.77614 6 9 5.77614 9 5.5V3C9 2.72386 8.77614 2.5 8.5 2.5H3.5ZM4.5 3.5C4.77614 3.5 5 3.72386 5 4V4.5C5 4.77614 4.77614 5 4.5 5C4.22386 5 4 4.77614 4 4.5V4C4 3.72386 4.22386 3.5 4.5 3.5ZM7.5 3.5C7.77614 3.5 8 3.72386 8 4V4.5C8 4.77614 7.77614 5 7.5 5C7.22386 5 7 4.77614 7 4.5V4C7 3.72386 7.22386 3.5 7.5 3.5Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Robot"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Robot.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/Robot.tsx
new file mode 100644
index 0000000..8bee6e2
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Robot.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Robot.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Robot'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Sliders02.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/Sliders02.json
new file mode 100644
index 0000000..d72b99a
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Sliders02.json
@@ -0,0 +1,77 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5 2C5.55228 2 6 2.44772 6 3V7C6 7.55228 5.55228 8 5 8C4.44772 8 4 7.55228 4 7V3C4 2.44772 4.44772 2 5 2Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6 15.8293C7.16519 15.4175 8 14.3062 8 13C8 11.3431 6.65685 10 5 10C3.34315 10 2 11.3431 2 13C2 14.3062 2.83481 15.4175 4 15.8293L4 21C4 21.5523 4.44772 22 5 22C5.55229 22 6 21.5523 6 21L6 15.8293Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13 15C13 14.4477 12.5523 14 12 14C11.4477 14 11 14.4477 11 15V21C11 21.5523 11.4477 22 12 22C12.5523 22 13 21.5523 13 21V15Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12 2C12.5523 2 13 2.44772 13 3V6.17071C14.1652 6.58254 15 7.69378 15 9C15 10.6569 13.6569 12 12 12C10.3431 12 9 10.6569 9 9C9 7.69378 9.83481 6.58254 11 6.17071V3C11 2.44772 11.4477 2 12 2Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M22 15C22 16.3062 21.1652 17.4175 20 17.8293V21C20 21.5523 19.5523 22 19 22C18.4477 22 18 21.5523 18 21V17.8293C16.8348 17.4175 16 16.3062 16 15C16 13.3431 17.3431 12 19 12C20.6569 12 22 13.3431 22 15Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M19 2C19.5523 2 20 2.44772 20 3V9C20 9.55228 19.5523 10 19 10C18.4477 10 18 9.55228 18 9V3C18 2.44772 18.4477 2 19 2Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Sliders02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Sliders02.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/Sliders02.tsx
new file mode 100644
index 0000000..f1d05e7
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Sliders02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Sliders02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Sliders02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Speaker.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/Speaker.json
new file mode 100644
index 0000000..3e5cbe1
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Speaker.json
@@ -0,0 +1,112 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "clip-path": "url(#clip0_109_6694)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M0 2.86666C0 2.05664 0.656649 1.39999 1.46667 1.39999H5.86667C6.67668 1.39999 7.33333 2.05664 7.33333 2.86666C7.33333 3.27167 7.00501 3.59999 6.6 3.59999C6.19499 3.59999 5.86667 3.27167 5.86667 2.86666H4.4V7.99999C4.80501 7.99999 5.13333 8.32831 5.13333 8.73332C5.13333 9.13833 4.80501 9.46666 4.4 9.46666H2.93333C2.52832 9.46666 2.2 9.13833 2.2 8.73332C2.2 8.32831 2.52832 7.99999 2.93333 7.99999V2.86666H1.46667C1.46667 3.27167 1.13834 3.59999 0.733333 3.59999C0.328324 3.59999 0 3.27167 0 2.86666Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.8205 0.782296C13.7434 0.62811 13.5233 0.62811 13.4462 0.782296C12.9664 1.74206 12.8754 1.83302 11.9156 2.3129C11.7615 2.39 11.7615 2.61003 11.9156 2.68712C12.8754 3.167 12.9664 3.25797 13.4462 4.21773C13.5233 4.37191 13.7434 4.37191 13.8205 4.21773C14.3003 3.25797 14.3913 3.167 15.3511 2.68712C15.5053 2.61003 15.5053 2.39 15.3511 2.3129C14.3913 1.83302 14.3003 1.74206 13.8205 0.782296Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.79394 2.25319C9.71404 2.09337 9.48596 2.09337 9.40605 2.25319C9.04994 2.96543 8.96544 3.04993 8.2532 3.40605C8.09338 3.48595 8.09338 3.71402 8.2532 3.79393C8.96544 4.15005 9.04994 4.23455 9.40606 4.94679C9.48596 5.10661 9.71404 5.10661 9.79394 4.94679C10.1501 4.23455 10.2346 4.15005 10.9468 3.79393C11.1066 3.71402 11.1066 3.48595 10.9468 3.40605C10.2346 3.04993 10.1501 2.96543 9.79394 2.25319Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.75377 11.049C2.67668 10.8948 2.45665 10.8948 2.37956 11.049C1.89969 12.0087 1.80872 12.0997 0.848971 12.5796C0.694788 12.6566 0.694787 12.8767 0.848971 12.9538C1.80872 13.4336 1.89969 13.5246 2.37956 14.4844C2.45665 14.6385 2.67668 14.6385 2.75377 14.4844C3.23365 13.5246 3.32461 13.4336 4.28436 12.9538C4.43855 12.8767 4.43855 12.6566 4.28436 12.5796C3.32461 12.0997 3.23365 12.0087 2.75377 11.049Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M14.6741 8.65106C14.8886 8.50146 15.1837 8.55405 15.3333 8.76853C15.7614 9.38226 16.0125 10.1292 16.0125 10.9333C16.0125 11.7375 15.7614 12.4844 15.3333 13.0981C15.1837 13.3126 14.8886 13.3652 14.6741 13.2156C14.4596 13.066 14.407 12.7708 14.5567 12.5564C14.8775 12.0964 15.0656 11.5375 15.0656 10.9333C15.0656 10.3291 14.8775 9.77025 14.5567 9.31028C14.407 9.09581 14.4596 8.80066 14.6741 8.65106Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12.5674 6.53771C12.794 6.51987 13.0155 6.61161 13.1632 6.78449C13.2954 6.93929 13.3164 7.12549 13.3244 7.21587C13.3334 7.31718 13.3334 7.44301 13.3333 7.57103C13.3333 7.57691 13.3333 7.58278 13.3333 7.58866L13.3333 14.3C13.3334 14.428 13.3334 14.5539 13.3244 14.6552C13.3164 14.7455 13.2954 14.9317 13.1632 15.0865C13.0155 15.2594 12.794 15.3512 12.5674 15.3333C12.3644 15.3173 12.2179 15.2005 12.1484 15.1423C12.0704 15.077 11.9814 14.988 11.8909 14.8975L10.3795 13.3861C10.3357 13.3423 10.3137 13.3205 10.2971 13.3053L10.2958 13.3041L10.2941 13.3041C10.2716 13.303 10.2407 13.3029 10.1787 13.3029L9.34101 13.3029C9.22151 13.3029 9.10513 13.3029 9.00657 13.2949C8.89833 13.286 8.77062 13.2652 8.6421 13.1997C8.46392 13.1089 8.31906 12.964 8.22827 12.7859C8.16279 12.6574 8.14192 12.5296 8.13308 12.4214C8.12503 12.3228 8.12504 12.2065 8.12505 12.087V9.79916C8.12505 9.79413 8.12505 9.78909 8.12505 9.78406C8.12504 9.66456 8.12503 9.54819 8.13308 9.44963C8.14192 9.34139 8.16279 9.21368 8.22827 9.08517C8.31906 8.90699 8.46392 8.76212 8.6421 8.67133C8.77062 8.60585 8.89833 8.58498 9.00657 8.57614C9.10512 8.56809 9.2215 8.5681 9.341 8.56812C9.34603 8.56812 9.35106 8.56812 9.3561 8.56812H10.1787C10.2407 8.56812 10.2716 8.56801 10.2941 8.56698L10.2958 8.5669L10.2971 8.56575C10.3137 8.55058 10.3357 8.52877 10.3795 8.48491L11.8784 6.98602C11.8826 6.98186 11.8867 6.97771 11.8909 6.97355C11.9814 6.88302 12.0704 6.79403 12.1484 6.72874C12.2179 6.67049 12.3644 6.55368 12.5674 6.53771Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_109_6694"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Speaker"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/Speaker.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/Speaker.tsx
new file mode 100644
index 0000000..0cf9364
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/Speaker.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Speaker.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Speaker'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.json
new file mode 100644
index 0000000..67e02fc
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "20",
+ "height": "20",
+ "viewBox": "0 0 20 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "stop-circle"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.99992 0.833984C4.93731 0.833984 0.833252 4.93804 0.833252 10.0007C0.833252 15.0633 4.93731 19.1673 9.99992 19.1673C15.0625 19.1673 19.1666 15.0633 19.1666 10.0007C19.1666 4.93804 15.0625 0.833984 9.99992 0.833984ZM6.75741 7.12232C6.66658 7.30058 6.66658 7.53394 6.66658 8.00065V12.0006C6.66658 12.4674 6.66658 12.7007 6.75741 12.879C6.83731 13.0358 6.96479 13.1633 7.12159 13.2432C7.29985 13.334 7.53321 13.334 7.99992 13.334H11.9999C12.4666 13.334 12.7 13.334 12.8782 13.2432C13.035 13.1633 13.1625 13.0358 13.2424 12.879C13.3333 12.7007 13.3333 12.4674 13.3333 12.0006V8.00065C13.3333 7.53394 13.3333 7.30058 13.2424 7.12232C13.1625 6.96552 13.035 6.83804 12.8782 6.75814C12.7 6.66732 12.4666 6.66732 11.9999 6.66732H7.99992C7.53321 6.66732 7.29985 6.66732 7.12159 6.75814C6.96479 6.83804 6.83731 6.96552 6.75741 7.12232Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "StopCircle"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.tsx
new file mode 100644
index 0000000..84430c3
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/StopCircle.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './StopCircle.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'StopCircle'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/VideoSupportIcon.json b/app/components/base/icons/src/vender/solid/mediaAndDevices/VideoSupportIcon.json
new file mode 100644
index 0000000..4bc6881
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/VideoSupportIcon.json
@@ -0,0 +1,26 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "xmlns": "http://www.w3.org/2000/svg",
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.2334 4.3469L10.3567 4.06406C10.5764 3.55974 10.9723 3.15821 11.4662 2.93854L11.846 2.76961C12.0514 2.67827 12.0514 2.37941 11.846 2.28806L11.4874 2.12857C10.9808 1.90326 10.5779 1.48687 10.3619 0.965415L10.2353 0.659765C10.1471 0.446745 9.8529 0.446745 9.76465 0.659765L9.63805 0.965415C9.4221 1.48687 9.0192 1.90326 8.5126 2.12857L8.154 2.28806C7.94865 2.37941 7.94865 2.67827 8.154 2.76961L8.53385 2.93854C9.02775 3.15821 9.42355 3.55974 9.6433 4.06406L9.76655 4.3469C9.8568 4.55396 10.1432 4.55396 10.2334 4.3469ZM1.4959 1.5H7V2.5H4V9.5H8V4.5H9V5.5H10H11V10.0033C11 10.2776 10.7723 10.5 10.5041 10.5H1.4959C1.22203 10.5 1 10.2775 1 10.0033V1.9967C1 1.72238 1.22766 1.5 1.4959 1.5ZM2 2.5V3.5H3V2.5H2ZM2 4.5V5.5H3V4.5H2ZM2 6.5V7.5H3V6.5H2ZM9 6.5V7.5H10V6.5H9ZM2 8.5V9.5H3V8.5H2ZM9 8.5V9.5H10V8.5H9Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "VideoSupportIcon"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/VideoSupportIcon.tsx b/app/components/base/icons/src/vender/solid/mediaAndDevices/VideoSupportIcon.tsx
new file mode 100644
index 0000000..4822f83
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/VideoSupportIcon.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './VideoSupportIcon.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'VideoSupportIcon'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts b/app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts
new file mode 100644
index 0000000..7c313fe
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts
@@ -0,0 +1,12 @@
+export { default as AudioSupportIcon } from './AudioSupportIcon'
+export { default as DocumentSupportIcon } from './DocumentSupportIcon'
+export { default as MagicBox } from './MagicBox'
+export { default as MagicEyes } from './MagicEyes'
+export { default as MagicWand } from './MagicWand'
+export { default as Microphone01 } from './Microphone01'
+export { default as Play } from './Play'
+export { default as Robot } from './Robot'
+export { default as Sliders02 } from './Sliders02'
+export { default as Speaker } from './Speaker'
+export { default as StopCircle } from './StopCircle'
+export { default as VideoSupportIcon } from './VideoSupportIcon'
diff --git a/app/components/base/icons/src/vender/solid/security/Lock01.json b/app/components/base/icons/src/vender/solid/security/Lock01.json
new file mode 100644
index 0000000..aa01bc5
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/security/Lock01.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "lock-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3 4C3 2.34315 4.34315 1 6 1C7.65685 1 9 2.34315 9 4V4.57516C9.1413 4.60613 9.27693 4.65121 9.40798 4.71799C9.78431 4.90973 10.0903 5.2157 10.282 5.59202C10.4057 5.83469 10.4549 6.09304 10.4779 6.37409C10.5 6.64468 10.5 6.97686 10.5 7.37934V8.12066C10.5 8.52314 10.5 8.85532 10.4779 9.12591C10.4549 9.40696 10.4057 9.66531 10.282 9.90798C10.0903 10.2843 9.78431 10.5903 9.40798 10.782C9.16531 10.9057 8.90696 10.9549 8.62591 10.9779C8.35531 11 8.02313 11 7.62064 11H4.37936C3.97687 11 3.64469 11 3.37409 10.9779C3.09304 10.9549 2.83469 10.9057 2.59202 10.782C2.2157 10.5903 1.90973 10.2843 1.71799 9.90798C1.59434 9.66531 1.54506 9.40696 1.5221 9.12591C1.49999 8.85532 1.49999 8.52314 1.5 8.12066V7.37934C1.49999 6.97687 1.49999 6.64468 1.5221 6.37409C1.54506 6.09304 1.59434 5.83469 1.71799 5.59202C1.90973 5.2157 2.2157 4.90973 2.59202 4.71799C2.72307 4.65121 2.8587 4.60613 3 4.57516V4ZM8 4V4.50081H4V4C4 2.89543 4.89543 2 6 2C7.10457 2 8 2.89543 8 4ZM6.5 7.25C6.5 6.97386 6.27614 6.75 6 6.75C5.72386 6.75 5.5 6.97386 5.5 7.25V8.25C5.5 8.52614 5.72386 8.75 6 8.75C6.27614 8.75 6.5 8.52614 6.5 8.25V7.25Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Lock01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/security/Lock01.tsx b/app/components/base/icons/src/vender/solid/security/Lock01.tsx
new file mode 100644
index 0000000..ea192d8
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/security/Lock01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Lock01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Lock01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/security/index.ts b/app/components/base/icons/src/vender/solid/security/index.ts
new file mode 100644
index 0000000..4879d82
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/security/index.ts
@@ -0,0 +1 @@
+export { default as Lock01 } from './Lock01'
diff --git a/app/components/base/icons/src/vender/solid/shapes/Corner.json b/app/components/base/icons/src/vender/solid/shapes/Corner.json
new file mode 100644
index 0000000..2f35483
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/shapes/Corner.json
@@ -0,0 +1,27 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "13",
+ "height": "20",
+ "viewBox": "0 0 13 20",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Shape",
+ "d": "M0 0H13V20C9.98017 20 7.26458 18.1615 6.14305 15.3576L0 0Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ },
+ "name": "Corner"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/shapes/Corner.tsx b/app/components/base/icons/src/vender/solid/shapes/Corner.tsx
new file mode 100644
index 0000000..6b02e92
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/shapes/Corner.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Corner.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Corner'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/shapes/Star04.json b/app/components/base/icons/src/vender/solid/shapes/Star04.json
new file mode 100644
index 0000000..5e5393a
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/shapes/Star04.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "11",
+ "height": "10",
+ "viewBox": "0 0 11 10",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "star-04"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Solid",
+ "d": "M5.88897 0.683596C5.82708 0.522683 5.67249 0.416504 5.50008 0.416504C5.32768 0.416504 5.17308 0.522683 5.11119 0.683596L4.27287 2.86321C4.1477 3.18865 4.10837 3.28243 4.05457 3.35809C4.00059 3.43401 3.93426 3.50034 3.85834 3.55433C3.78267 3.60813 3.68889 3.64746 3.36346 3.77263L1.18384 4.61094C1.02293 4.67283 0.916748 4.82743 0.916748 4.99984C0.916748 5.17224 1.02293 5.32684 1.18384 5.38873L3.36346 6.22705C3.68889 6.35221 3.78267 6.39155 3.85834 6.44535C3.93426 6.49933 4.00059 6.56566 4.05457 6.64158C4.10837 6.71724 4.1477 6.81102 4.27287 7.13646L5.11119 9.31608C5.17308 9.47699 5.32768 9.58317 5.50008 9.58317C5.67249 9.58317 5.82709 9.47699 5.88898 9.31608L6.72729 7.13646C6.85246 6.81102 6.89179 6.71724 6.94559 6.64158C6.99957 6.56566 7.06591 6.49933 7.14183 6.44535C7.21749 6.39155 7.31127 6.35221 7.6367 6.22705L9.81632 5.38873C9.97723 5.32684 10.0834 5.17224 10.0834 4.99984C10.0834 4.82743 9.97723 4.67283 9.81632 4.61094L7.6367 3.77263C7.31127 3.64746 7.21749 3.60813 7.14183 3.55433C7.06591 3.50034 6.99957 3.43401 6.94559 3.35809C6.89179 3.28243 6.85246 3.18865 6.72729 2.86321L5.88897 0.683596Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Star04"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/shapes/Star04.tsx b/app/components/base/icons/src/vender/solid/shapes/Star04.tsx
new file mode 100644
index 0000000..eb699cd
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/shapes/Star04.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Star04.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Star04'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/shapes/Star06.json b/app/components/base/icons/src/vender/solid/shapes/Star06.json
new file mode 100644
index 0000000..0466602
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/shapes/Star06.json
@@ -0,0 +1,62 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "star-06"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.66675 1.33268C3.66675 0.964492 3.36827 0.666016 3.00008 0.666016C2.63189 0.666016 2.33341 0.964492 2.33341 1.33268V2.33268H1.33341C0.965225 2.33268 0.666748 2.63116 0.666748 2.99935C0.666748 3.36754 0.965225 3.66602 1.33341 3.66602H2.33341V4.66602C2.33341 5.0342 2.63189 5.33268 3.00008 5.33268C3.36827 5.33268 3.66675 5.0342 3.66675 4.66602V3.66602H4.66675C5.03494 3.66602 5.33341 3.36754 5.33341 2.99935C5.33341 2.63116 5.03494 2.33268 4.66675 2.33268H3.66675V1.33268Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.66675 11.3327C3.66675 10.9645 3.36827 10.666 3.00008 10.666C2.63189 10.666 2.33341 10.9645 2.33341 11.3327V12.3327H1.33341C0.965225 12.3327 0.666748 12.6312 0.666748 12.9993C0.666748 13.3675 0.965225 13.666 1.33341 13.666H2.33341V14.666C2.33341 15.0342 2.63189 15.3327 3.00008 15.3327C3.36827 15.3327 3.66675 15.0342 3.66675 14.666V13.666H4.66675C5.03494 13.666 5.33341 13.3675 5.33341 12.9993C5.33341 12.6312 5.03494 12.3327 4.66675 12.3327H3.66675V11.3327Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.28898 1.76003C9.18995 1.50257 8.94259 1.33268 8.66675 1.33268C8.3909 1.33268 8.14354 1.50257 8.04452 1.76003L6.8884 4.76594C6.68813 5.28663 6.6252 5.43668 6.53912 5.55774C6.45274 5.67921 6.34661 5.78534 6.22514 5.87172C6.10408 5.9578 5.95403 6.02073 5.43334 6.221L2.42743 7.37712C2.16997 7.47614 2.00008 7.7235 2.00008 7.99935C2.00008 8.2752 2.16997 8.52256 2.42743 8.62158L5.43334 9.7777C5.95403 9.97797 6.10408 10.0409 6.22514 10.127C6.34661 10.2134 6.45274 10.3195 6.53912 10.441C6.6252 10.562 6.68813 10.7121 6.8884 11.2328L8.04452 14.2387C8.14354 14.4961 8.3909 14.666 8.66675 14.666C8.9426 14.666 9.18995 14.4961 9.28898 14.2387L10.4451 11.2328C10.6454 10.7121 10.7083 10.562 10.7944 10.441C10.8808 10.3195 10.9869 10.2134 11.1084 10.127C11.2294 10.0409 11.3795 9.97797 11.9002 9.7777L14.9061 8.62158C15.1635 8.52256 15.3334 8.2752 15.3334 7.99935C15.3334 7.7235 15.1635 7.47614 14.9061 7.37712L11.9002 6.221C11.3795 6.02073 11.2294 5.9578 11.1084 5.87172C10.9869 5.78534 10.8808 5.67921 10.7944 5.55774C10.7083 5.43668 10.6454 5.28663 10.4451 4.76594L9.28898 1.76003Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Star06"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/shapes/Star06.tsx b/app/components/base/icons/src/vender/solid/shapes/Star06.tsx
new file mode 100644
index 0000000..9b320a6
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/shapes/Star06.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Star06.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Star06'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/shapes/index.ts b/app/components/base/icons/src/vender/solid/shapes/index.ts
new file mode 100644
index 0000000..2768e39
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/shapes/index.ts
@@ -0,0 +1,3 @@
+export { default as Corner } from './Corner'
+export { default as Star04 } from './Star04'
+export { default as Star06 } from './Star06'
diff --git a/app/components/base/icons/src/vender/solid/users/User01.json b/app/components/base/icons/src/vender/solid/users/User01.json
new file mode 100644
index 0000000..c9b8ea9
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/users/User01.json
@@ -0,0 +1,57 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "user-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.85731 9.66669C7.28575 9.66701 8.71419 9.66701 10.1426 9.66669C10.6271 9.66659 10.9572 9.66652 11.2455 9.71735C12.6255 9.96068 13.706 11.0412 13.9493 12.4212C14.0002 12.7095 14.0001 13.0396 14 13.524C14 13.6296 14.0032 13.7359 13.9848 13.8404C13.9118 14.2544 13.5876 14.5785 13.1736 14.6515C13.0828 14.6675 12.9872 14.667 12.9396 14.6668C9.64686 14.6491 6.35308 14.6491 3.06031 14.6668C3.01274 14.667 2.9171 14.6675 2.82632 14.6515C2.41231 14.5785 2.08816 14.2544 2.01516 13.8404C1.99675 13.7359 1.99998 13.6296 1.99996 13.524C1.99985 13.0396 1.99978 12.7095 2.05061 12.4212C2.29395 11.0412 3.37444 9.96068 4.75447 9.71735C5.04275 9.66652 5.37286 9.66659 5.85731 9.66669Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4.3333 5.00004C4.3333 2.975 5.97493 1.33337 7.99997 1.33337C10.025 1.33337 11.6666 2.975 11.6666 5.00004C11.6666 7.02508 10.025 8.66671 7.99997 8.66671C5.97493 8.66671 4.3333 7.02508 4.3333 5.00004Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "User01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/users/User01.tsx b/app/components/base/icons/src/vender/solid/users/User01.tsx
new file mode 100644
index 0000000..24fd0df
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/users/User01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './User01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'User01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/users/UserEdit02.json b/app/components/base/icons/src/vender/solid/users/UserEdit02.json
new file mode 100644
index 0000000..f4451ea
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/users/UserEdit02.json
@@ -0,0 +1,92 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "user-edit 2",
+ "clip-path": "url(#clip0_10419_49994)"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Group"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M5.83333 6.41667C7.60525 6.41667 9.04167 4.98025 9.04167 3.20833C9.04167 1.43642 7.60525 0 5.83333 0C4.06142 0 2.625 1.43642 2.625 3.20833C2.625 4.98025 4.06142 6.41667 5.83333 6.41667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M5.90917 13.2465L6.78417 10.6221C6.85533 10.4086 6.97725 10.2114 7.1365 10.0522L8.79083 8.39783C7.92225 7.88391 6.91308 7.5835 5.83333 7.5835C2.61683 7.5835 0 10.2003 0 13.4168C0 13.7394 0.261333 14.0002 0.583333 14.0002H5.86717C5.817 13.7546 5.82575 13.4962 5.90917 13.2465Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M13.5524 7.44766C12.9562 6.85208 11.9856 6.85208 11.39 7.44766L7.96057 10.8771C7.92849 10.9092 7.90457 10.9482 7.88999 10.9908L7.01499 13.6158C6.97999 13.7208 7.0074 13.8363 7.08557 13.9145C7.14099 13.9705 7.21565 13.9997 7.29207 13.9997C7.32299 13.9997 7.3539 13.9944 7.38424 13.9851L10.0092 13.1101C10.0524 13.0961 10.0915 13.0716 10.123 13.0395L13.5524 9.61008C14.148 9.0145 14.148 8.04383 13.5524 7.44766Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "element",
+ "name": "defs",
+ "attributes": {},
+ "children": [
+ {
+ "type": "element",
+ "name": "clipPath",
+ "attributes": {
+ "id": "clip0_10419_49994"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "rect",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "fill": "white"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "UserEdit02"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/users/UserEdit02.tsx b/app/components/base/icons/src/vender/solid/users/UserEdit02.tsx
new file mode 100644
index 0000000..588b6ae
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/users/UserEdit02.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './UserEdit02.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'UserEdit02'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/users/Users01.json b/app/components/base/icons/src/vender/solid/users/Users01.json
new file mode 100644
index 0000000..c18d59a
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/users/Users01.json
@@ -0,0 +1,79 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "users-01"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12.0211 9.91782C12.1128 9.56125 12.4763 9.34659 12.8329 9.43837C14.2704 9.80837 15.3334 11.1125 15.3334 12.6666V14C15.3334 14.3682 15.0349 14.6666 14.6667 14.6666C14.2985 14.6666 14 14.3682 14 14V12.6666C14 11.7356 13.3633 10.9517 12.5005 10.7296C12.1439 10.6378 11.9293 10.2744 12.0211 9.91782Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M9.7154 1.94368C9.85355 1.60239 10.2422 1.43771 10.5835 1.57586C11.8039 2.06985 12.6667 3.26669 12.6667 4.66665C12.6667 6.0666 11.8039 7.26344 10.5835 7.75743C10.2422 7.89558 9.85355 7.73091 9.7154 7.38962C9.57725 7.04833 9.74193 6.65967 10.0832 6.52152C10.8174 6.22432 11.3334 5.50494 11.3334 4.66665C11.3334 3.82835 10.8174 3.10897 10.0832 2.81178C9.74193 2.67363 9.57725 2.28496 9.7154 1.94368Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4.78598 9.33329C5.81757 9.33363 6.84915 9.33363 7.88073 9.33329C8.60781 9.33305 9.10395 9.33289 9.52942 9.44689C10.6797 9.75512 11.5782 10.6536 11.8864 11.8039C12.0399 12.3768 11.9955 12.989 12.0001 13.576C12.0007 13.6473 12.0019 13.7915 11.966 13.9255C11.8735 14.2706 11.6039 14.5401 11.2588 14.6326C11.1248 14.6685 10.9807 14.6673 10.9094 14.6668C7.85941 14.6424 4.80731 14.6424 1.7573 14.6668C1.68602 14.6673 1.54188 14.6685 1.40787 14.6326C1.06278 14.5401 0.793233 14.2706 0.700765 13.9255C0.664858 13.7915 0.666007 13.6473 0.666575 13.576C0.671243 12.9905 0.627014 12.3759 0.780272 11.8039C1.0885 10.6536 1.98699 9.75512 3.13729 9.44689C3.56277 9.33289 4.05891 9.33305 4.78598 9.33329Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3.00002 4.66665C3.00002 2.8257 4.49241 1.33331 6.33336 1.33331C8.17431 1.33331 9.66669 2.8257 9.66669 4.66665C9.66669 6.5076 8.17431 7.99998 6.33336 7.99998C4.49241 7.99998 3.00002 6.5076 3.00002 4.66665Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Users01"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/users/Users01.tsx b/app/components/base/icons/src/vender/solid/users/Users01.tsx
new file mode 100644
index 0000000..f26ff03
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/users/Users01.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Users01.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Users01'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/users/UsersPlus.json b/app/components/base/icons/src/vender/solid/users/UsersPlus.json
new file mode 100644
index 0000000..a70117f
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/users/UsersPlus.json
@@ -0,0 +1,77 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "24",
+ "viewBox": "0 0 24 24",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "users-plus"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Solid"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M20 15C20 14.4477 19.5523 14 19 14C18.4477 14 18 14.4477 18 15V17H16C15.4477 17 15 17.4477 15 18C15 18.5523 15.4477 19 16 19H18V21C18 21.5523 18.4477 22 19 22C19.5523 22 20 21.5523 20 21V19H22C22.5523 19 23 18.5523 23 18C23 17.4477 22.5523 17 22 17H20V15Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M12.181 14.1635C12.4632 14.3073 12.6927 14.5368 12.8365 14.819C12.9896 15.1194 13.0001 15.4476 13 15.7769C13 15.7847 13 15.7924 13 15.8C13 17.2744 12.9995 18.7488 13 20.2231C13.0001 20.3422 13.0001 20.4845 12.9899 20.6098C12.978 20.755 12.9476 20.963 12.8365 21.181C12.6927 21.4632 12.4632 21.6927 12.181 21.8365C11.963 21.9476 11.7551 21.978 11.6098 21.9899C11.4845 22.0001 11.3423 22.0001 11.2231 22C8.4077 21.999 5.59226 21.999 2.77682 22C2.65755 22.0001 2.51498 22.0001 2.38936 21.9898C2.24364 21.9778 2.03523 21.9472 1.81695 21.8356C1.53435 21.6911 1.30428 21.46 1.16109 21.1767C1.05079 20.9585 1.02087 20.7506 1.0095 20.6046C0.999737 20.4791 1.00044 20.3369 1.00103 20.2185C1.00619 19.1792 0.975203 18.0653 1.38061 17.0866C1.88808 15.8614 2.86145 14.8881 4.08659 14.3806C4.59629 14.1695 5.13457 14.0819 5.74331 14.0404C6.33532 14 7.06273 14 7.96449 14C9.05071 14 10.1369 14.0004 11.2231 14C11.5524 13.9999 11.8806 14.0104 12.181 14.1635Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M14.5731 2.91554C14.7803 2.40361 15.3633 2.1566 15.8752 2.36382C17.7058 3.10481 19 4.90006 19 7C19 9.09994 17.7058 10.8952 15.8752 11.6362C15.3633 11.8434 14.7803 11.5964 14.5731 11.0845C14.3658 10.5725 14.6129 9.98953 15.1248 9.7823C16.2261 9.33652 17 8.25744 17 7C17 5.74256 16.2261 4.66348 15.1248 4.2177C14.6129 4.01047 14.3658 3.42748 14.5731 2.91554Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M4.50001 7C4.50001 4.23858 6.73858 2 9.50001 2C12.2614 2 14.5 4.23858 14.5 7C14.5 9.76142 12.2614 12 9.50001 12C6.73858 12 4.50001 9.76142 4.50001 7Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "UsersPlus"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/solid/users/UsersPlus.tsx b/app/components/base/icons/src/vender/solid/users/UsersPlus.tsx
new file mode 100644
index 0000000..3594435
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/users/UsersPlus.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './UsersPlus.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'UsersPlus'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/solid/users/index.ts b/app/components/base/icons/src/vender/solid/users/index.ts
new file mode 100644
index 0000000..4c969bf
--- /dev/null
+++ b/app/components/base/icons/src/vender/solid/users/index.ts
@@ -0,0 +1,4 @@
+export { default as User01 } from './User01'
+export { default as UserEdit02 } from './UserEdit02'
+export { default as Users01 } from './Users01'
+export { default as UsersPlus } from './UsersPlus'
diff --git a/app/components/base/icons/src/vender/workflow/Agent.json b/app/components/base/icons/src/vender/workflow/Agent.json
new file mode 100644
index 0000000..e7ed193
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Agent.json
@@ -0,0 +1,53 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "agent"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.7401 5.80454C14.5765 4.77996 14.1638 3.79808 13.5306 2.97273C12.8973 2.14738 12.0648 1.48568 11.1185 1.06589C10.1722 0.646098 9.12632 0.461106 8.08751 0.546487C7.05582 0.624753 6.04548 0.966277 5.17744 1.53548C4.3094 2.09758 3.58366 2.88024 3.09272 3.79808C2.59466 4.70881 2.33852 5.7405 2.33852 6.7793V7.22756L1.25703 9.3692C1.04357 9.80322 1.22145 10.3368 1.65547 10.5574L2.3314 10.8989V12.3006C2.3314 12.82 2.53063 13.3038 2.90061 13.6738C3.2706 14.0367 3.75442 14.243 4.27382 14.243H6.01702V14.7624C6.01702 15.1538 6.3372 15.4739 6.72853 15.4739C7.11986 15.4739 7.44004 15.1538 7.44004 14.7624V13.7094C7.44004 13.2185 7.04159 12.82 6.55065 12.82H4.27382C4.13864 12.82 4.00345 12.7631 3.91095 12.6706C3.81846 12.5781 3.76154 12.4429 3.76154 12.3077V10.5716C3.76154 10.2301 3.56943 9.92417 3.2706 9.77476L2.77254 9.52573L3.66904 7.73984C3.72596 7.61889 3.76154 7.4837 3.76154 7.34851V6.77219C3.76154 5.96818 3.96076 5.17129 4.34498 4.4669C4.72919 3.76251 5.28417 3.15772 5.9601 2.7237C6.63603 2.28968 7.41158 2.02643 8.20847 1.96239C9.00536 1.89835 9.81648 2.04066 10.5493 2.36795C11.2822 2.69524 11.9225 3.20042 12.4135 3.84077C12.8973 4.47402 13.2246 5.23533 13.3456 6.02511C13.4665 6.81488 13.3954 7.63312 13.125 8.38731C12.8617 9.12017 12.4206 9.78187 11.8585 10.3084C11.6735 10.4792 11.5668 10.7139 11.5668 10.9701V14.7624C11.5668 15.1538 11.887 15.4739 12.2783 15.4739C12.6696 15.4739 12.9898 15.1538 12.9898 14.7624V11.1978C13.6515 10.5432 14.1567 9.73918 14.4697 8.87114C14.8184 7.89637 14.918 6.83623 14.7615 5.81165L14.7401 5.80454Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M10.8055 7.99599C10.8909 7.83234 10.962 7.66158 11.0189 7.4837H11.6522C12.0435 7.4837 12.3637 7.16352 12.3637 6.77219C12.3637 6.38086 12.0435 6.06068 11.6522 6.06068H11.0189C10.9691 5.8828 10.898 5.71204 10.8055 5.54839L11.2537 5.10014C11.5312 4.82266 11.5312 4.3744 11.2537 4.09692C10.9762 3.81943 10.528 3.81943 10.2505 4.09692L9.80225 4.54517C9.6386 4.45267 9.46784 4.38863 9.28996 4.33171V3.69847C9.28996 3.30714 8.96978 2.98696 8.57845 2.98696C8.18712 2.98696 7.86694 3.30714 7.86694 3.69847V4.33171C7.68907 4.38152 7.5183 4.45267 7.35466 4.54517L6.90641 4.09692C6.62892 3.81943 6.18067 3.81943 5.90318 4.09692C5.62569 4.3744 5.62569 4.82266 5.90318 5.10014L6.35143 5.54839C6.26605 5.71204 6.1949 5.8828 6.13798 6.06068H5.50473C5.1134 6.06068 4.79323 6.38086 4.79323 6.77219C4.79323 7.16352 5.1134 7.4837 5.50473 7.4837H6.13798C6.18778 7.66158 6.25893 7.83234 6.35143 7.99599L5.90318 8.44424C5.62569 8.72172 5.62569 9.16997 5.90318 9.44746C6.04548 9.58976 6.22336 9.6538 6.40835 9.6538C6.59334 9.6538 6.77122 9.58265 6.91352 9.44746L7.36177 8.99921C7.52542 9.08459 7.69618 9.15574 7.87406 9.21267V9.84591C7.87406 10.2372 8.19424 10.5574 8.58557 10.5574C8.9769 10.5574 9.29708 10.2372 9.29708 9.84591V9.21267C9.47496 9.16286 9.64572 9.09171 9.80936 8.99921L10.2576 9.44746C10.3999 9.58976 10.5778 9.6538 10.7628 9.6538C10.9478 9.6538 11.1257 9.58265 11.268 9.44746C11.5454 9.16997 11.5454 8.72172 11.268 8.44424L10.8197 7.99599H10.8055ZM7.44004 6.77219C7.44004 6.14606 7.94521 5.64089 8.57134 5.64089C9.19747 5.64089 9.70264 6.14606 9.70264 6.77219C9.70264 7.39832 9.19747 7.90349 8.57134 7.90349C7.94521 7.90349 7.44004 7.39832 7.44004 6.77219Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Agent"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Agent.tsx b/app/components/base/icons/src/vender/workflow/Agent.tsx
new file mode 100644
index 0000000..58a2426
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Agent.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Agent.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Agent'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/Answer.json b/app/components/base/icons/src/vender/workflow/Answer.json
new file mode 100644
index 0000000..4f15b33
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Answer.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/answer"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3.50114 1.67701L10.5011 1.677C11.5079 1.677 12.3241 2.49311 12.3241 3.49992V9.35414C12.3241 10.3609 11.5079 11.177 10.5012 11.1771H8.9954L7.41734 12.4845C7.17339 12.6866 6.81987 12.6856 6.57708 12.4821L5.02026 11.1771H3.50114C2.49436 11.1771 1.67822 10.3608 1.67822 9.35414V3.49993C1.67822 2.49316 2.49437 1.67701 3.50114 1.67701ZM10.5011 2.9895L3.50114 2.98951C3.21924 2.98951 2.99072 3.21803 2.99072 3.49993V9.35414C2.99072 9.63601 3.21926 9.86455 3.50114 9.86455H5.04675C5.33794 9.86455 5.61984 9.96705 5.84302 10.1541L7.00112 11.1249L8.17831 10.1496C8.40069 9.96537 8.68041 9.86455 8.96916 9.86455H10.5011C10.5011 9.86455 10.5011 9.86455 10.5011 9.86455C10.783 9.8645 11.0116 9.63592 11.0116 9.35414V3.49992C11.0116 3.21806 10.7831 2.9895 10.5011 2.9895ZM9.06809 4.93171C9.32437 5.18799 9.32437 5.60351 9.06809 5.85979L7.02642 7.90146C6.77014 8.15774 6.35464 8.15774 6.09835 7.90146L5.22333 7.02646C4.96704 6.77019 4.96704 6.35467 5.22332 6.09839C5.4796 5.8421 5.89511 5.8421 6.15139 6.09837L6.56238 6.50935L8.14001 4.93171C8.3963 4.67543 8.81181 4.67543 9.06809 4.93171Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Answer"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Answer.tsx b/app/components/base/icons/src/vender/workflow/Answer.tsx
new file mode 100644
index 0000000..91bf788
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Answer.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Answer.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Answer'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/Assigner.json b/app/components/base/icons/src/vender/workflow/Assigner.json
new file mode 100644
index 0000000..7106e5a
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Assigner.json
@@ -0,0 +1,68 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "variable assigner"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M1.71438 4.42875C1.71438 3.22516 2.68954 2.25 3.89313 2.25C4.30734 2.25 4.64313 2.58579 4.64313 3C4.64313 3.41421 4.30734 3.75 3.89313 3.75C3.51796 3.75 3.21438 4.05359 3.21438 4.42875V7.28563C3.21438 7.48454 3.13536 7.6753 2.9947 7.81596L2.81066 8L2.9947 8.18404C3.13536 8.3247 3.21438 8.51546 3.21438 8.71437V11.5713C3.21438 11.9464 3.51796 12.25 3.89313 12.25C4.30734 12.25 4.64313 12.5858 4.64313 13C4.64313 13.4142 4.30734 13.75 3.89313 13.75C2.68954 13.75 1.71438 12.7748 1.71438 11.5713V9.02503L1.21967 8.53033C1.07902 8.38968 1 8.19891 1 8C1 7.80109 1.07902 7.61032 1.21967 7.46967L1.71438 6.97497V4.42875ZM11.3568 3C11.3568 2.58579 11.6925 2.25 12.1068 2.25C13.3103 2.25 14.2855 3.22516 14.2855 4.42875V6.97497L14.7802 7.46967C14.9209 7.61032 14.9999 7.80109 14.9999 8C14.9999 8.19891 14.9209 8.38968 14.7802 8.53033L14.2855 9.02503V11.5713C14.2855 12.7751 13.3095 13.75 12.1068 13.75C11.6925 13.75 11.3568 13.4142 11.3568 13C11.3568 12.5858 11.6925 12.25 12.1068 12.25C12.4815 12.25 12.7855 11.9462 12.7855 11.5713V8.71437C12.7855 8.51546 12.8645 8.3247 13.0052 8.18404L13.1892 8L13.0052 7.81596C12.8645 7.6753 12.7855 7.48454 12.7855 7.28563V4.42875C12.7855 4.05359 12.4819 3.75 12.1068 3.75C11.6925 3.75 11.3568 3.41421 11.3568 3Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.25 6C5.25 5.58579 5.58579 5.25 6 5.25H10C10.4142 5.25 10.75 5.58579 10.75 6C10.75 6.41421 10.4142 6.75 10 6.75H6C5.58579 6.75 5.25 6.41421 5.25 6Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.25 10C5.25 9.58579 5.58579 9.25 6 9.25H10C10.4142 9.25 10.75 9.58579 10.75 10C10.75 10.4142 10.4142 10.75 10 10.75H6C5.58579 10.75 5.25 10.4142 5.25 10Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Assigner"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Assigner.tsx b/app/components/base/icons/src/vender/workflow/Assigner.tsx
new file mode 100644
index 0000000..c4d1382
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Assigner.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Assigner.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Assigner'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/Code.json b/app/components/base/icons/src/vender/workflow/Code.json
new file mode 100644
index 0000000..d94f12a
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Code.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/code"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.32593 1.69675C8.67754 1.78466 8.89132 2.14096 8.80342 2.49257L6.47009 11.8259C6.38218 12.1775 6.02588 12.3913 5.67427 12.3034C5.32265 12.2155 5.10887 11.8592 5.19678 11.5076L7.53011 2.17424C7.61801 1.82263 7.97431 1.60885 8.32593 1.69675ZM3.96414 4.20273C4.22042 4.45901 4.22042 4.87453 3.96413 5.13081L2.45578 6.63914C2.45577 6.63915 2.45578 6.63914 2.45578 6.63914C2.25645 6.83851 2.25643 7.16168 2.45575 7.36103C2.45574 7.36103 2.45576 7.36104 2.45575 7.36103L3.96413 8.86936C4.22041 9.12564 4.22042 9.54115 3.96414 9.79744C3.70787 10.0537 3.29235 10.0537 3.03607 9.79745L1.52769 8.28913C0.815811 7.57721 0.815803 6.42302 1.52766 5.7111L3.03606 4.20272C3.29234 3.94644 3.70786 3.94644 3.96414 4.20273ZM10.0361 4.20273C10.2923 3.94644 10.7078 3.94644 10.9641 4.20272L12.4725 5.71108C13.1843 6.423 13.1844 7.57717 12.4725 8.28909L10.9641 9.79745C10.7078 10.0537 10.2923 10.0537 10.036 9.79744C9.77977 9.54115 9.77978 9.12564 10.0361 8.86936L11.5444 7.36107C11.7437 7.16172 11.7438 6.83854 11.5444 6.63917C11.5444 6.63915 11.5445 6.63918 11.5444 6.63917L10.0361 5.13081C9.77978 4.87453 9.77978 4.45901 10.0361 4.20273Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Code"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Code.tsx b/app/components/base/icons/src/vender/workflow/Code.tsx
new file mode 100644
index 0000000..1ec2e49
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Code.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Code.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Code'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/DocsExtractor.json b/app/components/base/icons/src/vender/workflow/DocsExtractor.json
new file mode 100644
index 0000000..5b45459
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/DocsExtractor.json
@@ -0,0 +1,64 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "docs-extractor"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M2.66663 3.33325C2.66663 2.22869 3.56206 1.33325 4.66663 1.33325H12.6666C13.0348 1.33325 13.3333 1.63173 13.3333 1.99992V13.9999C13.3333 14.3681 13.0348 14.6666 12.6666 14.6666H4.66663C3.56206 14.6666 2.66663 13.7712 2.66663 12.6666V3.33325ZM3.99996 10.7804V3.33325C3.99996 2.96507 4.29844 2.66659 4.66663 2.66659H12V10.6666H4.66663C4.43287 10.6666 4.20848 10.7067 3.99996 10.7804ZM12 11.9999H4.66663C4.29844 11.9999 3.99996 12.2984 3.99996 12.6666C3.99996 13.0348 4.29844 13.3333 4.66663 13.3333H12V11.9999Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M8.12296 4.9385C8.18749 4.90624 8.23983 4.85394 8.27203 4.78942L8.70203 3.92954C8.82483 3.68385 9.17543 3.68385 9.29829 3.92954L9.72823 4.78942C9.76049 4.85394 9.81276 4.90624 9.87729 4.9385L10.7372 5.36844C10.9829 5.49128 10.9829 5.84189 10.7372 5.96473L9.87729 6.39467C9.81276 6.42692 9.76049 6.47923 9.72823 6.54375L9.29829 7.40365C9.17543 7.64932 8.82483 7.64932 8.70203 7.40365L8.27203 6.54375C8.23983 6.47923 8.18749 6.42692 8.12296 6.39467L7.26309 5.96473C7.01743 5.84189 7.01743 5.49128 7.26309 5.36844L8.12296 4.9385Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.71829 7.80752C5.757 7.78819 5.78838 7.75678 5.80773 7.71805L6.15459 7.02438C6.22829 6.87692 6.43865 6.87692 6.51236 7.02438L6.85923 7.71805C6.87856 7.75678 6.90996 7.78819 6.94863 7.80752L7.64236 8.15439C7.78976 8.22805 7.78976 8.43845 7.64236 8.51212L6.94863 8.85898C6.90996 8.87832 6.87856 8.90972 6.85923 8.94845L6.51236 9.64212C6.43865 9.78959 6.22829 9.78959 6.15459 9.64212L5.80773 8.94845C5.78838 8.90972 5.757 8.87832 5.71829 8.85898L5.02458 8.51212C4.87717 8.43845 4.87717 8.22805 5.02458 8.15439L5.71829 7.80752Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "DocsExtractor"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/DocsExtractor.tsx b/app/components/base/icons/src/vender/workflow/DocsExtractor.tsx
new file mode 100644
index 0000000..838fb8a
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/DocsExtractor.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './DocsExtractor.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'DocsExtractor'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/End.json b/app/components/base/icons/src/vender/workflow/End.json
new file mode 100644
index 0000000..3e281cb
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/End.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/end"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6.67315 1.18094C6.87691 1.0639 7.12769 1.06475 7.33067 1.18315L10.8307 3.22481C11.0323 3.34242 11.1562 3.55826 11.1562 3.79167C11.1562 4.02507 11.0323 4.24091 10.8307 4.35852L7.65625 6.21026V9.91667C7.65625 10.2791 7.36244 10.5729 7 10.5729C6.63756 10.5729 6.34375 10.2791 6.34375 9.91667V5.84577C6.34361 5.83788 6.34361 5.83 6.34375 5.82213V1.75C6.34375 1.51502 6.46939 1.29797 6.67315 1.18094ZM7.65625 4.69078L9.19758 3.79167L7.65625 2.89256V4.69078ZM5.31099 8.25466C5.37977 8.61051 5.14704 8.95473 4.79119 9.0235C3.97285 9.18165 3.32667 9.41764 2.90374 9.67762C2.45323 9.95454 2.40625 10.1564 2.40625 10.2086C2.40625 10.2448 2.42254 10.3508 2.60674 10.5202C2.79151 10.6901 3.09509 10.8732 3.52555 11.0406C4.38229 11.3738 5.61047 11.594 7 11.594C8.38954 11.594 9.61773 11.3738 10.4745 11.0406C10.9049 10.8732 11.2085 10.6901 11.3933 10.5202C11.5775 10.3508 11.5938 10.2448 11.5938 10.2086C11.5938 10.1564 11.5468 9.95454 11.0963 9.67762C10.6733 9.41764 10.0271 9.18165 9.20881 9.0235C8.85296 8.95473 8.62023 8.61051 8.68901 8.25465C8.75778 7.8988 9.102 7.66608 9.45786 7.73485C10.3682 7.91077 11.1803 8.18867 11.7836 8.55947C12.3592 8.91331 12.9062 9.45912 12.9062 10.2086C12.9062 10.7361 12.6287 11.1672 12.2816 11.4864C11.935 11.805 11.4698 12.0618 10.9502 12.2639C9.90679 12.6696 8.50997 12.9065 7 12.9065C5.49004 12.9065 4.09322 12.6696 3.04983 12.2639C2.53023 12.0618 2.06497 11.805 1.7184 11.4864C1.37128 11.1672 1.09375 10.7361 1.09375 10.2086C1.09375 9.45913 1.64077 8.91332 2.21642 8.55947C2.81966 8.18867 3.63181 7.91077 4.54215 7.73485C4.898 7.66608 5.24222 7.8988 5.31099 8.25466Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "End"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/End.tsx b/app/components/base/icons/src/vender/workflow/End.tsx
new file mode 100644
index 0000000..8d7f693
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/End.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './End.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'End'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/Home.json b/app/components/base/icons/src/vender/workflow/Home.json
new file mode 100644
index 0000000..fd3096f
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Home.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/home"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6.99999 2.44562C6.97241 2.46663 6.94086 2.49116 6.90151 2.52177L3.43971 5.21428C3.17896 5.41708 3.15115 5.44593 3.13396 5.46918C3.10759 5.50483 3.08794 5.545 3.07599 5.58771C3.0682 5.61555 3.0625 5.65522 3.0625 5.98554V9.67837C3.0625 9.97506 3.06301 10.1581 3.07422 10.2954C3.08463 10.4228 3.10101 10.4541 3.10219 10.4563C3.13714 10.5249 3.19296 10.5808 3.26156 10.6157C3.2638 10.6169 3.29514 10.6333 3.42254 10.6437C3.55984 10.6549 3.74289 10.6555 4.03958 10.6555H4.8125V7.53462C4.8125 7.52831 4.81249 7.52199 4.81249 7.51565C4.81247 7.38933 4.81245 7.25834 4.82163 7.14594C4.8319 7.02025 4.85685 6.86124 4.93966 6.69872C5.05151 6.4792 5.22998 6.30072 5.44951 6.18886C5.61203 6.10605 5.77104 6.08111 5.89673 6.07084C6.00913 6.06166 6.14012 6.06168 6.26644 6.0617C6.27278 6.0617 6.2791 6.06171 6.28541 6.06171H7.71458C7.72089 6.06171 7.72721 6.0617 7.73355 6.0617C7.85987 6.06168 7.99086 6.06166 8.10326 6.07084C8.22896 6.08111 8.38796 6.10605 8.55049 6.18886C8.77001 6.30072 8.94849 6.4792 9.06034 6.69872C9.14315 6.86124 9.16809 7.02025 9.17836 7.14594C9.18755 7.25834 9.18752 7.38933 9.1875 7.51565C9.1875 7.52199 9.1875 7.52831 9.1875 7.53462V10.6555H9.96041C10.2571 10.6555 10.4402 10.6549 10.5775 10.6437C10.7049 10.6333 10.7361 10.6169 10.7383 10.6158C10.8069 10.5808 10.8628 10.525 10.8978 10.4564C10.8989 10.4541 10.9154 10.4228 10.9258 10.2954C10.937 10.1581 10.9375 9.97506 10.9375 9.67837V5.98554C10.9375 5.65522 10.9318 5.61555 10.924 5.58771C10.912 5.545 10.8924 5.50483 10.866 5.46918C10.8488 5.44593 10.821 5.41708 10.5603 5.21428L7.09848 2.52177C7.05913 2.49116 7.02757 2.46663 6.99999 2.44562ZM9.98433 11.968C10.2497 11.968 10.4871 11.968 10.6843 11.9519C10.8951 11.9346 11.1172 11.8958 11.3343 11.7852C11.6499 11.6244 11.9064 11.3678 12.0672 11.0523C12.1778 10.8351 12.2167 10.6131 12.2339 10.4023C12.25 10.205 12.25 9.96764 12.25 9.70225L12.25 5.98554C12.25 5.9671 12.25 5.94866 12.2501 5.93025C12.2504 5.69307 12.2508 5.45861 12.1879 5.23392C12.1329 5.03748 12.0426 4.85272 11.9213 4.68871C11.7825 4.50112 11.5972 4.35747 11.4098 4.21216C11.3952 4.20087 11.3806 4.18958 11.3661 4.17826L7.90428 1.48574C7.89214 1.4763 7.87933 1.46621 7.86587 1.4556C7.73357 1.35131 7.53852 1.19755 7.3049 1.1343C7.10523 1.08023 6.89477 1.08023 6.69509 1.1343C6.46148 1.19755 6.26642 1.35131 6.13412 1.4556C6.12066 1.46621 6.10785 1.4763 6.09571 1.48574L2.63391 4.17826C2.61935 4.18958 2.60478 4.20088 2.59022 4.21216C2.40278 4.35747 2.21747 4.50112 2.07873 4.68871C1.95742 4.85271 1.86706 5.03748 1.81207 5.23392C1.74918 5.4586 1.74956 5.69307 1.74994 5.93024C1.74997 5.94866 1.75 5.96709 1.75 5.98554L1.75 9.70227C1.74998 9.96765 1.74997 10.205 1.76608 10.4023C1.78331 10.6131 1.82216 10.8351 1.93279 11.0523C2.09357 11.3678 2.35014 11.6244 2.6657 11.7852C2.88282 11.8958 3.10485 11.9346 3.31566 11.9519C3.5129 11.968 3.75029 11.968 4.01566 11.968H9.98433ZM7.875 10.6555V7.53462C7.875 7.47093 7.87498 7.41945 7.87447 7.37473C7.82975 7.37422 7.77828 7.37421 7.71458 7.37421H6.28541C6.22172 7.37421 6.17024 7.37422 6.12553 7.37473C6.12501 7.41945 6.125 7.47093 6.125 7.53462V10.6555H7.875Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Home"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Home.tsx b/app/components/base/icons/src/vender/workflow/Home.tsx
new file mode 100644
index 0000000..6210e6b
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Home.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Home.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Home'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/Http.json b/app/components/base/icons/src/vender/workflow/Http.json
new file mode 100644
index 0000000..53b5c3a
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Http.json
@@ -0,0 +1,71 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/http"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M13.0968 4.66675H10.8387V9.18288H11.7419V7.82804H13.0968C13.3362 7.82772 13.5658 7.73245 13.7351 7.56313C13.9044 7.39382 13.9997 7.16426 14 6.92481V5.56997C13.9997 5.33051 13.9045 5.10093 13.7351 4.9316C13.5658 4.76227 13.3362 4.66702 13.0968 4.66675ZM11.7419 6.92481V5.56997H13.0968L13.0972 6.92481H11.7419Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M4.06452 5.56997H4.96774V9.18288H5.87097V5.56997H6.77419V4.66675H4.06452V5.56997Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M9.93548 4.66675H7.22581V5.56997H8.12903V9.18288H9.03226V5.56997H9.93548V4.66675Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M2.25806 4.66675V6.4732H0.903226V4.66675H0V9.18288H0.903226V7.37643H2.25806V9.18288H3.16129V4.66675H2.25806Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Http"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Http.tsx b/app/components/base/icons/src/vender/workflow/Http.tsx
new file mode 100644
index 0000000..77f46bf
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Http.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Http.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Http'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/IfElse.json b/app/components/base/icons/src/vender/workflow/IfElse.json
new file mode 100644
index 0000000..0ff778b
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/IfElse.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/if-else"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8.16667 2.98975C7.80423 2.98975 7.51042 2.69593 7.51042 2.3335C7.51042 1.97106 7.80423 1.67725 8.16667 1.67725H11.0833C11.4458 1.67725 11.7396 1.97106 11.7396 2.3335V5.25016C11.7396 5.6126 11.4458 5.90641 11.0833 5.90641C10.7209 5.90641 10.4271 5.6126 10.4271 5.25016V3.91782L7.34474 7.00016L10.4271 10.0825V8.75016C10.4271 8.38773 10.7209 8.09391 11.0833 8.09391C11.4458 8.09391 11.7396 8.38773 11.7396 8.75016V11.6668C11.7396 12.0293 11.4458 12.3231 11.0833 12.3231H8.16667C7.80423 12.3231 7.51042 12.0293 7.51042 11.6668C7.51042 11.3044 7.80423 11.0106 8.16667 11.0106H9.49901L6.14484 7.65641H1.75C1.38756 7.65641 1.09375 7.3626 1.09375 7.00016C1.09375 6.63773 1.38756 6.34391 1.75 6.34391H6.14484L9.49901 2.98975H8.16667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "IfElse"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/IfElse.tsx b/app/components/base/icons/src/vender/workflow/IfElse.tsx
new file mode 100644
index 0000000..aed6635
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/IfElse.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './IfElse.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'IfElse'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/Iteration.json b/app/components/base/icons/src/vender/workflow/Iteration.json
new file mode 100644
index 0000000..ee5748d
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Iteration.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/iteration"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M6.82849 0.754349C6.6007 0.526545 6.23133 0.526545 6.00354 0.754349C5.77573 0.982158 5.77573 1.3515 6.00354 1.57931L6.82849 0.754349ZM8.16602 2.91683L8.57849 3.32931C8.80628 3.1015 8.80628 2.73216 8.57849 2.50435L8.16602 2.91683ZM6.00354 4.25435C5.77573 4.48216 5.77573 4.8515 6.00354 5.07931C6.23133 5.30711 6.6007 5.30711 6.82849 5.07931L6.00354 4.25435ZM7.99516 9.74597C8.22295 9.51818 8.22295 9.14881 7.99516 8.92102C7.76737 8.69323 7.398 8.69323 7.17021 8.92102L7.99516 9.74597ZM5.83268 11.0835L5.4202 10.671C5.1924 10.8988 5.1924 11.2682 5.4202 11.496L5.83268 11.0835ZM7.17021 13.246C7.398 13.4738 7.76737 13.4738 7.99516 13.246C8.22295 13.0182 8.22295 12.6488 7.99516 12.421L7.17021 13.246ZM11.4993 3.73414C11.2738 3.50404 10.9045 3.5003 10.6744 3.72578C10.4443 3.95127 10.4405 4.32059 10.6661 4.55069L11.4993 3.73414ZM7.58268 3.50016C7.90486 3.50016 8.16602 3.23899 8.16602 2.91683C8.16602 2.59467 7.90486 2.3335 7.58268 2.3335L7.58268 3.50016ZM2.49938 10.2662C2.72486 10.4963 3.09419 10.5 3.32429 10.2745C3.55439 10.0491 3.55814 9.6797 3.33266 9.44964L2.49938 10.2662ZM6.00354 1.57931L7.75354 3.32931L8.57849 2.50435L6.82849 0.754349L6.00354 1.57931ZM7.75354 2.50435L6.00354 4.25435L6.82849 5.07931L8.57849 3.32931L7.75354 2.50435ZM7.17021 8.92102L5.4202 10.671L6.24516 11.496L7.99516 9.74597L7.17021 8.92102ZM5.4202 11.496L7.17021 13.246L7.99516 12.421L6.24516 10.671L5.4202 11.496ZM8.16602 10.5002L6.41602 10.5002V11.6668L8.16602 11.6668V10.5002ZM11.666 7.00016C11.666 8.93316 10.099 10.5002 8.16602 10.5002V11.6668C10.7434 11.6668 12.8327 9.57751 12.8327 7.00016H11.666ZM12.8327 7.00016C12.8327 5.72882 12.3235 4.57524 11.4993 3.73414L10.6661 4.55069C11.2852 5.18256 11.666 6.0463 11.666 7.00016H12.8327ZM5.83268 3.50016H7.58268L7.58268 2.3335H5.83268L5.83268 3.50016ZM2.33268 7.00016C2.33268 5.06717 3.89968 3.50016 5.83268 3.50016L5.83268 2.3335C3.25535 2.3335 1.16602 4.42283 1.16602 7.00016H2.33268ZM1.16602 7.00016C1.16602 8.27148 1.67517 9.42508 2.49938 10.2662L3.33266 9.44964C2.71348 8.81777 2.33268 7.95403 2.33268 7.00016H1.16602Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Iteration"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Iteration.tsx b/app/components/base/icons/src/vender/workflow/Iteration.tsx
new file mode 100644
index 0000000..5e2b2c9
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Iteration.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Iteration.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Iteration'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/IterationStart.json b/app/components/base/icons/src/vender/workflow/IterationStart.json
new file mode 100644
index 0000000..2941cdb
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/IterationStart.json
@@ -0,0 +1,36 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "12",
+ "height": "12",
+ "viewBox": "0 0 12 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/block-start"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M6.8498 1.72732C6.3379 1.3754 5.6621 1.3754 5.1502 1.72732L2.1502 3.78982C1.74317 4.06965 1.5 4.53193 1.5 5.02588V8.99983C1.5 9.82828 2.17158 10.4998 3 10.4998H4.25C4.52614 10.4998 4.75 10.276 4.75 9.99983V8.24983C4.75 7.55948 5.30965 6.99983 6 6.99983C6.69035 6.99983 7.25 7.55948 7.25 8.24983V9.99983C7.25 10.276 7.47385 10.4998 7.75 10.4998H9C9.82845 10.4998 10.5 9.82828 10.5 8.99983V5.02588C10.5 4.53193 10.2568 4.06965 9.8498 3.78982L6.8498 1.72732Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "IterationStart"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/IterationStart.tsx b/app/components/base/icons/src/vender/workflow/IterationStart.tsx
new file mode 100644
index 0000000..939d696
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/IterationStart.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './IterationStart.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'IterationStart'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/Jinja.json b/app/components/base/icons/src/vender/workflow/Jinja.json
new file mode 100644
index 0000000..ba46cb9
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Jinja.json
@@ -0,0 +1,98 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "24",
+ "height": "12",
+ "viewBox": "0 0 24 12",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Jinja Icon"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.46013 5.99982C7.46013 4.87982 7.48013 3.92982 7.53013 3.16982V3.06982L6.13013 3.23982L6.15013 3.32982C6.29013 4.03982 6.36013 4.93982 6.36013 5.99982C6.36013 6.93982 6.33013 7.78982 6.28013 8.51982V8.60982H7.55013V8.51982C7.49013 7.72982 7.46013 6.87982 7.46013 5.99982Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.33016 1.31998C3.38016 2.31998 3.38016 5.13998 3.38016 7.00998V7.77998C3.38016 8.21998 3.35016 8.58998 3.28016 8.85998C3.22016 9.12998 3.11016 9.34998 2.96016 9.52998C2.82016 9.70998 2.62016 9.83998 2.37016 9.92998C2.12016 10.01 1.82016 10.06 1.49016 10.06C1.19016 10.06 0.900156 9.99998 0.620156 9.87998L0.520156 9.83998L0.410156 10.83L0.480156 10.85C0.800156 10.93 1.16016 10.97 1.56016 10.97C2.08016 10.97 2.53016 10.9 2.90016 10.77C3.28016 10.64 3.59016 10.43 3.83016 10.15C4.07016 9.87998 4.25016 9.52998 4.36016 9.13998C4.47016 8.74998 4.53016 8.23998 4.53016 7.64998C4.53016 6.78998 4.59016 3.54998 4.59016 3.17998C4.61016 2.47998 4.63016 1.86998 4.66016 1.31998V1.22998H3.33016V1.31998Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M7.08021 0.919922C6.82022 0.919922 6.60021 0.999922 6.45021 1.14992C6.30021 1.29992 6.22021 1.47992 6.22021 1.68992C6.22021 1.87992 6.28021 2.04992 6.41021 2.18992C6.54022 2.31992 6.73022 2.38992 6.96022 2.38992C7.23022 2.38992 7.44021 2.30992 7.59021 2.15992C7.74021 1.99992 7.81021 1.81992 7.81021 1.60992C7.81021 1.42992 7.74021 1.25992 7.61021 1.12992C7.48021 0.989922 7.30021 0.919922 7.08021 0.919922Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M15.6102 3.30981C15.7702 4.07981 15.8502 5.25981 15.8502 6.81981C15.8502 8.26981 15.7902 9.23981 15.6702 9.67981C15.5902 9.96981 15.3802 10.2598 15.0302 10.5198L14.9702 10.5698L15.3502 11.0998H15.4002C16.4302 10.8198 16.9602 10.0598 16.9602 8.83981C16.9602 8.64981 16.9502 8.30981 16.9202 7.80981C16.9002 7.31981 16.8902 6.90981 16.8902 6.59981C16.8902 5.44981 16.9202 4.28981 16.9902 3.15981V3.05981L15.5802 3.21981L15.6002 3.30981H15.6102Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M14.2901 5.77C14.2901 5.7 14.2901 5.56 14.3001 5.36C14.3001 5.15 14.3101 5.01 14.3101 4.94C14.3101 4.22 14.1101 3.71 13.7201 3.43C13.3401 3.15 12.8001 3 12.1101 3C11.4201 3 10.7901 3.24 10.2001 3.71L10.0901 3.06L8.8501 3.22L8.8701 3.31C9.0501 4.11 9.1401 4.95 9.1401 5.8C9.1401 6.36 9.1101 7.27 9.0401 8.52V8.61H10.3101V8.53C10.2901 7.07 10.2801 5.71 10.2801 4.49C10.7401 4.14 11.2501 3.96 11.7901 3.96C12.2401 3.96 12.5801 4.06 12.8201 4.26C13.0501 4.45 13.1701 4.82 13.1701 5.36C13.1701 6.5 13.1301 7.56 13.0401 8.53V8.62H14.3101V8.54C14.2901 7.35 14.2801 6.42 14.2801 5.79L14.2901 5.77Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M16.5302 0.919922C16.2702 0.919922 16.0502 0.999922 15.9002 1.14992C15.7502 1.29992 15.6702 1.47992 15.6702 1.68992C15.6702 1.87992 15.7302 2.04992 15.8602 2.18992C15.9902 2.31992 16.1802 2.38992 16.4102 2.38992C16.6702 2.38992 16.8902 2.30992 17.0302 2.15992C17.1802 1.99992 17.2502 1.81992 17.2502 1.60992C17.2502 1.42992 17.1802 1.25992 17.0502 1.12992C16.9202 0.989922 16.7402 0.919922 16.5202 0.919922H16.5302Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M23.1802 8.51001C23.0702 8.00001 23.0202 7.40001 23.0202 6.73001C23.0202 6.57001 23.0202 6.26001 23.0402 5.83001C23.0602 5.38001 23.0702 5.06001 23.0702 4.88001C23.0702 4.20001 22.8602 3.71001 22.4502 3.43001C22.0402 3.15001 21.4702 3.01001 20.7302 3.01001C19.9402 3.01001 19.2302 3.09001 18.6102 3.25001H18.5602L18.4302 4.20001L18.5502 4.17001C19.1602 4.03001 19.7802 3.96001 20.4102 3.96001C20.9302 3.96001 21.3202 4.03001 21.5702 4.18001C21.8102 4.31001 21.9302 4.59001 21.9302 5.01001C21.9302 5.09001 21.9302 5.16001 21.9302 5.23001C20.5102 5.25001 19.5602 5.44001 19.0302 5.79001C18.4802 6.15001 18.2002 6.63001 18.2002 7.23001C18.2002 7.72001 18.3802 8.10001 18.7402 8.36001C19.0902 8.62001 19.5102 8.75001 19.9902 8.75001C20.8202 8.75001 21.5002 8.55001 22.0102 8.17001C22.0102 8.30001 22.0402 8.44001 22.0802 8.58001L22.1002 8.64001L23.2202 8.60001L23.2002 8.50001L23.1802 8.51001ZM20.2802 6.18001C20.6502 6.08001 21.2002 6.03001 21.9102 6.03001C21.9102 6.45001 21.9202 6.92001 21.9402 7.42001C21.5602 7.69001 21.0502 7.83001 20.4302 7.83001C19.7002 7.83001 19.3502 7.61001 19.3502 7.16001C19.3502 6.68001 19.6602 6.36001 20.2802 6.18001Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Jinja"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Jinja.tsx b/app/components/base/icons/src/vender/workflow/Jinja.tsx
new file mode 100644
index 0000000..67422f6
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Jinja.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Jinja.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Jinja'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/KnowledgeRetrieval.json b/app/components/base/icons/src/vender/workflow/KnowledgeRetrieval.json
new file mode 100644
index 0000000..4bdc83f
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/KnowledgeRetrieval.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/knowledge-retrieval"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M3.78528 2.62834C3.78527 2.62834 3.78528 2.62834 3.78528 2.62834L8 3.56494L12.2147 2.62834C13.5158 2.33921 14.75 3.32924 14.75 4.66206V11.2637C14.75 12.2401 14.0718 13.0855 13.1187 13.2974L8.1627 14.3987C8.05554 14.4225 7.94446 14.4225 7.8373 14.3987L2.88139 13.2974C1.92824 13.0855 1.25 12.2401 1.25 11.2637V4.66206C1.25 3.32925 2.4842 2.33921 3.78528 2.62834ZM7.25 4.93487L3.45988 4.09262C3.09558 4.01166 2.75 4.28887 2.75 4.66206V11.2637C2.75 11.537 2.93986 11.7738 3.20679 11.8331C3.20678 11.8331 3.20681 11.8331 3.20679 11.8331L7.25 12.7316V4.93487ZM8.75 12.7316L12.7932 11.8331C13.0601 11.7738 13.25 11.537 13.25 11.2637V4.66206C13.25 4.28887 12.9044 4.01165 12.5401 4.09262L8.75 4.93487V12.7316Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "KnowledgeRetrieval"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/KnowledgeRetrieval.tsx b/app/components/base/icons/src/vender/workflow/KnowledgeRetrieval.tsx
new file mode 100644
index 0000000..abe3f35
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/KnowledgeRetrieval.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './KnowledgeRetrieval.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'KnowledgeRetrieval'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/ListFilter.json b/app/components/base/icons/src/vender/workflow/ListFilter.json
new file mode 100644
index 0000000..568020f
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/ListFilter.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "filter"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M2 4C2 2.89543 2.89543 2 4 2L12 2C13.1046 2 14 2.89544 14 4V4.78105C14 5.31148 13.7893 5.82019 13.4142 6.19528L10.1953 9.4142C10.0702 9.53925 10 9.70881 10 9.8856V12.8713C10 13.427 9.65528 13.9246 9.13482 14.1198C9.13479 14.1198 9.13476 14.1198 9.13473 14.1198L7.80153 14.6197C6.92984 14.9467 6 14.3022 6 13.3713L6 9.8856C6 9.70883 5.92978 9.53926 5.80474 9.4142C5.80473 9.4142 5.80473 9.4142 5.80472 9.41419L2.58579 6.19526L3.05004 5.73102L2.58579 6.19526C2.21071 5.82019 2 5.31148 2 4.78105V4ZM4 3.33333C3.63181 3.33333 3.33333 3.63181 3.33333 4L3.33333 4.78105C3.33333 4.95786 3.40357 5.12743 3.5286 5.25246L6.74754 8.47139L6.74756 8.47141C7.12262 8.84649 7.33333 9.35518 7.33333 9.8856L7.33333 13.3713L8.66665 12.8713L8.66667 12.8713L8.66667 9.8856C8.66667 9.35518 8.87737 8.84648 9.25246 8.4714L12.4714 5.25246L12.4714 5.25244C12.5964 5.12742 12.6667 4.95787 12.6667 4.78105V4C12.6667 3.6318 12.3682 3.33333 12 3.33333L4 3.33333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ListFilter"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/ListFilter.tsx b/app/components/base/icons/src/vender/workflow/ListFilter.tsx
new file mode 100644
index 0000000..4eb992a
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/ListFilter.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ListFilter.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ListFilter'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/Llm.json b/app/components/base/icons/src/vender/workflow/Llm.json
new file mode 100644
index 0000000..d900a67
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Llm.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/llm"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M5.83333 2.40625C5.04971 2.40625 4.39011 2.94431 4.20689 3.67206C4.13982 3.93846 3.91391 4.1349 3.64078 4.16432C2.94692 4.23906 2.40625 4.82766 2.40625 5.54167C2.40625 5.92943 2.56471 6.27904 2.82212 6.53129C2.94807 6.65472 3.01905 6.82365 3.01905 7C3.01905 7.17635 2.94807 7.34528 2.82212 7.46871C2.56471 7.72096 2.40625 8.07057 2.40625 8.45833C2.40625 9.03652 2.76061 9.53347 3.26651 9.74092C3.45247 9.81717 3.59324 9.97444 3.64849 10.1677C3.8841 10.9917 4.64342 11.5938 5.54167 11.5938C5.82802 11.5938 6.09916 11.533 6.34375 11.4237V9.91667C6.34375 9.31258 5.85409 8.82292 5.25 8.82292C4.88756 8.82292 4.59375 8.5291 4.59375 8.16667C4.59375 7.80423 4.88756 7.51042 5.25 7.51042C5.64385 7.51042 6.0156 7.60503 6.34375 7.77278V2.48514C6.18319 2.43393 6.01183 2.40625 5.83333 2.40625ZM7.65625 2.48514V4.08333C7.65625 4.6874 8.14592 5.17708 8.75 5.17708C9.11244 5.17708 9.40625 5.4709 9.40625 5.83333C9.40625 6.19577 9.11244 6.48958 8.75 6.48958C8.35615 6.48958 7.9844 6.39496 7.65625 6.22722V11.4237C7.90087 11.533 8.17199 11.5938 8.45833 11.5938C9.35657 11.5938 10.1159 10.9917 10.3515 10.1677C10.4068 9.97444 10.5475 9.81717 10.7335 9.74092C11.2394 9.53347 11.5938 9.03652 11.5938 8.45833C11.5938 8.07056 11.4353 7.72096 11.1779 7.46871C11.0519 7.34528 10.981 7.17635 10.981 7C10.981 6.82365 11.0519 6.65472 11.1779 6.53129C11.4353 6.27904 11.5938 5.92944 11.5938 5.54167C11.5938 4.82766 11.0531 4.23906 10.3592 4.16432C10.0861 4.1349 9.86022 3.93847 9.79315 3.67208C9.6099 2.94432 8.95027 2.40625 8.16667 2.40625C7.98817 2.40625 7.81681 2.43393 7.65625 2.48514ZM7.00001 12.565C6.56031 12.7835 6.06472 12.9062 5.54167 12.9062C4.14996 12.9062 2.96198 12.0403 2.48457 10.8188C1.65595 10.3591 1.09375 9.47501 1.09375 8.45833C1.09375 7.9213 1.2511 7.42042 1.52161 7C1.2511 6.57958 1.09375 6.0787 1.09375 5.54167C1.09375 4.30153 1.93005 3.25742 3.06973 2.94157C3.51828 1.85715 4.586 1.09375 5.83333 1.09375C6.24643 1.09375 6.64104 1.17788 7 1.33013C7.35896 1.17788 7.75357 1.09375 8.16667 1.09375C9.41399 1.09375 10.4817 1.85716 10.9303 2.94157C12.0699 3.25742 12.9062 4.30153 12.9062 5.54167C12.9062 6.07869 12.7489 6.57958 12.4784 7C12.7489 7.42043 12.9062 7.92131 12.9062 8.45833C12.9062 9.47502 12.344 10.3591 11.5154 10.8188C11.038 12.0403 9.85003 12.9062 8.45833 12.9062C7.93526 12.9062 7.4397 12.7834 7.00001 12.565Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Llm"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Llm.tsx b/app/components/base/icons/src/vender/workflow/Llm.tsx
new file mode 100644
index 0000000..d72c5f2
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Llm.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Llm.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Llm'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/Loop.json b/app/components/base/icons/src/vender/workflow/Loop.json
new file mode 100644
index 0000000..65a70d8
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Loop.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "18",
+ "height": "16",
+ "viewBox": "0 0 18 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "loop"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M2.02915 5.34506C3.50752 3.88498 5.9006 3.88498 7.37896 5.34506L8.99983 6.94588L10.6207 5.34506C12.0991 3.88499 14.4921 3.88498 15.9705 5.34506C17.454 6.81027 17.454 9.18971 15.9705 10.6549C14.4921 12.115 12.0991 12.115 10.6207 10.655L8.99983 9.05413L7.37896 10.655C5.9006 12.115 3.50753 12.115 2.02916 10.655C0.545627 9.18974 0.545611 6.81028 2.02915 5.34506ZM7.93251 8L6.32492 6.4123C5.4308 5.52924 3.97732 5.52923 3.08319 6.4123C2.19426 7.29026 2.19426 8.70975 3.0832 9.58772C3.97733 10.4708 5.4308 10.4707 6.32492 9.58771C6.32492 9.58772 6.32492 9.58771 6.32492 9.58771L7.93251 8ZM10.0671 8L11.6747 9.5877C11.6747 9.58769 11.6747 9.58771 11.6747 9.5877C12.5688 10.4707 14.0223 10.4707 14.9165 9.58773C15.8054 8.70975 15.8054 7.29024 14.9165 6.41229C14.0223 5.52923 12.5689 5.52924 11.6747 6.4123C11.6747 6.4123 11.6747 6.41229 11.6747 6.4123L10.0671 8Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "Loop"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/Loop.tsx b/app/components/base/icons/src/vender/workflow/Loop.tsx
new file mode 100644
index 0000000..3ac3ffd
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/Loop.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Loop.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'Loop'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/LoopEnd.json b/app/components/base/icons/src/vender/workflow/LoopEnd.json
new file mode 100644
index 0000000..1427dfd
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/LoopEnd.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "16",
+ "height": "16",
+ "viewBox": "0 0 16 16",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "ongoing"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M8 2.75C5.10051 2.75 2.75 5.10051 2.75 8C2.75 10.8995 5.1005 13.25 8 13.25C8.41421 13.25 8.75 13.5858 8.75 14C8.75 14.4142 8.41421 14.75 8 14.75C4.27208 14.75 1.25 11.7279 1.25 8C1.25 4.27208 4.27208 1.25 8 1.25C8.41421 1.25 8.75 1.58579 8.75 2C8.75 2.41421 8.41421 2.75 8 2.75ZM10.3508 2.42715C10.5582 2.06861 11.017 1.94608 11.3755 2.15349C11.9971 2.51301 12.5556 2.96859 13.0311 3.49984C13.3073 3.8085 13.281 4.28264 12.9724 4.55887C12.6637 4.8351 12.1896 4.80882 11.9133 4.50016C11.5429 4.08625 11.1079 3.73153 10.6245 3.4519C10.2659 3.2445 10.1434 2.7857 10.3508 2.42715ZM8.13634 5.46967C8.42923 5.17678 8.9041 5.17678 9.197 5.46967L11.197 7.46967C11.4899 7.76256 11.4899 8.23744 11.197 8.53033L9.197 10.5303C8.9041 10.8232 8.42923 10.8232 8.13634 10.5303C7.84344 10.2374 7.84344 9.76256 8.13634 9.46967L8.85601 8.75H5.33333C4.91912 8.75 4.58333 8.41421 4.58333 8C4.58333 7.58579 4.91912 7.25 5.33333 7.25H8.85601L8.13634 6.53033C7.84344 6.23744 7.84344 5.76256 8.13634 5.46967ZM13.7414 6.09691C14.1478 6.01676 14.5422 6.28123 14.6224 6.68762C14.7062 7.1128 14.75 7.55166 14.75 8C14.75 8.44834 14.7062 8.88721 14.6224 9.31234C14.5422 9.71872 14.1478 9.98318 13.7414 9.90302C13.335 9.82287 13.0706 9.42845 13.1507 9.02206C13.2158 8.69213 13.25 8.35046 13.25 8C13.25 7.64954 13.2158 7.30787 13.1507 6.97785C13.0706 6.57146 13.335 6.17705 13.7414 6.09691ZM12.9723 11.4411C13.281 11.7173 13.3073 12.1915 13.0311 12.5002C12.5556 13.0314 11.9971 13.487 11.3756 13.8465C11.017 14.0539 10.5582 13.9314 10.3508 13.5729C10.1434 13.2143 10.2659 12.7556 10.6244 12.5481C11.1079 12.2685 11.5429 11.9138 11.9133 11.4999C12.1895 11.1912 12.6637 11.1649 12.9723 11.4411Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "LoopEnd"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/LoopEnd.tsx b/app/components/base/icons/src/vender/workflow/LoopEnd.tsx
new file mode 100644
index 0000000..0b8f71d
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/LoopEnd.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './LoopEnd.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'LoopEnd'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/ParameterExtractor.json b/app/components/base/icons/src/vender/workflow/ParameterExtractor.json
new file mode 100644
index 0000000..7d4fa64
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/ParameterExtractor.json
@@ -0,0 +1,266 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/parma-extractor"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector",
+ "d": "M7.58398 10.3543C7.58398 10.0322 7.84514 9.771 8.16732 9.771C8.48949 9.771 8.75065 10.0322 8.75065 10.3543C8.75065 10.6765 8.48949 10.9377 8.16732 10.9377C7.84514 10.9377 7.58398 10.6765 7.58398 10.3543Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_2",
+ "d": "M9.625 10.3543C9.625 10.0322 9.88616 9.771 10.2083 9.771C10.5305 9.771 10.7917 10.0322 10.7917 10.3543C10.7917 10.6765 10.5305 10.9377 10.2083 10.9377C9.88616 10.9377 9.625 10.6765 9.625 10.3543Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_3",
+ "d": "M7.58398 3.64583C7.58398 3.32366 7.84514 3.0625 8.16732 3.0625C8.48949 3.0625 8.75065 3.32366 8.75065 3.64583C8.75065 3.968 8.48949 4.22917 8.16732 4.22917C7.84514 4.22917 7.58398 3.968 7.58398 3.64583Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_4",
+ "d": "M7.72852 12.104C7.72852 11.8624 7.9244 11.6665 8.16602 11.6665C8.40763 11.6665 8.60352 11.8624 8.60352 12.104C8.60352 12.3456 8.40763 12.5415 8.16602 12.5415C7.9244 12.5415 7.72852 12.3456 7.72852 12.104Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_5",
+ "d": "M11.375 8.1665C11.375 7.92489 11.5709 7.729 11.8125 7.729C12.0541 7.729 12.25 7.92489 12.25 8.1665C12.25 8.40812 12.0541 8.604 11.8125 8.604C11.5709 8.604 11.375 8.40812 11.375 8.1665Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_6",
+ "d": "M11.375 5.8335C11.375 5.59187 11.5709 5.396 11.8125 5.396C12.0541 5.396 12.25 5.59187 12.25 5.8335C12.25 6.07511 12.0541 6.271 11.8125 6.271C11.5709 6.271 11.375 6.07511 11.375 5.8335Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_7",
+ "d": "M7.72852 1.896C7.72852 1.65437 7.9244 1.4585 8.16602 1.4585C8.40763 1.4585 8.60352 1.65437 8.60352 1.896C8.60352 2.13762 8.40763 2.3335 8.16602 2.3335C7.9244 2.3335 7.72852 2.13762 7.72852 1.896Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_8",
+ "d": "M7.29102 8.1665C7.29102 7.68327 7.68278 7.2915 8.16602 7.2915C8.64925 7.2915 9.04102 7.68327 9.04102 8.1665C9.04102 8.64974 8.64925 9.0415 8.16602 9.0415C7.68278 9.0415 7.29102 8.64974 7.29102 8.1665Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_9",
+ "d": "M7.29102 5.8335C7.29102 5.35025 7.68278 4.9585 8.16602 4.9585C8.64925 4.9585 9.04102 5.35025 9.04102 5.8335C9.04102 6.31673 8.64925 6.7085 8.16602 6.7085C7.68278 6.7085 7.29102 6.31673 7.29102 5.8335Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_10",
+ "d": "M9.625 8.16683C9.625 7.84465 9.88616 7.5835 10.2083 7.5835C10.5305 7.5835 10.7917 7.84465 10.7917 8.16683C10.7917 8.489 10.5305 8.75016 10.2083 8.75016C9.88616 8.75016 9.625 8.489 9.625 8.16683Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_11",
+ "d": "M9.625 5.83333C9.625 5.51116 9.88616 5.25 10.2083 5.25C10.5305 5.25 10.7917 5.51116 10.7917 5.83333C10.7917 6.15551 10.5305 6.41667 10.2083 6.41667C9.88616 6.41667 9.625 6.15551 9.625 5.83333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_12",
+ "d": "M9.625 3.64583C9.625 3.32366 9.88616 3.0625 10.2083 3.0625C10.5305 3.0625 10.7917 3.32366 10.7917 3.64583C10.7917 3.968 10.5305 4.22917 10.2083 4.22917C9.88616 4.22917 9.625 3.968 9.625 3.64583Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_13",
+ "d": "M6.41667 3.64583C6.41667 3.968 6.15551 4.22917 5.83333 4.22917C5.51117 4.22917 5.25 3.968 5.25 3.64583C5.25 3.32367 5.51117 3.0625 5.83333 3.0625C6.15551 3.0625 6.41667 3.32367 6.41667 3.64583Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_14",
+ "d": "M4.37565 3.64583C4.37565 3.968 4.11448 4.22917 3.79232 4.22917C3.47015 4.22917 3.20898 3.968 3.20898 3.64583C3.20898 3.32367 3.47015 3.0625 3.79232 3.0625C4.11448 3.0625 4.37565 3.32367 4.37565 3.64583Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_15",
+ "d": "M6.41667 10.3543C6.41667 10.6765 6.15551 10.9377 5.83333 10.9377C5.51117 10.9377 5.25 10.6765 5.25 10.3543C5.25 10.0322 5.51117 9.771 5.83333 9.771C6.15551 9.771 6.41667 10.0322 6.41667 10.3543Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_16",
+ "d": "M6.27148 1.896C6.27148 2.13762 6.0756 2.3335 5.83398 2.3335C5.59236 2.3335 5.39648 2.13762 5.39648 1.896C5.39648 1.65437 5.59236 1.4585 5.83398 1.4585C6.0756 1.4585 6.27148 1.65437 6.27148 1.896Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_17",
+ "d": "M2.625 5.8335C2.625 6.07511 2.42912 6.271 2.1875 6.271C1.94588 6.271 1.75 6.07511 1.75 5.8335C1.75 5.59187 1.94588 5.396 2.1875 5.396C2.42912 5.396 2.625 5.59187 2.625 5.8335Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_18",
+ "d": "M2.625 8.1665C2.625 8.40812 2.42912 8.604 2.1875 8.604C1.94588 8.604 1.75 8.40812 1.75 8.1665C1.75 7.92489 1.94588 7.729 2.1875 7.729C2.42912 7.729 2.625 7.92489 2.625 8.1665Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_19",
+ "d": "M6.27148 12.104C6.27148 12.3456 6.0756 12.5415 5.83398 12.5415C5.59236 12.5415 5.39648 12.3456 5.39648 12.104C5.39648 11.8624 5.59236 11.6665 5.83398 11.6665C6.0756 11.6665 6.27148 11.8624 6.27148 12.104Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_20",
+ "d": "M6.70898 5.8335C6.70898 6.31673 6.31722 6.7085 5.83398 6.7085C5.35073 6.7085 4.95898 6.31673 4.95898 5.8335C4.95898 5.35025 5.35073 4.9585 5.83398 4.9585C6.31722 4.9585 6.70898 5.35025 6.70898 5.8335Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_21",
+ "d": "M6.70898 8.1665C6.70898 8.64974 6.31722 9.0415 5.83398 9.0415C5.35073 9.0415 4.95898 8.64974 4.95898 8.1665C4.95898 7.68327 5.35073 7.2915 5.83398 7.2915C6.31722 7.2915 6.70898 7.68327 6.70898 8.1665Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_22",
+ "d": "M4.37565 5.83333C4.37565 6.15551 4.11448 6.41667 3.79232 6.41667C3.47015 6.41667 3.20898 6.15551 3.20898 5.83333C3.20898 5.51117 3.47015 5.25 3.79232 5.25C4.11448 5.25 4.37565 5.51117 4.37565 5.83333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_23",
+ "d": "M4.37565 8.16683C4.37565 8.489 4.11448 8.75016 3.79232 8.75016C3.47015 8.75016 3.20898 8.489 3.20898 8.16683C3.20898 7.84465 3.47015 7.5835 3.79232 7.5835C4.11448 7.5835 4.37565 7.84465 4.37565 8.16683Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector_24",
+ "d": "M4.37565 10.3543C4.37565 10.6765 4.11448 10.9377 3.79232 10.9377C3.47015 10.9377 3.20898 10.6765 3.20898 10.3543C3.20898 10.0322 3.47015 9.771 3.79232 9.771C4.11448 9.771 4.37565 10.0322 4.37565 10.3543Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "ParameterExtractor"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/ParameterExtractor.tsx b/app/components/base/icons/src/vender/workflow/ParameterExtractor.tsx
new file mode 100644
index 0000000..7066a74
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/ParameterExtractor.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ParameterExtractor.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'ParameterExtractor'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/QuestionClassifier.json b/app/components/base/icons/src/vender/workflow/QuestionClassifier.json
new file mode 100644
index 0000000..a50ee6c
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/QuestionClassifier.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/question-classifier"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Vector (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6.34379 3.53597C6.34379 2.35003 7.45832 1.47985 8.60885 1.76749L10.9422 2.35082C11.7537 2.55369 12.323 3.28283 12.323 4.1193V9.88081C12.323 10.7173 11.7537 11.4464 10.9422 11.6493L8.60886 12.2326C7.45832 12.5203 6.34379 11.6501 6.34379 10.4641V3.53597ZM8.29052 3.0408C7.96836 2.96026 7.65629 3.20392 7.65629 3.53597V10.4641C7.65629 10.7962 7.96836 11.0399 8.29051 10.9593L10.6238 10.376C10.6238 10.376 10.6238 10.376 10.6238 10.376C10.8511 10.3192 11.0105 10.115 11.0105 9.88081V4.1193C11.0105 3.88509 10.851 3.68093 10.6239 3.62413L8.29052 3.0408ZM4.66671 2.26048C5.02914 2.26048 5.32296 2.5543 5.32296 2.91673V11.0834C5.32296 11.4458 5.02914 11.7397 4.66671 11.7397C4.30427 11.7397 4.01046 11.4458 4.01046 11.0834V2.91673C4.01046 2.5543 4.30427 2.26048 4.66671 2.26048ZM2.33337 2.84382C2.69581 2.84382 2.98962 3.13763 2.98962 3.50007V10.5001C2.98962 10.8625 2.69581 11.1563 2.33337 11.1563C1.97094 11.1563 1.67712 10.8625 1.67712 10.5001V3.50007C1.67712 3.13763 1.97094 2.84382 2.33337 2.84382Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "QuestionClassifier"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/QuestionClassifier.tsx b/app/components/base/icons/src/vender/workflow/QuestionClassifier.tsx
new file mode 100644
index 0000000..59b2bcc
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/QuestionClassifier.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './QuestionClassifier.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'QuestionClassifier'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/TemplatingTransform.json b/app/components/base/icons/src/vender/workflow/TemplatingTransform.json
new file mode 100644
index 0000000..69ee236
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/TemplatingTransform.json
@@ -0,0 +1,154 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/templating-transform"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "Vector"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M6.34375 1.75C6.34375 1.38756 6.63756 1.09375 7 1.09375C10.262 1.09375 12.9062 3.73807 12.9062 7C12.9062 10.262 10.262 12.9062 7 12.9062C6.63756 12.9062 6.34375 12.6124 6.34375 12.25V1.75Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.54167 3.64583C5.54167 3.968 5.2805 4.22917 4.95833 4.22917C4.63617 4.22917 4.375 3.968 4.375 3.64583C4.375 3.32367 4.63617 3.0625 4.95833 3.0625C5.2805 3.0625 5.54167 3.32367 5.54167 3.64583Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.5 3.64583C3.5 3.968 3.23883 4.22917 2.91667 4.22917C2.5945 4.22917 2.33333 3.968 2.33333 3.64583C2.33333 3.32367 2.5945 3.0625 2.91667 3.0625C3.23883 3.0625 3.5 3.32367 3.5 3.64583Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.54167 10.3542C5.54167 10.6763 5.2805 10.9375 4.95833 10.9375C4.63617 10.9375 4.375 10.6763 4.375 10.3542C4.375 10.032 4.63617 9.77083 4.95833 9.77083C5.2805 9.77083 5.54167 10.032 5.54167 10.3542Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.39583 1.89583C5.39583 2.13746 5.19996 2.33333 4.95833 2.33333C4.71671 2.33333 4.52083 2.13746 4.52083 1.89583C4.52083 1.65421 4.71671 1.45833 4.95833 1.45833C5.19996 1.45833 5.39583 1.65421 5.39583 1.89583Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M1.75 5.83333C1.75 6.07495 1.55412 6.27083 1.3125 6.27083C1.07088 6.27083 0.875 6.07495 0.875 5.83333C0.875 5.59171 1.07088 5.39583 1.3125 5.39583C1.55412 5.39583 1.75 5.59171 1.75 5.83333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M1.75 8.16667C1.75 8.40828 1.55412 8.60417 1.3125 8.60417C1.07088 8.60417 0.875 8.40828 0.875 8.16667C0.875 7.92505 1.07088 7.72917 1.3125 7.72917C1.55412 7.72917 1.75 7.92505 1.75 8.16667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.39583 12.1042C5.39583 12.3458 5.19996 12.5417 4.95833 12.5417C4.71671 12.5417 4.52083 12.3458 4.52083 12.1042C4.52083 11.8625 4.71671 11.6667 4.95833 11.6667C5.19996 11.6667 5.39583 11.8625 5.39583 12.1042Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.83333 5.83333C5.83333 6.31657 5.44158 6.70833 4.95833 6.70833C4.47508 6.70833 4.08333 6.31657 4.08333 5.83333C4.08333 5.35008 4.47508 4.95833 4.95833 4.95833C5.44158 4.95833 5.83333 5.35008 5.83333 5.83333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M5.83333 8.16667C5.83333 8.6499 5.44158 9.04167 4.95833 9.04167C4.47508 9.04167 4.08333 8.6499 4.08333 8.16667C4.08333 7.68343 4.47508 7.29167 4.95833 7.29167C5.44158 7.29167 5.83333 7.68343 5.83333 8.16667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.5 5.83333C3.5 6.15551 3.23883 6.41667 2.91667 6.41667C2.5945 6.41667 2.33333 6.15551 2.33333 5.83333C2.33333 5.51117 2.5945 5.25 2.91667 5.25C3.23883 5.25 3.5 5.51117 3.5 5.83333Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.5 8.16667C3.5 8.48884 3.23883 8.75 2.91667 8.75C2.5945 8.75 2.33333 8.48884 2.33333 8.16667C2.33333 7.84449 2.5945 7.58333 2.91667 7.58333C3.23883 7.58333 3.5 7.84449 3.5 8.16667Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ },
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "d": "M3.5 10.3542C3.5 10.6763 3.23883 10.9375 2.91667 10.9375C2.5945 10.9375 2.33333 10.6763 2.33333 10.3542C2.33333 10.032 2.5945 9.77083 2.91667 9.77083C3.23883 9.77083 3.5 10.032 3.5 10.3542Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "name": "TemplatingTransform"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/TemplatingTransform.tsx b/app/components/base/icons/src/vender/workflow/TemplatingTransform.tsx
new file mode 100644
index 0000000..a4d1e50
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/TemplatingTransform.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './TemplatingTransform.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'TemplatingTransform'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/VariableX.json b/app/components/base/icons/src/vender/workflow/VariableX.json
new file mode 100644
index 0000000..1560684
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/VariableX.json
@@ -0,0 +1,38 @@
+{
+ "icon": {
+ "type": "element",
+ "isRootNode": true,
+ "name": "svg",
+ "attributes": {
+ "width": "14",
+ "height": "14",
+ "viewBox": "0 0 14 14",
+ "fill": "none",
+ "xmlns": "http://www.w3.org/2000/svg"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "g",
+ "attributes": {
+ "id": "icons/variable-x"
+ },
+ "children": [
+ {
+ "type": "element",
+ "name": "path",
+ "attributes": {
+ "id": "Icon (Stroke)",
+ "fill-rule": "evenodd",
+ "clip-rule": "evenodd",
+ "d": "M0.714375 3.42875C0.714375 2.22516 1.68954 1.25 2.89313 1.25C3.30734 1.25 3.64313 1.58579 3.64313 2C3.64313 2.41421 3.30734 2.75 2.89313 2.75C2.51796 2.75 2.21438 3.05359 2.21438 3.42875V6.28563C2.21438 6.48454 2.13536 6.6753 1.9947 6.81596L1.81066 7L1.9947 7.18404C2.13536 7.3247 2.21438 7.51546 2.21438 7.71437V10.5713C2.21438 10.9464 2.51796 11.25 2.89313 11.25C3.30734 11.25 3.64313 11.5858 3.64313 12C3.64313 12.4142 3.30734 12.75 2.89313 12.75C1.68954 12.75 0.714375 11.7748 0.714375 10.5713V8.02503L0.21967 7.53033C0.0790176 7.38968 0 7.19891 0 7C0 6.80109 0.0790176 6.61032 0.21967 6.46967L0.714375 5.97497V3.42875ZM10.3568 2C10.3568 1.58579 10.6925 1.25 11.1068 1.25C12.3103 1.25 13.2855 2.22516 13.2855 3.42875V5.97497L13.7802 6.46967C13.9209 6.61032 13.9999 6.80109 13.9999 7C13.9999 7.19891 13.9209 7.38968 13.7802 7.53033L13.2855 8.02503V10.5713C13.2855 11.7751 12.3095 12.75 11.1068 12.75C10.6925 12.75 10.3568 12.4142 10.3568 12C10.3568 11.5858 10.6925 11.25 11.1068 11.25C11.4815 11.25 11.7855 10.9462 11.7855 10.5713V7.71437C11.7855 7.51546 11.8645 7.3247 12.0052 7.18404L12.1892 7L12.0052 6.81596C11.8645 6.6753 11.7855 6.48454 11.7855 6.28563V3.42875C11.7855 3.05359 11.4819 2.75 11.1068 2.75C10.6925 2.75 10.3568 2.41421 10.3568 2ZM4.59467 4.59467C4.88756 4.30178 5.36244 4.30178 5.65533 4.59467L7 5.93934L8.34467 4.59467C8.63756 4.30178 9.11244 4.30178 9.40533 4.59467C9.69822 4.88756 9.69822 5.36244 9.40533 5.65533L8.06066 7L9.40533 8.34467C9.69822 8.63756 9.69822 9.11244 9.40533 9.40533C9.11244 9.69822 8.63756 9.69822 8.34467 9.40533L7 8.06066L5.65533 9.40533C5.36244 9.69822 4.88756 9.69822 4.59467 9.40533C4.30178 9.11244 4.30178 8.63756 4.59467 8.34467L5.93934 7L4.59467 5.65533C4.30178 5.36244 4.30178 4.88756 4.59467 4.59467Z",
+ "fill": "currentColor"
+ },
+ "children": []
+ }
+ ]
+ }
+ ]
+ },
+ "name": "VariableX"
+}
\ No newline at end of file
diff --git a/app/components/base/icons/src/vender/workflow/VariableX.tsx b/app/components/base/icons/src/vender/workflow/VariableX.tsx
new file mode 100644
index 0000000..43ec10a
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/VariableX.tsx
@@ -0,0 +1,20 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './VariableX.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = (
+ {
+ ref,
+ ...props
+ }: React.SVGProps<SVGSVGElement> & {
+ ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
+ },
+) => <IconBase {...props} ref={ref} data={data as IconData} />
+
+Icon.displayName = 'VariableX'
+
+export default Icon
diff --git a/app/components/base/icons/src/vender/workflow/index.ts b/app/components/base/icons/src/vender/workflow/index.ts
new file mode 100644
index 0000000..7167b71
--- /dev/null
+++ b/app/components/base/icons/src/vender/workflow/index.ts
@@ -0,0 +1,21 @@
+export { default as Agent } from './Agent'
+export { default as Answer } from './Answer'
+export { default as Assigner } from './Assigner'
+export { default as Code } from './Code'
+export { default as DocsExtractor } from './DocsExtractor'
+export { default as End } from './End'
+export { default as Home } from './Home'
+export { default as Http } from './Http'
+export { default as IfElse } from './IfElse'
+export { default as IterationStart } from './IterationStart'
+export { default as Iteration } from './Iteration'
+export { default as Jinja } from './Jinja'
+export { default as KnowledgeRetrieval } from './KnowledgeRetrieval'
+export { default as ListFilter } from './ListFilter'
+export { default as Llm } from './Llm'
+export { default as LoopEnd } from './LoopEnd'
+export { default as Loop } from './Loop'
+export { default as ParameterExtractor } from './ParameterExtractor'
+export { default as QuestionClassifier } from './QuestionClassifier'
+export { default as TemplatingTransform } from './TemplatingTransform'
+export { default as VariableX } from './VariableX'
diff --git a/app/components/base/icons/utils.spec.ts b/app/components/base/icons/utils.spec.ts
new file mode 100644
index 0000000..bfa8e39
--- /dev/null
+++ b/app/components/base/icons/utils.spec.ts
@@ -0,0 +1,70 @@
+import type { AbstractNode } from './utils'
+import { generate, normalizeAttrs } from './utils'
+import { render } from '@testing-library/react'
+import '@testing-library/jest-dom'
+
+describe('generate icon base utils', () => {
+ describe('normalizeAttrs', () => {
+ it('should normalize class to className', () => {
+ const attrs = { class: 'test-class' }
+ const result = normalizeAttrs(attrs)
+ expect(result).toEqual({ className: 'test-class' })
+ })
+
+ it('should normalize style string to style object', () => {
+ const attrs = { style: 'color:red;font-size:14px;' }
+ const result = normalizeAttrs(attrs)
+ expect(result).toEqual({ style: { color: 'red', fontSize: '14px' } })
+ })
+
+ it('should handle attributes with dashes and colons', () => {
+ const attrs = { 'data-test': 'value', 'xlink:href': 'url' }
+ const result = normalizeAttrs(attrs)
+ expect(result).toEqual({ dataTest: 'value', xlinkHref: 'url' })
+ })
+ })
+
+ describe('generate', () => {
+ it('should generate React elements from AbstractNode', () => {
+ const node: AbstractNode = {
+ name: 'div',
+ attributes: { class: 'container' },
+ children: [
+ {
+ name: 'span',
+ attributes: { style: 'color:blue;' },
+ children: [],
+ },
+ ],
+ }
+
+ const { container } = render(generate(node, 'key'))
+ // to svg element
+ expect(container.firstChild).toHaveClass('container')
+ expect(container.querySelector('span')).toHaveStyle({ color: 'blue' })
+ })
+
+ // add not has children
+ it('should generate React elements without children', () => {
+ const node: AbstractNode = {
+ name: 'div',
+ attributes: { class: 'container' },
+ }
+ const { container } = render(generate(node, 'key'))
+ // to svg element
+ expect(container.firstChild).toHaveClass('container')
+ })
+
+ it('should merge rootProps when provided', () => {
+ const node: AbstractNode = {
+ name: 'div',
+ attributes: { class: 'container' },
+ children: [],
+ }
+
+ const rootProps = { id: 'root' }
+ const { container } = render(generate(node, 'key', rootProps))
+ expect(container.querySelector('div')).toHaveAttribute('id', 'root')
+ })
+ })
+})
diff --git a/app/components/base/icons/utils.ts b/app/components/base/icons/utils.ts
new file mode 100644
index 0000000..90d075f
--- /dev/null
+++ b/app/components/base/icons/utils.ts
@@ -0,0 +1,66 @@
+import React from 'react'
+
+export type AbstractNode = {
+ name: string
+ attributes: {
+ [key: string]: string
+ }
+ children?: AbstractNode[]
+}
+
+export type Attrs = {
+ [key: string]: string
+}
+
+export function normalizeAttrs(attrs: Attrs = {}): Attrs {
+ return Object.keys(attrs).reduce((acc: Attrs, key) => {
+ const val = attrs[key]
+ key = key.replace(/([-]\w)/g, (g: string) => g[1].toUpperCase())
+ key = key.replace(/([:]\w)/g, (g: string) => g[1].toUpperCase())
+ switch (key) {
+ case 'class':
+ acc.className = val
+ delete acc.class
+ break
+ case 'style':
+ (acc.style as any) = val.split(';').reduce((prev, next) => {
+ const pairs = next?.split(':')
+
+ if (pairs[0] && pairs[1]) {
+ const k = pairs[0].replace(/([-]\w)/g, (g: string) => g[1].toUpperCase())
+ prev[k] = pairs[1]
+ }
+
+ return prev
+ }, {} as Attrs)
+ break
+ default:
+ acc[key] = val
+ }
+ return acc
+ }, {})
+}
+
+export function generate(
+ node: AbstractNode,
+ key: string,
+ rootProps?: { [key: string]: any } | false,
+): any {
+ if (!rootProps) {
+ return React.createElement(
+ node.name,
+ { key, ...normalizeAttrs(node.attributes) },
+ (node.children || []).map((child, index) => generate(child, `${key}-${node.name}-${index}`)),
+ )
+ }
+
+ return React.createElement(
+ node.name,
+ {
+ key,
+ ...normalizeAttrs(node.attributes),
+ ...rootProps,
+ },
+ (node.children || []).map((child, index) => generate(child, `${key}-${node.name}-${index}`)),
+ )
+}
diff --git a/app/components/base/image-gallery/index.tsx b/app/components/base/image-gallery/index.tsx
new file mode 100644
index 0000000..0f9061f
--- /dev/null
+++ b/app/components/base/image-gallery/index.tsx
@@ -0,0 +1,84 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import ImagePreview from '@/app/components/base/image-uploader/image-preview'
+
+type Props = {
+ srcs: string[]
+}
+
+const getWidthStyle = (imgNum: number) => {
+ if (imgNum === 1) {
+ return {
+ maxWidth: '100%',
+ }
+ }
+
+ if (imgNum === 2 || imgNum === 4) {
+ return {
+ width: 'calc(50% - 4px)',
+ }
+ }
+
+ return {
+ width: 'calc(33.3333% - 5.3333px)',
+ }
+}
+
+const ImageGallery: FC<Props> = ({
+ srcs,
+}) => {
+ const [imagePreviewUrl, setImagePreviewUrl] = useState('')
+
+ const imgNum = srcs.length
+ const imgStyle = getWidthStyle(imgNum)
+ return (
+ <div className={cn(s[`img-${imgNum}`], 'flex flex-wrap')}>
+ {/* TODO: support preview */}
+ {srcs.map((src, index) => (
+
+ <img
+ key={index}
+ className={s.item}
+ style={imgStyle}
+ src={src}
+ alt=''
+ onClick={() => setImagePreviewUrl(src)}
+ onError={e => e.currentTarget.remove()}
+ />
+ ))}
+ {
+ imagePreviewUrl && (
+ <ImagePreview
+ url={imagePreviewUrl}
+ onCancel={() => setImagePreviewUrl('')} title={''} />
+ )
+ }
+ </div>
+ )
+}
+
+export default React.memo(ImageGallery)
+
+export const ImageGalleryTest = () => {
+ const imgGallerySrcs = (() => {
+ const srcs = []
+ for (let i = 0; i < 6; i++)
+ // srcs.push('https://placekitten.com/640/360')
+ // srcs.push('https://placekitten.com/360/640')
+ srcs.push('https://placekitten.com/360/360')
+
+ return srcs
+ })()
+ return (
+ <div className='space-y-2'>
+ {imgGallerySrcs.map((_, index) => (
+ <div key={index} className='rounded-lg bg-[#D1E9FF80] p-4 pb-2'>
+ <ImageGallery srcs={imgGallerySrcs.slice(0, index + 1)} />
+ </div>
+ ))}
+ </div>
+ )
+}
diff --git a/app/components/base/image-gallery/style.module.css b/app/components/base/image-gallery/style.module.css
new file mode 100644
index 0000000..2e4c62e
--- /dev/null
+++ b/app/components/base/image-gallery/style.module.css
@@ -0,0 +1,22 @@
+.item {
+ max-height: 200px;
+ margin-right: 8px;
+ margin-bottom: 8px;
+ object-fit: contain;
+ object-position: center;
+ border-radius: 8px;
+ cursor: pointer;
+}
+
+.item:nth-child(3n) {
+ margin-right: 0;
+}
+
+.img-2 .item:nth-child(2n),
+.img-4 .item:nth-child(2n) {
+ margin-right: 0;
+}
+
+.img-4 .item:nth-child(3n) {
+ margin-right: 8px;
+}
diff --git a/app/components/base/image-uploader/audio-preview.tsx b/app/components/base/image-uploader/audio-preview.tsx
new file mode 100644
index 0000000..d1f71f8
--- /dev/null
+++ b/app/components/base/image-uploader/audio-preview.tsx
@@ -0,0 +1,37 @@
+import type { FC } from 'react'
+import { createPortal } from 'react-dom'
+import { RiCloseLine } from '@remixicon/react'
+
+type AudioPreviewProps = {
+ url: string
+ title: string
+ onCancel: () => void
+}
+const AudioPreview: FC<AudioPreviewProps> = ({
+ url,
+ title,
+ onCancel,
+}) => {
+ return createPortal(
+ <div className='fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 p-8' onClick={e => e.stopPropagation()}>
+ <div>
+ <audio controls title={title} autoPlay={false} preload="metadata">
+ <source
+ type="audio/mpeg"
+ src={url}
+ className='max-h-full max-w-full'
+ />
+ </audio>
+ </div>
+ <div
+ className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/[0.08] backdrop-blur-[2px]'
+ onClick={onCancel}
+ >
+ <RiCloseLine className='h-4 w-4 text-gray-500'/>
+ </div>
+ </div>,
+ document.body,
+ )
+}
+
+export default AudioPreview
diff --git a/app/components/base/image-uploader/chat-image-uploader.tsx b/app/components/base/image-uploader/chat-image-uploader.tsx
new file mode 100644
index 0000000..401af2b
--- /dev/null
+++ b/app/components/base/image-uploader/chat-image-uploader.tsx
@@ -0,0 +1,159 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import Uploader from './uploader'
+import ImageLinkInput from './image-link-input'
+import cn from '@/utils/classnames'
+import { ImagePlus } from '@/app/components/base/icons/src/vender/line/images'
+import { TransferMethod } from '@/types/app'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { Upload03 } from '@/app/components/base/icons/src/vender/line/general'
+import type { ImageFile, VisionSettings } from '@/types/app'
+
+type UploadOnlyFromLocalProps = {
+ onUpload: (imageFile: ImageFile) => void
+ disabled?: boolean
+ limit?: number
+}
+const UploadOnlyFromLocal: FC<UploadOnlyFromLocalProps> = ({
+ onUpload,
+ disabled,
+ limit,
+}) => {
+ return (
+ <Uploader onUpload={onUpload} disabled={disabled} limit={limit}>
+ {hovering => (
+ <div
+ className={`
+ relative flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg
+ ${hovering && 'bg-gray-100'}
+ `}
+ >
+ <ImagePlus className="h-4 w-4 text-gray-500" />
+ </div>
+ )}
+ </Uploader>
+ )
+}
+
+type UploaderButtonProps = {
+ methods: VisionSettings['transfer_methods']
+ onUpload: (imageFile: ImageFile) => void
+ disabled?: boolean
+ limit?: number
+}
+const UploaderButton: FC<UploaderButtonProps> = ({
+ methods,
+ onUpload,
+ disabled,
+ limit,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ const hasUploadFromLocal = methods.find(
+ method => method === TransferMethod.local_file,
+ )
+
+ const handleUpload = (imageFile: ImageFile) => {
+ onUpload(imageFile)
+ }
+
+ const closePopover = () => setOpen(false)
+
+ const handleToggle = () => {
+ if (disabled)
+ return
+
+ setOpen(v => !v)
+ }
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement="top-start"
+ >
+ <PortalToFollowElemTrigger onClick={handleToggle}>
+ <button
+ type="button"
+ disabled={disabled}
+ className="relative flex h-8 w-8 items-center justify-center rounded-lg enabled:hover:bg-gray-100 disabled:cursor-not-allowed"
+ >
+ <ImagePlus className="h-4 w-4 text-gray-500" />
+ </button>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className="z-50">
+ <div className="w-[260px] rounded-lg border-[0.5px] border-gray-200 bg-white p-2 shadow-lg">
+ <ImageLinkInput onUpload={handleUpload} disabled={disabled} />
+ {hasUploadFromLocal && (
+ <>
+ <div className="mt-2 flex items-center px-2 text-xs font-medium text-gray-400">
+ <div className="mr-3 h-[1px] w-[93px] bg-gradient-to-l from-[#F3F4F6]" />
+ OR
+ <div className="ml-3 h-[1px] w-[93px] bg-gradient-to-r from-[#F3F4F6]" />
+ </div>
+ <Uploader
+ onUpload={handleUpload}
+ limit={limit}
+ closePopover={closePopover}
+ >
+ {hovering => (
+ <div
+ className={cn(
+ 'flex h-8 cursor-pointer items-center justify-center rounded-lg text-[13px] font-medium text-[#155EEF]',
+ hovering && 'bg-primary-50',
+ )}
+ >
+ <Upload03 className="mr-1 h-4 w-4" />
+ {t('common.imageUploader.uploadFromComputer')}
+ </div>
+ )}
+ </Uploader>
+ </>
+ )}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+type ChatImageUploaderProps = {
+ settings: VisionSettings
+ onUpload: (imageFile: ImageFile) => void
+ disabled?: boolean
+}
+const ChatImageUploader: FC<ChatImageUploaderProps> = ({
+ settings,
+ onUpload,
+ disabled,
+}) => {
+ const onlyUploadLocal
+ = settings.transfer_methods.length === 1
+ && settings.transfer_methods[0] === TransferMethod.local_file
+
+ if (onlyUploadLocal) {
+ return (
+ <UploadOnlyFromLocal
+ onUpload={onUpload}
+ disabled={disabled}
+ limit={+settings.image_file_size_limit!}
+ />
+ )
+ }
+
+ return (
+ <UploaderButton
+ methods={settings.transfer_methods}
+ onUpload={onUpload}
+ disabled={disabled}
+ limit={+settings.image_file_size_limit!}
+ />
+ )
+}
+
+export default ChatImageUploader
diff --git a/app/components/base/image-uploader/hooks.ts b/app/components/base/image-uploader/hooks.ts
new file mode 100644
index 0000000..4107400
--- /dev/null
+++ b/app/components/base/image-uploader/hooks.ts
@@ -0,0 +1,270 @@
+import { useCallback, useMemo, useRef, useState } from 'react'
+import type { ClipboardEvent } from 'react'
+import { useParams } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import { imageUpload } from './utils'
+import { useToastContext } from '@/app/components/base/toast'
+import { ALLOW_FILE_EXTENSIONS, TransferMethod } from '@/types/app'
+import type { ImageFile, VisionSettings } from '@/types/app'
+
+export const useImageFiles = () => {
+ const params = useParams()
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const [files, setFiles] = useState<ImageFile[]>([])
+ const filesRef = useRef<ImageFile[]>([])
+
+ const handleUpload = (imageFile: ImageFile) => {
+ const files = filesRef.current
+ const index = files.findIndex(file => file._id === imageFile._id)
+
+ if (index > -1) {
+ const currentFile = files[index]
+ const newFiles = [...files.slice(0, index), { ...currentFile, ...imageFile }, ...files.slice(index + 1)]
+ setFiles(newFiles)
+ filesRef.current = newFiles
+ }
+ else {
+ const newFiles = [...files, imageFile]
+ setFiles(newFiles)
+ filesRef.current = newFiles
+ }
+ }
+ const handleRemove = (imageFileId: string) => {
+ const files = filesRef.current
+ const index = files.findIndex(file => file._id === imageFileId)
+
+ if (index > -1) {
+ const currentFile = files[index]
+ const newFiles = [...files.slice(0, index), { ...currentFile, deleted: true }, ...files.slice(index + 1)]
+ setFiles(newFiles)
+ filesRef.current = newFiles
+ }
+ }
+ const handleImageLinkLoadError = (imageFileId: string) => {
+ const files = filesRef.current
+ const index = files.findIndex(file => file._id === imageFileId)
+
+ if (index > -1) {
+ const currentFile = files[index]
+ const newFiles = [...files.slice(0, index), { ...currentFile, progress: -1 }, ...files.slice(index + 1)]
+ filesRef.current = newFiles
+ setFiles(newFiles)
+ }
+ }
+ const handleImageLinkLoadSuccess = (imageFileId: string) => {
+ const files = filesRef.current
+ const index = files.findIndex(file => file._id === imageFileId)
+
+ if (index > -1) {
+ const currentImageFile = files[index]
+ const newFiles = [...files.slice(0, index), { ...currentImageFile, progress: 100 }, ...files.slice(index + 1)]
+ filesRef.current = newFiles
+ setFiles(newFiles)
+ }
+ }
+ const handleReUpload = (imageFileId: string) => {
+ const files = filesRef.current
+ const index = files.findIndex(file => file._id === imageFileId)
+
+ if (index > -1) {
+ const currentImageFile = files[index]
+ imageUpload({
+ file: currentImageFile.file!,
+ onProgressCallback: (progress) => {
+ const newFiles = [...files.slice(0, index), { ...currentImageFile, progress }, ...files.slice(index + 1)]
+ filesRef.current = newFiles
+ setFiles(newFiles)
+ },
+ onSuccessCallback: (res) => {
+ const newFiles = [...files.slice(0, index), { ...currentImageFile, fileId: res.id, progress: 100 }, ...files.slice(index + 1)]
+ filesRef.current = newFiles
+ setFiles(newFiles)
+ },
+ onErrorCallback: () => {
+ notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerUploadError') })
+ const newFiles = [...files.slice(0, index), { ...currentImageFile, progress: -1 }, ...files.slice(index + 1)]
+ filesRef.current = newFiles
+ setFiles(newFiles)
+ },
+ }, !!params.token)
+ }
+ }
+
+ const handleClear = () => {
+ setFiles([])
+ filesRef.current = []
+ }
+
+ const filteredFiles = useMemo(() => {
+ return files.filter(file => !file.deleted)
+ }, [files])
+
+ return {
+ files: filteredFiles,
+ onUpload: handleUpload,
+ onRemove: handleRemove,
+ onImageLinkLoadError: handleImageLinkLoadError,
+ onImageLinkLoadSuccess: handleImageLinkLoadSuccess,
+ onReUpload: handleReUpload,
+ onClear: handleClear,
+ }
+}
+
+type useLocalUploaderProps = {
+ disabled?: boolean
+ limit?: number
+ onUpload: (imageFile: ImageFile) => void
+}
+
+export const useLocalFileUploader = ({ limit, disabled = false, onUpload }: useLocalUploaderProps) => {
+ const { notify } = useToastContext()
+ const params = useParams()
+ const { t } = useTranslation()
+
+ const handleLocalFileUpload = useCallback((file: File) => {
+ if (disabled) {
+ // TODO: leave some warnings?
+ return
+ }
+
+ if (!ALLOW_FILE_EXTENSIONS.includes(file.type.split('/')[1]))
+ return
+
+ if (limit && file.size > limit * 1024 * 1024) {
+ notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerLimit', { size: limit }) })
+ return
+ }
+
+ const reader = new FileReader()
+ reader.addEventListener(
+ 'load',
+ () => {
+ const imageFile = {
+ type: TransferMethod.local_file,
+ _id: `${Date.now()}`,
+ fileId: '',
+ file,
+ url: reader.result as string,
+ base64Url: reader.result as string,
+ progress: 0,
+ }
+ onUpload(imageFile)
+ imageUpload({
+ file: imageFile.file,
+ onProgressCallback: (progress) => {
+ onUpload({ ...imageFile, progress })
+ },
+ onSuccessCallback: (res) => {
+ onUpload({ ...imageFile, fileId: res.id, progress: 100 })
+ },
+ onErrorCallback: () => {
+ notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerUploadError') })
+ onUpload({ ...imageFile, progress: -1 })
+ },
+ }, !!params.token)
+ },
+ false,
+ )
+ reader.addEventListener(
+ 'error',
+ () => {
+ notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerReadError') })
+ },
+ false,
+ )
+ reader.readAsDataURL(file)
+ }, [disabled, limit, notify, t, onUpload, params.token])
+
+ return { disabled, handleLocalFileUpload }
+}
+
+type useClipboardUploaderProps = {
+ files: ImageFile[]
+ visionConfig?: VisionSettings
+ onUpload: (imageFile: ImageFile) => void
+}
+
+export const useClipboardUploader = ({ visionConfig, onUpload, files }: useClipboardUploaderProps) => {
+ const allowLocalUpload = visionConfig?.transfer_methods?.includes(TransferMethod.local_file)
+ const disabled = useMemo(() =>
+ !visionConfig
+ || !visionConfig?.enabled
+ || !allowLocalUpload
+ || files.length >= visionConfig.number_limits!,
+ [allowLocalUpload, files.length, visionConfig])
+ const limit = useMemo(() => visionConfig ? +visionConfig.image_file_size_limit! : 0, [visionConfig])
+ const { handleLocalFileUpload } = useLocalFileUploader({ limit, onUpload, disabled })
+
+ const handleClipboardPaste = useCallback((e: ClipboardEvent<HTMLTextAreaElement>) => {
+ // reserve native text copy behavior
+ const file = e.clipboardData?.files[0]
+ // when copied file, prevent default action
+ if (file) {
+ e.preventDefault()
+ handleLocalFileUpload(file)
+ }
+ }, [handleLocalFileUpload])
+
+ return {
+ onPaste: handleClipboardPaste,
+ }
+}
+
+type useDraggableUploaderProps = {
+ files: ImageFile[]
+ visionConfig?: VisionSettings
+ onUpload: (imageFile: ImageFile) => void
+}
+
+export const useDraggableUploader = <T extends HTMLElement>({ visionConfig, onUpload, files }: useDraggableUploaderProps) => {
+ const allowLocalUpload = visionConfig?.transfer_methods?.includes(TransferMethod.local_file)
+ const disabled = useMemo(() =>
+ !visionConfig
+ || !visionConfig?.enabled
+ || !allowLocalUpload
+ || files.length >= visionConfig.number_limits!,
+ [allowLocalUpload, files.length, visionConfig])
+ const limit = useMemo(() => visionConfig ? +visionConfig.image_file_size_limit! : 0, [visionConfig])
+ const { handleLocalFileUpload } = useLocalFileUploader({ disabled, onUpload, limit })
+ const [isDragActive, setIsDragActive] = useState(false)
+
+ const handleDragEnter = useCallback((e: React.DragEvent<T>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ if (!disabled)
+ setIsDragActive(true)
+ }, [disabled])
+
+ const handleDragOver = useCallback((e: React.DragEvent<T>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }, [])
+
+ const handleDragLeave = useCallback((e: React.DragEvent<T>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragActive(false)
+ }, [])
+
+ const handleDrop = useCallback((e: React.DragEvent<T>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setIsDragActive(false)
+
+ const file = e.dataTransfer.files[0]
+
+ if (!file)
+ return
+
+ handleLocalFileUpload(file)
+ }, [handleLocalFileUpload])
+
+ return {
+ onDragEnter: handleDragEnter,
+ onDragOver: handleDragOver,
+ onDragLeave: handleDragLeave,
+ onDrop: handleDrop,
+ isDragActive,
+ }
+}
diff --git a/app/components/base/image-uploader/image-link-input.tsx b/app/components/base/image-uploader/image-link-input.tsx
new file mode 100644
index 0000000..a767e0c
--- /dev/null
+++ b/app/components/base/image-uploader/image-link-input.tsx
@@ -0,0 +1,56 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import Button from '@/app/components/base/button'
+import type { ImageFile } from '@/types/app'
+import { TransferMethod } from '@/types/app'
+
+type ImageLinkInputProps = {
+ onUpload: (imageFile: ImageFile) => void
+ disabled?: boolean
+}
+const regex = /^(https?|ftp):\/\//
+const ImageLinkInput: FC<ImageLinkInputProps> = ({
+ onUpload,
+ disabled,
+}) => {
+ const { t } = useTranslation()
+ const [imageLink, setImageLink] = useState('')
+
+ const handleClick = () => {
+ if (disabled)
+ return
+
+ const imageFile = {
+ type: TransferMethod.remote_url,
+ _id: `${Date.now()}`,
+ fileId: '',
+ progress: regex.test(imageLink) ? 0 : -1,
+ url: imageLink,
+ }
+
+ onUpload(imageFile)
+ }
+
+ return (
+ <div className='flex h-8 items-center rounded-lg border border-components-panel-border bg-components-panel-bg pl-1.5 pr-1 shadow-xs'>
+ <input
+ type="text"
+ className='mr-0.5 h-[18px] grow appearance-none bg-transparent px-1 text-[13px] text-text-primary outline-none'
+ value={imageLink}
+ onChange={e => setImageLink(e.target.value)}
+ placeholder={t('common.imageUploader.pasteImageLinkInputPlaceholder') || ''}
+ />
+ <Button
+ variant='primary'
+ size='small'
+ disabled={!imageLink || disabled}
+ onClick={handleClick}
+ >
+ {t('common.operation.ok')}
+ </Button>
+ </div>
+ )
+}
+
+export default ImageLinkInput
diff --git a/app/components/base/image-uploader/image-list.tsx b/app/components/base/image-uploader/image-list.tsx
new file mode 100644
index 0000000..758ffe9
--- /dev/null
+++ b/app/components/base/image-uploader/image-list.tsx
@@ -0,0 +1,143 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiCloseLine,
+ RiLoader2Line,
+} from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
+import Tooltip from '@/app/components/base/tooltip'
+import type { ImageFile } from '@/types/app'
+import { TransferMethod } from '@/types/app'
+import ImagePreview from '@/app/components/base/image-uploader/image-preview'
+
+type ImageListProps = {
+ list: ImageFile[]
+ readonly?: boolean
+ onRemove?: (imageFileId: string) => void
+ onReUpload?: (imageFileId: string) => void
+ onImageLinkLoadSuccess?: (imageFileId: string) => void
+ onImageLinkLoadError?: (imageFileId: string) => void
+}
+
+const ImageList: FC<ImageListProps> = ({
+ list,
+ readonly,
+ onRemove,
+ onReUpload,
+ onImageLinkLoadSuccess,
+ onImageLinkLoadError,
+}) => {
+ const { t } = useTranslation()
+ const [imagePreviewUrl, setImagePreviewUrl] = useState('')
+
+ const handleImageLinkLoadSuccess = (item: ImageFile) => {
+ if (
+ item.type === TransferMethod.remote_url
+ && onImageLinkLoadSuccess
+ && item.progress !== -1
+ )
+ onImageLinkLoadSuccess(item._id)
+ }
+ const handleImageLinkLoadError = (item: ImageFile) => {
+ if (item.type === TransferMethod.remote_url && onImageLinkLoadError)
+ onImageLinkLoadError(item._id)
+ }
+
+ return (
+ <div className="flex flex-wrap">
+ {list.map(item => (
+ <div
+ key={item._id}
+ className="group relative mr-1 rounded-lg border-[0.5px] border-black/5"
+ >
+ {item.type === TransferMethod.local_file && item.progress !== 100 && (
+ <>
+ <div
+ className="absolute inset-0 z-[1] flex items-center justify-center bg-black/30"
+ style={{ left: item.progress > -1 ? `${item.progress}%` : 0 }}
+ >
+ {item.progress === -1 && (
+ <RefreshCcw01
+ className="h-5 w-5 text-white"
+ onClick={() => onReUpload && onReUpload(item._id)}
+ />
+ )}
+ </div>
+ {item.progress > -1 && (
+ <span className="absolute left-[50%] top-[50%] z-[1] translate-x-[-50%] translate-y-[-50%] text-sm text-white mix-blend-lighten">
+ {item.progress}%
+ </span>
+ )}
+ </>
+ )}
+ {item.type === TransferMethod.remote_url && item.progress !== 100 && (
+ <div
+ className={`
+ absolute inset-0 z-[1] flex items-center justify-center rounded-lg border
+ ${item.progress === -1
+ ? 'border-[#DC6803] bg-[#FEF0C7]'
+ : 'border-transparent bg-black/[0.16]'
+ }
+ `}
+ >
+ {item.progress > -1 && (
+ <RiLoader2Line className="h-5 w-5 animate-spin text-white" />
+ )}
+ {item.progress === -1 && (
+ <Tooltip
+ popupContent={t('common.imageUploader.pasteImageLinkInvalid')}
+ >
+ <AlertTriangle className="h-4 w-4 text-[#DC6803]" />
+ </Tooltip>
+ )}
+ </div>
+ )}
+ <img
+ className="h-16 w-16 cursor-pointer rounded-lg border-[0.5px] border-black/5 object-cover"
+ alt={item.file?.name}
+ onLoad={() => handleImageLinkLoadSuccess(item)}
+ onError={() => handleImageLinkLoadError(item)}
+ src={
+ item.type === TransferMethod.remote_url
+ ? item.url
+ : item.base64Url
+ }
+ onClick={() =>
+ item.progress === 100
+ && setImagePreviewUrl(
+ (item.type === TransferMethod.remote_url
+ ? item.url
+ : item.base64Url) as string,
+ )
+ }
+ />
+ {!readonly && (
+ <button
+ type="button"
+ className={cn(
+ 'absolute -right-[9px] -top-[9px] z-10 h-[18px] w-[18px] items-center justify-center',
+ 'rounded-2xl shadow-lg hover:bg-state-base-hover',
+ item.progress === -1 ? 'flex' : 'hidden group-hover:flex',
+ )}
+ onClick={() => onRemove && onRemove(item._id)}
+ >
+ <RiCloseLine className="h-3 w-3 text-text-tertiary" />
+ </button>
+ )}
+ </div>
+ ))}
+ {imagePreviewUrl && (
+ <ImagePreview
+ url={imagePreviewUrl}
+ onCancel={() => setImagePreviewUrl('')}
+ title=''
+ />
+ )}
+ </div>
+ )
+}
+
+export default ImageList
diff --git a/app/components/base/image-uploader/image-preview.tsx b/app/components/base/image-uploader/image-preview.tsx
new file mode 100644
index 0000000..e67edaa
--- /dev/null
+++ b/app/components/base/image-uploader/image-preview.tsx
@@ -0,0 +1,269 @@
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import { t } from 'i18next'
+import { createPortal } from 'react-dom'
+import { RiAddBoxLine, RiCloseLine, RiDownloadCloud2Line, RiFileCopyLine, RiZoomInLine, RiZoomOutLine } from '@remixicon/react'
+import { useHotkeys } from 'react-hotkeys-hook'
+import Tooltip from '@/app/components/base/tooltip'
+import Toast from '@/app/components/base/toast'
+import { noop } from 'lodash-es'
+
+type ImagePreviewProps = {
+ url: string
+ title: string
+ onCancel: () => void
+ onPrev?: () => void
+ onNext?: () => void
+}
+
+const isBase64 = (str: string): boolean => {
+ try {
+ return btoa(atob(str)) === str
+ }
+ catch (err) {
+ return false
+ }
+}
+
+const ImagePreview: FC<ImagePreviewProps> = ({
+ url,
+ title,
+ onCancel,
+ onPrev,
+ onNext,
+}) => {
+ const [scale, setScale] = useState(1)
+ const [position, setPosition] = useState({ x: 0, y: 0 })
+ const [isDragging, setIsDragging] = useState(false)
+ const imgRef = useRef<HTMLImageElement>(null)
+ const dragStartRef = useRef({ x: 0, y: 0 })
+ const [isCopied, setIsCopied] = useState(false)
+
+ const openInNewTab = () => {
+ // Open in a new window, considering the case when the page is inside an iframe
+ if (url.startsWith('http') || url.startsWith('https')) {
+ window.open(url, '_blank')
+ }
+ else if (url.startsWith('data:image')) {
+ // Base64 image
+ const win = window.open()
+ win?.document.write(`<img src="${url}" alt="${title}" />`)
+ }
+ else {
+ Toast.notify({
+ type: 'error',
+ message: `Unable to open image: ${url}`,
+ })
+ }
+ }
+
+ const downloadImage = () => {
+ // Open in a new window, considering the case when the page is inside an iframe
+ if (url.startsWith('http') || url.startsWith('https')) {
+ const a = document.createElement('a')
+ a.href = url
+ a.target = '_blank'
+ a.download = title
+ a.click()
+ }
+ else if (url.startsWith('data:image')) {
+ // Base64 image
+ const a = document.createElement('a')
+ a.href = url
+ a.target = '_blank'
+ a.download = title
+ a.click()
+ }
+ else {
+ Toast.notify({
+ type: 'error',
+ message: `Unable to open image: ${url}`,
+ })
+ }
+ }
+
+ const zoomIn = () => {
+ setScale(prevScale => Math.min(prevScale * 1.2, 15))
+ }
+
+ const zoomOut = () => {
+ setScale((prevScale) => {
+ const newScale = Math.max(prevScale / 1.2, 0.5)
+ if (newScale === 1)
+ setPosition({ x: 0, y: 0 }) // Reset position when fully zoomed out
+
+ return newScale
+ })
+ }
+
+ const imageBase64ToBlob = (base64: string, type = 'image/png'): Blob => {
+ const byteCharacters = atob(base64)
+ const byteArrays = []
+
+ for (let offset = 0; offset < byteCharacters.length; offset += 512) {
+ const slice = byteCharacters.slice(offset, offset + 512)
+ const byteNumbers = Array.from({ length: slice.length })
+ for (let i = 0; i < slice.length; i++)
+ byteNumbers[i] = slice.charCodeAt(i)
+
+ const byteArray = new Uint8Array(byteNumbers as any)
+ byteArrays.push(byteArray)
+ }
+
+ return new Blob(byteArrays, { type })
+ }
+
+ const imageCopy = useCallback(() => {
+ const shareImage = async () => {
+ try {
+ const base64Data = url.split(',')[1]
+ const blob = imageBase64ToBlob(base64Data, 'image/png')
+
+ await navigator.clipboard.write([
+ new ClipboardItem({
+ [blob.type]: blob,
+ }),
+ ])
+ setIsCopied(true)
+
+ Toast.notify({
+ type: 'success',
+ message: t('common.operation.imageCopied'),
+ })
+ }
+ catch (err) {
+ console.error('Failed to copy image:', err)
+
+ const link = document.createElement('a')
+ link.href = url
+ link.download = `${title}.png`
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+
+ Toast.notify({
+ type: 'info',
+ message: t('common.operation.imageDownloaded'),
+ })
+ }
+ }
+ shareImage()
+ }, [title, url])
+
+ const handleWheel = useCallback((e: React.WheelEvent<HTMLDivElement>) => {
+ if (e.deltaY < 0)
+ zoomIn()
+ else
+ zoomOut()
+ }, [])
+
+ const handleMouseDown = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
+ if (scale > 1) {
+ setIsDragging(true)
+ dragStartRef.current = { x: e.clientX - position.x, y: e.clientY - position.y }
+ }
+ }, [scale, position])
+
+ const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
+ if (isDragging && scale > 1) {
+ const deltaX = e.clientX - dragStartRef.current.x
+ const deltaY = e.clientY - dragStartRef.current.y
+
+ // Calculate boundaries
+ const imgRect = imgRef.current?.getBoundingClientRect()
+ const containerRect = imgRef.current?.parentElement?.getBoundingClientRect()
+
+ if (imgRect && containerRect) {
+ const maxX = (imgRect.width * scale - containerRect.width) / 2
+ const maxY = (imgRect.height * scale - containerRect.height) / 2
+
+ setPosition({
+ x: Math.max(-maxX, Math.min(maxX, deltaX)),
+ y: Math.max(-maxY, Math.min(maxY, deltaY)),
+ })
+ }
+ }
+ }, [isDragging, scale])
+
+ const handleMouseUp = useCallback(() => {
+ setIsDragging(false)
+ }, [])
+
+ useEffect(() => {
+ document.addEventListener('mouseup', handleMouseUp)
+ return () => {
+ document.removeEventListener('mouseup', handleMouseUp)
+ }
+ }, [handleMouseUp])
+
+ useHotkeys('esc', onCancel)
+ useHotkeys('up', zoomIn)
+ useHotkeys('down', zoomOut)
+ useHotkeys('left', onPrev || noop)
+ useHotkeys('right', onNext || noop)
+
+ return createPortal(
+ <div className='image-preview-container fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 p-8'
+ onClick={e => e.stopPropagation()}
+ onWheel={handleWheel}
+ onMouseDown={handleMouseDown}
+ onMouseMove={handleMouseMove}
+ onMouseUp={handleMouseUp}
+ style={{ cursor: scale > 1 ? 'move' : 'default' }}
+ tabIndex={-1}>
+ { }
+ <img
+ ref={imgRef}
+ alt={title}
+ src={isBase64(url) ? `data:image/png;base64,${url}` : url}
+ className='max-h-full max-w-full'
+ style={{
+ transform: `scale(${scale}) translate(${position.x}px, ${position.y}px)`,
+ transition: isDragging ? 'none' : 'transform 0.2s ease-in-out',
+ }}
+ />
+ <Tooltip popupContent={t('common.operation.copyImage')}>
+ <div className='absolute right-48 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
+ onClick={imageCopy}>
+ {isCopied
+ ? <RiFileCopyLine className='h-4 w-4 text-green-500' />
+ : <RiFileCopyLine className='h-4 w-4 text-gray-500' />}
+ </div>
+ </Tooltip>
+ <Tooltip popupContent={t('common.operation.zoomOut')}>
+ <div className='absolute right-40 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
+ onClick={zoomOut}>
+ <RiZoomOutLine className='h-4 w-4 text-gray-500' />
+ </div>
+ </Tooltip>
+ <Tooltip popupContent={t('common.operation.zoomIn')}>
+ <div className='absolute right-32 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
+ onClick={zoomIn}>
+ <RiZoomInLine className='h-4 w-4 text-gray-500' />
+ </div>
+ </Tooltip>
+ <Tooltip popupContent={t('common.operation.download')}>
+ <div className='absolute right-24 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
+ onClick={downloadImage}>
+ <RiDownloadCloud2Line className='h-4 w-4 text-gray-500' />
+ </div>
+ </Tooltip>
+ <Tooltip popupContent={t('common.operation.openInNewTab')}>
+ <div className='absolute right-16 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
+ onClick={openInNewTab}>
+ <RiAddBoxLine className='h-4 w-4 text-gray-500' />
+ </div>
+ </Tooltip>
+ <Tooltip popupContent={t('common.operation.cancel')}>
+ <div
+ className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/8 backdrop-blur-[2px]'
+ onClick={onCancel}>
+ <RiCloseLine className='h-4 w-4 text-gray-500' />
+ </div>
+ </Tooltip>
+ </div>,
+ document.body,
+ )
+}
+
+export default ImagePreview
diff --git a/app/components/base/image-uploader/text-generation-image-uploader.tsx b/app/components/base/image-uploader/text-generation-image-uploader.tsx
new file mode 100644
index 0000000..99aef56
--- /dev/null
+++ b/app/components/base/image-uploader/text-generation-image-uploader.tsx
@@ -0,0 +1,148 @@
+import type { FC } from 'react'
+import {
+ Fragment,
+ useEffect,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import Uploader from './uploader'
+import ImageLinkInput from './image-link-input'
+import ImageList from './image-list'
+import { useImageFiles } from './hooks'
+import { ImagePlus } from '@/app/components/base/icons/src/vender/line/images'
+import { Link03 } from '@/app/components/base/icons/src/vender/line/general'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import type { ImageFile, VisionSettings } from '@/types/app'
+import { TransferMethod } from '@/types/app'
+
+type PasteImageLinkButtonProps = {
+ onUpload: (imageFile: ImageFile) => void
+ disabled?: boolean
+}
+const PasteImageLinkButton: FC<PasteImageLinkButtonProps> = ({
+ onUpload,
+ disabled,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ const handleUpload = (imageFile: ImageFile) => {
+ setOpen(false)
+ onUpload(imageFile)
+ }
+
+ const handleToggle = () => {
+ if (disabled)
+ return
+
+ setOpen(v => !v)
+ }
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='top-start'
+ >
+ <PortalToFollowElemTrigger onClick={handleToggle}>
+ <div className={`
+ relative flex h-8 items-center justify-center rounded-lg bg-components-button-tertiary-bg px-3 text-xs text-text-tertiary hover:bg-components-button-tertiary-bg-hover
+ ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}
+ `}>
+ <Link03 className='mr-2 h-4 w-4' />
+ {t('common.imageUploader.pasteImageLink')}
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-10'>
+ <div className='w-[320px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg p-2 shadow-lg'>
+ <ImageLinkInput onUpload={handleUpload} />
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+type TextGenerationImageUploaderProps = {
+ settings: VisionSettings
+ onFilesChange: (files: ImageFile[]) => void
+}
+const TextGenerationImageUploader: FC<TextGenerationImageUploaderProps> = ({
+ settings,
+ onFilesChange,
+}) => {
+ const { t } = useTranslation()
+
+ const {
+ files,
+ onUpload,
+ onRemove,
+ onImageLinkLoadError,
+ onImageLinkLoadSuccess,
+ onReUpload,
+ } = useImageFiles()
+
+ useEffect(() => {
+ onFilesChange(files)
+ }, [files])
+
+ const localUpload = (
+ <Uploader
+ onUpload={onUpload}
+ disabled={files.length >= settings.number_limits}
+ limit={+settings.image_file_size_limit!}
+ >
+ {
+ hovering => (
+ <div className={`
+ flex h-8 cursor-pointer items-center justify-center rounded-lg
+ bg-components-button-tertiary-bg px-3 text-xs text-text-tertiary
+ ${hovering && 'hover:bg-components-button-tertiary-bg-hover'}
+ `}>
+ <ImagePlus className='mr-2 h-4 w-4' />
+ {t('common.imageUploader.uploadFromComputer')}
+ </div>
+ )
+ }
+ </Uploader>
+ )
+
+ const urlUpload = (
+ <PasteImageLinkButton
+ onUpload={onUpload}
+ disabled={files.length >= settings.number_limits}
+ />
+ )
+
+ return (
+ <div>
+ <div className='mb-1'>
+ <ImageList
+ list={files}
+ onRemove={onRemove}
+ onReUpload={onReUpload}
+ onImageLinkLoadError={onImageLinkLoadError}
+ onImageLinkLoadSuccess={onImageLinkLoadSuccess}
+ />
+ </div>
+ <div className={`grid gap-1 ${settings.transfer_methods.length === 2 ? 'grid-cols-2' : 'grid-cols-1'}`}>
+ {
+ settings.transfer_methods.map((method) => {
+ if (method === TransferMethod.local_file)
+ return <Fragment key={TransferMethod.local_file}>{localUpload}</Fragment>
+
+ if (method === TransferMethod.remote_url)
+ return <Fragment key={TransferMethod.remote_url}>{urlUpload}</Fragment>
+
+ return null
+ })
+ }
+ </div>
+ </div>
+ )
+}
+
+export default TextGenerationImageUploader
diff --git a/app/components/base/image-uploader/uploader.tsx b/app/components/base/image-uploader/uploader.tsx
new file mode 100644
index 0000000..2f922ec
--- /dev/null
+++ b/app/components/base/image-uploader/uploader.tsx
@@ -0,0 +1,58 @@
+import type { ChangeEvent, FC } from 'react'
+import { useState } from 'react'
+import { useLocalFileUploader } from './hooks'
+import type { ImageFile } from '@/types/app'
+import { ALLOW_FILE_EXTENSIONS } from '@/types/app'
+
+type UploaderProps = {
+ children: (hovering: boolean) => React.JSX.Element
+ onUpload: (imageFile: ImageFile) => void
+ closePopover?: () => void
+ limit?: number
+ disabled?: boolean
+}
+
+const Uploader: FC<UploaderProps> = ({
+ children,
+ onUpload,
+ closePopover,
+ limit,
+ disabled,
+}) => {
+ const [hovering, setHovering] = useState(false)
+ const { handleLocalFileUpload } = useLocalFileUploader({
+ limit,
+ onUpload,
+ disabled,
+ })
+
+ const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
+ const file = e.target.files?.[0]
+
+ if (!file)
+ return
+
+ handleLocalFileUpload(file)
+ closePopover?.()
+ }
+
+ return (
+ <div
+ className='relative'
+ onMouseEnter={() => setHovering(true)}
+ onMouseLeave={() => setHovering(false)}
+ >
+ {children(hovering)}
+ <input
+ className='absolute inset-0 block w-full cursor-pointer text-[0] opacity-0 disabled:cursor-not-allowed'
+ onClick={e => ((e.target as HTMLInputElement).value = '')}
+ type='file'
+ accept={ALLOW_FILE_EXTENSIONS.map(ext => `.${ext}`).join(',')}
+ onChange={handleChange}
+ disabled={disabled}
+ />
+ </div>
+ )
+}
+
+export default Uploader
diff --git a/app/components/base/image-uploader/utils.ts b/app/components/base/image-uploader/utils.ts
new file mode 100644
index 0000000..0c1ada7
--- /dev/null
+++ b/app/components/base/image-uploader/utils.ts
@@ -0,0 +1,36 @@
+import { upload } from '@/service/base'
+
+type ImageUploadParams = {
+ file: File
+ onProgressCallback: (progress: number) => void
+ onSuccessCallback: (res: { id: string }) => void
+ onErrorCallback: () => void
+}
+type ImageUpload = (v: ImageUploadParams, isPublic?: boolean, url?: string) => void
+export const imageUpload: ImageUpload = ({
+ file,
+ onProgressCallback,
+ onSuccessCallback,
+ onErrorCallback,
+}, isPublic, url) => {
+ const formData = new FormData()
+ formData.append('file', file)
+ const onProgress = (e: ProgressEvent) => {
+ if (e.lengthComputable) {
+ const percent = Math.floor(e.loaded / e.total * 100)
+ onProgressCallback(percent)
+ }
+ }
+
+ upload({
+ xhr: new XMLHttpRequest(),
+ data: formData,
+ onprogress: onProgress,
+ }, isPublic, url)
+ .then((res: { id: string }) => {
+ onSuccessCallback(res)
+ })
+ .catch(() => {
+ onErrorCallback()
+ })
+}
diff --git a/app/components/base/image-uploader/video-preview.tsx b/app/components/base/image-uploader/video-preview.tsx
new file mode 100644
index 0000000..09ca3d8
--- /dev/null
+++ b/app/components/base/image-uploader/video-preview.tsx
@@ -0,0 +1,37 @@
+import type { FC } from 'react'
+import { createPortal } from 'react-dom'
+import { RiCloseLine } from '@remixicon/react'
+
+type VideoPreviewProps = {
+ url: string
+ title: string
+ onCancel: () => void
+}
+const VideoPreview: FC<VideoPreviewProps> = ({
+ url,
+ title,
+ onCancel,
+}) => {
+ return createPortal(
+ <div className='fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 p-8' onClick={e => e.stopPropagation()}>
+ <div>
+ <video controls title={title} autoPlay={false} preload="metadata">
+ <source
+ type="video/mp4"
+ src={url}
+ className='max-h-full max-w-full'
+ />
+ </video>
+ </div>
+ <div
+ className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/[0.08] backdrop-blur-[2px]'
+ onClick={onCancel}
+ >
+ <RiCloseLine className='h-4 w-4 text-gray-500'/>
+ </div>
+ </div>,
+ document.body,
+ )
+}
+
+export default VideoPreview
diff --git a/app/components/base/input-number/index.spec.tsx b/app/components/base/input-number/index.spec.tsx
new file mode 100644
index 0000000..8dfd118
--- /dev/null
+++ b/app/components/base/input-number/index.spec.tsx
@@ -0,0 +1,97 @@
+import { fireEvent, render, screen } from '@testing-library/react'
+import { InputNumber } from './index'
+
+jest.mock('react-i18next', () => ({
+ useTranslation: () => ({
+ t: (key: string) => key,
+ }),
+}))
+
+describe('InputNumber Component', () => {
+ const defaultProps = {
+ onChange: jest.fn(),
+ }
+
+ afterEach(() => {
+ jest.clearAllMocks()
+ })
+
+ it('renders input with default values', () => {
+ render(<InputNumber {...defaultProps} />)
+ const input = screen.getByRole('textbox')
+ expect(input).toBeInTheDocument()
+ })
+
+ it('handles increment button click', () => {
+ render(<InputNumber {...defaultProps} value={5} />)
+ const incrementBtn = screen.getByRole('button', { name: /increment/i })
+
+ fireEvent.click(incrementBtn)
+ expect(defaultProps.onChange).toHaveBeenCalledWith(6)
+ })
+
+ it('handles decrement button click', () => {
+ render(<InputNumber {...defaultProps} value={5} />)
+ const decrementBtn = screen.getByRole('button', { name: /decrement/i })
+
+ fireEvent.click(decrementBtn)
+ expect(defaultProps.onChange).toHaveBeenCalledWith(4)
+ })
+
+ it('respects max value constraint', () => {
+ render(<InputNumber {...defaultProps} value={10} max={10} />)
+ const incrementBtn = screen.getByRole('button', { name: /increment/i })
+
+ fireEvent.click(incrementBtn)
+ expect(defaultProps.onChange).not.toHaveBeenCalled()
+ })
+
+ it('respects min value constraint', () => {
+ render(<InputNumber {...defaultProps} value={0} min={0} />)
+ const decrementBtn = screen.getByRole('button', { name: /decrement/i })
+
+ fireEvent.click(decrementBtn)
+ expect(defaultProps.onChange).not.toHaveBeenCalled()
+ })
+
+ it('handles direct input changes', () => {
+ render(<InputNumber {...defaultProps} />)
+ const input = screen.getByRole('textbox')
+
+ fireEvent.change(input, { target: { value: '42' } })
+ expect(defaultProps.onChange).toHaveBeenCalledWith(42)
+ })
+
+ it('handles empty input', () => {
+ render(<InputNumber {...defaultProps} value={0} />)
+ const input = screen.getByRole('textbox')
+
+ fireEvent.change(input, { target: { value: '' } })
+ expect(defaultProps.onChange).toHaveBeenCalledWith(undefined)
+ })
+
+ it('handles invalid input', () => {
+ render(<InputNumber {...defaultProps} />)
+ const input = screen.getByRole('textbox')
+
+ fireEvent.change(input, { target: { value: 'abc' } })
+ expect(defaultProps.onChange).not.toHaveBeenCalled()
+ })
+
+ it('displays unit when provided', () => {
+ const unit = 'px'
+ render(<InputNumber {...defaultProps} unit={unit} />)
+ expect(screen.getByText(unit)).toBeInTheDocument()
+ })
+
+ it('disables controls when disabled prop is true', () => {
+ render(<InputNumber {...defaultProps} disabled />)
+ const input = screen.getByRole('textbox')
+ const incrementBtn = screen.getByRole('button', { name: /increment/i })
+ const decrementBtn = screen.getByRole('button', { name: /decrement/i })
+
+ expect(input).toBeDisabled()
+ expect(incrementBtn).toBeDisabled()
+ expect(decrementBtn).toBeDisabled()
+ })
+})
diff --git a/app/components/base/input-number/index.tsx b/app/components/base/input-number/index.tsx
new file mode 100644
index 0000000..98efc94
--- /dev/null
+++ b/app/components/base/input-number/index.tsx
@@ -0,0 +1,114 @@
+import type { FC } from 'react'
+import { RiArrowDownSLine, RiArrowUpSLine } from '@remixicon/react'
+import Input, { type InputProps } from '../input'
+import classNames from '@/utils/classnames'
+
+export type InputNumberProps = {
+ unit?: string
+ value?: number
+ onChange: (value?: number) => void
+ amount?: number
+ size?: 'regular' | 'large'
+ max?: number
+ min?: number
+ defaultValue?: number
+ disabled?: boolean
+ wrapClassName?: string
+ controlWrapClassName?: string
+ controlClassName?: string
+} & Omit<InputProps, 'value' | 'onChange' | 'size' | 'min' | 'max' | 'defaultValue'>
+
+export const InputNumber: FC<InputNumberProps> = (props) => {
+ const { unit, className, onChange, amount = 1, value, size = 'regular', max, min, defaultValue, wrapClassName, controlWrapClassName, controlClassName, disabled, ...rest } = props
+
+ const isValidValue = (v: number) => {
+ if (typeof max === 'number' && v > max)
+ return false
+ return !(typeof min === 'number' && v < min)
+ }
+
+ const inc = () => {
+ if (disabled) return
+
+ if (value === undefined) {
+ onChange(defaultValue)
+ return
+ }
+ const newValue = value + amount
+ if (!isValidValue(newValue))
+ return
+ onChange(newValue)
+ }
+ const dec = () => {
+ if (disabled) return
+
+ if (value === undefined) {
+ onChange(defaultValue)
+ return
+ }
+ const newValue = value - amount
+ if (!isValidValue(newValue))
+ return
+ onChange(newValue)
+ }
+
+ return <div className={classNames('flex', wrapClassName)}>
+ <Input {...rest}
+ // disable default controller
+ type='text'
+ className={classNames('rounded-r-none', className)}
+ value={value}
+ max={max}
+ min={min}
+ disabled={disabled}
+ onChange={(e) => {
+ if (e.target.value === '')
+ onChange(undefined)
+
+ const parsed = Number(e.target.value)
+ if (Number.isNaN(parsed))
+ return
+
+ if (!isValidValue(parsed))
+ return
+ onChange(parsed)
+ }}
+ unit={unit}
+ size={size}
+ />
+ <div className={classNames(
+ 'flex flex-col bg-components-input-bg-normal rounded-r-md border-l border-divider-subtle text-text-tertiary focus:shadow-xs',
+ disabled && 'opacity-50 cursor-not-allowed',
+ controlWrapClassName)}
+ >
+ <button
+ type='button'
+ onClick={inc}
+ disabled={disabled}
+ aria-label='increment'
+ className={classNames(
+ size === 'regular' ? 'pt-1' : 'pt-1.5',
+ 'px-1.5 hover:bg-components-input-bg-hover',
+ disabled && 'cursor-not-allowed hover:bg-transparent',
+ controlClassName,
+ )}
+ >
+ <RiArrowUpSLine className='size-3' />
+ </button>
+ <button
+ type='button'
+ onClick={dec}
+ disabled={disabled}
+ aria-label='decrement'
+ className={classNames(
+ size === 'regular' ? 'pb-1' : 'pb-1.5',
+ 'px-1.5 hover:bg-components-input-bg-hover',
+ disabled && 'cursor-not-allowed hover:bg-transparent',
+ controlClassName,
+ )}
+ >
+ <RiArrowDownSLine className='size-3' />
+ </button>
+ </div>
+ </div>
+}
diff --git a/app/components/base/input/index.spec.tsx b/app/components/base/input/index.spec.tsx
new file mode 100644
index 0000000..12dd9bc
--- /dev/null
+++ b/app/components/base/input/index.spec.tsx
@@ -0,0 +1,124 @@
+import React from 'react'
+import { fireEvent, render, screen } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import Input, { inputVariants } from './index'
+
+// Mock the i18n hook
+jest.mock('react-i18next', () => ({
+ useTranslation: () => ({
+ t: (key: string) => {
+ const translations: Record<string, string> = {
+ 'common.operation.search': 'Search',
+ 'common.placeholder.input': 'Please input',
+ }
+ return translations[key] || ''
+ },
+ }),
+}))
+
+describe('Input component', () => {
+ describe('Variants', () => {
+ it('should return correct classes for regular size', () => {
+ const result = inputVariants({ size: 'regular' })
+ expect(result).toContain('px-3')
+ expect(result).toContain('radius-md')
+ expect(result).toContain('system-sm-regular')
+ })
+
+ it('should return correct classes for large size', () => {
+ const result = inputVariants({ size: 'large' })
+ expect(result).toContain('px-4')
+ expect(result).toContain('radius-lg')
+ expect(result).toContain('system-md-regular')
+ })
+
+ it('should use regular size as default', () => {
+ const result = inputVariants({})
+ expect(result).toContain('px-3')
+ expect(result).toContain('radius-md')
+ expect(result).toContain('system-sm-regular')
+ })
+ })
+
+ it('renders correctly with default props', () => {
+ render(<Input />)
+ const input = screen.getByPlaceholderText('Please input')
+ expect(input).toBeInTheDocument()
+ expect(input).not.toBeDisabled()
+ expect(input).not.toHaveClass('cursor-not-allowed')
+ })
+
+ it('shows left icon when showLeftIcon is true', () => {
+ render(<Input showLeftIcon />)
+ const searchIcon = document.querySelector('svg')
+ expect(searchIcon).toBeInTheDocument()
+ const input = screen.getByPlaceholderText('Search')
+ expect(input).toHaveClass('pl-[26px]')
+ })
+
+ it('shows clear icon when showClearIcon is true and has value', () => {
+ render(<Input showClearIcon value="test" />)
+ const clearIcon = document.querySelector('.group svg')
+ expect(clearIcon).toBeInTheDocument()
+ const input = screen.getByDisplayValue('test')
+ expect(input).toHaveClass('pr-[26px]')
+ })
+
+ it('does not show clear icon when disabled, even with value', () => {
+ render(<Input showClearIcon value="test" disabled />)
+ const clearIcon = document.querySelector('.group svg')
+ expect(clearIcon).not.toBeInTheDocument()
+ })
+
+ it('calls onClear when clear icon is clicked', () => {
+ const onClear = jest.fn()
+ render(<Input showClearIcon value="test" onClear={onClear} />)
+ const clearIconContainer = document.querySelector('.group')
+ fireEvent.click(clearIconContainer!)
+ expect(onClear).toHaveBeenCalledTimes(1)
+ })
+
+ it('shows warning icon when destructive is true', () => {
+ render(<Input destructive />)
+ const warningIcon = document.querySelector('svg')
+ expect(warningIcon).toBeInTheDocument()
+ const input = screen.getByPlaceholderText('Please input')
+ expect(input).toHaveClass('border-components-input-border-destructive')
+ })
+
+ it('applies disabled styles when disabled', () => {
+ render(<Input disabled />)
+ const input = screen.getByPlaceholderText('Please input')
+ expect(input).toBeDisabled()
+ expect(input).toHaveClass('cursor-not-allowed')
+ expect(input).toHaveClass('bg-components-input-bg-disabled')
+ })
+
+ it('displays custom unit when provided', () => {
+ render(<Input unit="km" />)
+ const unitElement = screen.getByText('km')
+ expect(unitElement).toBeInTheDocument()
+ })
+
+ it('applies custom className and style', () => {
+ const customClass = 'test-class'
+ const customStyle = { color: 'red' }
+ render(<Input className={customClass} styleCss={customStyle} />)
+ const input = screen.getByPlaceholderText('Please input')
+ expect(input).toHaveClass(customClass)
+ expect(input).toHaveStyle('color: red')
+ })
+
+ it('applies large size variant correctly', () => {
+ render(<Input size={'large' as any} />)
+ const input = screen.getByPlaceholderText('Please input')
+ expect(input.className).toContain(inputVariants({ size: 'large' }))
+ })
+
+ it('uses custom placeholder when provided', () => {
+ const placeholder = 'Custom placeholder'
+ render(<Input placeholder={placeholder} />)
+ const input = screen.getByPlaceholderText(placeholder)
+ expect(input).toBeInTheDocument()
+ })
+})
diff --git a/app/components/base/input/index.tsx b/app/components/base/input/index.tsx
new file mode 100644
index 0000000..30fd90a
--- /dev/null
+++ b/app/components/base/input/index.tsx
@@ -0,0 +1,97 @@
+import type { CSSProperties } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseCircleFill, RiErrorWarningLine, RiSearchLine } from '@remixicon/react'
+import { type VariantProps, cva } from 'class-variance-authority'
+import cn from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+export const inputVariants = cva(
+ '',
+ {
+ variants: {
+ size: {
+ regular: 'px-3 radius-md system-sm-regular',
+ large: 'px-4 radius-lg system-md-regular',
+ },
+ },
+ defaultVariants: {
+ size: 'regular',
+ },
+ },
+)
+
+export type InputProps = {
+ showLeftIcon?: boolean
+ showClearIcon?: boolean
+ onClear?: () => void
+ disabled?: boolean
+ destructive?: boolean
+ wrapperClassName?: string
+ styleCss?: CSSProperties
+ unit?: string
+} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & VariantProps<typeof inputVariants>
+
+const Input = ({
+ size,
+ disabled,
+ destructive,
+ showLeftIcon,
+ showClearIcon,
+ onClear,
+ wrapperClassName,
+ className,
+ styleCss,
+ value,
+ placeholder,
+ onChange = noop,
+ unit,
+ ...props
+}: InputProps) => {
+ const { t } = useTranslation()
+ return (
+ <div className={cn('relative w-full', wrapperClassName)}>
+ {showLeftIcon && <RiSearchLine className={cn('absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-components-input-text-placeholder')} />}
+ <input
+ style={styleCss}
+ className={cn(
+ 'w-full appearance-none border border-transparent bg-components-input-bg-normal py-[7px] text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs',
+ inputVariants({ size }),
+ showLeftIcon && 'pl-[26px]',
+ showLeftIcon && size === 'large' && 'pl-7',
+ showClearIcon && value && 'pr-[26px]',
+ showClearIcon && value && size === 'large' && 'pr-7',
+ destructive && 'pr-[26px]',
+ destructive && size === 'large' && 'pr-7',
+ disabled && 'cursor-not-allowed border-transparent bg-components-input-bg-disabled text-components-input-text-filled-disabled hover:border-transparent hover:bg-components-input-bg-disabled',
+ destructive && 'border-components-input-border-destructive bg-components-input-bg-destructive text-components-input-text-filled hover:border-components-input-border-destructive hover:bg-components-input-bg-destructive focus:border-components-input-border-destructive focus:bg-components-input-bg-destructive',
+ className,
+ )}
+ placeholder={placeholder ?? (showLeftIcon
+ ? (t('common.operation.search') || '')
+ : (t('common.placeholder.input') || ''))}
+ value={value}
+ onChange={onChange}
+ disabled={disabled}
+ {...props}
+ />
+ {showClearIcon && value && !disabled && !destructive && (
+ <div className={cn('group absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer p-[1px]')} onClick={onClear}>
+ <RiCloseCircleFill className='h-3.5 w-3.5 cursor-pointer text-text-quaternary group-hover:text-text-tertiary' />
+ </div>
+ )}
+ {destructive && (
+ <RiErrorWarningLine className='absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 text-text-destructive-secondary' />
+ )}
+ {
+ unit && (
+ <div className='system-sm-regular absolute right-2 top-1/2 -translate-y-1/2 text-text-tertiary'>
+ {unit}
+ </div>
+ )
+ }
+ </div>
+ )
+}
+
+export default Input
diff --git a/app/components/base/install-button/index.tsx b/app/components/base/install-button/index.tsx
new file mode 100644
index 0000000..0d9e953
--- /dev/null
+++ b/app/components/base/install-button/index.tsx
@@ -0,0 +1,27 @@
+import Button from '../button'
+import { RiInstallLine, RiLoader2Line } from '@remixicon/react'
+
+type InstallButtonProps = {
+ loading: boolean
+ onInstall: (e: React.MouseEvent) => void
+ t: any
+}
+
+const InstallButton = ({ loading, onInstall, t }: InstallButtonProps) => {
+ return (
+ <Button size='small' className='z-[100]' onClick={onInstall}>
+ <div className={`flex items-center justify-center gap-1 px-[3px]
+ ${loading ? 'text-components-button-secondary-text-disabled' : 'text-components-button-secondary-text'}
+ system-xs-medium`}
+ >
+ {loading ? t('workflow.nodes.agent.pluginInstaller.installing') : t('workflow.nodes.agent.pluginInstaller.install')}
+ </div>
+ {loading
+ ? <RiLoader2Line className='h-3.5 w-3.5 animate-spin text-text-quaternary' />
+ : <RiInstallLine className='h-3.5 w-3.5 text-text-secondary' />
+ }
+ </Button>
+ )
+}
+
+export default InstallButton
diff --git a/app/components/base/linked-apps-panel/index.tsx b/app/components/base/linked-apps-panel/index.tsx
new file mode 100644
index 0000000..4ee67c5
--- /dev/null
+++ b/app/components/base/linked-apps-panel/index.tsx
@@ -0,0 +1,62 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import Link from 'next/link'
+import { useTranslation } from 'react-i18next'
+import { RiArrowRightUpLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import AppIcon from '@/app/components/base/app-icon'
+import type { RelatedApp } from '@/models/datasets'
+
+type ILikedItemProps = {
+ appStatus?: boolean
+ detail: RelatedApp
+ isMobile: boolean
+}
+
+const appTypeMap = {
+ 'chat': 'Chatbot',
+ 'completion': 'Completion',
+ 'agent-chat': 'Agent',
+ 'advanced-chat': 'Chatflow',
+ 'workflow': 'Workflow',
+}
+
+const LikedItem = ({
+ detail,
+ isMobile,
+}: ILikedItemProps) => {
+ return (
+ <Link className={cn('group/link-item flex h-8 w-full cursor-pointer items-center justify-between rounded-lg px-2 hover:bg-state-base-hover', isMobile && 'justify-center')} href={`/app/${detail?.id}/overview`}>
+ <div className='flex items-center'>
+ <div className={cn('relative h-6 w-6 rounded-md')}>
+ <AppIcon size='tiny' iconType={detail.icon_type} icon={detail.icon} background={detail.icon_background} imageUrl={detail.icon_url} />
+ </div>
+ {!isMobile && <div className={cn(' system-sm-medium ml-2 truncate text-text-primary')}>{detail?.name || '--'}</div>}
+ </div>
+ <div className='system-2xs-medium-uppercase shrink-0 text-text-tertiary group-hover/link-item:hidden'>{appTypeMap[detail.mode]}</div>
+ <RiArrowRightUpLine className='hidden h-4 w-4 text-text-tertiary group-hover/link-item:block' />
+ </Link>
+ )
+}
+
+type Props = {
+ relatedApps: RelatedApp[]
+ isMobile: boolean
+}
+
+const LinkedAppsPanel: FC<Props> = ({
+ relatedApps,
+ isMobile,
+}) => {
+ const { t } = useTranslation()
+ return (
+ <div className='w-[320px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-[5px]'>
+ <div className='system-xs-medium-uppercase mb-0.5 mt-1 pl-2 text-text-tertiary'>{relatedApps.length || '--'} {t('common.datasetMenus.relatedApp')}</div>
+ {relatedApps.map((item, index) => (
+ <LikedItem key={index} detail={item} isMobile={isMobile} />
+ ))}
+ </div>
+ )
+}
+export default React.memo(LinkedAppsPanel)
diff --git a/app/components/base/list-empty/horizontal-line.tsx b/app/components/base/list-empty/horizontal-line.tsx
new file mode 100644
index 0000000..cb8edb8
--- /dev/null
+++ b/app/components/base/list-empty/horizontal-line.tsx
@@ -0,0 +1,21 @@
+type HorizontalLineProps = {
+ className?: string
+}
+const HorizontalLine = ({
+ className,
+}: HorizontalLineProps) => {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" width="240" height="2" viewBox="0 0 240 2" fill="none" className={className}>
+ <path d="M0 1H240" stroke="url(#paint0_linear_8619_59125)"/>
+ <defs>
+ <linearGradient id="paint0_linear_8619_59125" x1="240" y1="9.99584" x2="3.95539e-05" y2="9.88094" gradientUnits="userSpaceOnUse">
+ <stop stopColor="white" stopOpacity="0.01"/>
+ <stop offset="0.9031" stopColor="#101828" stopOpacity="0.04"/>
+ <stop offset="1" stopColor="white" stopOpacity="0.01"/>
+ </linearGradient>
+ </defs>
+ </svg>
+ )
+}
+
+export default HorizontalLine
diff --git a/app/components/base/list-empty/index.tsx b/app/components/base/list-empty/index.tsx
new file mode 100644
index 0000000..db3eaff
--- /dev/null
+++ b/app/components/base/list-empty/index.tsx
@@ -0,0 +1,38 @@
+import type { ReactNode } from 'react'
+import React from 'react'
+import { Variable02 } from '../icons/src/vender/solid/development'
+import VerticalLine from './vertical-line'
+import HorizontalLine from './horizontal-line'
+
+type ListEmptyProps = {
+ title?: string
+ description?: ReactNode
+ icon?: ReactNode
+}
+
+const ListEmpty = ({
+ title,
+ description,
+ icon,
+}: ListEmptyProps) => {
+ return (
+ <div className='flex w-[320px] flex-col items-start gap-2 rounded-[10px] bg-workflow-process-bg p-4'>
+ <div className='flex h-10 w-10 items-center justify-center gap-2 rounded-[10px]'>
+ <div className='relative flex grow items-center justify-center gap-2 self-stretch rounded-[10px] border-[0.5px]
+ border-components-card-border bg-components-card-bg p-1 shadow-lg'>
+ {icon || <Variable02 className='h-5 w-5 shrink-0 text-text-accent' />}
+ <VerticalLine className='absolute -right-[1px] top-1/2 -translate-y-1/4'/>
+ <VerticalLine className='absolute -left-[1px] top-1/2 -translate-y-1/4'/>
+ <HorizontalLine className='absolute left-3/4 top-0 -translate-x-1/4 -translate-y-1/2'/>
+ <HorizontalLine className='absolute left-3/4 top-full -translate-x-1/4 -translate-y-1/2' />
+ </div>
+ </div>
+ <div className='flex flex-col items-start gap-1 self-stretch'>
+ <div className='system-sm-medium text-text-secondary'>{title}</div>
+ {description}
+ </div>
+ </div>
+ )
+}
+
+export default ListEmpty
diff --git a/app/components/base/list-empty/vertical-line.tsx b/app/components/base/list-empty/vertical-line.tsx
new file mode 100644
index 0000000..63e5744
--- /dev/null
+++ b/app/components/base/list-empty/vertical-line.tsx
@@ -0,0 +1,21 @@
+type VerticalLineProps = {
+ className?: string
+}
+const VerticalLine = ({
+ className,
+}: VerticalLineProps) => {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" width="2" height="132" viewBox="0 0 2 132" fill="none" className={className}>
+ <path d="M1 0L1 132" stroke="url(#paint0_linear_8619_59128)"/>
+ <defs>
+ <linearGradient id="paint0_linear_8619_59128" x1="-7.99584" y1="132" x2="-7.96108" y2="6.4974e-07" gradientUnits="userSpaceOnUse">
+ <stop stopColor="white" stopOpacity="0.01"/>
+ <stop offset="0.877606" stopColor="#101828" stopOpacity="0.04"/>
+ <stop offset="1" stopColor="white" stopOpacity="0.01"/>
+ </linearGradient>
+ </defs>
+ </svg>
+ )
+}
+
+export default VerticalLine
diff --git a/app/components/base/loading/index.spec.tsx b/app/components/base/loading/index.spec.tsx
new file mode 100644
index 0000000..03e2cfb
--- /dev/null
+++ b/app/components/base/loading/index.spec.tsx
@@ -0,0 +1,29 @@
+import React from 'react'
+import { render } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import Loading from './index'
+
+describe('Loading Component', () => {
+ it('renders correctly with default props', () => {
+ const { container } = render(<Loading />)
+ expect(container.firstChild).toHaveClass('flex w-full items-center justify-center')
+ expect(container.firstChild).not.toHaveClass('h-full')
+ })
+
+ it('renders correctly with area type', () => {
+ const { container } = render(<Loading type="area" />)
+ expect(container.firstChild).not.toHaveClass('h-full')
+ })
+
+ it('renders correctly with app type', () => {
+ const { container } = render(<Loading type='app' />)
+ expect(container.firstChild).toHaveClass('h-full')
+ })
+
+ it('contains SVG with spin-animation class', () => {
+ const { container } = render(<Loading />)
+
+ const svgElement = container.querySelector('svg')
+ expect(svgElement).toHaveClass('spin-animation')
+ })
+})
diff --git a/app/components/base/loading/index.tsx b/app/components/base/loading/index.tsx
new file mode 100644
index 0000000..2ae3310
--- /dev/null
+++ b/app/components/base/loading/index.tsx
@@ -0,0 +1,29 @@
+import React from 'react'
+
+import './style.css'
+type ILoadingProps = {
+ type?: 'area' | 'app'
+}
+const Loading = (
+ { type = 'area' }: ILoadingProps = { type: 'area' },
+) => {
+ return (
+ <div className={`flex w-full items-center justify-center ${type === 'app' ? 'h-full' : ''}`}>
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className='spin-animation'>
+ <g clipPath="url(#clip0_324_2488)">
+ <path d="M15 0H10C9.44772 0 9 0.447715 9 1V6C9 6.55228 9.44772 7 10 7H15C15.5523 7 16 6.55228 16 6V1C16 0.447715 15.5523 0 15 0Z" fill="#1C64F2" />
+ <path opacity="0.5" d="M15 9H10C9.44772 9 9 9.44772 9 10V15C9 15.5523 9.44772 16 10 16H15C15.5523 16 16 15.5523 16 15V10C16 9.44772 15.5523 9 15 9Z" fill="#1C64F2" />
+ <path opacity="0.1" d="M6 9H1C0.447715 9 0 9.44772 0 10V15C0 15.5523 0.447715 16 1 16H6C6.55228 16 7 15.5523 7 15V10C7 9.44772 6.55228 9 6 9Z" fill="#1C64F2" />
+ <path opacity="0.2" d="M6 0H1C0.447715 0 0 0.447715 0 1V6C0 6.55228 0.447715 7 1 7H6C6.55228 7 7 6.55228 7 6V1C7 0.447715 6.55228 0 6 0Z" fill="#1C64F2" />
+ </g>
+ <defs>
+ <clipPath id="clip0_324_2488">
+ <rect width="16" height="16" fill="white" />
+ </clipPath>
+ </defs>
+ </svg>
+
+ </div>
+ )
+}
+export default Loading
diff --git a/app/components/base/loading/style.css b/app/components/base/loading/style.css
new file mode 100644
index 0000000..276654a
--- /dev/null
+++ b/app/components/base/loading/style.css
@@ -0,0 +1,41 @@
+.spin-animation path {
+ animation: custom 2s linear infinite;
+}
+
+@keyframes custom {
+ 0% {
+ opacity: 0;
+ }
+
+ 25% {
+ opacity: 0.1;
+ }
+
+ 50% {
+ opacity: 0.2;
+ }
+
+ 75% {
+ opacity: 0.5;
+ }
+
+ 100% {
+ opacity: 1;
+ }
+}
+
+.spin-animation path:nth-child(1) {
+ animation-delay: 0s;
+}
+
+.spin-animation path:nth-child(2) {
+ animation-delay: 0.5s;
+}
+
+.spin-animation path:nth-child(3) {
+ animation-delay: 1s;
+}
+
+.spin-animation path:nth-child(4) {
+ animation-delay: 2s;
+}
diff --git a/app/components/base/logo/dify-logo.tsx b/app/components/base/logo/dify-logo.tsx
new file mode 100644
index 0000000..ce59ba7
--- /dev/null
+++ b/app/components/base/logo/dify-logo.tsx
@@ -0,0 +1,45 @@
+'use client'
+import type { FC } from 'react'
+import { WEB_PREFIX } from '@/config'
+import classNames from '@/utils/classnames'
+import useTheme from '@/hooks/use-theme'
+
+export type LogoStyle = 'default' | 'monochromeWhite'
+
+export const logoPathMap: Record<LogoStyle, string> = {
+ default: '/logo/logo.svg',
+ monochromeWhite: '/logo/logo-monochrome-white.svg',
+}
+
+export type LogoSize = 'large' | 'medium' | 'small'
+
+export const logoSizeMap: Record<LogoSize, string> = {
+ large: 'w-16 h-7',
+ medium: 'w-12 h-[22px]',
+ small: 'w-9 h-4',
+}
+
+type DifyLogoProps = {
+ style?: LogoStyle
+ size?: LogoSize
+ className?: string
+}
+
+const DifyLogo: FC<DifyLogoProps> = ({
+ style = 'default',
+ size = 'medium',
+ className,
+}) => {
+ const { theme } = useTheme()
+ const themedStyle = (theme === 'dark' && style === 'default') ? 'monochromeWhite' : style
+
+ return (
+ <img
+ src={`${WEB_PREFIX}${logoPathMap[themedStyle]}`}
+ className={classNames('block object-contain', logoSizeMap[size], className)}
+ alt='Dify logo'
+ />
+ )
+}
+
+export default DifyLogo
diff --git a/app/components/base/logo/logo-embedded-chat-avatar.tsx b/app/components/base/logo/logo-embedded-chat-avatar.tsx
new file mode 100644
index 0000000..170a23b
--- /dev/null
+++ b/app/components/base/logo/logo-embedded-chat-avatar.tsx
@@ -0,0 +1,19 @@
+import type { FC } from 'react'
+import { WEB_PREFIX } from '@/config'
+
+type LogoEmbeddedChatAvatarProps = {
+ className?: string
+}
+const LogoEmbeddedChatAvatar: FC<LogoEmbeddedChatAvatarProps> = ({
+ className,
+}) => {
+ return (
+ <img
+ src={`${WEB_PREFIX}/logo/logo-embedded-chat-avatar.png`}
+ className={`block h-10 w-10 ${className}`}
+ alt='logo'
+ />
+ )
+}
+
+export default LogoEmbeddedChatAvatar
diff --git a/app/components/base/logo/logo-embedded-chat-header.tsx b/app/components/base/logo/logo-embedded-chat-header.tsx
new file mode 100644
index 0000000..012b659
--- /dev/null
+++ b/app/components/base/logo/logo-embedded-chat-header.tsx
@@ -0,0 +1,24 @@
+import classNames from '@/utils/classnames'
+import type { FC } from 'react'
+import { WEB_PREFIX } from '@/config'
+
+type LogoEmbeddedChatHeaderProps = {
+ className?: string
+}
+
+const LogoEmbeddedChatHeader: FC<LogoEmbeddedChatHeaderProps> = ({
+ className,
+}) => {
+ return <picture>
+ <source media="(resolution: 1x)" srcSet='/logo/logo-embedded-chat-header.png' />
+ <source media="(resolution: 2x)" srcSet='/logo/logo-embedded-chat-header@2x.png' />
+ <source media="(resolution: 3x)" srcSet='/logo/logo-embedded-chat-header@3x.png' />
+ <img
+ src={`${WEB_PREFIX}/logo/logo-embedded-chat-header.png`}
+ alt='logo'
+ className={classNames('block h-6 w-auto', className)}
+ />
+ </picture>
+}
+
+export default LogoEmbeddedChatHeader
diff --git a/app/components/base/markdown-blocks/button.tsx b/app/components/base/markdown-blocks/button.tsx
new file mode 100644
index 0000000..81a3f30
--- /dev/null
+++ b/app/components/base/markdown-blocks/button.tsx
@@ -0,0 +1,39 @@
+import { useChatContext } from '@/app/components/base/chat/chat/context'
+import Button from '@/app/components/base/button'
+import cn from '@/utils/classnames'
+
+const MarkdownButton = ({ node }: any) => {
+ const { onSend } = useChatContext()
+ const variant = node.properties.dataVariant
+ const message = node.properties.dataMessage
+ const link = node.properties.dataLink
+ const size = node.properties.dataSize
+
+ function is_valid_url(url: string): boolean {
+ try {
+ const parsed_url = new URL(url)
+ return ['http:', 'https:'].includes(parsed_url.protocol)
+ }
+ catch {
+ return false
+ }
+ }
+
+ return <Button
+ variant={variant}
+ size={size}
+ className={cn('!h-auto min-h-8 select-none whitespace-normal !px-3')}
+ onClick={() => {
+ if (is_valid_url(link)) {
+ window.open(link, '_blank')
+ return
+ }
+ onSend?.(message)
+ }}
+ >
+ <span className='text-[13px]'>{node.children[0]?.value || ''}</span>
+ </Button>
+}
+MarkdownButton.displayName = 'MarkdownButton'
+
+export default MarkdownButton
diff --git a/app/components/base/markdown-blocks/form.tsx b/app/components/base/markdown-blocks/form.tsx
new file mode 100644
index 0000000..ab7e7ce
--- /dev/null
+++ b/app/components/base/markdown-blocks/form.tsx
@@ -0,0 +1,238 @@
+import React, { useEffect, useState } from 'react'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import DatePicker from '@/app/components/base/date-and-time-picker/date-picker'
+import TimePicker from '@/app/components/base/date-and-time-picker/time-picker'
+import Checkbox from '@/app/components/base/checkbox'
+import Select from '@/app/components/base/select'
+import { useChatContext } from '@/app/components/base/chat/chat/context'
+
+enum DATA_FORMAT {
+ TEXT = 'text',
+ JSON = 'json',
+}
+enum SUPPORTED_TAGS {
+ LABEL = 'label',
+ INPUT = 'input',
+ TEXTAREA = 'textarea',
+ BUTTON = 'button',
+}
+enum SUPPORTED_TYPES {
+ TEXT = 'text',
+ PASSWORD = 'password',
+ EMAIL = 'email',
+ NUMBER = 'number',
+ DATE = 'date',
+ TIME = 'time',
+ DATETIME = 'datetime',
+ CHECKBOX = 'checkbox',
+ SELECT = 'select',
+}
+const MarkdownForm = ({ node }: any) => {
+ const { onSend } = useChatContext()
+
+ const [formValues, setFormValues] = useState<{ [key: string]: any }>({})
+
+ useEffect(() => {
+ const initialValues: { [key: string]: any } = {}
+ node.children.forEach((child: any) => {
+ if ([SUPPORTED_TAGS.INPUT, SUPPORTED_TAGS.TEXTAREA].includes(child.tagName))
+ initialValues[child.properties.name] = child.properties.value
+ })
+ setFormValues(initialValues)
+ }, [node.children])
+
+ const getFormValues = (children: any) => {
+ const values: { [key: string]: any } = {}
+ children.forEach((child: any) => {
+ if ([SUPPORTED_TAGS.INPUT, SUPPORTED_TAGS.TEXTAREA].includes(child.tagName))
+ values[child.properties.name] = formValues[child.properties.name]
+ })
+ return values
+ }
+
+ const onSubmit = (e: any) => {
+ e.preventDefault()
+ const format = node.properties.dataFormat || DATA_FORMAT.TEXT
+ const result = getFormValues(node.children)
+
+ if (format === DATA_FORMAT.JSON) {
+ onSend?.(JSON.stringify(result))
+ }
+ else {
+ const textResult = Object.entries(result)
+ .map(([key, value]) => `${key}: ${value}`)
+ .join('\n')
+ onSend?.(textResult)
+ }
+ }
+ return (
+ <form
+ autoComplete="off"
+ className='flex flex-col self-stretch'
+ onSubmit={(e: any) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }}
+ >
+ {node.children.filter((i: any) => i.type === 'element').map((child: any, index: number) => {
+ if (child.tagName === SUPPORTED_TAGS.LABEL) {
+ return (
+ <label
+ key={index}
+ htmlFor={child.properties.for}
+ className="system-md-semibold my-2 text-text-secondary"
+ >
+ {child.children[0]?.value || ''}
+ </label>
+ )
+ }
+ if (child.tagName === SUPPORTED_TAGS.INPUT && Object.values(SUPPORTED_TYPES).includes(child.properties.type)) {
+ if (child.properties.type === SUPPORTED_TYPES.DATE || child.properties.type === SUPPORTED_TYPES.DATETIME) {
+ return (
+ <DatePicker
+ key={index}
+ value={formValues[child.properties.name]}
+ needTimePicker={child.properties.type === SUPPORTED_TYPES.DATETIME}
+ onChange={(date) => {
+ setFormValues(prevValues => ({
+ ...prevValues,
+ [child.properties.name]: date,
+ }))
+ }}
+ onClear={() => {
+ setFormValues(prevValues => ({
+ ...prevValues,
+ [child.properties.name]: undefined,
+ }))
+ }}
+ />
+ )
+ }
+ if (child.properties.type === SUPPORTED_TYPES.TIME) {
+ return (
+ <TimePicker
+ key={index}
+ value={formValues[child.properties.name]}
+ onChange={(time) => {
+ setFormValues(prevValues => ({
+ ...prevValues,
+ [child.properties.name]: time,
+ }))
+ }}
+ onClear={() => {
+ setFormValues(prevValues => ({
+ ...prevValues,
+ [child.properties.name]: undefined,
+ }))
+ }}
+ />
+ )
+ }
+ if (child.properties.type === SUPPORTED_TYPES.CHECKBOX) {
+ return (
+ <div className='mt-2 flex h-6 items-center space-x-2' key={index}>
+ <Checkbox
+ key={index}
+ checked={formValues[child.properties.name]}
+ onCheck={() => {
+ setFormValues(prevValues => ({
+ ...prevValues,
+ [child.properties.name]: !prevValues[child.properties.name],
+ }))
+ }}
+ />
+ <span>{child.properties.dataTip || child.properties['data-tip'] || ''}</span>
+ </div>
+ )
+ }
+ if (child.properties.type === SUPPORTED_TYPES.SELECT) {
+ return (
+ <Select
+ key={index}
+ allowSearch={false}
+ className="w-full"
+ items={(() => {
+ let options = child.properties.dataOptions || child.properties['data-options'] || []
+ if (typeof options === 'string') {
+ try {
+ options = JSON.parse(options)
+ }
+ catch (e) {
+ console.error('Failed to parse options:', e)
+ options = []
+ }
+ }
+ return options.map((option: string) => ({
+ name: option,
+ value: option,
+ }))
+ })()}
+ defaultValue={formValues[child.properties.name]}
+ onSelect={(item) => {
+ setFormValues(prevValues => ({
+ ...prevValues,
+ [child.properties.name]: item.value,
+ }))
+ }}
+ />
+ )
+ }
+
+ return (
+ <Input
+ key={index}
+ type={child.properties.type}
+ name={child.properties.name}
+ placeholder={child.properties.placeholder}
+ value={formValues[child.properties.name]}
+ onChange={(e) => {
+ setFormValues(prevValues => ({
+ ...prevValues,
+ [child.properties.name]: e.target.value,
+ }))
+ }}
+ />
+ )
+ }
+ if (child.tagName === SUPPORTED_TAGS.TEXTAREA) {
+ return (
+ <Textarea
+ key={index}
+ name={child.properties.name}
+ placeholder={child.properties.placeholder}
+ value={formValues[child.properties.name]}
+ onChange={(e) => {
+ setFormValues(prevValues => ({
+ ...prevValues,
+ [child.properties.name]: e.target.value,
+ }))
+ }}
+ />
+ )
+ }
+ if (child.tagName === SUPPORTED_TAGS.BUTTON) {
+ const variant = child.properties.dataVariant
+ const size = child.properties.dataSize
+
+ return (
+ <Button
+ variant={variant}
+ size={size}
+ className='mt-4'
+ key={index}
+ onClick={onSubmit}
+ >
+ <span className='text-[13px]'>{child.children[0]?.value || ''}</span>
+ </Button>
+ )
+ }
+
+ return <p key={index}>Unsupported tag: {child.tagName}</p>
+ })}
+ </form>
+ )
+}
+MarkdownForm.displayName = 'MarkdownForm'
+export default MarkdownForm
diff --git a/app/components/base/markdown-blocks/music.tsx b/app/components/base/markdown-blocks/music.tsx
new file mode 100644
index 0000000..7edd171
--- /dev/null
+++ b/app/components/base/markdown-blocks/music.tsx
@@ -0,0 +1,37 @@
+import abcjs from 'abcjs'
+import { useEffect, useRef } from 'react'
+import 'abcjs/abcjs-audio.css'
+
+const MarkdownMusic = ({ children }: { children: React.ReactNode }) => {
+ const containerRef = useRef<HTMLDivElement>(null)
+ const controlsRef = useRef<HTMLDivElement>(null)
+
+ useEffect(() => {
+ if (containerRef.current && controlsRef.current) {
+ if (typeof children === 'string') {
+ const visualObjs = abcjs.renderAbc(containerRef.current, children, {
+ add_classes: true, // Add classes to SVG elements for cursor tracking
+ responsive: 'resize', // Make notation responsive
+ })
+ const synthControl = new abcjs.synth.SynthController()
+ synthControl.load(controlsRef.current, {}, { displayPlay: true })
+ const synth = new abcjs.synth.CreateSynth()
+ const visualObj = visualObjs[0]
+ synth.init({ visualObj }).then(() => {
+ synthControl.setTune(visualObj, false)
+ })
+ containerRef.current.style.overflow = 'auto'
+ }
+ }
+ }, [children])
+
+ return (
+ <div style={{ minWidth: '100%', overflow: 'auto' }}>
+ <div ref={containerRef} />
+ <div ref={controlsRef} />
+ </div>
+ )
+}
+MarkdownMusic.displayName = 'MarkdownMusic'
+
+export default MarkdownMusic
diff --git a/app/components/base/markdown-blocks/think-block.tsx b/app/components/base/markdown-blocks/think-block.tsx
new file mode 100644
index 0000000..565582e
--- /dev/null
+++ b/app/components/base/markdown-blocks/think-block.tsx
@@ -0,0 +1,99 @@
+import React, { useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+
+const hasEndThink = (children: any): boolean => {
+ if (typeof children === 'string')
+ return children.includes('[ENDTHINKFLAG]')
+
+ if (Array.isArray(children))
+ return children.some(child => hasEndThink(child))
+
+ if (children?.props?.children)
+ return hasEndThink(children.props.children)
+
+ return false
+}
+
+const removeEndThink = (children: any): any => {
+ if (typeof children === 'string')
+ return children.replace('[ENDTHINKFLAG]', '')
+
+ if (Array.isArray(children))
+ return children.map(child => removeEndThink(child))
+
+ if (children?.props?.children) {
+ return React.cloneElement(
+ children,
+ {
+ ...children.props,
+ children: removeEndThink(children.props.children),
+ },
+ )
+ }
+
+ return children
+}
+
+const useThinkTimer = (children: any) => {
+ const [startTime] = useState(Date.now())
+ const [elapsedTime, setElapsedTime] = useState(0)
+ const [isComplete, setIsComplete] = useState(false)
+ const timerRef = useRef<NodeJS.Timeout>()
+
+ useEffect(() => {
+ if (isComplete) return
+
+ timerRef.current = setInterval(() => {
+ setElapsedTime(Math.floor((Date.now() - startTime) / 100) / 10)
+ }, 100)
+
+ return () => {
+ if (timerRef.current)
+ clearInterval(timerRef.current)
+ }
+ }, [startTime, isComplete])
+
+ useEffect(() => {
+ if (hasEndThink(children))
+ setIsComplete(true)
+ }, [children])
+
+ return { elapsedTime, isComplete }
+}
+
+export const ThinkBlock = ({ children, ...props }: any) => {
+ const { elapsedTime, isComplete } = useThinkTimer(children)
+ const displayContent = removeEndThink(children)
+ const { t } = useTranslation()
+
+ if (!(props['data-think'] ?? false))
+ return (<details {...props}>{children}</details>)
+
+ return (
+ <details {...(!isComplete && { open: true })} className="group">
+ <summary className="flex cursor-pointer select-none list-none items-center whitespace-nowrap pl-2 font-bold text-gray-500">
+ <div className="flex shrink-0 items-center">
+ <svg
+ className="mr-2 h-3 w-3 transition-transform duration-500 group-open:rotate-90"
+ fill="none"
+ stroke="currentColor"
+ viewBox="0 0 24 24"
+ >
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ strokeWidth={2}
+ d="M9 5l7 7-7 7"
+ />
+ </svg>
+ {isComplete ? `${t('common.chat.thought')}(${elapsedTime.toFixed(1)}s)` : `${t('common.chat.thinking')}(${elapsedTime.toFixed(1)}s)`}
+ </div>
+ </summary>
+ <div className="ml-2 border-l border-gray-300 bg-gray-50 p-3 text-gray-500">
+ {displayContent}
+ </div>
+ </details>
+ )
+}
+
+export default ThinkBlock
diff --git a/app/components/base/markdown.tsx b/app/components/base/markdown.tsx
new file mode 100644
index 0000000..bc6fe0e
--- /dev/null
+++ b/app/components/base/markdown.tsx
@@ -0,0 +1,355 @@
+import ReactMarkdown from 'react-markdown'
+import ReactEcharts from 'echarts-for-react'
+import 'katex/dist/katex.min.css'
+import RemarkMath from 'remark-math'
+import RemarkBreaks from 'remark-breaks'
+import RehypeKatex from 'rehype-katex'
+import RemarkGfm from 'remark-gfm'
+import RehypeRaw from 'rehype-raw'
+import SyntaxHighlighter from 'react-syntax-highlighter'
+import {
+ atelierHeathDark,
+ atelierHeathLight,
+} from 'react-syntax-highlighter/dist/esm/styles/hljs'
+import { Component, memo, useMemo, useRef, useState } from 'react'
+import { flow } from 'lodash-es'
+import ActionButton from '@/app/components/base/action-button'
+import CopyIcon from '@/app/components/base/copy-icon'
+import SVGBtn from '@/app/components/base/svg'
+import Flowchart from '@/app/components/base/mermaid'
+import ImageGallery from '@/app/components/base/image-gallery'
+import { useChatContext } from '@/app/components/base/chat/chat/context'
+import VideoGallery from '@/app/components/base/video-gallery'
+import AudioGallery from '@/app/components/base/audio-gallery'
+import MarkdownButton from '@/app/components/base/markdown-blocks/button'
+import MarkdownForm from '@/app/components/base/markdown-blocks/form'
+import MarkdownMusic from '@/app/components/base/markdown-blocks/music'
+import ThinkBlock from '@/app/components/base/markdown-blocks/think-block'
+import { Theme } from '@/types/app'
+import useTheme from '@/hooks/use-theme'
+import cn from '@/utils/classnames'
+import SVGRenderer from './svg-gallery'
+
+// Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD
+const capitalizationLanguageNameMap: Record<string, string> = {
+ sql: 'SQL',
+ javascript: 'JavaScript',
+ java: 'Java',
+ typescript: 'TypeScript',
+ vbscript: 'VBScript',
+ css: 'CSS',
+ html: 'HTML',
+ xml: 'XML',
+ php: 'PHP',
+ python: 'Python',
+ yaml: 'Yaml',
+ mermaid: 'Mermaid',
+ markdown: 'MarkDown',
+ makefile: 'MakeFile',
+ echarts: 'ECharts',
+ shell: 'Shell',
+ powershell: 'PowerShell',
+ json: 'JSON',
+ latex: 'Latex',
+ svg: 'SVG',
+ abc: 'ABC',
+}
+const getCorrectCapitalizationLanguageName = (language: string) => {
+ if (!language)
+ return 'Plain'
+
+ if (language in capitalizationLanguageNameMap)
+ return capitalizationLanguageNameMap[language]
+
+ return language.charAt(0).toUpperCase() + language.substring(1)
+}
+
+const preprocessLaTeX = (content: string) => {
+ if (typeof content !== 'string')
+ return content
+
+ const codeBlockRegex = /```[\s\S]*?```/g
+ const codeBlocks = content.match(codeBlockRegex) || []
+ let processedContent = content.replace(codeBlockRegex, 'CODE_BLOCK_PLACEHOLDER')
+
+ processedContent = flow([
+ (str: string) => str.replace(/\\\[(.*?)\\\]/g, (_, equation) => `$$${equation}$$`),
+ (str: string) => str.replace(/\\\[(.*?)\\\]/gs, (_, equation) => `$$${equation}$$`),
+ (str: string) => str.replace(/\\\((.*?)\\\)/g, (_, equation) => `$$${equation}$$`),
+ (str: string) => str.replace(/(^|[^\\])\$(.+?)\$/g, (_, prefix, equation) => `${prefix}$${equation}$`),
+ ])(processedContent)
+
+ codeBlocks.forEach((block) => {
+ processedContent = processedContent.replace('CODE_BLOCK_PLACEHOLDER', block)
+ })
+
+ return processedContent
+}
+
+const preprocessThinkTag = (content: string) => {
+ const thinkOpenTagRegex = /<think>\n/g
+ const thinkCloseTagRegex = /\n<\/think>/g
+ return flow([
+ (str: string) => str.replace(thinkOpenTagRegex, '<details data-think=true>\n'),
+ (str: string) => str.replace(thinkCloseTagRegex, '\n[ENDTHINKFLAG]</details>'),
+ ])(content)
+}
+
+export function PreCode(props: { children: any }) {
+ const ref = useRef<HTMLPreElement>(null)
+
+ return (
+ <pre ref={ref}>
+ <span
+ className="copy-code-button"
+ ></span>
+ {props.children}
+ </pre>
+ )
+}
+
+// **Add code block
+// Avoid error #185 (Maximum update depth exceeded.
+// This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.
+// React limits the number of nested updates to prevent infinite loops.)
+// Reference A: https://reactjs.org/docs/error-decoder.html?invariant=185
+// Reference B1: https://react.dev/reference/react/memo
+// Reference B2: https://react.dev/reference/react/useMemo
+// ****
+// The original error that occurred in the streaming response during the conversation:
+// Error: Minified React error 185;
+// visit https://reactjs.org/docs/error-decoder.html?invariant=185 for the full message
+// or use the non-minified dev environment for full errors and additional helpful warnings.
+
+const CodeBlock: any = memo(({ inline, className, children = '', ...props }: any) => {
+ const { theme } = useTheme()
+ const [isSVG, setIsSVG] = useState(true)
+ const match = /language-(\w+)/.exec(className || '')
+ const language = match?.[1]
+ const languageShowName = getCorrectCapitalizationLanguageName(language || '')
+ const chartData = useMemo(() => {
+ const str = String(children).replace(/\n$/, '')
+ if (language === 'echarts') {
+ try {
+ return JSON.parse(str)
+ }
+ catch { }
+ try {
+ // eslint-disable-next-line no-new-func, sonarjs/code-eval
+ return new Function(`return ${str}`)()
+ }
+ catch { }
+ }
+ return JSON.parse('{"title":{"text":"ECharts error - Wrong option."}}')
+ }, [language, children])
+
+ const renderCodeContent = useMemo(() => {
+ const content = String(children).replace(/\n$/, '')
+ switch (language) {
+ case 'mermaid':
+ if (isSVG)
+ return <Flowchart PrimitiveCode={content} />
+ break
+ case 'echarts':
+ return (
+ <div style={{ minHeight: '350px', minWidth: '100%', overflowX: 'scroll' }}>
+ <ErrorBoundary>
+ <ReactEcharts option={chartData} style={{ minWidth: '700px' }} />
+ </ErrorBoundary>
+ </div>
+ )
+ case 'svg':
+ if (isSVG) {
+ return (
+ <ErrorBoundary>
+ <SVGRenderer content={content} />
+ </ErrorBoundary>
+ )
+ }
+ break
+ case 'abc':
+ return (
+ <ErrorBoundary>
+ <MarkdownMusic children={content} />
+ </ErrorBoundary>
+ )
+ default:
+ return (
+ <SyntaxHighlighter
+ {...props}
+ style={theme === Theme.light ? atelierHeathLight : atelierHeathDark}
+ customStyle={{
+ paddingLeft: 12,
+ borderBottomLeftRadius: '10px',
+ borderBottomRightRadius: '10px',
+ backgroundColor: 'var(--color-components-input-bg-normal)',
+ }}
+ language={match?.[1]}
+ showLineNumbers
+ PreTag="div"
+ >
+ {content}
+ </SyntaxHighlighter>
+ )
+ }
+ }, [children, language, isSVG, chartData, props, theme, match])
+
+ if (inline || !match)
+ return <code {...props} className={className}>{children}</code>
+
+ return (
+ <div className='relative'>
+ <div className='flex h-8 items-center justify-between rounded-t-[10px] border-b border-divider-subtle bg-components-input-bg-normal p-1 pl-3'>
+ <div className='system-xs-semibold-uppercase text-text-secondary'>{languageShowName}</div>
+ <div className='flex items-center gap-1'>
+ {(['mermaid', 'svg']).includes(language!) && <SVGBtn isSVG={isSVG} setIsSVG={setIsSVG} />}
+ <ActionButton>
+ <CopyIcon content={String(children).replace(/\n$/, '')} />
+ </ActionButton>
+ </div>
+ </div>
+ {renderCodeContent}
+ </div>
+ )
+})
+CodeBlock.displayName = 'CodeBlock'
+
+const VideoBlock: any = memo(({ node }: any) => {
+ const srcs = node.children.filter((child: any) => 'properties' in child).map((child: any) => (child as any).properties.src)
+ if (srcs.length === 0)
+ return null
+ return <VideoGallery key={srcs.join()} srcs={srcs} />
+})
+VideoBlock.displayName = 'VideoBlock'
+
+const AudioBlock: any = memo(({ node }: any) => {
+ const srcs = node.children.filter((child: any) => 'properties' in child).map((child: any) => (child as any).properties.src)
+ if (srcs.length === 0)
+ return null
+ return <AudioGallery key={srcs.join()} srcs={srcs} />
+})
+AudioBlock.displayName = 'AudioBlock'
+
+const ScriptBlock = memo(({ node }: any) => {
+ const scriptContent = node.children[0]?.value || ''
+ return `<script>${scriptContent}</script>`
+})
+ScriptBlock.displayName = 'ScriptBlock'
+
+const Paragraph = (paragraph: any) => {
+ const { node }: any = paragraph
+ const children_node = node.children
+ if (children_node && children_node[0] && 'tagName' in children_node[0] && children_node[0].tagName === 'img') {
+ return (
+ <div className="markdown-img-wrapper">
+ <ImageGallery srcs={[children_node[0].properties.src]} />
+ {
+ Array.isArray(paragraph.children) && paragraph.children.length > 1 && (
+ <div className="mt-2">{paragraph.children.slice(1)}</div>
+ )
+ }
+ </div>
+ )
+ }
+ return <p>{paragraph.children}</p>
+}
+
+const Img = ({ src }: any) => {
+ return <div className="markdown-img-wrapper"><ImageGallery srcs={[src]} /></div>
+}
+
+const Link = ({ node, children, ...props }: any) => {
+ if (node.properties?.href && node.properties.href?.toString().startsWith('abbr')) {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ const { onSend } = useChatContext()
+ const hidden_text = decodeURIComponent(node.properties.href.toString().split('abbr:')[1])
+
+ return <abbr className="cursor-pointer underline !decoration-primary-700 decoration-dashed" onClick={() => onSend?.(hidden_text)} title={node.children[0]?.value || ''}>{node.children[0]?.value || ''}</abbr>
+ }
+ else {
+ return <a {...props} target="_blank" className="cursor-pointer underline !decoration-primary-700 decoration-dashed">{children || 'Download'}</a>
+ }
+}
+
+export function Markdown(props: { content: string; className?: string; customDisallowedElements?: string[] }) {
+ const latexContent = flow([
+ preprocessThinkTag,
+ preprocessLaTeX,
+ ])(props.content)
+
+ return (
+ <div className={cn('markdown-body', '!text-text-primary', props.className)}>
+ <ReactMarkdown
+ remarkPlugins={[
+ RemarkGfm,
+ [RemarkMath, { singleDollarTextMath: false }],
+ RemarkBreaks,
+ ]}
+ rehypePlugins={[
+ RehypeKatex,
+ RehypeRaw as any,
+ // The Rehype plug-in is used to remove the ref attribute of an element
+ () => {
+ return (tree) => {
+ const iterate = (node: any) => {
+ if (node.type === 'element' && node.properties?.ref)
+ delete node.properties.ref
+
+ if (node.type === 'element' && !/^[a-z][a-z0-9]*$/i.test(node.tagName)) {
+ node.type = 'text'
+ node.value = `<${node.tagName}`
+ }
+
+ if (node.children)
+ node.children.forEach(iterate)
+ }
+ tree.children.forEach(iterate)
+ }
+ },
+ ]}
+ disallowedElements={['iframe', 'head', 'html', 'meta', 'link', 'style', 'body', ...(props.customDisallowedElements || [])]}
+ components={{
+ code: CodeBlock,
+ img: Img,
+ video: VideoBlock,
+ audio: AudioBlock,
+ a: Link,
+ p: Paragraph,
+ button: MarkdownButton,
+ form: MarkdownForm,
+ script: ScriptBlock as any,
+ details: ThinkBlock,
+ }}
+ >
+ {/* Markdown detect has problem. */}
+ {latexContent}
+ </ReactMarkdown>
+ </div>
+ )
+}
+
+// **Add an ECharts runtime error handler
+// Avoid error #7832 (Crash when ECharts accesses undefined objects)
+// This can happen when a component attempts to access an undefined object that references an unregistered map, causing the program to crash.
+
+export default class ErrorBoundary extends Component {
+ constructor(props: any) {
+ super(props)
+ this.state = { hasError: false }
+ }
+
+ componentDidCatch(error: any, errorInfo: any) {
+ this.setState({ hasError: true })
+ console.error(error, errorInfo)
+ }
+
+ render() {
+ // eslint-disable-next-line ts/ban-ts-comment
+ // @ts-expect-error
+ if (this.state.hasError)
+ return <div>Oops! An error occurred. This could be due to an ECharts runtime error or invalid SVG content. <br />(see the browser console for more information)</div>
+ // eslint-disable-next-line ts/ban-ts-comment
+ // @ts-expect-error
+ return this.props.children
+ }
+}
diff --git a/app/components/base/mermaid/index.tsx b/app/components/base/mermaid/index.tsx
new file mode 100644
index 0000000..a484261
--- /dev/null
+++ b/app/components/base/mermaid/index.tsx
@@ -0,0 +1,590 @@
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import mermaid from 'mermaid'
+import { useTranslation } from 'react-i18next'
+import { ExclamationTriangleIcon } from '@heroicons/react/24/outline'
+import { MoonIcon, SunIcon } from '@heroicons/react/24/solid'
+import {
+ cleanUpSvgCode,
+ isMermaidCodeComplete,
+ prepareMermaidCode,
+ processSvgForTheme,
+ svgToBase64,
+ waitForDOMElement,
+} from './utils'
+import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
+import cn from '@/utils/classnames'
+import ImagePreview from '@/app/components/base/image-uploader/image-preview'
+import { Theme } from '@/types/app'
+
+// Global flags and cache for mermaid
+let isMermaidInitialized = false
+const diagramCache = new Map<string, string>()
+let mermaidAPI: any = null
+
+if (typeof window !== 'undefined')
+ mermaidAPI = mermaid.mermaidAPI
+
+// Theme configurations
+const THEMES = {
+ light: {
+ name: 'Light Theme',
+ background: '#ffffff',
+ primaryColor: '#ffffff',
+ primaryBorderColor: '#000000',
+ primaryTextColor: '#000000',
+ secondaryColor: '#ffffff',
+ tertiaryColor: '#ffffff',
+ nodeColors: [
+ { bg: '#f0f9ff', color: '#0369a1' },
+ { bg: '#f0fdf4', color: '#166534' },
+ { bg: '#fef2f2', color: '#b91c1c' },
+ { bg: '#faf5ff', color: '#7e22ce' },
+ { bg: '#fffbeb', color: '#b45309' },
+ ],
+ connectionColor: '#74a0e0',
+ },
+ dark: {
+ name: 'Dark Theme',
+ background: '#1e293b',
+ primaryColor: '#334155',
+ primaryBorderColor: '#94a3b8',
+ primaryTextColor: '#e2e8f0',
+ secondaryColor: '#475569',
+ tertiaryColor: '#334155',
+ nodeColors: [
+ { bg: '#164e63', color: '#e0f2fe' },
+ { bg: '#14532d', color: '#dcfce7' },
+ { bg: '#7f1d1d', color: '#fee2e2' },
+ { bg: '#581c87', color: '#f3e8ff' },
+ { bg: '#78350f', color: '#fef3c7' },
+ ],
+ connectionColor: '#60a5fa',
+ },
+}
+
+/**
+ * Initializes mermaid library with default configuration
+ */
+const initMermaid = () => {
+ if (typeof window !== 'undefined' && !isMermaidInitialized) {
+ try {
+ mermaid.initialize({
+ startOnLoad: false,
+ fontFamily: 'sans-serif',
+ securityLevel: 'loose',
+ flowchart: {
+ htmlLabels: true,
+ useMaxWidth: true,
+ diagramPadding: 10,
+ curve: 'basis',
+ nodeSpacing: 50,
+ rankSpacing: 70,
+ },
+ gantt: {
+ titleTopMargin: 25,
+ barHeight: 20,
+ barGap: 4,
+ topPadding: 50,
+ leftPadding: 75,
+ gridLineStartPadding: 35,
+ fontSize: 11,
+ numberSectionStyles: 4,
+ axisFormat: '%Y-%m-%d',
+ },
+ maxTextSize: 50000,
+ })
+ isMermaidInitialized = true
+ }
+ catch (error) {
+ console.error('Mermaid initialization error:', error)
+ return null
+ }
+ }
+ return isMermaidInitialized
+}
+
+const Flowchart = React.forwardRef((props: {
+ PrimitiveCode: string
+ theme?: 'light' | 'dark'
+}, ref) => {
+ const { t } = useTranslation()
+ const [svgCode, setSvgCode] = useState<string | null>(null)
+ const [look, setLook] = useState<'classic' | 'handDrawn'>('classic')
+ const [isInitialized, setIsInitialized] = useState(false)
+ const [currentTheme, setCurrentTheme] = useState<'light' | 'dark'>(props.theme || 'light')
+ const containerRef = useRef<HTMLDivElement>(null)
+ const chartId = useRef(`mermaid-chart-${Math.random().toString(36).substr(2, 9)}`).current
+ const [isLoading, setIsLoading] = useState(true)
+ const renderTimeoutRef = useRef<NodeJS.Timeout>()
+ const [errMsg, setErrMsg] = useState('')
+ const [imagePreviewUrl, setImagePreviewUrl] = useState('')
+ const [isCodeComplete, setIsCodeComplete] = useState(false)
+ const codeCompletionCheckRef = useRef<NodeJS.Timeout>()
+
+ // Create cache key from code, style and theme
+ const cacheKey = useMemo(() => {
+ return `${props.PrimitiveCode}-${look}-${currentTheme}`
+ }, [props.PrimitiveCode, look, currentTheme])
+
+ /**
+ * Renders Mermaid chart
+ */
+ const renderMermaidChart = async (code: string, style: 'classic' | 'handDrawn') => {
+ if (style === 'handDrawn') {
+ // Special handling for hand-drawn style
+ if (containerRef.current)
+ containerRef.current.innerHTML = `<div id="${chartId}"></div>`
+ await new Promise(resolve => setTimeout(resolve, 30))
+
+ if (typeof window !== 'undefined' && mermaidAPI) {
+ // Prefer using mermaidAPI directly for hand-drawn style
+ return await mermaidAPI.render(chartId, code)
+ }
+ else {
+ // Fall back to standard rendering if mermaidAPI is not available
+ const { svg } = await mermaid.render(chartId, code)
+ return { svg }
+ }
+ }
+ else {
+ // Standard rendering for classic style - using the extracted waitForDOMElement function
+ const renderWithRetry = async () => {
+ if (containerRef.current)
+ containerRef.current.innerHTML = `<div id="${chartId}"></div>`
+ await new Promise(resolve => setTimeout(resolve, 30))
+ const { svg } = await mermaid.render(chartId, code)
+ return { svg }
+ }
+ return await waitForDOMElement(renderWithRetry)
+ }
+ }
+
+ /**
+ * Handle rendering errors
+ */
+ const handleRenderError = (error: any) => {
+ console.error('Mermaid rendering error:', error)
+ const errorMsg = (error as Error).message
+
+ if (errorMsg.includes('getAttribute')) {
+ diagramCache.clear()
+ mermaid.initialize({
+ startOnLoad: false,
+ securityLevel: 'loose',
+ })
+ }
+ else {
+ setErrMsg(`Rendering chart failed, please refresh and try again ${look === 'handDrawn' ? 'Or try using classic mode' : ''}`)
+ }
+
+ if (look === 'handDrawn') {
+ try {
+ // Clear possible cache issues
+ diagramCache.delete(`${props.PrimitiveCode}-handDrawn-${currentTheme}`)
+
+ // Reset mermaid configuration
+ mermaid.initialize({
+ startOnLoad: false,
+ securityLevel: 'loose',
+ theme: 'default',
+ maxTextSize: 50000,
+ })
+
+ // Try rendering with standard mode
+ setLook('classic')
+ setErrMsg('Hand-drawn mode is not supported for this diagram. Switched to classic mode.')
+
+ // Delay error clearing
+ setTimeout(() => {
+ if (containerRef.current) {
+ // Try rendering again with standard mode, but can't call renderFlowchart directly due to circular dependency
+ // Instead set state to trigger re-render
+ setIsCodeComplete(true) // This will trigger useEffect re-render
+ }
+ }, 500)
+ }
+ catch (e) {
+ console.error('Reset after handDrawn error failed:', e)
+ }
+ }
+
+ setIsLoading(false)
+ }
+
+ // Initialize mermaid
+ useEffect(() => {
+ const api = initMermaid()
+ if (api)
+ setIsInitialized(true)
+ }, [])
+
+ // Update theme when prop changes
+ useEffect(() => {
+ if (props.theme)
+ setCurrentTheme(props.theme)
+ }, [props.theme])
+
+ // Validate mermaid code and check for completeness
+ useEffect(() => {
+ if (codeCompletionCheckRef.current)
+ clearTimeout(codeCompletionCheckRef.current)
+
+ // Reset code complete status when code changes
+ setIsCodeComplete(false)
+
+ // If no code or code is extremely short, don't proceed
+ if (!props.PrimitiveCode || props.PrimitiveCode.length < 10)
+ return
+
+ // Check if code already in cache - if so we know it's valid
+ if (diagramCache.has(cacheKey)) {
+ setIsCodeComplete(true)
+ return
+ }
+
+ // Initial check using the extracted isMermaidCodeComplete function
+ const isComplete = isMermaidCodeComplete(props.PrimitiveCode)
+ if (isComplete) {
+ setIsCodeComplete(true)
+ return
+ }
+
+ // Set a delay to check again in case code is still being generated
+ codeCompletionCheckRef.current = setTimeout(() => {
+ setIsCodeComplete(isMermaidCodeComplete(props.PrimitiveCode))
+ }, 300)
+
+ return () => {
+ if (codeCompletionCheckRef.current)
+ clearTimeout(codeCompletionCheckRef.current)
+ }
+ }, [props.PrimitiveCode, cacheKey])
+
+ /**
+ * Renders flowchart based on provided code
+ */
+ const renderFlowchart = useCallback(async (primitiveCode: string) => {
+ if (!isInitialized || !containerRef.current) {
+ setIsLoading(false)
+ setErrMsg(!isInitialized ? 'Mermaid initialization failed' : 'Container element not found')
+ return
+ }
+
+ // Don't render if code is not complete yet
+ if (!isCodeComplete) {
+ setIsLoading(true)
+ return
+ }
+
+ // Return cached result if available
+ if (diagramCache.has(cacheKey)) {
+ setSvgCode(diagramCache.get(cacheKey) || null)
+ setIsLoading(false)
+ return
+ }
+
+ setIsLoading(true)
+ setErrMsg('')
+
+ try {
+ let finalCode: string
+
+ // Check if it's a gantt chart
+ const isGanttChart = primitiveCode.trim().startsWith('gantt')
+
+ if (isGanttChart) {
+ // For gantt charts, ensure each task is on its own line
+ // and preserve exact whitespace/format
+ finalCode = primitiveCode.trim()
+ }
+ else {
+ // Step 1: Clean and prepare Mermaid code using the extracted prepareMermaidCode function
+ finalCode = prepareMermaidCode(primitiveCode, look)
+ }
+
+ // Step 2: Render chart
+ const svgGraph = await renderMermaidChart(finalCode, look)
+
+ // Step 3: Apply theme to SVG using the extracted processSvgForTheme function
+ const processedSvg = processSvgForTheme(
+ svgGraph.svg,
+ currentTheme === Theme.dark,
+ look === 'handDrawn',
+ THEMES,
+ )
+
+ // Step 4: Clean SVG code and convert to base64 using the extracted functions
+ const cleanedSvg = cleanUpSvgCode(processedSvg)
+ const base64Svg = await svgToBase64(cleanedSvg)
+
+ if (base64Svg && typeof base64Svg === 'string') {
+ diagramCache.set(cacheKey, base64Svg)
+ setSvgCode(base64Svg)
+ }
+
+ setIsLoading(false)
+ }
+ catch (error) {
+ // Error handling
+ handleRenderError(error)
+ }
+ }, [chartId, isInitialized, cacheKey, isCodeComplete, look, currentTheme, t])
+
+ /**
+ * Configure mermaid based on selected style and theme
+ */
+ const configureMermaid = useCallback(() => {
+ if (typeof window !== 'undefined' && isInitialized) {
+ const themeVars = THEMES[currentTheme]
+ const config: any = {
+ startOnLoad: false,
+ securityLevel: 'loose',
+ fontFamily: 'sans-serif',
+ maxTextSize: 50000,
+ gantt: {
+ titleTopMargin: 25,
+ barHeight: 20,
+ barGap: 4,
+ topPadding: 50,
+ leftPadding: 75,
+ gridLineStartPadding: 35,
+ fontSize: 11,
+ numberSectionStyles: 4,
+ axisFormat: '%Y-%m-%d',
+ },
+ }
+
+ if (look === 'classic') {
+ config.theme = currentTheme === 'dark' ? 'dark' : 'neutral'
+ config.flowchart = {
+ htmlLabels: true,
+ useMaxWidth: true,
+ diagramPadding: 12,
+ nodeSpacing: 60,
+ rankSpacing: 80,
+ curve: 'linear',
+ ranker: 'tight-tree',
+ }
+ }
+ else {
+ config.theme = 'default'
+ config.themeCSS = `
+ .node rect { fill-opacity: 0.85; }
+ .edgePath .path { stroke-width: 1.5px; }
+ .label { font-family: 'sans-serif'; }
+ .edgeLabel { font-family: 'sans-serif'; }
+ .cluster rect { rx: 5px; ry: 5px; }
+ `
+ config.themeVariables = {
+ fontSize: '14px',
+ fontFamily: 'sans-serif',
+ }
+ config.flowchart = {
+ htmlLabels: true,
+ useMaxWidth: true,
+ diagramPadding: 10,
+ nodeSpacing: 40,
+ rankSpacing: 60,
+ curve: 'basis',
+ }
+ config.themeVariables.primaryBorderColor = currentTheme === 'dark' ? THEMES.dark.connectionColor : THEMES.light.connectionColor
+ }
+
+ if (currentTheme === 'dark' && !config.themeVariables) {
+ config.themeVariables = {
+ background: themeVars.background,
+ primaryColor: themeVars.primaryColor,
+ primaryBorderColor: themeVars.primaryBorderColor,
+ primaryTextColor: themeVars.primaryTextColor,
+ secondaryColor: themeVars.secondaryColor,
+ tertiaryColor: themeVars.tertiaryColor,
+ fontFamily: 'sans-serif',
+ }
+ }
+
+ try {
+ mermaid.initialize(config)
+ return true
+ }
+ catch (error) {
+ console.error('Config error:', error)
+ return false
+ }
+ }
+ return false
+ }, [currentTheme, isInitialized, look])
+
+ // Effect for theme and style configuration
+ useEffect(() => {
+ if (diagramCache.has(cacheKey)) {
+ setSvgCode(diagramCache.get(cacheKey) || null)
+ setIsLoading(false)
+ return
+ }
+
+ if (configureMermaid() && containerRef.current && isCodeComplete)
+ renderFlowchart(props.PrimitiveCode)
+ }, [look, props.PrimitiveCode, renderFlowchart, isInitialized, cacheKey, currentTheme, isCodeComplete, configureMermaid])
+
+ // Effect for rendering with debounce
+ useEffect(() => {
+ if (diagramCache.has(cacheKey)) {
+ setSvgCode(diagramCache.get(cacheKey) || null)
+ setIsLoading(false)
+ return
+ }
+
+ if (renderTimeoutRef.current)
+ clearTimeout(renderTimeoutRef.current)
+
+ if (isCodeComplete) {
+ renderTimeoutRef.current = setTimeout(() => {
+ if (isInitialized)
+ renderFlowchart(props.PrimitiveCode)
+ }, 300)
+ }
+ else {
+ setIsLoading(true)
+ }
+
+ return () => {
+ if (renderTimeoutRef.current)
+ clearTimeout(renderTimeoutRef.current)
+ }
+ }, [props.PrimitiveCode, renderFlowchart, isInitialized, cacheKey, isCodeComplete])
+
+ // Cleanup on unmount
+ useEffect(() => {
+ return () => {
+ if (containerRef.current)
+ containerRef.current.innerHTML = ''
+ if (renderTimeoutRef.current)
+ clearTimeout(renderTimeoutRef.current)
+ if (codeCompletionCheckRef.current)
+ clearTimeout(codeCompletionCheckRef.current)
+ }
+ }, [])
+
+ const toggleTheme = () => {
+ setCurrentTheme(prevTheme => prevTheme === 'light' ? Theme.dark : Theme.light)
+ diagramCache.clear()
+ }
+
+ // Style classes for theme-dependent elements
+ const themeClasses = {
+ container: cn('relative', {
+ 'bg-white': currentTheme === Theme.light,
+ 'bg-slate-900': currentTheme === Theme.dark,
+ }),
+ mermaidDiv: cn('mermaid relative h-auto w-full cursor-pointer', {
+ 'bg-white': currentTheme === Theme.light,
+ 'bg-slate-900': currentTheme === Theme.dark,
+ }),
+ errorMessage: cn('px-[26px] py-4', {
+ 'text-red-500': currentTheme === Theme.light,
+ 'text-red-400': currentTheme === Theme.dark,
+ }),
+ errorIcon: cn('h-6 w-6', {
+ 'text-red-500': currentTheme === Theme.light,
+ 'text-red-400': currentTheme === Theme.dark,
+ }),
+ segmented: cn('msh-segmented msh-segmented-sm css-23bs09 css-var-r1', {
+ 'text-gray-700': currentTheme === Theme.light,
+ 'text-gray-300': currentTheme === Theme.dark,
+ }),
+ themeToggle: cn('flex h-10 w-10 items-center justify-center rounded-full shadow-md backdrop-blur-sm transition-all duration-300', {
+ 'bg-white/80 hover:bg-white hover:shadow-lg text-gray-700 border border-gray-200': currentTheme === Theme.light,
+ 'bg-slate-800/80 hover:bg-slate-700 hover:shadow-lg text-yellow-300 border border-slate-600': currentTheme === Theme.dark,
+ }),
+ }
+
+ // Style classes for look options
+ const getLookButtonClass = (lookType: 'classic' | 'handDrawn') => {
+ return cn(
+ 'system-sm-medium mb-4 flex h-8 w-[calc((100%-8px)/2)] cursor-pointer items-center justify-center rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary',
+ look === lookType && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary',
+ currentTheme === Theme.dark && 'border-slate-600 bg-slate-800 text-slate-300',
+ look === lookType && currentTheme === Theme.dark && 'border-blue-500 bg-slate-700 text-white',
+ )
+ }
+
+ return (
+ <div ref={ref as React.RefObject<HTMLDivElement>} className={themeClasses.container}>
+ <div className={themeClasses.segmented}>
+ <div className="msh-segmented-group">
+ <label className="msh-segmented-item m-2 flex w-[200px] items-center space-x-1">
+ <div
+ key='classic'
+ className={getLookButtonClass('classic')}
+ onClick={() => setLook('classic')}
+ >
+ <div className="msh-segmented-item-label">{t('app.mermaid.classic')}</div>
+ </div>
+ <div
+ key='handDrawn'
+ className={getLookButtonClass('handDrawn')}
+ onClick={() => setLook('handDrawn')}
+ >
+ <div className="msh-segmented-item-label">{t('app.mermaid.handDrawn')}</div>
+ </div>
+ </label>
+ </div>
+ </div>
+
+ <div ref={containerRef} style={{ position: 'absolute', visibility: 'hidden', height: 0, overflow: 'hidden' }} />
+
+ {isLoading && !svgCode && (
+ <div className='px-[26px] py-4'>
+ <LoadingAnim type='text'/>
+ {!isCodeComplete && (
+ <div className="mt-2 text-sm text-gray-500">
+ {t('common.wait_for_completion', 'Waiting for diagram code to complete...')}
+ </div>
+ )}
+ </div>
+ )}
+
+ {svgCode && (
+ <div className={themeClasses.mermaidDiv} style={{ objectFit: 'cover' }} onClick={() => setImagePreviewUrl(svgCode)}>
+ <div className="absolute bottom-2 left-2 z-[100]">
+ <button
+ onClick={(e) => {
+ e.stopPropagation()
+ toggleTheme()
+ }}
+ className={themeClasses.themeToggle}
+ title={(currentTheme === Theme.light ? t('app.theme.switchDark') : t('app.theme.switchLight')) || ''}
+ style={{ transform: 'translate3d(0, 0, 0)' }}
+ >
+ {currentTheme === Theme.light ? <MoonIcon className="h-5 w-5" /> : <SunIcon className="h-5 w-5" />}
+ </button>
+ </div>
+
+ <img
+ src={svgCode}
+ alt="mermaid_chart"
+ style={{ maxWidth: '100%' }}
+ onError={() => { setErrMsg('Chart rendering failed, please refresh and retry') }}
+ />
+ </div>
+ )}
+
+ {errMsg && (
+ <div className={themeClasses.errorMessage}>
+ <div className="flex items-center">
+ <ExclamationTriangleIcon className={themeClasses.errorIcon}/>
+ <span className="ml-2">{errMsg}</span>
+ </div>
+ </div>
+ )}
+
+ {imagePreviewUrl && (
+ <ImagePreview title='mermaid_chart' url={imagePreviewUrl} onCancel={() => setImagePreviewUrl('')} />
+ )}
+ </div>
+ )
+})
+
+Flowchart.displayName = 'Flowchart'
+
+export default Flowchart
diff --git a/app/components/base/mermaid/utils.spec.ts b/app/components/base/mermaid/utils.spec.ts
new file mode 100644
index 0000000..6ea7f17
--- /dev/null
+++ b/app/components/base/mermaid/utils.spec.ts
@@ -0,0 +1,8 @@
+import { cleanUpSvgCode } from './utils'
+
+describe('cleanUpSvgCode', () => {
+ it('replaces old-style <br> tags with the new style', () => {
+ const result = cleanUpSvgCode('<br>test<br>')
+ expect(result).toEqual('<br/>test<br/>')
+ })
+})
diff --git a/app/components/base/mermaid/utils.ts b/app/components/base/mermaid/utils.ts
new file mode 100644
index 0000000..7d94150
--- /dev/null
+++ b/app/components/base/mermaid/utils.ts
@@ -0,0 +1,232 @@
+export function cleanUpSvgCode(svgCode: string): string {
+ return svgCode.replaceAll('<br>', '<br/>')
+}
+
+/**
+ * Preprocesses mermaid code to fix common syntax issues
+ */
+export function preprocessMermaidCode(code: string): string {
+ if (!code || typeof code !== 'string')
+ return ''
+
+ // First check if this is a gantt chart
+ if (code.trim().startsWith('gantt')) {
+ // For gantt charts, we need to ensure each task is on its own line
+ // Split the code into lines and process each line separately
+ const lines = code.split('\n').map(line => line.trim())
+ return lines.join('\n')
+ }
+
+ return code
+ // Replace English colons with Chinese colons in section nodes to avoid parsing issues
+ .replace(/section\s+([^:]+):/g, (match, sectionName) => `section ${sectionName}锛歚)
+ // Fix common syntax issues
+ .replace(/fifopacket/g, 'rect')
+ // Clean up empty lines and extra spaces
+ .trim()
+}
+
+/**
+ * Prepares mermaid code based on selected style
+ */
+export function prepareMermaidCode(code: string, style: 'classic' | 'handDrawn'): string {
+ let finalCode = preprocessMermaidCode(code)
+
+ // Special handling for gantt charts
+ if (finalCode.trim().startsWith('gantt')) {
+ // For gantt charts, preserve the structure exactly as is
+ return finalCode
+ }
+
+ if (style === 'handDrawn') {
+ finalCode = finalCode
+ // Remove style definitions that interfere with hand-drawn style
+ .replace(/style\s+[^\n]+/g, '')
+ .replace(/linkStyle\s+[^\n]+/g, '')
+ .replace(/^flowchart/, 'graph')
+ // Remove any styles that might interfere with hand-drawn style
+ .replace(/class="[^"]*"/g, '')
+ .replace(/fill="[^"]*"/g, '')
+ .replace(/stroke="[^"]*"/g, '')
+
+ // Ensure hand-drawn style charts always start with graph
+ if (!finalCode.startsWith('graph') && !finalCode.startsWith('flowchart'))
+ finalCode = `graph TD\n${finalCode}`
+ }
+
+ return finalCode
+}
+
+/**
+ * Converts SVG to base64 string for image rendering
+ */
+export function svgToBase64(svgGraph: string): Promise<string> {
+ if (!svgGraph)
+ return Promise.resolve('')
+
+ try {
+ // Ensure SVG has correct XML declaration
+ if (!svgGraph.includes('<?xml'))
+ svgGraph = `<?xml version="1.0" encoding="UTF-8"?>${svgGraph}`
+
+ const blob = new Blob([new TextEncoder().encode(svgGraph)], { type: 'image/svg+xml;charset=utf-8' })
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader()
+ reader.onloadend = () => resolve(reader.result as string)
+ reader.onerror = reject
+ reader.readAsDataURL(blob)
+ })
+ }
+ catch (error) {
+ console.error('Error converting SVG to base64:', error)
+ return Promise.resolve('')
+ }
+}
+
+/**
+ * Processes SVG for theme styling
+ */
+export function processSvgForTheme(
+ svg: string,
+ isDark: boolean,
+ isHandDrawn: boolean,
+ themes: {
+ light: any
+ dark: any
+ },
+): string {
+ let processedSvg = svg
+
+ if (isDark) {
+ processedSvg = processedSvg
+ .replace(/style="fill: ?#000000"/g, 'style="fill: #e2e8f0"')
+ .replace(/style="stroke: ?#000000"/g, 'style="stroke: #94a3b8"')
+ .replace(/<rect [^>]*fill="#ffffff"/g, '<rect $& fill="#1e293b"')
+
+ if (isHandDrawn) {
+ processedSvg = processedSvg
+ .replace(/fill="#[a-fA-F0-9]{6}"/g, `fill="${themes.dark.nodeColors[0].bg}"`)
+ .replace(/stroke="#[a-fA-F0-9]{6}"/g, `stroke="${themes.dark.connectionColor}"`)
+ .replace(/stroke-width="1"/g, 'stroke-width="1.5"')
+ }
+ else {
+ let i = 0
+ themes.dark.nodeColors.forEach(() => {
+ const regex = /fill="#[a-fA-F0-9]{6}"[^>]*class="node-[^"]*"/g
+ processedSvg = processedSvg.replace(regex, (match: string) => {
+ const colorIndex = i % themes.dark.nodeColors.length
+ i++
+ return match.replace(/fill="#[a-fA-F0-9]{6}"/, `fill="${themes.dark.nodeColors[colorIndex].bg}"`)
+ })
+ })
+
+ processedSvg = processedSvg
+ .replace(/<path [^>]*stroke="#[a-fA-F0-9]{6}"/g,
+ `<path stroke="${themes.dark.connectionColor}" stroke-width="1.5"`)
+ .replace(/<(line|polyline) [^>]*stroke="#[a-fA-F0-9]{6}"/g,
+ `<$1 stroke="${themes.dark.connectionColor}" stroke-width="1.5"`)
+ }
+ }
+ else {
+ if (isHandDrawn) {
+ processedSvg = processedSvg
+ .replace(/fill="#[a-fA-F0-9]{6}"/g, `fill="${themes.light.nodeColors[0].bg}"`)
+ .replace(/stroke="#[a-fA-F0-9]{6}"/g, `stroke="${themes.light.connectionColor}"`)
+ .replace(/stroke-width="1"/g, 'stroke-width="1.5"')
+ }
+ else {
+ themes.light.nodeColors.forEach(() => {
+ const regex = /fill="#[a-fA-F0-9]{6}"[^>]*class="node-[^"]*"/g
+ let i = 0
+ processedSvg = processedSvg.replace(regex, (match: string) => {
+ const colorIndex = i % themes.light.nodeColors.length
+ i++
+ return match.replace(/fill="#[a-fA-F0-9]{6}"/, `fill="${themes.light.nodeColors[colorIndex].bg}"`)
+ })
+ })
+
+ processedSvg = processedSvg
+ .replace(/<path [^>]*stroke="#[a-fA-F0-9]{6}"/g,
+ `<path stroke="${themes.light.connectionColor}"`)
+ .replace(/<(line|polyline) [^>]*stroke="#[a-fA-F0-9]{6}"/g,
+ `<$1 stroke="${themes.light.connectionColor}"`)
+ }
+ }
+
+ return processedSvg
+}
+
+/**
+ * Checks if mermaid code is complete and valid
+ */
+export function isMermaidCodeComplete(code: string): boolean {
+ if (!code || code.trim().length === 0)
+ return false
+
+ try {
+ const trimmedCode = code.trim()
+
+ // Special handling for gantt charts
+ if (trimmedCode.startsWith('gantt')) {
+ // For gantt charts, check if it has at least a title and one task
+ const lines = trimmedCode.split('\n').filter(line => line.trim().length > 0)
+ return lines.length >= 3
+ }
+
+ // Check for basic syntax structure
+ const hasValidStart = /^(graph|flowchart|sequenceDiagram|classDiagram|classDef|class|stateDiagram|gantt|pie|er|journey|requirementDiagram)/.test(trimmedCode)
+
+ // Check for balanced brackets and parentheses
+ const isBalanced = (() => {
+ const stack = []
+ const pairs = { '{': '}', '[': ']', '(': ')' }
+
+ for (const char of trimmedCode) {
+ if (char in pairs) {
+ stack.push(char)
+ }
+ else if (Object.values(pairs).includes(char)) {
+ const last = stack.pop()
+ if (pairs[last as keyof typeof pairs] !== char)
+ return false
+ }
+ }
+
+ return stack.length === 0
+ })()
+
+ // Check for common syntax errors
+ const hasNoSyntaxErrors = !trimmedCode.includes('undefined')
+ && !trimmedCode.includes('[object Object]')
+ && trimmedCode.split('\n').every(line =>
+ !(line.includes('-->') && !line.match(/\S+\s*-->\s*\S+/)))
+
+ return hasValidStart && isBalanced && hasNoSyntaxErrors
+ }
+ catch (error) {
+ console.debug('Mermaid code validation error:', error)
+ return false
+ }
+}
+
+/**
+ * Helper to wait for DOM element with retry mechanism
+ */
+export function waitForDOMElement(callback: () => Promise<any>, maxAttempts = 3, delay = 100): Promise<any> {
+ return new Promise((resolve, reject) => {
+ let attempts = 0
+ const tryRender = async () => {
+ try {
+ resolve(await callback())
+ }
+ catch (error) {
+ attempts++
+ if (attempts < maxAttempts)
+ setTimeout(tryRender, delay)
+ else
+ reject(error)
+ }
+ }
+ tryRender()
+ })
+}
diff --git a/app/components/base/message-log-modal/index.tsx b/app/components/base/message-log-modal/index.tsx
new file mode 100644
index 0000000..d5ff818
--- /dev/null
+++ b/app/components/base/message-log-modal/index.tsx
@@ -0,0 +1,71 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useEffect, useRef, useState } from 'react'
+import { useClickAway } from 'ahooks'
+import { RiCloseLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import type { IChatItem } from '@/app/components/base/chat/chat/type'
+import Run from '@/app/components/workflow/run'
+
+type MessageLogModalProps = {
+ currentLogItem?: IChatItem
+ defaultTab?: string
+ width: number
+ fixedWidth?: boolean
+ onCancel: () => void
+}
+const MessageLogModal: FC<MessageLogModalProps> = ({
+ currentLogItem,
+ defaultTab = 'DETAIL',
+ width,
+ fixedWidth,
+ onCancel,
+}) => {
+ const { t } = useTranslation()
+ const ref = useRef(null)
+ const [mounted, setMounted] = useState(false)
+
+ useClickAway(() => {
+ if (mounted)
+ onCancel()
+ }, ref)
+
+ useEffect(() => {
+ setMounted(true)
+ }, [])
+
+ if (!currentLogItem || !currentLogItem.workflow_run_id)
+ return null
+
+ return (
+ <div
+ className={cn('relative z-10 flex flex-col rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg pt-3 shadow-xl')}
+ style={{
+ width: fixedWidth ? width : 480,
+ ...(!fixedWidth
+ ? {
+ position: 'fixed',
+ top: 56 + 8,
+ left: 8 + (width - 480),
+ bottom: 16,
+ }
+ : {
+ marginRight: 8,
+ }),
+ }}
+ ref={ref}
+ >
+ <h1 className='system-xl-semibold shrink-0 px-4 py-1 text-text-primary'>{t('appLog.runDetail.title')}</h1>
+ <span className='absolute right-3 top-4 z-20 cursor-pointer p-1' onClick={onCancel}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </span>
+ <Run
+ hideResult
+ activeTab={defaultTab as any}
+ runID={currentLogItem.workflow_run_id}
+ />
+ </div>
+ )
+}
+
+export default MessageLogModal
diff --git a/app/components/base/modal-like-wrap/index.tsx b/app/components/base/modal-like-wrap/index.tsx
new file mode 100644
index 0000000..cf18ef1
--- /dev/null
+++ b/app/components/base/modal-like-wrap/index.tsx
@@ -0,0 +1,58 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import { useTranslation } from 'react-i18next'
+import Button from '../button'
+import { RiCloseLine } from '@remixicon/react'
+
+type Props = {
+ title: string
+ className?: string
+ beforeHeader?: React.ReactNode
+ onClose: () => void
+ hideCloseBtn?: boolean
+ onConfirm: () => void
+ children: React.ReactNode
+}
+
+const ModalLikeWrap: FC<Props> = ({
+ title,
+ className,
+ beforeHeader,
+ children,
+ onClose,
+ hideCloseBtn,
+ onConfirm,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={cn('w-[320px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg px-3 pb-4 pt-3.5 shadow-xl', className)}>
+ {beforeHeader || null}
+ <div className='mb-1 flex h-6 items-center justify-between'>
+ <div className='system-xl-semibold text-text-primary'>{title}</div>
+ {!hideCloseBtn && (
+ <div
+ className='cursor-pointer p-1.5 text-text-tertiary'
+ onClick={onClose}
+ >
+ <RiCloseLine className='size-4' />
+ </div>
+ )}
+ </div>
+ <div className='mt-2'>{children}</div>
+ <div className='mt-4 flex justify-end'>
+ <Button
+ className='mr-2'
+ onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button
+ onClick={onConfirm}
+ variant='primary'
+ >{t('common.operation.save')}</Button>
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(ModalLikeWrap)
diff --git a/app/components/base/modal/index.css b/app/components/base/modal/index.css
new file mode 100644
index 0000000..3787da2
--- /dev/null
+++ b/app/components/base/modal/index.css
@@ -0,0 +1,7 @@
+.modal-dialog {
+ @apply relative z-50;
+}
+
+.modal-panel {
+ @apply w-full max-w-[480px] transform rounded-2xl bg-components-panel-bg p-6 text-left align-middle shadow-xl transition-all;
+}
diff --git a/app/components/base/modal/index.tsx b/app/components/base/modal/index.tsx
new file mode 100644
index 0000000..dd60b00
--- /dev/null
+++ b/app/components/base/modal/index.tsx
@@ -0,0 +1,86 @@
+import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react'
+import { Fragment } from 'react'
+import { RiCloseLine } from '@remixicon/react'
+import classNames from '@/utils/classnames'
+import { noop } from 'lodash-es'
+// https://headlessui.com/react/dialog
+
+type IModal = {
+ className?: string
+ wrapperClassName?: string
+ isShow: boolean
+ onClose?: () => void
+ title?: React.ReactNode
+ description?: React.ReactNode
+ children?: React.ReactNode
+ closable?: boolean
+ overflowVisible?: boolean
+}
+
+export default function Modal({
+ className,
+ wrapperClassName,
+ isShow,
+ onClose = noop,
+ title,
+ description,
+ children,
+ closable = false,
+ overflowVisible = false,
+}: IModal) {
+ return (
+ <Transition appear show={isShow} as={Fragment}>
+ <Dialog as="div" className={classNames('relative z-[60]', wrapperClassName)} onClose={onClose}>
+ <TransitionChild>
+ <div className={classNames(
+ 'fixed inset-0 bg-background-overlay',
+ 'duration-300 ease-in data-[closed]:opacity-0',
+ 'data-[enter]:opacity-100',
+ 'data-[leave]:opacity-0',
+ )} />
+ </TransitionChild>
+
+ <div
+ className="fixed inset-0 overflow-y-auto"
+ onClick={(e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }}
+ >
+ <div className="flex min-h-full items-center justify-center p-4 text-center">
+ <TransitionChild>
+ <DialogPanel className={classNames(
+ 'w-full max-w-[480px] transform rounded-2xl bg-components-panel-bg p-6 text-left align-middle shadow-xl transition-all',
+ overflowVisible ? 'overflow-visible' : 'overflow-hidden',
+ 'duration-100 ease-in data-[closed]:opacity-0 data-[closed]:scale-95',
+ 'data-[enter]:opacity-100 data-[enter]:scale-100',
+ 'data-[leave]:opacity-0 data-[enter]:scale-95',
+ className,
+ )}>
+ {title && <DialogTitle
+ as="h3"
+ className="title-2xl-semi-bold text-text-primary"
+ >
+ {title}
+ </DialogTitle>}
+ {description && <div className='body-md-regular mt-2 text-text-secondary'>
+ {description}
+ </div>}
+ {closable
+ && <div className='absolute right-6 top-6 z-10 flex h-5 w-5 items-center justify-center rounded-2xl hover:cursor-pointer hover:bg-state-base-hover'>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' onClick={
+ (e) => {
+ e.stopPropagation()
+ onClose()
+ }
+ } />
+ </div>}
+ {children}
+ </DialogPanel>
+ </TransitionChild>
+ </div>
+ </div>
+ </Dialog>
+ </Transition>
+ )
+}
diff --git a/app/components/base/new-audio-button/index.tsx b/app/components/base/new-audio-button/index.tsx
new file mode 100644
index 0000000..107b53b
--- /dev/null
+++ b/app/components/base/new-audio-button/index.tsx
@@ -0,0 +1,99 @@
+'use client'
+import { useState } from 'react'
+import { useParams, usePathname } from 'next/navigation'
+import {
+ RiVolumeUpLine,
+} from '@remixicon/react'
+import { t } from 'i18next'
+import Tooltip from '@/app/components/base/tooltip'
+import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+
+type AudioBtnProps = {
+ id?: string
+ voice?: string
+ value?: string
+}
+
+type AudioState = 'initial' | 'loading' | 'playing' | 'paused' | 'ended'
+
+const AudioBtn = ({
+ id,
+ voice,
+ value,
+}: AudioBtnProps) => {
+ const [audioState, setAudioState] = useState<AudioState>('initial')
+
+ const params = useParams()
+ const pathname = usePathname()
+ const audio_finished_call = (event: string): any => {
+ switch (event) {
+ case 'ended':
+ setAudioState('ended')
+ break
+ case 'paused':
+ setAudioState('ended')
+ break
+ case 'loaded':
+ setAudioState('loading')
+ break
+ case 'play':
+ setAudioState('playing')
+ break
+ case 'error':
+ setAudioState('ended')
+ break
+ }
+ }
+ let url = ''
+ let isPublic = false
+
+ if (params.token) {
+ url = '/text-to-audio'
+ isPublic = true
+ }
+ else if (params.appId) {
+ if (pathname.search('explore/installed') > -1)
+ url = `/installed-apps/${params.appId}/text-to-audio`
+ else
+ url = `/apps/${params.appId}/text-to-audio`
+ }
+ const handleToggle = async () => {
+ if (audioState === 'playing' || audioState === 'loading') {
+ setTimeout(() => setAudioState('paused'), 1)
+ AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).pauseAudio()
+ }
+ else {
+ setTimeout(() => setAudioState('loading'), 1)
+ AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).playAudio()
+ }
+ }
+
+ const tooltipContent = {
+ initial: t('appApi.play'),
+ ended: t('appApi.play'),
+ paused: t('appApi.pause'),
+ playing: t('appApi.playing'),
+ loading: t('appApi.loading'),
+ }[audioState]
+
+ return (
+ <Tooltip
+ popupContent={tooltipContent}
+ >
+ <ActionButton
+ state={
+ audioState === 'loading' || audioState === 'playing'
+ ? ActionButtonState.Active
+ : ActionButtonState.Default
+ }
+ onClick={handleToggle}
+ disabled={audioState === 'loading'}
+ >
+ <RiVolumeUpLine className='h-4 w-4' />
+ </ActionButton>
+ </Tooltip>
+ )
+}
+
+export default AudioBtn
diff --git a/app/components/base/notion-icon/index.tsx b/app/components/base/notion-icon/index.tsx
new file mode 100644
index 0000000..75fea8c
--- /dev/null
+++ b/app/components/base/notion-icon/index.tsx
@@ -0,0 +1,58 @@
+import { RiFileTextLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import type { DataSourceNotionPage } from '@/models/common'
+
+type IconTypes = 'workspace' | 'page'
+type NotionIconProps = {
+ type?: IconTypes
+ name?: string | null
+ className?: string
+ src?: string | null | DataSourceNotionPage['page_icon']
+}
+const NotionIcon = ({
+ type = 'workspace',
+ src,
+ name,
+ className,
+}: NotionIconProps) => {
+ if (type === 'workspace') {
+ if (typeof src === 'string') {
+ if (src.startsWith('https://') || src.startsWith('http://')) {
+ return (
+ <img
+ alt='workspace icon'
+ src={src}
+ className={cn('block h-5 w-5 object-cover', className)}
+ />
+ )
+ }
+ return (
+ <div className={cn('flex h-5 w-5 items-center justify-center', className)}>{src}</div>
+ )
+ }
+ return (
+ <div className={cn('flex h-5 w-5 items-center justify-center rounded bg-gray-200 text-xs font-medium text-gray-500', className)}>{name?.[0].toLocaleUpperCase()}</div>
+ )
+ }
+
+ if (typeof src === 'object' && src !== null) {
+ if (src?.type === 'url') {
+ return (
+ <img
+ alt='page icon'
+ src={src.url || ''}
+ className={cn('block h-5 w-5 object-cover', className)}
+ />
+ )
+ }
+ return (
+ <div className={cn('flex h-5 w-5 items-center justify-center', className)}>{src?.emoji}</div>
+ )
+ }
+
+ return (
+ <RiFileTextLine className={cn('h-5 w-5 text-text-tertiary', className)} />
+ )
+}
+
+export default NotionIcon
diff --git a/app/components/base/notion-page-selector/assets/clear.svg b/app/components/base/notion-page-selector/assets/clear.svg
new file mode 100644
index 0000000..3d1bbf5
--- /dev/null
+++ b/app/components/base/notion-page-selector/assets/clear.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8 2.5C4.96243 2.5 2.5 4.96243 2.5 8C2.5 11.0376 4.96243 13.5 8 13.5C11.0376 13.5 13.5 11.0376 13.5 8C13.5 4.96243 11.0376 2.5 8 2.5ZM9.85355 6.14645C10.0488 6.34171 10.0488 6.65829 9.85355 6.85355L8.70711 8L9.85355 9.14645C10.0488 9.34171 10.0488 9.65829 9.85355 9.85355C9.65829 10.0488 9.34171 10.0488 9.14645 9.85355L8 8.70711L6.85355 9.85355C6.65829 10.0488 6.34171 10.0488 6.14645 9.85355C5.95118 9.65829 5.95118 9.34171 6.14645 9.14645L7.29289 8L6.14645 6.85355C5.95118 6.65829 5.95118 6.34171 6.14645 6.14645C6.34171 5.95118 6.65829 5.95118 6.85355 6.14645L8 7.29289L9.14645 6.14645C9.34171 5.95118 9.65829 5.95118 9.85355 6.14645Z" fill="#98A2B3"/>
+</svg>
diff --git a/app/components/base/notion-page-selector/assets/down-arrow.svg b/app/components/base/notion-page-selector/assets/down-arrow.svg
new file mode 100644
index 0000000..0676e96
--- /dev/null
+++ b/app/components/base/notion-page-selector/assets/down-arrow.svg
@@ -0,0 +1,3 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M3 4.5L6 7.5L9 4.5" stroke="#344054" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/base/notion-page-selector/assets/notion-empty-page.svg b/app/components/base/notion-page-selector/assets/notion-empty-page.svg
new file mode 100644
index 0000000..7493621
--- /dev/null
+++ b/app/components/base/notion-page-selector/assets/notion-empty-page.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.49939 19.1498H13.6897C15.3354 19.1498 16.1891 18.2807 16.1891 16.6273V9.6521C16.1891 8.58313 16.0507 8.09095 15.3816 7.41418L11.3441 3.30749C10.6981 2.65381 10.1675 2.5 9.20618 2.5H5.49939C3.85363 2.5 3 3.36902 3 5.02246V16.6273C3 18.2884 3.85363 19.1498 5.49939 19.1498ZM5.62243 17.6424C4.87646 17.6424 4.50732 17.2502 4.50732 16.5351V5.11475C4.50732 4.40722 4.87646 4.00732 5.62243 4.00732H8.89856V8.22168C8.89856 9.32142 9.44457 9.85205 10.5366 9.85205H14.6818V16.5351C14.6818 17.2502 14.3049 17.6424 13.5589 17.6424H5.62243ZM10.675 8.52929C10.3597 8.52929 10.229 8.39087 10.229 8.07556V4.21496L14.4741 8.52929H10.675Z" fill="#37352F" fill-opacity="0.45"/>
+</svg>
diff --git a/app/components/base/notion-page-selector/assets/notion-page.svg b/app/components/base/notion-page-selector/assets/notion-page.svg
new file mode 100644
index 0000000..237fc2e
--- /dev/null
+++ b/app/components/base/notion-page-selector/assets/notion-page.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.49939 19.1498H13.6897C15.3354 19.1498 16.1891 18.2807 16.1891 16.6273V9.6521C16.1891 8.58313 16.0507 8.09095 15.3816 7.41418L11.3441 3.30749C10.6981 2.65381 10.1675 2.5 9.20618 2.5H5.49939C3.85363 2.5 3 3.36902 3 5.02246V16.6273C3 18.2884 3.85363 19.1498 5.49939 19.1498ZM5.62243 17.6424C4.87645 17.6424 4.50732 17.2502 4.50732 16.5351V5.11475C4.50732 4.40722 4.87645 4.00732 5.62243 4.00732H8.89856V8.22168C8.89856 9.32142 9.44457 9.85205 10.5366 9.85205H14.6818V16.5351C14.6818 17.2502 14.3049 17.6424 13.5589 17.6424H5.62243ZM10.675 8.52929C10.3597 8.52929 10.229 8.39087 10.229 8.07556V4.21496L14.4741 8.52929H10.675ZM12.3362 11.8746H6.70678C6.41454 11.8746 6.2069 12.09 6.2069 12.3591C6.2069 12.636 6.41454 12.8513 6.70678 12.8513H12.3362C12.613 12.8513 12.8207 12.636 12.8207 12.3591C12.8207 12.09 12.613 11.8746 12.3362 11.8746ZM12.3362 14.4587H6.70678C6.41454 14.4587 6.2069 14.674 6.2069 14.9509C6.2069 15.22 6.41454 15.4276 6.70678 15.4276H12.3362C12.613 15.4276 12.8207 15.22 12.8207 14.9509C12.8207 14.674 12.613 14.4587 12.3362 14.4587Z" fill="#37352F" fill-opacity="0.45"/>
+</svg>
diff --git a/app/components/base/notion-page-selector/assets/search.svg b/app/components/base/notion-page-selector/assets/search.svg
new file mode 100644
index 0000000..1d083d0
--- /dev/null
+++ b/app/components/base/notion-page-selector/assets/search.svg
@@ -0,0 +1,5 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Icon">
+<path id="Icon_2" d="M12.25 12.25L10.2084 10.2083M11.6667 6.70833C11.6667 9.44675 9.44675 11.6667 6.70833 11.6667C3.96992 11.6667 1.75 9.44675 1.75 6.70833C1.75 3.96992 3.96992 1.75 6.70833 1.75C9.44675 1.75 11.6667 3.96992 11.6667 6.70833Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>
diff --git a/app/components/base/notion-page-selector/assets/setting.svg b/app/components/base/notion-page-selector/assets/setting.svg
new file mode 100644
index 0000000..6d3ecf5
--- /dev/null
+++ b/app/components/base/notion-page-selector/assets/setting.svg
@@ -0,0 +1,11 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5943_4745)">
+<path d="M6.99984 8.74984C7.96634 8.74984 8.74984 7.96634 8.74984 6.99984C8.74984 6.03334 7.96634 5.24984 6.99984 5.24984C6.03334 5.24984 5.24984 6.03334 5.24984 6.99984C5.24984 7.96634 6.03334 8.74984 6.99984 8.74984Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M10.9241 8.59075C10.8535 8.75069 10.8324 8.92812 10.8636 9.10015C10.8948 9.27218 10.9768 9.43092 11.0991 9.5559L11.1309 9.58772C11.2295 9.68622 11.3077 9.80319 11.3611 9.93195C11.4145 10.0607 11.442 10.1987 11.442 10.3381C11.442 10.4775 11.4145 10.6155 11.3611 10.7442C11.3077 10.873 11.2295 10.99 11.1309 11.0885C11.0324 11.1871 10.9154 11.2653 10.7867 11.3187C10.6579 11.3721 10.5199 11.3995 10.3805 11.3995C10.2411 11.3995 10.1031 11.3721 9.97437 11.3187C9.84561 11.2653 9.72864 11.1871 9.63014 11.0885L9.59832 11.0567C9.47334 10.9344 9.3146 10.8524 9.14257 10.8212C8.97055 10.79 8.79312 10.8111 8.63317 10.8817C8.47632 10.9489 8.34256 11.0605 8.24833 11.2028C8.15411 11.345 8.10355 11.5118 8.10287 11.6824V11.7726C8.10287 12.0539 7.99112 12.3236 7.79222 12.5225C7.59332 12.7214 7.32355 12.8332 7.04226 12.8332C6.76097 12.8332 6.4912 12.7214 6.2923 12.5225C6.0934 12.3236 5.98166 12.0539 5.98166 11.7726V11.7248C5.97755 11.5493 5.92073 11.3791 5.81859 11.2363C5.71645 11.0935 5.57371 10.9847 5.40893 10.9241C5.24898 10.8535 5.07155 10.8324 4.89953 10.8636C4.7275 10.8948 4.56876 10.9768 4.44378 11.0991L4.41196 11.1309C4.31346 11.2295 4.19648 11.3077 4.06773 11.3611C3.93897 11.4145 3.80096 11.442 3.66158 11.442C3.5222 11.442 3.38419 11.4145 3.25543 11.3611C3.12668 11.3077 3.0097 11.2295 2.9112 11.1309C2.81259 11.0324 2.73436 10.9154 2.68099 10.7867C2.62761 10.6579 2.60014 10.5199 2.60014 10.3805C2.60014 10.2411 2.62761 10.1031 2.68099 9.97437C2.73436 9.84561 2.81259 9.72864 2.9112 9.63014L2.94302 9.59832C3.06527 9.47334 3.14728 9.3146 3.17848 9.14257C3.20967 8.97055 3.18861 8.79312 3.11802 8.63317C3.0508 8.47632 2.93918 8.34256 2.7969 8.24833C2.65463 8.15411 2.48791 8.10355 2.31726 8.10287H2.22711C1.94582 8.10287 1.67605 7.99112 1.47715 7.79222C1.27825 7.59332 1.1665 7.32355 1.1665 7.04226C1.1665 6.76097 1.27825 6.4912 1.47715 6.2923C1.67605 6.0934 1.94582 5.98166 2.22711 5.98166H2.27484C2.45036 5.97755 2.6206 5.92073 2.7634 5.81859C2.90621 5.71645 3.01499 5.57371 3.07559 5.40893C3.14619 5.24898 3.16724 5.07155 3.13605 4.89953C3.10486 4.7275 3.02285 4.56876 2.90059 4.44378L2.86878 4.41196C2.77017 4.31346 2.69194 4.19648 2.63856 4.06773C2.58519 3.93897 2.55772 3.80096 2.55772 3.66158C2.55772 3.5222 2.58519 3.38419 2.63856 3.25543C2.69194 3.12668 2.77017 3.0097 2.86878 2.9112C2.96728 2.81259 3.08425 2.73436 3.21301 2.68099C3.34176 2.62761 3.47978 2.60014 3.61916 2.60014C3.75854 2.60014 3.89655 2.62761 4.0253 2.68099C4.15406 2.73436 4.27103 2.81259 4.36953 2.9112L4.40135 2.94302C4.52633 3.06527 4.68507 3.14728 4.8571 3.17848C5.02913 3.20967 5.20656 3.18861 5.3665 3.11802H5.40893C5.56578 3.0508 5.69954 2.93918 5.79377 2.7969C5.88799 2.65463 5.93855 2.48791 5.93923 2.31726V2.22711C5.93923 1.94582 6.05097 1.67605 6.24988 1.47715C6.44878 1.27825 6.71855 1.1665 6.99984 1.1665C7.28113 1.1665 7.5509 1.27825 7.7498 1.47715C7.9487 1.67605 8.06044 1.94582 8.06044 2.22711V2.27484C8.06112 2.44548 8.11169 2.6122 8.20591 2.75448C8.30013 2.89675 8.4339 3.00837 8.59075 3.07559C8.75069 3.14619 8.92812 3.16724 9.10015 3.13605C9.27218 3.10486 9.43092 3.02285 9.5559 2.90059L9.58772 2.86878C9.68622 2.77017 9.80319 2.69194 9.93195 2.63856C10.0607 2.58519 10.1987 2.55772 10.3381 2.55772C10.4775 2.55772 10.6155 2.58519 10.7442 2.63856C10.873 2.69194 10.99 2.77017 11.0885 2.86878C11.1871 2.96728 11.2653 3.08425 11.3187 3.21301C11.3721 3.34176 11.3995 3.47978 11.3995 3.61916C11.3995 3.75854 11.3721 3.89655 11.3187 4.0253C11.2653 4.15406 11.1871 4.27103 11.0885 4.36953L11.0567 4.40135C10.9344 4.52633 10.8524 4.68507 10.8212 4.8571C10.79 5.02913 10.8111 5.20656 10.8817 5.3665V5.40893C10.9489 5.56578 11.0605 5.69954 11.2028 5.79377C11.345 5.88799 11.5118 5.93855 11.6824 5.93923H11.7726C12.0539 5.93923 12.3236 6.05097 12.5225 6.24988C12.7214 6.44878 12.8332 6.71855 12.8332 6.99984C12.8332 7.28113 12.7214 7.5509 12.5225 7.7498C12.3236 7.9487 12.0539 8.06044 11.7726 8.06044H11.7248C11.5542 8.06112 11.3875 8.11169 11.2452 8.20591C11.1029 8.30013 10.9913 8.4339 10.9241 8.59075Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_5943_4745">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/base/notion-page-selector/base.tsx b/app/components/base/notion-page-selector/base.tsx
new file mode 100644
index 0000000..7ee7587
--- /dev/null
+++ b/app/components/base/notion-page-selector/base.tsx
@@ -0,0 +1,136 @@
+import { useCallback, useEffect, useMemo, useState } from 'react'
+import useSWR from 'swr'
+import { RiEqualizer2Line } from '@remixicon/react'
+import WorkspaceSelector from './workspace-selector'
+import SearchInput from './search-input'
+import PageSelector from './page-selector'
+import { preImportNotionPages } from '@/service/datasets'
+import { NotionConnector } from '@/app/components/datasets/create/step-one'
+import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common'
+import { useModalContext } from '@/context/modal-context'
+
+type NotionPageSelectorProps = {
+ value?: string[]
+ onSelect: (selectedPages: NotionPage[]) => void
+ canPreview?: boolean
+ previewPageId?: string
+ onPreview?: (selectedPage: NotionPage) => void
+ datasetId?: string
+}
+
+const NotionPageSelector = ({
+ value,
+ onSelect,
+ canPreview,
+ previewPageId,
+ onPreview,
+ datasetId = '',
+}: NotionPageSelectorProps) => {
+ const { data, mutate } = useSWR({ url: '/notion/pre-import/pages', datasetId }, preImportNotionPages)
+ const [prevData, setPrevData] = useState(data)
+ const [searchValue, setSearchValue] = useState('')
+ const [currentWorkspaceId, setCurrentWorkspaceId] = useState('')
+ const { setShowAccountSettingModal } = useModalContext()
+
+ const notionWorkspaces = useMemo(() => {
+ return data?.notion_info || []
+ }, [data?.notion_info])
+ const firstWorkspaceId = notionWorkspaces[0]?.workspace_id
+ const currentWorkspace = notionWorkspaces.find(workspace => workspace.workspace_id === currentWorkspaceId)
+
+ const getPagesMapAndSelectedPagesId: [DataSourceNotionPageMap, Set<string>, Set<string>] = useMemo(() => {
+ const selectedPagesId = new Set<string>()
+ const boundPagesId = new Set<string>()
+ const pagesMap = notionWorkspaces.reduce((prev: DataSourceNotionPageMap, next: DataSourceNotionWorkspace) => {
+ next.pages.forEach((page) => {
+ if (page.is_bound) {
+ selectedPagesId.add(page.page_id)
+ boundPagesId.add(page.page_id)
+ }
+ prev[page.page_id] = {
+ ...page,
+ workspace_id: next.workspace_id,
+ }
+ })
+
+ return prev
+ }, {})
+ return [pagesMap, selectedPagesId, boundPagesId]
+ }, [notionWorkspaces])
+ const defaultSelectedPagesId = [...Array.from(getPagesMapAndSelectedPagesId[1]), ...(value || [])]
+ const [selectedPagesId, setSelectedPagesId] = useState<Set<string>>(new Set(defaultSelectedPagesId))
+
+ if (prevData !== data) {
+ setPrevData(data)
+ setSelectedPagesId(new Set(defaultSelectedPagesId))
+ }
+
+ const handleSearchValueChange = useCallback((value: string) => {
+ setSearchValue(value)
+ }, [])
+ const handleSelectWorkspace = useCallback((workspaceId: string) => {
+ setCurrentWorkspaceId(workspaceId)
+ }, [])
+ const handleSelectPages = (newSelectedPagesId: Set<string>) => {
+ const selectedPages = Array.from(newSelectedPagesId).map(pageId => getPagesMapAndSelectedPagesId[0][pageId])
+
+ setSelectedPagesId(new Set(Array.from(newSelectedPagesId)))
+ onSelect(selectedPages)
+ }
+ const handlePreviewPage = (previewPageId: string) => {
+ if (onPreview)
+ onPreview(getPagesMapAndSelectedPagesId[0][previewPageId])
+ }
+
+ useEffect(() => {
+ setCurrentWorkspaceId(firstWorkspaceId)
+ }, [firstWorkspaceId])
+
+ return (
+ <div className='rounded-xl border border-components-panel-border bg-background-default-subtle'>
+ {
+ data?.notion_info?.length
+ ? (
+ <>
+ <div className='flex h-12 items-center gap-x-2 rounded-t-xl border-b border-b-divider-regular bg-components-panel-bg p-2'>
+ <div className='flex grow items-center gap-x-1'>
+ <WorkspaceSelector
+ value={currentWorkspaceId || firstWorkspaceId}
+ items={notionWorkspaces}
+ onSelect={handleSelectWorkspace}
+ />
+ <div className='mx-1 h-3 w-[1px] bg-divider-regular' />
+ <RiEqualizer2Line
+ className='h-4 w-4 cursor-pointer text-text-tertiary'
+ onClick={() => setShowAccountSettingModal({ payload: 'data-source', onCancelCallback: mutate })}
+ />
+ </div>
+ <SearchInput
+ value={searchValue}
+ onChange={handleSearchValueChange}
+ />
+ </div>
+ <div className='overflow-hidden rounded-b-xl'>
+ <PageSelector
+ value={selectedPagesId}
+ disabledValue={getPagesMapAndSelectedPagesId[2]}
+ searchValue={searchValue}
+ list={currentWorkspace?.pages || []}
+ pagesMap={getPagesMapAndSelectedPagesId[0]}
+ onSelect={handleSelectPages}
+ canPreview={canPreview}
+ previewPageId={previewPageId}
+ onPreview={handlePreviewPage}
+ />
+ </div>
+ </>
+ )
+ : (
+ <NotionConnector onSetting={() => setShowAccountSettingModal({ payload: 'data-source', onCancelCallback: mutate })} />
+ )
+ }
+ </div>
+ )
+}
+
+export default NotionPageSelector
diff --git a/app/components/base/notion-page-selector/index.tsx b/app/components/base/notion-page-selector/index.tsx
new file mode 100644
index 0000000..0a44c70
--- /dev/null
+++ b/app/components/base/notion-page-selector/index.tsx
@@ -0,0 +1,2 @@
+export { default as NotionPageSelectorModal } from './notion-page-selector-modal'
+export { default as NotionPageSelector } from './base'
diff --git a/app/components/base/notion-page-selector/notion-page-selector-modal/index.module.css b/app/components/base/notion-page-selector/notion-page-selector-modal/index.module.css
new file mode 100644
index 0000000..cd1f9c7
--- /dev/null
+++ b/app/components/base/notion-page-selector/notion-page-selector-modal/index.module.css
@@ -0,0 +1,28 @@
+.modal {
+ width: 600px !important;
+ max-width: 600px !important;
+ padding: 24px 32px !important;
+}
+
+.operate {
+ padding: 0 8px;
+ min-width: 96px;
+ height: 36px;
+ line-height: 36px;
+ text-align: center;
+ background-color: #ffffff;
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+ border-radius: 8px;
+ border: 0.5px solid #eaecf0;
+ font-size: 14px;
+ font-weight: 500;
+ color: #667085;
+ cursor: pointer;
+}
+
+.operate-save {
+ margin-left: 8px;
+ border-color: #155eef;
+ background-color: #155eef;
+ color: #ffffff;
+}
diff --git a/app/components/base/notion-page-selector/notion-page-selector-modal/index.tsx b/app/components/base/notion-page-selector/notion-page-selector-modal/index.tsx
new file mode 100644
index 0000000..22d2a16
--- /dev/null
+++ b/app/components/base/notion-page-selector/notion-page-selector-modal/index.tsx
@@ -0,0 +1,63 @@
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { XMarkIcon } from '@heroicons/react/24/outline'
+import NotionPageSelector from '../base'
+import s from './index.module.css'
+import type { NotionPage } from '@/models/common'
+import cn from '@/utils/classnames'
+import Modal from '@/app/components/base/modal'
+import { noop } from 'lodash-es'
+
+type NotionPageSelectorModalProps = {
+ isShow: boolean
+ onClose: () => void
+ onSave: (selectedPages: NotionPage[]) => void
+ datasetId: string
+}
+const NotionPageSelectorModal = ({
+ isShow,
+ onClose,
+ onSave,
+ datasetId,
+}: NotionPageSelectorModalProps) => {
+ const { t } = useTranslation()
+ const [selectedPages, setSelectedPages] = useState<NotionPage[]>([])
+
+ const handleClose = () => {
+ onClose()
+ }
+ const handleSelectPage = (newSelectedPages: NotionPage[]) => {
+ setSelectedPages(newSelectedPages)
+ }
+ const handleSave = () => {
+ onSave(selectedPages)
+ }
+
+ return (
+ <Modal
+ className={s.modal}
+ isShow={isShow}
+ onClose={noop}
+ >
+ <div className='mb-6 flex h-8 items-center justify-between'>
+ <div className='text-xl font-semibold text-gray-900'>{t('common.dataSource.notion.selector.addPages')}</div>
+ <div
+ className='-mr-2 flex h-8 w-8 cursor-pointer items-center justify-center'
+ onClick={handleClose}>
+ <XMarkIcon className='h-4 w-4' />
+ </div>
+ </div>
+ <NotionPageSelector
+ onSelect={handleSelectPage}
+ canPreview={false}
+ datasetId={datasetId}
+ />
+ <div className='mt-8 flex justify-end'>
+ <div className={s.operate} onClick={handleClose}>{t('common.operation.cancel')}</div>
+ <div className={cn(s.operate, s['operate-save'])} onClick={handleSave}>{t('common.operation.save')}</div>
+ </div>
+ </Modal>
+ )
+}
+
+export default NotionPageSelectorModal
diff --git a/app/components/base/notion-page-selector/page-selector/index.tsx b/app/components/base/notion-page-selector/page-selector/index.tsx
new file mode 100644
index 0000000..4989559
--- /dev/null
+++ b/app/components/base/notion-page-selector/page-selector/index.tsx
@@ -0,0 +1,320 @@
+import { memo, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { FixedSizeList as List, areEqual } from 'react-window'
+import type { ListChildComponentProps } from 'react-window'
+import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react'
+import Checkbox from '../../checkbox'
+import NotionIcon from '../../notion-icon'
+import cn from '@/utils/classnames'
+import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common'
+
+type PageSelectorProps = {
+ value: Set<string>
+ disabledValue: Set<string>
+ searchValue: string
+ pagesMap: DataSourceNotionPageMap
+ list: DataSourceNotionPage[]
+ onSelect: (selectedPagesId: Set<string>) => void
+ canPreview?: boolean
+ previewPageId?: string
+ onPreview?: (selectedPageId: string) => void
+}
+type NotionPageTreeItem = {
+ children: Set<string>
+ descendants: Set<string>
+ depth: number
+ ancestors: string[]
+} & DataSourceNotionPage
+type NotionPageTreeMap = Record<string, NotionPageTreeItem>
+type NotionPageItem = {
+ expand: boolean
+ depth: number
+} & DataSourceNotionPage
+
+const recursivePushInParentDescendants = (
+ pagesMap: DataSourceNotionPageMap,
+ listTreeMap: NotionPageTreeMap,
+ current: NotionPageTreeItem,
+ leafItem: NotionPageTreeItem,
+) => {
+ const parentId = current.parent_id
+ const pageId = current.page_id
+
+ if (!parentId || !pageId)
+ return
+
+ if (parentId !== 'root' && pagesMap[parentId]) {
+ if (!listTreeMap[parentId]) {
+ const children = new Set([pageId])
+ const descendants = new Set([pageId, leafItem.page_id])
+ listTreeMap[parentId] = {
+ ...pagesMap[parentId],
+ children,
+ descendants,
+ depth: 0,
+ ancestors: [],
+ }
+ }
+ else {
+ listTreeMap[parentId].children.add(pageId)
+ listTreeMap[parentId].descendants.add(pageId)
+ listTreeMap[parentId].descendants.add(leafItem.page_id)
+ }
+ leafItem.depth++
+ leafItem.ancestors.unshift(listTreeMap[parentId].page_name)
+
+ if (listTreeMap[parentId].parent_id !== 'root')
+ recursivePushInParentDescendants(pagesMap, listTreeMap, listTreeMap[parentId], leafItem)
+ }
+}
+
+const ItemComponent = ({ index, style, data }: ListChildComponentProps<{
+ dataList: NotionPageItem[]
+ handleToggle: (index: number) => void
+ checkedIds: Set<string>
+ disabledCheckedIds: Set<string>
+ handleCheck: (index: number) => void
+ canPreview?: boolean
+ handlePreview: (index: number) => void
+ listMapWithChildrenAndDescendants: NotionPageTreeMap
+ searchValue: string
+ previewPageId: string
+ pagesMap: DataSourceNotionPageMap
+}>) => {
+ const { t } = useTranslation()
+ const { dataList, handleToggle, checkedIds, disabledCheckedIds, handleCheck, canPreview, handlePreview, listMapWithChildrenAndDescendants, searchValue, previewPageId, pagesMap } = data
+ const current = dataList[index]
+ const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[current.page_id]
+ const hasChild = currentWithChildrenAndDescendants.descendants.size > 0
+ const ancestors = currentWithChildrenAndDescendants.ancestors
+ const breadCrumbs = ancestors.length ? [...ancestors, current.page_name] : [current.page_name]
+ const disabled = disabledCheckedIds.has(current.page_id)
+
+ const renderArrow = () => {
+ if (hasChild) {
+ return (
+ <div
+ className='mr-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-md hover:bg-components-button-ghost-bg-hover'
+ style={{ marginLeft: current.depth * 8 }}
+ onClick={() => handleToggle(index)}
+ >
+ {
+ current.expand
+ ? <RiArrowDownSLine className='h-4 w-4 text-text-tertiary' />
+ : <RiArrowRightSLine className='h-4 w-4 text-text-tertiary' />
+ }
+ </div>
+ )
+ }
+ if (current.parent_id === 'root' || !pagesMap[current.parent_id]) {
+ return (
+ <div></div>
+ )
+ }
+ return (
+ <div className='mr-1 h-5 w-5 shrink-0' style={{ marginLeft: current.depth * 8 }} />
+ )
+ }
+
+ return (
+ <div
+ className={cn('group flex cursor-pointer items-center rounded-md pl-2 pr-[2px] hover:bg-state-base-hover',
+ previewPageId === current.page_id && 'bg-state-base-hover')}
+ style={{ ...style, top: style.top as number + 8, left: 8, right: 8, width: 'calc(100% - 16px)' }}
+ >
+ <Checkbox
+ className='mr-2 shrink-0'
+ checked={checkedIds.has(current.page_id)}
+ disabled={disabled}
+ onCheck={() => {
+ if (disabled)
+ return
+ handleCheck(index)
+ }}
+ />
+ {!searchValue && renderArrow()}
+ <NotionIcon
+ className='mr-1 shrink-0'
+ type='page'
+ src={current.page_icon}
+ />
+ <div
+ className='grow truncate text-[13px] font-medium leading-4 text-text-secondary'
+ title={current.page_name}
+ >
+ {current.page_name}
+ </div>
+ {
+ canPreview && (
+ <div
+ className='ml-1 hidden h-6 shrink-0 cursor-pointer items-center rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-2 text-xs
+ font-medium leading-4 text-components-button-secondary-text shadow-xs shadow-shadow-shadow-3 backdrop-blur-[10px]
+ hover:border-components-button-secondary-border-hover hover:bg-components-button-secondary-bg-hover group-hover:flex'
+ onClick={() => handlePreview(index)}>
+ {t('common.dataSource.notion.selector.preview')}
+ </div>
+ )
+ }
+ {
+ searchValue && (
+ <div
+ className='ml-1 max-w-[120px] shrink-0 truncate text-xs text-text-quaternary'
+ title={breadCrumbs.join(' / ')}
+ >
+ {breadCrumbs.join(' / ')}
+ </div>
+ )
+ }
+ </div>
+ )
+}
+const Item = memo(ItemComponent, areEqual)
+
+const PageSelector = ({
+ value,
+ disabledValue,
+ searchValue,
+ pagesMap,
+ list,
+ onSelect,
+ canPreview = true,
+ previewPageId,
+ onPreview,
+}: PageSelectorProps) => {
+ const { t } = useTranslation()
+ const [prevDataList, setPrevDataList] = useState(list)
+ const [dataList, setDataList] = useState<NotionPageItem[]>([])
+ const [localPreviewPageId, setLocalPreviewPageId] = useState('')
+ if (prevDataList !== list) {
+ setPrevDataList(list)
+ setDataList(list.filter(item => item.parent_id === 'root' || !pagesMap[item.parent_id]).map((item) => {
+ return {
+ ...item,
+ expand: false,
+ depth: 0,
+ }
+ }))
+ }
+ const searchDataList = list.filter((item) => {
+ return item.page_name.includes(searchValue)
+ }).map((item) => {
+ return {
+ ...item,
+ expand: false,
+ depth: 0,
+ }
+ })
+ const currentDataList = searchValue ? searchDataList : dataList
+ const currentPreviewPageId = previewPageId === undefined ? localPreviewPageId : previewPageId
+
+ const listMapWithChildrenAndDescendants = useMemo(() => {
+ return list.reduce((prev: NotionPageTreeMap, next: DataSourceNotionPage) => {
+ const pageId = next.page_id
+ if (!prev[pageId])
+ prev[pageId] = { ...next, children: new Set(), descendants: new Set(), depth: 0, ancestors: [] }
+
+ recursivePushInParentDescendants(pagesMap, prev, prev[pageId], prev[pageId])
+ return prev
+ }, {})
+ }, [list, pagesMap])
+
+ const handleToggle = (index: number) => {
+ const current = dataList[index]
+ const pageId = current.page_id
+ const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[pageId]
+ const descendantsIds = Array.from(currentWithChildrenAndDescendants.descendants)
+ const childrenIds = Array.from(currentWithChildrenAndDescendants.children)
+ let newDataList = []
+
+ if (current.expand) {
+ current.expand = false
+
+ newDataList = [...dataList.filter(item => !descendantsIds.includes(item.page_id))]
+ }
+ else {
+ current.expand = true
+
+ newDataList = [
+ ...dataList.slice(0, index + 1),
+ ...childrenIds.map(item => ({
+ ...pagesMap[item],
+ expand: false,
+ depth: listMapWithChildrenAndDescendants[item].depth,
+ })),
+ ...dataList.slice(index + 1)]
+ }
+ setDataList(newDataList)
+ }
+
+ const copyValue = new Set([...value])
+ const handleCheck = (index: number) => {
+ const current = currentDataList[index]
+ const pageId = current.page_id
+ const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[pageId]
+
+ if (copyValue.has(pageId)) {
+ if (!searchValue) {
+ for (const item of currentWithChildrenAndDescendants.descendants)
+ copyValue.delete(item)
+ }
+
+ copyValue.delete(pageId)
+ }
+ else {
+ if (!searchValue) {
+ for (const item of currentWithChildrenAndDescendants.descendants)
+ copyValue.add(item)
+ }
+
+ copyValue.add(pageId)
+ }
+
+ onSelect(new Set([...copyValue]))
+ }
+
+ const handlePreview = (index: number) => {
+ const current = currentDataList[index]
+ const pageId = current.page_id
+
+ setLocalPreviewPageId(pageId)
+
+ if (onPreview)
+ onPreview(pageId)
+ }
+
+ if (!currentDataList.length) {
+ return (
+ <div className='flex h-[296px] items-center justify-center text-[13px] text-text-tertiary'>
+ {t('common.dataSource.notion.selector.noSearchResult')}
+ </div>
+ )
+ }
+
+ return (
+ <List
+ className='py-2'
+ height={296}
+ itemCount={currentDataList.length}
+ itemSize={28}
+ width='100%'
+ itemKey={(index, data) => data.dataList[index].page_id}
+ itemData={{
+ dataList: currentDataList,
+ handleToggle,
+ checkedIds: value,
+ disabledCheckedIds: disabledValue,
+ handleCheck,
+ canPreview,
+ handlePreview,
+ listMapWithChildrenAndDescendants,
+ searchValue,
+ previewPageId: currentPreviewPageId,
+ pagesMap,
+ }}
+ >
+ {Item}
+ </List>
+ )
+}
+
+export default PageSelector
diff --git a/app/components/base/notion-page-selector/search-input/index.tsx b/app/components/base/notion-page-selector/search-input/index.tsx
new file mode 100644
index 0000000..6bf819e
--- /dev/null
+++ b/app/components/base/notion-page-selector/search-input/index.tsx
@@ -0,0 +1,42 @@
+import { useCallback } from 'react'
+import type { ChangeEvent } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseCircleFill, RiSearchLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+
+type SearchInputProps = {
+ value: string
+ onChange: (v: string) => void
+}
+const SearchInput = ({
+ value,
+ onChange,
+}: SearchInputProps) => {
+ const { t } = useTranslation()
+
+ const handleClear = useCallback(() => {
+ onChange('')
+ }, [onChange])
+
+ return (
+ <div className={cn('flex h-8 w-[200px] items-center rounded-lg bg-components-input-bg-normal p-2')}>
+ <RiSearchLine className={'mr-0.5 h-4 w-4 shrink-0 text-components-input-text-placeholder'} />
+ <input
+ className='min-w-0 grow appearance-none border-0 bg-transparent px-1 text-[13px] leading-[16px] text-components-input-text-filled outline-0 placeholder:text-components-input-text-placeholder'
+ value={value}
+ onChange={(e: ChangeEvent<HTMLInputElement>) => onChange(e.target.value)}
+ placeholder={t('common.dataSource.notion.selector.searchPages') || ''}
+ />
+ {
+ value && (
+ <RiCloseCircleFill
+ className={'h-4 w-4 shrink-0 cursor-pointer text-components-input-text-placeholder'}
+ onClick={handleClear}
+ />
+ )
+ }
+ </div>
+ )
+}
+
+export default SearchInput
diff --git a/app/components/base/notion-page-selector/workspace-selector/index.tsx b/app/components/base/notion-page-selector/workspace-selector/index.tsx
new file mode 100644
index 0000000..2e7b57f
--- /dev/null
+++ b/app/components/base/notion-page-selector/workspace-selector/index.tsx
@@ -0,0 +1,80 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { Fragment } from 'react'
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import { RiArrowDownSLine } from '@remixicon/react'
+import NotionIcon from '../../notion-icon'
+import type { DataSourceNotionWorkspace } from '@/models/common'
+
+type WorkspaceSelectorProps = {
+ value: string
+ items: Omit<DataSourceNotionWorkspace, 'total'>[]
+ onSelect: (v: string) => void
+}
+export default function WorkspaceSelector({
+ value,
+ items,
+ onSelect,
+}: WorkspaceSelectorProps) {
+ const { t } = useTranslation()
+ const currentWorkspace = items.find(item => item.workspace_id === value)
+
+ return (
+ <Menu as="div" className="relative inline-block text-left">
+ {
+ ({ open }) => (
+ <>
+ <MenuButton className={`flex h-7 items-center justify-center rounded-md p-1 pr-2 hover:bg-state-base-hover ${open && 'bg-state-base-hover'} cursor-pointer`}>
+ <NotionIcon
+ className='mr-2'
+ src={currentWorkspace?.workspace_icon}
+ name={currentWorkspace?.workspace_name}
+ />
+ <div className='mr-1 w-[90px] truncate text-left text-sm font-medium text-text-secondary' title={currentWorkspace?.workspace_name}>{currentWorkspace?.workspace_name}</div>
+ {/* <div className='mr-1 px-1 h-[18px] bg-primary-50 rounded-lg text-xs font-medium text-text-accent'>{currentWorkspace?.pages.length}</div> */}
+ <RiArrowDownSLine className='h-4 w-4 text-text-secondary' />
+ </MenuButton>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems
+ className='absolute left-0 top-8 z-10 w-80
+ origin-top-right rounded-lg border-[0.5px]
+ border-components-panel-border bg-components-panel-bg-blur shadow-lg shadow-shadow-shadow-5 backdrop-blur-[5px]'
+ >
+ <div className="max-h-50 overflow-auto p-1">
+ {
+ items.map(item => (
+ <MenuItem key={item.workspace_id}>
+ <div
+ className='flex h-9 cursor-pointer items-center rounded-lg px-3 hover:bg-state-base-hover'
+ onClick={() => onSelect(item.workspace_id)}
+ >
+ <NotionIcon
+ className='mr-2 shrink-0'
+ src={item.workspace_icon}
+ name={item.workspace_name}
+ />
+ <div className='system-sm-medium mr-2 grow truncate text-text-secondary' title={item.workspace_name}>{item.workspace_name}</div>
+ <div className='system-xs-medium shrink-0 text-text-accent'>
+ {item.pages.length} {t('common.dataSource.notion.selector.pageSelected')}
+ </div>
+ </div>
+ </MenuItem>
+ ))
+ }
+ </div>
+ </MenuItems>
+ </Transition>
+ </>
+ )
+ }
+ </Menu>
+ )
+}
diff --git a/app/components/base/pagination/hook.ts b/app/components/base/pagination/hook.ts
new file mode 100644
index 0000000..32a2af8
--- /dev/null
+++ b/app/components/base/pagination/hook.ts
@@ -0,0 +1,95 @@
+import React, { useCallback } from 'react'
+import type { IPaginationProps, IUsePagination } from './type'
+
+const usePagination = ({
+ currentPage,
+ setCurrentPage,
+ truncableText = '...',
+ truncableClassName = '',
+ totalPages,
+ edgePageCount,
+ middlePagesSiblingCount,
+}: IPaginationProps): IUsePagination => {
+ const pages = new Array(totalPages)
+ .fill(0)
+ .map((_, i) => i + 1)
+
+ const hasPreviousPage = currentPage > 1
+ const hasNextPage = currentPage < totalPages
+
+ const isReachedToFirst = currentPage <= middlePagesSiblingCount
+ const isReachedToLast = currentPage + middlePagesSiblingCount >= totalPages
+
+ const middlePages = React.useMemo(() => {
+ const middlePageCount = middlePagesSiblingCount * 2 + 1
+ if (isReachedToFirst)
+ return pages.slice(0, middlePageCount)
+
+ if (isReachedToLast)
+ return pages.slice(-middlePageCount)
+
+ return pages.slice(
+ currentPage - middlePagesSiblingCount,
+ currentPage + middlePagesSiblingCount + 1,
+ )
+ }, [currentPage, isReachedToFirst, isReachedToLast, middlePagesSiblingCount, pages])
+
+ const getAllPreviousPages = useCallback(() => {
+ return pages.slice(0, middlePages[0] - 1)
+ }, [middlePages, pages])
+
+ const previousPages = React.useMemo(() => {
+ if (isReachedToFirst || getAllPreviousPages().length < 1)
+ return []
+
+ return pages
+ .slice(0, edgePageCount)
+ .filter(p => !middlePages.includes(p))
+ }, [edgePageCount, getAllPreviousPages, isReachedToFirst, middlePages, pages])
+
+ const getAllNextPages = React.useMemo(() => {
+ return pages.slice(
+ middlePages[middlePages.length - 1],
+ pages[pages.length],
+ )
+ }, [pages, middlePages])
+
+ const nextPages = React.useMemo(() => {
+ if (isReachedToLast)
+ return []
+
+ if (getAllNextPages.length < 1)
+ return []
+
+ return pages
+ .slice(pages.length - edgePageCount, pages.length)
+ .filter(p => !middlePages.includes(p))
+ }, [edgePageCount, getAllNextPages.length, isReachedToLast, middlePages, pages])
+
+ const isPreviousTruncable = React.useMemo(() => {
+ // Is truncable if first value of middlePage is larger than last value of previousPages
+ return middlePages[0] > previousPages[previousPages.length - 1] + 1
+ }, [previousPages, middlePages])
+
+ const isNextTruncable = React.useMemo(() => {
+ // Is truncable if last value of middlePage is larger than first value of previousPages
+ return middlePages[middlePages.length - 1] + 1 < nextPages[0]
+ }, [nextPages, middlePages])
+
+ return {
+ currentPage,
+ setCurrentPage,
+ truncableText,
+ truncableClassName,
+ pages,
+ hasPreviousPage,
+ hasNextPage,
+ previousPages,
+ isPreviousTruncable,
+ middlePages,
+ isNextTruncable,
+ nextPages,
+ }
+}
+
+export default usePagination
diff --git a/app/components/base/pagination/index.tsx b/app/components/base/pagination/index.tsx
new file mode 100644
index 0000000..8126f66
--- /dev/null
+++ b/app/components/base/pagination/index.tsx
@@ -0,0 +1,167 @@
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowLeftLine, RiArrowRightLine } from '@remixicon/react'
+import { useDebounceFn } from 'ahooks'
+import { Pagination } from './pagination'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import cn from '@/utils/classnames'
+
+export type Props = {
+ className?: string
+ current: number
+ onChange: (cur: number) => void
+ total: number
+ limit?: number
+ onLimitChange?: (limit: number) => void
+}
+
+const CustomizedPagination: FC<Props> = ({
+ className,
+ current,
+ onChange,
+ total,
+ limit = 10,
+ onLimitChange,
+}) => {
+ const { t } = useTranslation()
+ const totalPages = Math.ceil(total / limit)
+ const inputRef = React.useRef<HTMLDivElement>(null)
+ const [showInput, setShowInput] = React.useState(false)
+ const [inputValue, setInputValue] = React.useState<string | number>(current + 1)
+ const [showPerPageTip, setShowPerPageTip] = React.useState(false)
+
+ const { run: handlePaging } = useDebounceFn((value: string) => {
+ if (Number.parseInt(value) > totalPages) {
+ setInputValue(totalPages)
+ onChange(totalPages - 1)
+ setShowInput(false)
+ return
+ }
+ if (Number.parseInt(value) < 1) {
+ setInputValue(1)
+ onChange(0)
+ setShowInput(false)
+ return
+ }
+ onChange(Number.parseInt(value) - 1)
+ setInputValue(Number.parseInt(value))
+ setShowInput(false)
+ }, { wait: 500 })
+
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ const value = e.target.value
+ if (!value)
+ return setInputValue('')
+ if (isNaN(Number.parseInt(value)))
+ return setInputValue('')
+ setInputValue(Number.parseInt(value))
+ handlePaging(value)
+ }
+
+ return (
+ <Pagination
+ className={cn('flex w-full select-none items-center px-6 py-3', className)}
+ currentPage={current}
+ edgePageCount={2}
+ middlePagesSiblingCount={1}
+ setCurrentPage={onChange}
+ totalPages={totalPages}
+ truncableClassName='flex items-center justify-center w-8 px-1 py-2 system-sm-medium text-text-tertiary'
+ truncableText='...'
+ >
+ <div className='flex items-center gap-0.5 rounded-[10px] bg-background-section-burn p-0.5'>
+ <Pagination.PrevButton
+ as={<div></div>}
+ disabled={current === 0}
+ >
+ <Button
+ variant='secondary'
+ className='h-7 w-7 px-1.5'
+ disabled={current === 0}
+ >
+ <RiArrowLeftLine className='h-4 w-4' />
+ </Button>
+ </Pagination.PrevButton>
+ {!showInput && (
+ <div
+ ref={inputRef}
+ className='flex items-center gap-0.5 rounded-lg px-2 py-1.5 hover:cursor-text hover:bg-state-base-hover-alt'
+ onClick={() => setShowInput(true)}
+ >
+ <div className='system-xs-medium text-text-secondary'>{current + 1}</div>
+ <div className='system-xs-medium text-text-quaternary'>/</div>
+ <div className='system-xs-medium text-text-secondary'>{totalPages}</div>
+ </div>
+ )}
+ {showInput && (
+ <Input
+ styleCss={{
+ height: '28px',
+ width: `${inputRef.current?.clientWidth}px`,
+ }}
+ placeholder=''
+ autoFocus
+ value={inputValue}
+ onChange={handleInputChange}
+ onBlur={() => setShowInput(false)}
+ />
+ )}
+ <Pagination.NextButton
+ as={<div></div>}
+ disabled={current === totalPages - 1}
+ >
+ <Button
+ variant='secondary'
+ className='h-7 w-7 px-1.5'
+ disabled={current === totalPages - 1}
+ >
+ <RiArrowRightLine className='h-4 w-4' />
+ </Button>
+ </Pagination.NextButton>
+ </div>
+ <div className={cn('flex grow list-none items-center justify-center gap-1')}>
+ <Pagination.PageButton
+ className='system-sm-medium flex min-w-8 cursor-pointer items-center justify-center rounded-lg px-1 py-2 hover:bg-components-button-ghost-bg-hover'
+ activeClassName='bg-components-button-tertiary-bg text-components-button-tertiary-text hover:bg-components-button-ghost-bg-hover'
+ inactiveClassName='text-text-tertiary'
+ />
+ </div>
+ {onLimitChange && (
+ <div className='flex shrink-0 items-center gap-2'>
+ <div className='system-2xs-regular-uppercase w-[51px] shrink-0 text-end text-text-tertiary'>{showPerPageTip ? t('common.pagination.perPage') : ''}</div>
+ <div
+ className='flex items-center gap-[1px] rounded-[10px] bg-components-segmented-control-bg-normal p-0.5'
+ onMouseEnter={() => setShowPerPageTip(true)}
+ onMouseLeave={() => setShowPerPageTip(false)}
+ >
+ <div
+ className={cn(
+ 'system-sm-medium cursor-pointer rounded-lg border-[0.5px] border-transparent px-2.5 py-1.5 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
+ limit === 10 && 'border-components-segmented-control-item-active-border bg-components-segmented-control-item-active-bg text-text-secondary shadow-xs hover:bg-components-segmented-control-item-active-bg',
+ )}
+ onClick={() => onLimitChange?.(10)}
+ >10</div>
+ <div
+ className={cn(
+ 'system-sm-medium cursor-pointer rounded-lg border-[0.5px] border-transparent px-2.5 py-1.5 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
+ limit === 25 && 'border-components-segmented-control-item-active-border bg-components-segmented-control-item-active-bg text-text-secondary shadow-xs hover:bg-components-segmented-control-item-active-bg',
+ )}
+ onClick={() => onLimitChange?.(25)}
+ >25</div>
+ <div
+ className={cn(
+ 'system-sm-medium cursor-pointer rounded-lg border-[0.5px] border-transparent px-2.5 py-1.5 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
+ limit === 50 && 'border-components-segmented-control-item-active-border bg-components-segmented-control-item-active-bg text-text-secondary shadow-xs hover:bg-components-segmented-control-item-active-bg',
+ )}
+ onClick={() => onLimitChange?.(50)}
+ >50</div>
+ </div>
+ </div>
+ )}
+ </Pagination>
+ )
+}
+
+export default CustomizedPagination
diff --git a/app/components/base/pagination/pagination.tsx b/app/components/base/pagination/pagination.tsx
new file mode 100644
index 0000000..ec8b035
--- /dev/null
+++ b/app/components/base/pagination/pagination.tsx
@@ -0,0 +1,190 @@
+import React from 'react'
+import clsx from 'clsx'
+import usePagination from './hook'
+import type {
+ ButtonProps,
+ IPagination,
+ IPaginationProps,
+ PageButtonProps,
+} from './type'
+import { noop } from 'lodash-es'
+
+const defaultState: IPagination = {
+ currentPage: 0,
+ setCurrentPage: noop,
+ truncableText: '...',
+ truncableClassName: '',
+ pages: [],
+ hasPreviousPage: false,
+ hasNextPage: false,
+ previousPages: [],
+ isPreviousTruncable: false,
+ middlePages: [],
+ isNextTruncable: false,
+ nextPages: [],
+}
+
+const PaginationContext: React.Context<IPagination> = React.createContext<IPagination>(defaultState)
+
+export const PrevButton = ({
+ className,
+ children,
+ dataTestId,
+ as = <button />,
+ ...buttonProps
+}: ButtonProps) => {
+ const pagination = React.useContext(PaginationContext)
+ const previous = () => {
+ if (pagination.currentPage + 1 > 1)
+ pagination.setCurrentPage(pagination.currentPage - 1)
+ }
+
+ const disabled = pagination.currentPage === 0
+
+ return (
+ <as.type
+ {...buttonProps}
+ {...as.props}
+ className={clsx(className, as.props.className)}
+ onClick={() => previous()}
+ tabIndex={disabled ? '-1' : 0}
+ disabled={disabled}
+ data-testid={dataTestId}
+ onKeyPress={(event: React.KeyboardEvent) => {
+ event.preventDefault()
+ if (event.key === 'Enter' && !disabled)
+ previous()
+ }}
+ >
+ {as.props.children ?? children}
+ </as.type>
+ )
+}
+
+export const NextButton = ({
+ className,
+ children,
+ dataTestId,
+ as = <button />,
+ ...buttonProps
+}: ButtonProps) => {
+ const pagination = React.useContext(PaginationContext)
+ const next = () => {
+ if (pagination.currentPage + 1 < pagination.pages.length)
+ pagination.setCurrentPage(pagination.currentPage + 1)
+ }
+
+ const disabled = pagination.currentPage === pagination.pages.length - 1
+
+ return (
+ <as.type
+ {...buttonProps}
+ {...as.props}
+ className={clsx(className, as.props.className)}
+ onClick={() => next()}
+ tabIndex={disabled ? '-1' : 0}
+ disabled={disabled}
+ data-testid={dataTestId}
+ onKeyPress={(event: React.KeyboardEvent) => {
+ event.preventDefault()
+ if (event.key === 'Enter' && !disabled)
+ next()
+ }}
+ >
+ {as.props.children ?? children}
+ </as.type>
+ )
+}
+
+type ITruncableElementProps = {
+ prev?: boolean
+}
+
+const TruncableElement = ({ prev }: ITruncableElementProps) => {
+ const pagination: IPagination = React.useContext(PaginationContext)
+
+ const {
+ isPreviousTruncable,
+ isNextTruncable,
+ truncableText,
+ truncableClassName,
+ } = pagination
+
+ return ((isPreviousTruncable && prev === true) || (isNextTruncable && !prev))
+ ? (
+ <li className={truncableClassName || undefined}>{truncableText}</li>
+ )
+ : null
+}
+
+export const PageButton = ({
+ as = <a />,
+ className,
+ dataTestIdActive,
+ dataTestIdInactive,
+ activeClassName,
+ inactiveClassName,
+ renderExtraProps,
+}: PageButtonProps) => {
+ const pagination: IPagination = React.useContext(PaginationContext)
+
+ const renderPageButton = (page: number) => (
+ <li key={page}>
+ <as.type
+ data-testid={
+ clsx({
+ [`${dataTestIdActive}`]:
+ dataTestIdActive && pagination.currentPage + 1 === page,
+ [`${dataTestIdInactive}-${page}`]:
+ dataTestIdActive && pagination.currentPage + 1 !== page,
+ }) || undefined
+ }
+ tabIndex={0}
+ onKeyPress={(event: React.KeyboardEvent) => {
+ if (event.key === 'Enter')
+ pagination.setCurrentPage(page - 1)
+ }}
+ onClick={() => pagination.setCurrentPage(page - 1)}
+ className={clsx(
+ className,
+ pagination.currentPage + 1 === page
+ ? activeClassName
+ : inactiveClassName,
+ )}
+ {...as.props}
+ {...(renderExtraProps ? renderExtraProps(page) : {})}
+ >
+ {page}
+ </as.type>
+ </li>
+ )
+
+ return (
+ <>
+ {pagination.previousPages.map(renderPageButton)}
+ <TruncableElement prev />
+ {pagination.middlePages.map(renderPageButton)}
+ <TruncableElement />
+ {pagination.nextPages.map(renderPageButton)}
+ </>
+ )
+}
+
+export const Pagination = ({
+ dataTestId,
+ ...paginationProps
+}: IPaginationProps & { dataTestId?: string }) => {
+ const pagination = usePagination(paginationProps)
+
+ return (
+ <PaginationContext.Provider value={pagination}>
+ <div className={paginationProps.className} data-testid={dataTestId}>
+ {paginationProps.children}
+ </div>
+ </PaginationContext.Provider>
+ )
+}
+
+Pagination.PrevButton = PrevButton
+Pagination.NextButton = NextButton
+Pagination.PageButton = PageButton
diff --git a/app/components/base/pagination/type.ts b/app/components/base/pagination/type.ts
new file mode 100644
index 0000000..c3744c0
--- /dev/null
+++ b/app/components/base/pagination/type.ts
@@ -0,0 +1,58 @@
+import type { ButtonHTMLAttributes } from 'react'
+
+type IBasePaginationProps = {
+ currentPage: number
+ setCurrentPage: (page: number) => void
+ truncableText?: string
+ truncableClassName?: string
+}
+
+type IPaginationProps = IBasePaginationProps & {
+ totalPages: number
+ edgePageCount: number
+ middlePagesSiblingCount: number
+ className?: string
+ children?: React.ReactNode
+}
+
+type IUsePagination = IBasePaginationProps & {
+ pages: number[]
+ hasPreviousPage: boolean
+ hasNextPage: boolean
+ previousPages: number[]
+ isPreviousTruncable: boolean
+ middlePages: number[]
+ isNextTruncable: boolean
+ nextPages: number[]
+}
+
+type IPagination = IUsePagination & {
+ setCurrentPage: (page: number) => void
+}
+
+type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
+ as?: React.ReactNode
+ children?: string | React.ReactNode
+ className?: string
+ dataTestId?: string
+}
+
+type PageButtonProps = ButtonProps & {
+ /**
+ * Provide a custom ReactNode (e.g. Next/Link)
+ */
+ as?: React.ReactNode
+ activeClassName?: string
+ inactiveClassName?: string
+ dataTestIdActive?: string
+ dataTestIdInactive?: string
+ renderExtraProps?: (pageNum: number) => {}
+}
+
+export type {
+ IPaginationProps,
+ IUsePagination,
+ IPagination,
+ ButtonProps,
+ PageButtonProps,
+}
diff --git a/app/components/base/param-item/index.tsx b/app/components/base/param-item/index.tsx
new file mode 100644
index 0000000..03eb5a7
--- /dev/null
+++ b/app/components/base/param-item/index.tsx
@@ -0,0 +1,79 @@
+'use client'
+import type { FC } from 'react'
+import { InputNumber } from '../input-number'
+import Tooltip from '@/app/components/base/tooltip'
+import Slider from '@/app/components/base/slider'
+import Switch from '@/app/components/base/switch'
+
+type Props = {
+ className?: string
+ id: string
+ name: string
+ noTooltip?: boolean
+ tip?: string
+ value: number
+ enable: boolean
+ step?: number
+ min?: number
+ max: number
+ onChange: (key: string, value: number) => void
+ hasSwitch?: boolean
+ onSwitchChange?: (key: string, enable: boolean) => void
+}
+
+const ParamItem: FC<Props> = ({ className, id, name, noTooltip, tip, step = 0.1, min = 0, max, value, enable, onChange, hasSwitch, onSwitchChange }) => {
+ return (
+ <div className={className}>
+ <div className="flex items-center justify-between">
+ <div className="flex h-6 items-center">
+ {hasSwitch && (
+ <Switch
+ size='md'
+ className='mr-2'
+ defaultValue={enable}
+ onChange={async (val) => {
+ onSwitchChange?.(id, val)
+ }}
+ />
+ )}
+ <span className="system-sm-semibold mr-1 text-text-secondary">{name}</span>
+ {!noTooltip && (
+ <Tooltip
+ triggerClassName='w-4 h-4 shrink-0'
+ popupContent={<div className="w-[200px]">{tip}</div>}
+ />
+ )}
+ </div>
+ </div>
+ <div className="mt-1 flex items-center">
+ <div className="mr-3 flex shrink-0 items-center">
+ <InputNumber
+ disabled={!enable}
+ type="number"
+ min={min}
+ max={max}
+ step={step}
+ amount={step}
+ size='regular'
+ value={value}
+ onChange={(value) => {
+ onChange(id, value)
+ }}
+ className='w-[72px]'
+ />
+ </div>
+ <div className="flex grow items-center">
+ <Slider
+ className='w-full'
+ disabled={!enable}
+ value={max < 5 ? value * 100 : value}
+ min={min < 1 ? min * 100 : min}
+ max={max < 5 ? max * 100 : max}
+ onChange={value => onChange(id, value / (max < 5 ? 100 : 1))}
+ />
+ </div>
+ </div>
+ </div>
+ )
+}
+export default ParamItem
diff --git a/app/components/base/param-item/score-threshold-item.tsx b/app/components/base/param-item/score-threshold-item.tsx
new file mode 100644
index 0000000..b5557c8
--- /dev/null
+++ b/app/components/base/param-item/score-threshold-item.tsx
@@ -0,0 +1,54 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import ParamItem from '.'
+
+type Props = {
+ className?: string
+ value: number
+ onChange: (key: string, value: number) => void
+ enable: boolean
+ hasSwitch?: boolean
+ onSwitchChange?: (key: string, enable: boolean) => void
+}
+
+const VALUE_LIMIT = {
+ default: 0.7,
+ step: 0.01,
+ min: 0,
+ max: 1,
+}
+
+const key = 'score_threshold'
+const ScoreThresholdItem: FC<Props> = ({
+ className,
+ value,
+ enable,
+ onChange,
+ hasSwitch,
+ onSwitchChange,
+}) => {
+ const { t } = useTranslation()
+ const handleParamChange = (key: string, value: number) => {
+ let notOutRangeValue = Number.parseFloat(value.toFixed(2))
+ notOutRangeValue = Math.max(VALUE_LIMIT.min, notOutRangeValue)
+ notOutRangeValue = Math.min(VALUE_LIMIT.max, notOutRangeValue)
+ onChange(key, notOutRangeValue)
+ }
+ return (
+ <ParamItem
+ className={className}
+ id={key}
+ name={t(`appDebug.datasetConfig.${key}`)}
+ tip={t(`appDebug.datasetConfig.${key}Tip`) as string}
+ {...VALUE_LIMIT}
+ value={value}
+ enable={enable}
+ onChange={handleParamChange}
+ hasSwitch={hasSwitch}
+ onSwitchChange={onSwitchChange}
+ />
+ )
+}
+export default React.memo(ScoreThresholdItem)
diff --git a/app/components/base/param-item/top-k-item.tsx b/app/components/base/param-item/top-k-item.tsx
new file mode 100644
index 0000000..4c4c857
--- /dev/null
+++ b/app/components/base/param-item/top-k-item.tsx
@@ -0,0 +1,54 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import ParamItem from '.'
+
+type Props = {
+ className?: string
+ value: number
+ onChange: (key: string, value: number) => void
+ enable: boolean
+}
+
+const maxTopK = (() => {
+ const configValue = Number.parseInt(globalThis.document?.body?.getAttribute('data-public-top-k-max-value') || '', 10)
+ if (configValue && !isNaN(configValue))
+ return configValue
+ return 10
+})()
+const VALUE_LIMIT = {
+ default: 2,
+ step: 1,
+ min: 1,
+ max: maxTopK,
+}
+
+const key = 'top_k'
+const TopKItem: FC<Props> = ({
+ className,
+ value,
+ enable,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const handleParamChange = (key: string, value: number) => {
+ let notOutRangeValue = Number.parseFloat(value.toFixed(2))
+ notOutRangeValue = Math.max(VALUE_LIMIT.min, notOutRangeValue)
+ notOutRangeValue = Math.min(VALUE_LIMIT.max, notOutRangeValue)
+ onChange(key, notOutRangeValue)
+ }
+ return (
+ <ParamItem
+ className={className}
+ id={key}
+ name={t(`appDebug.datasetConfig.${key}`)}
+ tip={t(`appDebug.datasetConfig.${key}Tip`) as string}
+ {...VALUE_LIMIT}
+ value={value}
+ enable={enable}
+ onChange={handleParamChange}
+ />
+ )
+}
+export default React.memo(TopKItem)
diff --git a/app/components/base/popover/index.tsx b/app/components/base/popover/index.tsx
new file mode 100644
index 0000000..2a831e0
--- /dev/null
+++ b/app/components/base/popover/index.tsx
@@ -0,0 +1,120 @@
+import { Popover, PopoverButton, PopoverPanel, Transition } from '@headlessui/react'
+import { Fragment, cloneElement, useRef } from 'react'
+import cn from '@/utils/classnames'
+
+export type HtmlContentProps = {
+ onClose?: () => void
+ onClick?: () => void
+}
+
+type IPopover = {
+ className?: string
+ htmlContent: React.ReactNode
+ popupClassName?: string
+ trigger?: 'click' | 'hover'
+ position?: 'bottom' | 'br' | 'bl'
+ btnElement?: string | React.ReactNode
+ btnClassName?: string | ((open: boolean) => string)
+ manualClose?: boolean
+ disabled?: boolean
+}
+
+const timeoutDuration = 100
+
+export default function CustomPopover({
+ trigger = 'hover',
+ position = 'bottom',
+ htmlContent,
+ popupClassName,
+ btnElement,
+ className,
+ btnClassName,
+ manualClose,
+ disabled = false,
+}: IPopover) {
+ const buttonRef = useRef<HTMLButtonElement>(null)
+ const timeOutRef = useRef<number | null>(null)
+
+ const onMouseEnter = (isOpen: boolean) => {
+ timeOutRef.current && window.clearTimeout(timeOutRef.current)
+ !isOpen && buttonRef.current?.click()
+ }
+
+ const onMouseLeave = (isOpen: boolean) => {
+ timeOutRef.current = window.setTimeout(() => {
+ isOpen && buttonRef.current?.click()
+ }, timeoutDuration)
+ }
+
+ return (
+ <Popover className="relative">
+ {({ open }: { open: boolean }) => {
+ return (
+ <>
+ <div
+ {...(trigger !== 'hover'
+ ? {}
+ : {
+ onMouseLeave: () => onMouseLeave(open),
+ onMouseEnter: () => onMouseEnter(open),
+ })}
+ >
+ <PopoverButton
+ ref={buttonRef}
+ disabled={disabled}
+ className={cn(
+ 'group inline-flex items-center rounded-lg border border-components-button-secondary-border bg-components-button-secondary-bg px-3 py-2 text-base font-medium hover:border-components-button-secondary-border-hover hover:bg-components-button-secondary-bg-hover focus:outline-none',
+ open && 'border-components-button-secondary-border bg-components-button-secondary-bg-hover',
+ (btnClassName && typeof btnClassName === 'string') && btnClassName,
+ (btnClassName && typeof btnClassName !== 'string') && btnClassName?.(open),
+ )}
+ >
+ {btnElement}
+ </PopoverButton>
+ <Transition as={Fragment}>
+ <PopoverPanel
+ className={cn(
+ 'absolute z-10 mt-1 w-full max-w-sm px-4 sm:px-0 lg:max-w-3xl',
+ position === 'bottom' && 'left-1/2 -translate-x-1/2',
+ position === 'bl' && 'left-0',
+ position === 'br' && 'right-0',
+ className,
+ )}
+ {...(trigger !== 'hover'
+ ? {}
+ : {
+ onMouseLeave: () => onMouseLeave(open),
+ onMouseEnter: () => onMouseEnter(open),
+ })
+ }
+ >
+ {({ close }) => (
+ <div
+ className={cn('w-fit min-w-[130px] overflow-hidden rounded-lg bg-components-panel-bg shadow-lg ring-1 ring-black/5', popupClassName)}
+ {...(trigger !== 'hover'
+ ? {}
+ : {
+ onMouseLeave: () => onMouseLeave(open),
+ onMouseEnter: () => onMouseEnter(open),
+ })
+ }
+ >
+ {cloneElement(htmlContent as React.ReactElement, {
+ onClose: () => onMouseLeave(open),
+ ...(manualClose
+ ? {
+ onClick: close,
+ }
+ : {}),
+ })}
+ </div>
+ )}
+ </PopoverPanel>
+ </Transition>
+ </div>
+ </>
+ )
+ }}
+ </Popover>
+ )
+}
diff --git a/app/components/base/portal-to-follow-elem/index.spec.tsx b/app/components/base/portal-to-follow-elem/index.spec.tsx
new file mode 100644
index 0000000..74790d7
--- /dev/null
+++ b/app/components/base/portal-to-follow-elem/index.spec.tsx
@@ -0,0 +1,121 @@
+import React from 'react'
+import { cleanup, fireEvent, render } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '.'
+
+afterEach(cleanup)
+
+describe('PortalToFollowElem', () => {
+ describe('Context and Provider', () => {
+ test('should throw error when using context outside provider', () => {
+ // Suppress console.error for this test
+ const originalError = console.error
+ console.error = jest.fn()
+
+ expect(() => {
+ render(
+ <PortalToFollowElemTrigger>Trigger </PortalToFollowElemTrigger>,
+ )
+ }).toThrow('PortalToFollowElem components must be wrapped in <PortalToFollowElem />')
+
+ console.error = originalError
+ })
+
+ test('should not throw when used within provider', () => {
+ expect(() => {
+ render(
+ <PortalToFollowElem>
+ <PortalToFollowElemTrigger>Trigger </PortalToFollowElemTrigger>
+ </PortalToFollowElem>,
+ )
+ }).not.toThrow()
+ })
+ })
+
+ describe('PortalToFollowElemTrigger', () => {
+ test('should render children correctly', () => {
+ const { getByText } = render(
+ <PortalToFollowElem>
+ <PortalToFollowElemTrigger>Trigger Text </PortalToFollowElemTrigger>
+ </PortalToFollowElem>,
+ )
+ expect(getByText('Trigger Text')).toBeInTheDocument()
+ })
+
+ test('should handle asChild prop correctly', () => {
+ const { getByRole } = render(
+ <PortalToFollowElem>
+ <PortalToFollowElemTrigger asChild >
+ <button>Button Trigger </button>
+ </PortalToFollowElemTrigger>
+ </PortalToFollowElem>,
+ )
+
+ expect(getByRole('button')).toHaveTextContent('Button Trigger')
+ })
+ })
+
+ describe('PortalToFollowElemContent', () => {
+ test('should not render content when closed', () => {
+ const { queryByText } = render(
+ <PortalToFollowElem open={false} >
+ <PortalToFollowElemTrigger>Trigger </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent > Popup Content </PortalToFollowElemContent>
+ </PortalToFollowElem>,
+ )
+
+ expect(queryByText('Popup Content')).not.toBeInTheDocument()
+ })
+
+ test('should render content when open', () => {
+ const { getByText } = render(
+ <PortalToFollowElem open={true} >
+ <PortalToFollowElemTrigger>Trigger </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent > Popup Content </PortalToFollowElemContent>
+ </PortalToFollowElem>,
+ )
+
+ expect(getByText('Popup Content')).toBeInTheDocument()
+ })
+ })
+
+ describe('Controlled behavior', () => {
+ test('should call onOpenChange when interaction happens', () => {
+ const handleOpenChange = jest.fn()
+
+ const { getByText } = render(
+ <PortalToFollowElem onOpenChange={handleOpenChange} >
+ <PortalToFollowElemTrigger>Hover Me </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent > Content </PortalToFollowElemContent>
+ </PortalToFollowElem>,
+ )
+
+ fireEvent.mouseEnter(getByText('Hover Me'))
+ expect(handleOpenChange).toHaveBeenCalled()
+
+ fireEvent.mouseLeave(getByText('Hover Me'))
+ expect(handleOpenChange).toHaveBeenCalled()
+ })
+ })
+
+ describe('Configuration options', () => {
+ test('should accept placement prop', () => {
+ // Since we can't easily test actual positioning, we'll check if the prop is passed correctly
+ const useFloatingMock = jest.spyOn(require('@floating-ui/react'), 'useFloating')
+
+ render(
+ <PortalToFollowElem placement="top-start" >
+ <PortalToFollowElemTrigger>Trigger </PortalToFollowElemTrigger>
+ </PortalToFollowElem>,
+ )
+
+ expect(useFloatingMock).toHaveBeenCalledWith(
+ expect.objectContaining({
+ placement: 'top-start',
+ }),
+ )
+
+ useFloatingMock.mockRestore()
+ })
+ })
+})
diff --git a/app/components/base/portal-to-follow-elem/index.tsx b/app/components/base/portal-to-follow-elem/index.tsx
new file mode 100644
index 0000000..1e2e198
--- /dev/null
+++ b/app/components/base/portal-to-follow-elem/index.tsx
@@ -0,0 +1,187 @@
+'use client'
+import React from 'react'
+import {
+ FloatingPortal,
+ autoUpdate,
+ flip,
+ offset,
+ shift,
+ size,
+ useDismiss,
+ useFloating,
+ useFocus,
+ useHover,
+ useInteractions,
+ useMergeRefs,
+ useRole,
+} from '@floating-ui/react'
+
+import type { OffsetOptions, Placement } from '@floating-ui/react'
+import cn from '@/utils/classnames'
+export type PortalToFollowElemOptions = {
+ /*
+ * top, bottom, left, right
+ * start, end. Default is middle
+ * combine: top-start, top-end
+ */
+ placement?: Placement
+ open?: boolean
+ offset?: number | OffsetOptions
+ onOpenChange?: (open: boolean) => void
+ triggerPopupSameWidth?: boolean
+}
+
+export function usePortalToFollowElem({
+ placement = 'bottom',
+ open,
+ offset: offsetValue = 0,
+ onOpenChange: setControlledOpen,
+ triggerPopupSameWidth,
+}: PortalToFollowElemOptions = {}) {
+ const setOpen = setControlledOpen
+
+ const data = useFloating({
+ placement,
+ open,
+ onOpenChange: setOpen,
+ whileElementsMounted: autoUpdate,
+ middleware: [
+ offset(offsetValue),
+ flip({
+ crossAxis: placement.includes('-'),
+ fallbackAxisSideDirection: 'start',
+ padding: 5,
+ }),
+ shift({ padding: 5 }),
+ size({
+ apply({ rects, elements }) {
+ if (triggerPopupSameWidth)
+ elements.floating.style.width = `${rects.reference.width}px`
+ },
+ }),
+ ],
+ })
+
+ const context = data.context
+
+ const hover = useHover(context, {
+ move: false,
+ enabled: open == null,
+ })
+ const focus = useFocus(context, {
+ enabled: open == null,
+ })
+ const dismiss = useDismiss(context)
+ const role = useRole(context, { role: 'tooltip' })
+
+ const interactions = useInteractions([hover, focus, dismiss, role])
+
+ return React.useMemo(
+ () => ({
+ open,
+ setOpen,
+ ...interactions,
+ ...data,
+ }),
+ [open, setOpen, interactions, data],
+ )
+}
+
+type ContextType = ReturnType<typeof usePortalToFollowElem> | null
+
+const PortalToFollowElemContext = React.createContext<ContextType>(null)
+
+export function usePortalToFollowElemContext() {
+ const context = React.useContext(PortalToFollowElemContext)
+
+ if (context == null)
+ throw new Error('PortalToFollowElem components must be wrapped in <PortalToFollowElem />')
+
+ return context
+}
+
+export function PortalToFollowElem({
+ children,
+ ...options
+}: { children: React.ReactNode } & PortalToFollowElemOptions) {
+ // This can accept any props as options, e.g. `placement`,
+ // or other positioning options.
+ const tooltip = usePortalToFollowElem(options)
+ return (
+ <PortalToFollowElemContext.Provider value={tooltip}>
+ {children}
+ </PortalToFollowElemContext.Provider>
+ )
+}
+
+export const PortalToFollowElemTrigger = (
+ {
+ ref: propRef,
+ children,
+ asChild = false,
+ ...props
+ }: React.HTMLProps<HTMLElement> & { ref?: React.RefObject<HTMLElement>, asChild?: boolean },
+) => {
+ const context = usePortalToFollowElemContext()
+ const childrenRef = (children as any).props?.ref
+ const ref = useMergeRefs([context.refs.setReference, propRef, childrenRef])
+
+ // `asChild` allows the user to pass any element as the anchor
+ if (asChild && React.isValidElement(children)) {
+ return React.cloneElement(
+ children,
+ context.getReferenceProps({
+ ref,
+ ...props,
+ ...children.props,
+ 'data-state': context.open ? 'open' : 'closed',
+ }),
+ )
+ }
+
+ return (
+ <div
+ ref={ref}
+ className={cn('inline-block', props.className)}
+ // The user can style the trigger based on the state
+ data-state={context.open ? 'open' : 'closed'}
+ {...context.getReferenceProps(props)}
+ >
+ {children}
+ </div>
+ )
+}
+PortalToFollowElemTrigger.displayName = 'PortalToFollowElemTrigger'
+
+export const PortalToFollowElemContent = (
+ {
+ ref: propRef,
+ style,
+ ...props
+ }: React.HTMLProps<HTMLDivElement> & {
+ ref?: React.RefObject<HTMLDivElement>;
+ },
+) => {
+ const context = usePortalToFollowElemContext()
+ const ref = useMergeRefs([context.refs.setFloating, propRef])
+
+ if (!context.open)
+ return null
+
+ const body = document.body
+
+ return (
+ <FloatingPortal root={body}>
+ <div
+ ref={ref}
+ style={{
+ ...context.floatingStyles,
+ ...style,
+ }}
+ {...context.getFloatingProps(props)}
+ />
+ </FloatingPortal>
+ )
+}
+
+PortalToFollowElemContent.displayName = 'PortalToFollowElemContent'
diff --git a/app/components/base/premium-badge/index.css b/app/components/base/premium-badge/index.css
new file mode 100644
index 0000000..61031cd
--- /dev/null
+++ b/app/components/base/premium-badge/index.css
@@ -0,0 +1,56 @@
+@tailwind components;
+
+@layer components {
+ .premium-badge {
+ @apply shrink-0 relative inline-flex justify-center items-center rounded-md box-border border border-transparent text-white shadow-xs hover:shadow-lg bg-origin-border overflow-hidden transition-all duration-100 ease-out;
+ background-clip: padding-box, border-box;
+ }
+ .allowHover {
+ @apply cursor-pointer;
+ }
+
+ /* m is for the regular button */
+ .premium-badge-m {
+ @apply !p-1 h-6 w-auto
+ }
+
+ .premium-badge-s {
+ @apply border-[0.5px] !px-1 !py-[3px] h-[18px] w-auto
+ }
+
+ .premium-badge-blue {
+ @apply bg-util-colors-blue-blue-200;
+ background-image: linear-gradient(90deg, #5289ffe6 0%, #155aefe6 100%), linear-gradient(135deg, var(--color-premium-badge-border-highlight-color) 0%, #155aef 100%);
+ }
+ .premium-badge-blue.allowHover:hover {
+ @apply bg-util-colors-blue-blue-300;
+ background-image: linear-gradient(90deg, #296dffe6 0%, #004aebe6 100%), linear-gradient(135deg, var(--color-premium-badge-border-highlight-color) 0%, #00329e 100%);
+ }
+
+ .premium-badge-indigo {
+ @apply bg-util-colors-indigo-indigo-200;
+ background-image: linear-gradient(90deg, #8098f9e6 0%, #444ce7e6 100%), linear-gradient(135deg, var(--color-premium-badge-border-highlight-color) 0%, #6172f3 100%);
+ }
+ .premium-badge-indigo.allowHover:hover {
+ @apply bg-util-colors-indigo-indigo-300;
+ background-image: linear-gradient(90deg, #6172f3e6 0%, #2d31a6e6 100%), linear-gradient(135deg, var(--color-premium-badge-border-highlight-color) 0%, #2d31a6 100%);
+ }
+
+ .premium-badge-gray {
+ @apply bg-util-colors-gray-gray-200;
+ background-image: linear-gradient(90deg, #98a2b2e6 0%, #676f83e6 100%), linear-gradient(135deg, var(--color-premium-badge-border-highlight-color) 0%, #676f83 100%);
+ }
+ .premium-badge-gray.allowHover:hover {
+ @apply bg-util-colors-gray-gray-300;
+ background-image: linear-gradient(90deg, #676f83e6 0%, #354052e6 100%), linear-gradient(135deg, var(--color-premium-badge-border-highlight-color) 0%, #354052 100%);
+ }
+
+ .premium-badge-orange {
+ @apply bg-util-colors-orange-orange-200;
+ background-image: linear-gradient(90deg, #ff692ee6 0%, #e04f16e6 100%), linear-gradient(135deg, var(--color-premium-badge-border-highlight-color) 0%, #e62e05 100%);
+ }
+ .premium-badge-orange.allowHover:hover {
+ @apply bg-util-colors-orange-orange-300;
+ background-image: linear-gradient(90deg, #ff4405e6 0%, #b93815e6 100%), linear-gradient(135deg, var(--color-premium-badge-border-highlight-color) 0%, #e62e05 100%);
+ }
+}
diff --git a/app/components/base/premium-badge/index.tsx b/app/components/base/premium-badge/index.tsx
new file mode 100644
index 0000000..ce162d7
--- /dev/null
+++ b/app/components/base/premium-badge/index.tsx
@@ -0,0 +1,74 @@
+import type { CSSProperties, ReactNode } from 'react'
+import React from 'react'
+import { type VariantProps, cva } from 'class-variance-authority'
+import { Highlight } from '@/app/components/base/icons/src/public/common'
+import classNames from '@/utils/classnames'
+import './index.css'
+
+const PremiumBadgeVariants = cva(
+ 'premium-badge',
+ {
+ variants: {
+ size: {
+ s: 'premium-badge-s',
+ m: 'premium-badge-m',
+ },
+ color: {
+ blue: 'premium-badge-blue',
+ indigo: 'premium-badge-indigo',
+ gray: 'premium-badge-gray',
+ orange: 'premium-badge-orange',
+ },
+ allowHover: {
+ true: 'allowHover',
+ false: '',
+ },
+ },
+ defaultVariants: {
+ size: 'm',
+ color: 'blue',
+ allowHover: false,
+ },
+ },
+)
+
+type PremiumBadgeProps = {
+ size?: 's' | 'm'
+ color?: 'blue' | 'indigo' | 'gray' | 'orange'
+ allowHover?: boolean
+ styleCss?: CSSProperties
+ children?: ReactNode
+} & React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof PremiumBadgeVariants>
+
+const PremiumBadge: React.FC<PremiumBadgeProps> = ({
+ className,
+ size,
+ color,
+ allowHover,
+ styleCss,
+ children,
+ ...props
+}) => {
+ return (
+ <div
+ className={classNames(
+ PremiumBadgeVariants({ size, color, allowHover, className }),
+ 'relative text-nowrap',
+ )}
+ style={styleCss}
+ {...props}
+ >
+ {children}
+ <Highlight
+ className={classNames(
+ 'absolute top-0 opacity-50 right-1/2 translate-x-[20%] transition-all duration-100 ease-out hover:opacity-80 hover:translate-x-[30%]',
+ size === 's' ? 'h-[18px] w-12' : 'h-6 w-12',
+ )}
+ />
+ </div>
+ )
+}
+PremiumBadge.displayName = 'PremiumBadge'
+
+export default PremiumBadge
+export { PremiumBadge, PremiumBadgeVariants }
diff --git a/app/components/base/progress-bar/index.tsx b/app/components/base/progress-bar/index.tsx
new file mode 100644
index 0000000..759c9ea
--- /dev/null
+++ b/app/components/base/progress-bar/index.tsx
@@ -0,0 +1,20 @@
+type ProgressBarProps = {
+ percent: number
+}
+const ProgressBar = ({
+ percent = 0,
+}: ProgressBarProps) => {
+ return (
+ <div className='flex items-center'>
+ <div className='mr-2 w-[100px] rounded-lg bg-gray-100'>
+ <div
+ className='h-1 rounded-lg bg-[#2970FF]'
+ style={{ width: `${percent}%` }}
+ />
+ </div>
+ <div className='text-xs font-medium text-gray-500'>{percent}%</div>
+ </div>
+ )
+}
+
+export default ProgressBar
diff --git a/app/components/base/progress-bar/progress-circle.tsx b/app/components/base/progress-bar/progress-circle.tsx
new file mode 100644
index 0000000..b9b280e
--- /dev/null
+++ b/app/components/base/progress-bar/progress-circle.tsx
@@ -0,0 +1,64 @@
+import { memo } from 'react'
+import cn from '@/utils/classnames'
+
+type ProgressCircleProps = {
+ className?: string
+ percentage?: number
+ size?: number
+ circleStrokeWidth?: number
+ circleStrokeColor?: string
+ circleFillColor?: string
+ sectorFillColor?: string
+}
+
+const ProgressCircle: React.FC<ProgressCircleProps> = ({
+ className,
+ percentage = 0,
+ size = 12,
+ circleStrokeWidth = 1,
+ circleStrokeColor = 'stroke-components-progress-brand-border',
+ circleFillColor = 'fill-components-progress-brand-bg',
+ sectorFillColor = 'fill-components-progress-brand-progress',
+}) => {
+ const radius = size / 2
+ const center = size / 2
+ const angle = (percentage / 101) * 360
+ const radians = (angle * Math.PI) / 180
+ const x = center + radius * Math.cos(radians - Math.PI / 2)
+ const y = center + radius * Math.sin(radians - Math.PI / 2)
+ const largeArcFlag = percentage > 50 ? 1 : 0
+
+ const pathData = `
+ M ${center},${center}
+ L ${center},${center - radius}
+ A ${radius},${radius} 0 ${largeArcFlag} 1 ${x},${y}
+ Z
+ `
+
+ return (
+ <svg
+ width={size + circleStrokeWidth}
+ height={size + circleStrokeWidth}
+ viewBox={`0 0 ${size + circleStrokeWidth} ${size + circleStrokeWidth}`}
+ className={className}
+ >
+ <circle
+ className={cn(
+ circleFillColor,
+ circleStrokeColor,
+ )}
+ cx={center + circleStrokeWidth / 2}
+ cy={center + circleStrokeWidth / 2}
+ r={radius}
+ strokeWidth={circleStrokeWidth}
+ />
+ <path
+ className={cn(sectorFillColor)}
+ d={pathData}
+ transform={`translate(${circleStrokeWidth / 2}, ${circleStrokeWidth / 2})`}
+ />
+ </svg>
+ )
+}
+
+export default memo(ProgressCircle)
diff --git a/app/components/base/prompt-editor/constants.tsx b/app/components/base/prompt-editor/constants.tsx
new file mode 100644
index 0000000..31fbc0a
--- /dev/null
+++ b/app/components/base/prompt-editor/constants.tsx
@@ -0,0 +1,58 @@
+import { SupportUploadFileTypes, type ValueSelector } from '../../workflow/types'
+
+export const CONTEXT_PLACEHOLDER_TEXT = '{{#context#}}'
+export const HISTORY_PLACEHOLDER_TEXT = '{{#histories#}}'
+export const QUERY_PLACEHOLDER_TEXT = '{{#query#}}'
+export const PRE_PROMPT_PLACEHOLDER_TEXT = '{{#pre_prompt#}}'
+export const UPDATE_DATASETS_EVENT_EMITTER = 'prompt-editor-context-block-update-datasets'
+export const UPDATE_HISTORY_EVENT_EMITTER = 'prompt-editor-history-block-update-role'
+
+export const checkHasContextBlock = (text: string) => {
+ if (!text)
+ return false
+ return text.includes(CONTEXT_PLACEHOLDER_TEXT)
+}
+
+export const checkHasHistoryBlock = (text: string) => {
+ if (!text)
+ return false
+ return text.includes(HISTORY_PLACEHOLDER_TEXT)
+}
+
+export const checkHasQueryBlock = (text: string) => {
+ if (!text)
+ return false
+ return text.includes(QUERY_PLACEHOLDER_TEXT)
+}
+
+/*
+* {{#1711617514996.name#}} => [1711617514996, name]
+* {{#1711617514996.sys.query#}} => [sys, query]
+*/
+export const getInputVars = (text: string): ValueSelector[] => {
+ if (!text)
+ return []
+
+ const allVars = text.match(/{{#([^#]*)#}}/g)
+ if (allVars && allVars?.length > 0) {
+ // {{#context#}}, {{#query#}} is not input vars
+ const inputVars = allVars
+ .filter(item => item.includes('.'))
+ .map((item) => {
+ const valueSelector = item.replace('{{#', '').replace('#}}', '').split('.')
+ if (valueSelector[1] === 'sys' && /^\d+$/.test(valueSelector[0]))
+ return valueSelector.slice(1)
+
+ return valueSelector
+ })
+ return inputVars
+ }
+ return []
+}
+
+export const FILE_EXTS: Record<string, string[]> = {
+ [SupportUploadFileTypes.image]: ['JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG'],
+ [SupportUploadFileTypes.document]: ['TXT', 'MD', 'MDX', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOC', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB'],
+ [SupportUploadFileTypes.audio]: ['MP3', 'M4A', 'WAV', 'AMR', 'MPGA'],
+ [SupportUploadFileTypes.video]: ['MP4', 'MOV', 'MPEG', 'WEBM'],
+}
diff --git a/app/components/base/prompt-editor/hooks.ts b/app/components/base/prompt-editor/hooks.ts
new file mode 100644
index 0000000..c9e4cc1
--- /dev/null
+++ b/app/components/base/prompt-editor/hooks.ts
@@ -0,0 +1,185 @@
+import {
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from 'react'
+import type { Dispatch, RefObject, SetStateAction } from 'react'
+import type {
+ Klass,
+ LexicalCommand,
+ LexicalEditor,
+ TextNode,
+} from 'lexical'
+import {
+ $getNodeByKey,
+ $getSelection,
+ $isDecoratorNode,
+ $isNodeSelection,
+ COMMAND_PRIORITY_LOW,
+ KEY_BACKSPACE_COMMAND,
+ KEY_DELETE_COMMAND,
+} from 'lexical'
+import type { EntityMatch } from '@lexical/text'
+import {
+ mergeRegister,
+} from '@lexical/utils'
+import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { $isContextBlockNode } from './plugins/context-block/node'
+import { DELETE_CONTEXT_BLOCK_COMMAND } from './plugins/context-block'
+import { $isHistoryBlockNode } from './plugins/history-block/node'
+import { DELETE_HISTORY_BLOCK_COMMAND } from './plugins/history-block'
+import { $isQueryBlockNode } from './plugins/query-block/node'
+import { DELETE_QUERY_BLOCK_COMMAND } from './plugins/query-block'
+import type { CustomTextNode } from './plugins/custom-text/node'
+import { registerLexicalTextEntity } from './utils'
+
+export type UseSelectOrDeleteHandler = (nodeKey: string, command?: LexicalCommand<undefined>) => [RefObject<HTMLDivElement>, boolean]
+export const useSelectOrDelete: UseSelectOrDeleteHandler = (nodeKey: string, command?: LexicalCommand<undefined>) => {
+ const ref = useRef<HTMLDivElement>(null)
+ const [editor] = useLexicalComposerContext()
+ const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey)
+
+ const handleDelete = useCallback(
+ (event: KeyboardEvent) => {
+ const selection = $getSelection()
+ const nodes = selection?.getNodes()
+ if (
+ !isSelected
+ && nodes?.length === 1
+ && (
+ ($isContextBlockNode(nodes[0]) && command === DELETE_CONTEXT_BLOCK_COMMAND)
+ || ($isHistoryBlockNode(nodes[0]) && command === DELETE_HISTORY_BLOCK_COMMAND)
+ || ($isQueryBlockNode(nodes[0]) && command === DELETE_QUERY_BLOCK_COMMAND)
+ )
+ )
+ editor.dispatchCommand(command, undefined)
+
+ if (isSelected && $isNodeSelection(selection)) {
+ event.preventDefault()
+ const node = $getNodeByKey(nodeKey)
+ if ($isDecoratorNode(node)) {
+ if (command)
+ editor.dispatchCommand(command, undefined)
+
+ node.remove()
+ return true
+ }
+ }
+
+ return false
+ },
+ [isSelected, nodeKey, command, editor],
+ )
+
+ const handleSelect = useCallback((e: MouseEvent) => {
+ e.stopPropagation()
+ clearSelection()
+ setSelected(true)
+ }, [setSelected, clearSelection])
+
+ useEffect(() => {
+ const ele = ref.current
+
+ if (ele)
+ ele.addEventListener('click', handleSelect)
+
+ return () => {
+ if (ele)
+ ele.removeEventListener('click', handleSelect)
+ }
+ }, [handleSelect])
+ useEffect(() => {
+ return mergeRegister(
+ editor.registerCommand(
+ KEY_DELETE_COMMAND,
+ handleDelete,
+ COMMAND_PRIORITY_LOW,
+ ),
+ editor.registerCommand(
+ KEY_BACKSPACE_COMMAND,
+ handleDelete,
+ COMMAND_PRIORITY_LOW,
+ ),
+ )
+ }, [editor, clearSelection, handleDelete])
+
+ return [ref, isSelected]
+}
+
+export type UseTriggerHandler = () => [RefObject<HTMLDivElement>, boolean, Dispatch<SetStateAction<boolean>>]
+export const useTrigger: UseTriggerHandler = () => {
+ const triggerRef = useRef<HTMLDivElement>(null)
+ const [open, setOpen] = useState(false)
+ const handleOpen = useCallback((e: MouseEvent) => {
+ e.stopPropagation()
+ setOpen(v => !v)
+ }, [])
+
+ useEffect(() => {
+ const trigger = triggerRef.current
+ if (trigger)
+ trigger.addEventListener('click', handleOpen)
+
+ return () => {
+ if (trigger)
+ trigger.removeEventListener('click', handleOpen)
+ }
+ }, [handleOpen])
+
+ return [triggerRef, open, setOpen]
+}
+
+export function useLexicalTextEntity<T extends TextNode>(
+ getMatch: (text: string) => null | EntityMatch,
+ targetNode: Klass<T>,
+ createNode: (textNode: CustomTextNode) => T,
+) {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ return mergeRegister(...registerLexicalTextEntity(editor, getMatch, targetNode, createNode))
+ }, [createNode, editor, getMatch, targetNode])
+}
+
+export type MenuTextMatch = {
+ leadOffset: number
+ matchingString: string
+ replaceableString: string
+}
+export type TriggerFn = (
+ text: string,
+ editor: LexicalEditor,
+) => MenuTextMatch | null
+export const PUNCTUATION = '\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%\'"~=<>_:;'
+export function useBasicTypeaheadTriggerMatch(
+ trigger: string,
+ { minLength = 1, maxLength = 75 }: { minLength?: number; maxLength?: number },
+): TriggerFn {
+ return useCallback(
+ (text: string) => {
+ const validChars = `[${PUNCTUATION}\\s]`
+ const TypeaheadTriggerRegex = new RegExp(
+ '(.*)('
+ + `[${trigger}]`
+ + `((?:${validChars}){0,${maxLength}})`
+ + ')$',
+ )
+ const match = TypeaheadTriggerRegex.exec(text)
+ if (match !== null) {
+ const maybeLeadingWhitespace = match[1]
+ const matchingString = match[3]
+ if (matchingString.length >= minLength) {
+ return {
+ leadOffset: match.index + maybeLeadingWhitespace.length,
+ matchingString,
+ replaceableString: match[2],
+ }
+ }
+ }
+ return null
+ },
+ [maxLength, minLength, trigger],
+ )
+}
diff --git a/app/components/base/prompt-editor/index.tsx b/app/components/base/prompt-editor/index.tsx
new file mode 100644
index 0000000..94a65e4
--- /dev/null
+++ b/app/components/base/prompt-editor/index.tsx
@@ -0,0 +1,226 @@
+'use client'
+
+import type { FC } from 'react'
+import { useEffect } from 'react'
+import type {
+ EditorState,
+} from 'lexical'
+import {
+ $getRoot,
+ TextNode,
+} from 'lexical'
+import { CodeNode } from '@lexical/code'
+import { LexicalComposer } from '@lexical/react/LexicalComposer'
+import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
+import { ContentEditable } from '@lexical/react/LexicalContentEditable'
+import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary'
+import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
+import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'
+// import TreeView from './plugins/tree-view'
+import Placeholder from './plugins/placeholder'
+import ComponentPickerBlock from './plugins/component-picker-block'
+import {
+ ContextBlock,
+ ContextBlockNode,
+ ContextBlockReplacementBlock,
+} from './plugins/context-block'
+import {
+ QueryBlock,
+ QueryBlockNode,
+ QueryBlockReplacementBlock,
+} from './plugins/query-block'
+import {
+ HistoryBlock,
+ HistoryBlockNode,
+ HistoryBlockReplacementBlock,
+} from './plugins/history-block'
+import {
+ WorkflowVariableBlock,
+ WorkflowVariableBlockNode,
+ WorkflowVariableBlockReplacementBlock,
+} from './plugins/workflow-variable-block'
+import VariableBlock from './plugins/variable-block'
+import VariableValueBlock from './plugins/variable-value-block'
+import { VariableValueBlockNode } from './plugins/variable-value-block/node'
+import { CustomTextNode } from './plugins/custom-text/node'
+import OnBlurBlock from './plugins/on-blur-or-focus-block'
+import UpdateBlock from './plugins/update-block'
+import { textToEditorState } from './utils'
+import type {
+ ContextBlockType,
+ ExternalToolBlockType,
+ HistoryBlockType,
+ QueryBlockType,
+ VariableBlockType,
+ WorkflowVariableBlockType,
+} from './types'
+import {
+ UPDATE_DATASETS_EVENT_EMITTER,
+ UPDATE_HISTORY_EVENT_EMITTER,
+} from './constants'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import cn from '@/utils/classnames'
+
+export type PromptEditorProps = {
+ instanceId?: string
+ compact?: boolean
+ className?: string
+ placeholder?: string
+ placeholderClassName?: string
+ style?: React.CSSProperties
+ value?: string
+ editable?: boolean
+ onChange?: (text: string) => void
+ onBlur?: () => void
+ onFocus?: () => void
+ contextBlock?: ContextBlockType
+ queryBlock?: QueryBlockType
+ historyBlock?: HistoryBlockType
+ variableBlock?: VariableBlockType
+ externalToolBlock?: ExternalToolBlockType
+ workflowVariableBlock?: WorkflowVariableBlockType
+ isSupportFileVar?: boolean
+}
+
+const PromptEditor: FC<PromptEditorProps> = ({
+ instanceId,
+ compact,
+ className,
+ placeholder,
+ placeholderClassName,
+ style,
+ value,
+ editable = true,
+ onChange,
+ onBlur,
+ onFocus,
+ contextBlock,
+ queryBlock,
+ historyBlock,
+ variableBlock,
+ externalToolBlock,
+ workflowVariableBlock,
+ isSupportFileVar,
+}) => {
+ const { eventEmitter } = useEventEmitterContextContext()
+ const initialConfig = {
+ namespace: 'prompt-editor',
+ nodes: [
+ CodeNode,
+ CustomTextNode,
+ {
+ replace: TextNode,
+ with: (node: TextNode) => new CustomTextNode(node.__text),
+ },
+ ContextBlockNode,
+ HistoryBlockNode,
+ QueryBlockNode,
+ WorkflowVariableBlockNode,
+ VariableValueBlockNode,
+ ],
+ editorState: textToEditorState(value || ''),
+ onError: (error: Error) => {
+ throw error
+ },
+ }
+
+ const handleEditorChange = (editorState: EditorState) => {
+ const text = editorState.read(() => {
+ return $getRoot().getChildren().map(p => p.getTextContent()).join('\n')
+ })
+ if (onChange)
+ onChange(text)
+ }
+
+ useEffect(() => {
+ eventEmitter?.emit({
+ type: UPDATE_DATASETS_EVENT_EMITTER,
+ payload: contextBlock?.datasets,
+ } as any)
+ }, [eventEmitter, contextBlock?.datasets])
+ useEffect(() => {
+ eventEmitter?.emit({
+ type: UPDATE_HISTORY_EVENT_EMITTER,
+ payload: historyBlock?.history,
+ } as any)
+ }, [eventEmitter, historyBlock?.history])
+
+ return (
+ <LexicalComposer initialConfig={{ ...initialConfig, editable }}>
+ <div className='relative min-h-5'>
+ <RichTextPlugin
+ contentEditable={<ContentEditable className={`${className} outline-none ${compact ? 'text-[13px] leading-5' : 'text-sm leading-6'} text-text-secondary`} style={style || {}} />}
+ placeholder={<Placeholder value={placeholder} className={cn('truncate', placeholderClassName)} compact={compact} />}
+ ErrorBoundary={LexicalErrorBoundary}
+ />
+ <ComponentPickerBlock
+ triggerString='/'
+ contextBlock={contextBlock}
+ historyBlock={historyBlock}
+ queryBlock={queryBlock}
+ variableBlock={variableBlock}
+ externalToolBlock={externalToolBlock}
+ workflowVariableBlock={workflowVariableBlock}
+ isSupportFileVar={isSupportFileVar}
+ />
+ <ComponentPickerBlock
+ triggerString='{'
+ contextBlock={contextBlock}
+ historyBlock={historyBlock}
+ queryBlock={queryBlock}
+ variableBlock={variableBlock}
+ externalToolBlock={externalToolBlock}
+ workflowVariableBlock={workflowVariableBlock}
+ isSupportFileVar={isSupportFileVar}
+ />
+ {
+ contextBlock?.show && (
+ <>
+ <ContextBlock {...contextBlock} />
+ <ContextBlockReplacementBlock {...contextBlock} />
+ </>
+ )
+ }
+ {
+ queryBlock?.show && (
+ <>
+ <QueryBlock {...queryBlock} />
+ <QueryBlockReplacementBlock />
+ </>
+ )
+ }
+ {
+ historyBlock?.show && (
+ <>
+ <HistoryBlock {...historyBlock} />
+ <HistoryBlockReplacementBlock {...historyBlock} />
+ </>
+ )
+ }
+ {
+ (variableBlock?.show || externalToolBlock?.show) && (
+ <>
+ <VariableBlock />
+ <VariableValueBlock />
+ </>
+ )
+ }
+ {
+ workflowVariableBlock?.show && (
+ <>
+ <WorkflowVariableBlock {...workflowVariableBlock} />
+ <WorkflowVariableBlockReplacementBlock {...workflowVariableBlock} />
+ </>
+ )
+ }
+ <OnChangePlugin onChange={handleEditorChange} />
+ <OnBlurBlock onBlur={onBlur} onFocus={onFocus} />
+ <UpdateBlock instanceId={instanceId} />
+ <HistoryPlugin />
+ {/* <TreeView /> */}
+ </div>
+ </LexicalComposer>
+ )
+}
+
+export default PromptEditor
diff --git a/app/components/base/prompt-editor/plugins/component-picker-block/hooks.tsx b/app/components/base/prompt-editor/plugins/component-picker-block/hooks.tsx
new file mode 100644
index 0000000..7332a0d
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/component-picker-block/hooks.tsx
@@ -0,0 +1,288 @@
+import { useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import { $insertNodes } from 'lexical'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import type {
+ ContextBlockType,
+ ExternalToolBlockType,
+ HistoryBlockType,
+ QueryBlockType,
+ VariableBlockType,
+ WorkflowVariableBlockType,
+} from '../../types'
+import { INSERT_CONTEXT_BLOCK_COMMAND } from '../context-block'
+import { INSERT_HISTORY_BLOCK_COMMAND } from '../history-block'
+import { INSERT_QUERY_BLOCK_COMMAND } from '../query-block'
+import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block'
+import { $createCustomTextNode } from '../custom-text/node'
+import { PromptMenuItem } from './prompt-option'
+import { VariableMenuItem } from './variable-option'
+import { PickerBlockMenuOption } from './menu'
+import { File05 } from '@/app/components/base/icons/src/vender/solid/files'
+import {
+ MessageClockCircle,
+ Tool03,
+} from '@/app/components/base/icons/src/vender/solid/general'
+import { BracketsX } from '@/app/components/base/icons/src/vender/line/development'
+import { UserEdit02 } from '@/app/components/base/icons/src/vender/solid/users'
+import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows'
+import AppIcon from '@/app/components/base/app-icon'
+
+export const usePromptOptions = (
+ contextBlock?: ContextBlockType,
+ queryBlock?: QueryBlockType,
+ historyBlock?: HistoryBlockType,
+) => {
+ const { t } = useTranslation()
+ const [editor] = useLexicalComposerContext()
+
+ const promptOptions: PickerBlockMenuOption[] = []
+ if (contextBlock?.show) {
+ promptOptions.push(new PickerBlockMenuOption({
+ key: t('common.promptEditor.context.item.title'),
+ group: 'prompt context',
+ render: ({ isSelected, onSelect, onSetHighlight }) => {
+ return <PromptMenuItem
+ title={t('common.promptEditor.context.item.title')}
+ icon={<File05 className='h-4 w-4 text-[#6938EF]' />}
+ disabled={!contextBlock.selectable}
+ isSelected={isSelected}
+ onClick={onSelect}
+ onMouseEnter={onSetHighlight}
+ />
+ },
+ onSelect: () => {
+ if (!contextBlock?.selectable)
+ return
+ editor.dispatchCommand(INSERT_CONTEXT_BLOCK_COMMAND, undefined)
+ },
+ }))
+ }
+
+ if (queryBlock?.show) {
+ promptOptions.push(
+ new PickerBlockMenuOption({
+ key: t('common.promptEditor.query.item.title'),
+ group: 'prompt query',
+ render: ({ isSelected, onSelect, onSetHighlight }) => {
+ return (
+ <PromptMenuItem
+ title={t('common.promptEditor.query.item.title')}
+ icon={<UserEdit02 className='h-4 w-4 text-[#FD853A]' />}
+ disabled={!queryBlock.selectable}
+ isSelected={isSelected}
+ onClick={onSelect}
+ onMouseEnter={onSetHighlight}
+ />
+ )
+ },
+ onSelect: () => {
+ if (!queryBlock?.selectable)
+ return
+ editor.dispatchCommand(INSERT_QUERY_BLOCK_COMMAND, undefined)
+ },
+ }),
+ )
+ }
+
+ if (historyBlock?.show) {
+ promptOptions.push(
+ new PickerBlockMenuOption({
+ key: t('common.promptEditor.history.item.title'),
+ group: 'prompt history',
+ render: ({ isSelected, onSelect, onSetHighlight }) => {
+ return (
+ <PromptMenuItem
+ title={t('common.promptEditor.history.item.title')}
+ icon={<MessageClockCircle className='h-4 w-4 text-[#DD2590]' />}
+ disabled={!historyBlock.selectable
+ }
+ isSelected={isSelected}
+ onClick={onSelect}
+ onMouseEnter={onSetHighlight}
+ />
+ )
+ },
+ onSelect: () => {
+ if (!historyBlock?.selectable)
+ return
+ editor.dispatchCommand(INSERT_HISTORY_BLOCK_COMMAND, undefined)
+ },
+ }),
+ )
+ }
+ return promptOptions
+}
+
+export const useVariableOptions = (
+ variableBlock?: VariableBlockType,
+ queryString?: string,
+): PickerBlockMenuOption[] => {
+ const { t } = useTranslation()
+ const [editor] = useLexicalComposerContext()
+
+ const options = useMemo(() => {
+ if (!variableBlock?.variables)
+ return []
+
+ const baseOptions = (variableBlock.variables).map((item) => {
+ return new PickerBlockMenuOption({
+ key: item.value,
+ group: 'prompt variable',
+ render: ({ queryString, isSelected, onSelect, onSetHighlight }) => {
+ return (
+ <VariableMenuItem
+ title={item.value}
+ icon={<BracketsX className='h-[14px] w-[14px] text-text-accent' />}
+ queryString={queryString}
+ isSelected={isSelected}
+ onClick={onSelect}
+ onMouseEnter={onSetHighlight}
+ />
+ )
+ },
+ onSelect: () => {
+ editor.dispatchCommand(INSERT_VARIABLE_VALUE_BLOCK_COMMAND, `{{${item.value}}}`)
+ },
+ })
+ })
+ if (!queryString)
+ return baseOptions
+
+ const regex = new RegExp(queryString, 'i')
+
+ return baseOptions.filter(option => regex.test(option.key))
+ }, [editor, queryString, variableBlock])
+
+ const addOption = useMemo(() => {
+ return new PickerBlockMenuOption({
+ key: t('common.promptEditor.variable.modal.add'),
+ group: 'prompt variable',
+ render: ({ queryString, isSelected, onSelect, onSetHighlight }) => {
+ return (
+ <VariableMenuItem
+ title={t('common.promptEditor.variable.modal.add')}
+ icon={<BracketsX className='h-[14px] w-[14px] text-text-accent' />}
+ queryString={queryString}
+ isSelected={isSelected}
+ onClick={onSelect}
+ onMouseEnter={onSetHighlight}
+ />
+ )
+ },
+ onSelect: () => {
+ editor.update(() => {
+ const prefixNode = $createCustomTextNode('{{')
+ const suffixNode = $createCustomTextNode('}}')
+ $insertNodes([prefixNode, suffixNode])
+ prefixNode.select()
+ })
+ },
+ })
+ }, [editor, t])
+
+ return useMemo(() => {
+ return variableBlock?.show ? [...options, addOption] : []
+ }, [options, addOption, variableBlock?.show])
+}
+
+export const useExternalToolOptions = (
+ externalToolBlockType?: ExternalToolBlockType,
+ queryString?: string,
+) => {
+ const { t } = useTranslation()
+ const [editor] = useLexicalComposerContext()
+
+ const options = useMemo(() => {
+ if (!externalToolBlockType?.externalTools)
+ return []
+ const baseToolOptions = (externalToolBlockType.externalTools).map((item) => {
+ return new PickerBlockMenuOption({
+ key: item.name,
+ group: 'external tool',
+ render: ({ queryString, isSelected, onSelect, onSetHighlight }) => {
+ return (
+ <VariableMenuItem
+ title={item.name}
+ icon={
+ <AppIcon
+ className='!h-[14px] !w-[14px]'
+ icon={item.icon}
+ background={item.icon_background}
+ />
+ }
+ extraElement={<div className='text-xs text-text-tertiary'>{item.variableName}</div>}
+ queryString={queryString}
+ isSelected={isSelected}
+ onClick={onSelect}
+ onMouseEnter={onSetHighlight}
+ />
+ )
+ },
+ onSelect: () => {
+ editor.dispatchCommand(INSERT_VARIABLE_VALUE_BLOCK_COMMAND, `{{${item.variableName}}}`)
+ },
+ })
+ })
+ if (!queryString)
+ return baseToolOptions
+
+ const regex = new RegExp(queryString, 'i')
+
+ return baseToolOptions.filter(option => regex.test(option.key))
+ }, [editor, queryString, externalToolBlockType])
+
+ const addOption = useMemo(() => {
+ return new PickerBlockMenuOption({
+ key: t('common.promptEditor.variable.modal.addTool'),
+ group: 'external tool',
+ render: ({ queryString, isSelected, onSelect, onSetHighlight }) => {
+ return (
+ <VariableMenuItem
+ title={t('common.promptEditor.variable.modal.addTool')}
+ icon={<Tool03 className='h-[14px] w-[14px] text-text-accent' />}
+ extraElement={< ArrowUpRight className='h-3 w-3 text-text-tertiary' />}
+ queryString={queryString}
+ isSelected={isSelected}
+ onClick={onSelect}
+ onMouseEnter={onSetHighlight}
+ />
+ )
+ },
+ onSelect: () => {
+ externalToolBlockType?.onAddExternalTool?.()
+ },
+ })
+ }, [externalToolBlockType, t])
+
+ return useMemo(() => {
+ return externalToolBlockType?.show ? [...options, addOption] : []
+ }, [options, addOption, externalToolBlockType?.show])
+}
+
+export const useOptions = (
+ contextBlock?: ContextBlockType,
+ queryBlock?: QueryBlockType,
+ historyBlock?: HistoryBlockType,
+ variableBlock?: VariableBlockType,
+ externalToolBlockType?: ExternalToolBlockType,
+ workflowVariableBlockType?: WorkflowVariableBlockType,
+ queryString?: string,
+) => {
+ const promptOptions = usePromptOptions(contextBlock, queryBlock, historyBlock)
+ const variableOptions = useVariableOptions(variableBlock, queryString)
+ const externalToolOptions = useExternalToolOptions(externalToolBlockType, queryString)
+ const workflowVariableOptions = useMemo(() => {
+ if (!workflowVariableBlockType?.show)
+ return []
+
+ return workflowVariableBlockType.variables || []
+ }, [workflowVariableBlockType])
+
+ return useMemo(() => {
+ return {
+ workflowVariableOptions,
+ allFlattenOptions: [...promptOptions, ...variableOptions, ...externalToolOptions],
+ }
+ }, [promptOptions, variableOptions, externalToolOptions, workflowVariableOptions])
+}
diff --git a/app/components/base/prompt-editor/plugins/component-picker-block/index.tsx b/app/components/base/prompt-editor/plugins/component-picker-block/index.tsx
new file mode 100644
index 0000000..b43d2c8
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/component-picker-block/index.tsx
@@ -0,0 +1,227 @@
+import {
+ Fragment,
+ memo,
+ useCallback,
+ useState,
+} from 'react'
+import ReactDOM from 'react-dom'
+import {
+ flip,
+ offset,
+ shift,
+ useFloating,
+} from '@floating-ui/react'
+import type { TextNode } from 'lexical'
+import type { MenuRenderFn } from '@lexical/react/LexicalTypeaheadMenuPlugin'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { LexicalTypeaheadMenuPlugin } from '@lexical/react/LexicalTypeaheadMenuPlugin'
+import type {
+ ContextBlockType,
+ ExternalToolBlockType,
+ HistoryBlockType,
+ QueryBlockType,
+ VariableBlockType,
+ WorkflowVariableBlockType,
+} from '../../types'
+import { useBasicTypeaheadTriggerMatch } from '../../hooks'
+import { INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND } from '../workflow-variable-block'
+import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block'
+import { $splitNodeContainingQuery } from '../../utils'
+import { useOptions } from './hooks'
+import type { PickerBlockMenuOption } from './menu'
+import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { KEY_ESCAPE_COMMAND } from 'lexical'
+
+type ComponentPickerProps = {
+ triggerString: string
+ contextBlock?: ContextBlockType
+ queryBlock?: QueryBlockType
+ historyBlock?: HistoryBlockType
+ variableBlock?: VariableBlockType
+ externalToolBlock?: ExternalToolBlockType
+ workflowVariableBlock?: WorkflowVariableBlockType
+ isSupportFileVar?: boolean
+}
+const ComponentPicker = ({
+ triggerString,
+ contextBlock,
+ queryBlock,
+ historyBlock,
+ variableBlock,
+ externalToolBlock,
+ workflowVariableBlock,
+ isSupportFileVar,
+}: ComponentPickerProps) => {
+ const { eventEmitter } = useEventEmitterContextContext()
+ const { refs, floatingStyles, isPositioned } = useFloating({
+ placement: 'bottom-start',
+ middleware: [
+ offset(0), // fix hide cursor
+ shift({
+ padding: 8,
+ }),
+ flip(),
+ ],
+ })
+ const [editor] = useLexicalComposerContext()
+ const checkForTriggerMatch = useBasicTypeaheadTriggerMatch(triggerString, {
+ minLength: 0,
+ maxLength: 0,
+ })
+
+ const [queryString, setQueryString] = useState<string | null>(null)
+
+ eventEmitter?.useSubscription((v: any) => {
+ if (v.type === INSERT_VARIABLE_VALUE_BLOCK_COMMAND)
+ editor.dispatchCommand(INSERT_VARIABLE_VALUE_BLOCK_COMMAND, `{{${v.payload}}}`)
+ })
+
+ const {
+ allFlattenOptions,
+ workflowVariableOptions,
+ } = useOptions(
+ contextBlock,
+ queryBlock,
+ historyBlock,
+ variableBlock,
+ externalToolBlock,
+ workflowVariableBlock,
+ )
+
+ const onSelectOption = useCallback(
+ (
+ selectedOption: PickerBlockMenuOption,
+ nodeToRemove: TextNode | null,
+ closeMenu: () => void,
+ ) => {
+ editor.update(() => {
+ if (nodeToRemove && selectedOption?.key)
+ nodeToRemove.remove()
+
+ selectedOption.onSelectMenuOption()
+ closeMenu()
+ })
+ },
+ [editor],
+ )
+
+ const handleSelectWorkflowVariable = useCallback((variables: string[]) => {
+ editor.update(() => {
+ const needRemove = $splitNodeContainingQuery(checkForTriggerMatch(triggerString, editor)!)
+ if (needRemove)
+ needRemove.remove()
+ })
+
+ if (variables[1] === 'sys.query' || variables[1] === 'sys.files')
+ editor.dispatchCommand(INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND, [variables[1]])
+ else
+ editor.dispatchCommand(INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND, variables)
+ }, [editor, checkForTriggerMatch, triggerString])
+
+ const handleClose = useCallback(() => {
+ const escapeEvent = new KeyboardEvent('keydown', { key: 'Escape' })
+ editor.dispatchCommand(KEY_ESCAPE_COMMAND, escapeEvent)
+ }, [editor])
+
+ const renderMenu = useCallback<MenuRenderFn<PickerBlockMenuOption>>((
+ anchorElementRef,
+ { options, selectedIndex, selectOptionAndCleanUp, setHighlightedIndex },
+ ) => {
+ if (!(anchorElementRef.current && (allFlattenOptions.length || workflowVariableBlock?.show)))
+ return null
+
+ setTimeout(() => {
+ if (anchorElementRef.current)
+ refs.setReference(anchorElementRef.current)
+ }, 0)
+
+ return (
+ <>
+ {
+ ReactDOM.createPortal(
+ // The `LexicalMenu` will try to calculate the position of the floating menu based on the first child.
+ // Since we use floating ui, we need to wrap it with a div to prevent the position calculation being affected.
+ // See https://github.com/facebook/lexical/blob/ac97dfa9e14a73ea2d6934ff566282d7f758e8bb/packages/lexical-react/src/shared/LexicalMenu.ts#L493
+ <div className='h-0 w-0'>
+ <div
+ className='w-[260px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg'
+ style={{
+ ...floatingStyles,
+ visibility: isPositioned ? 'visible' : 'hidden',
+ }}
+ ref={refs.setFloating}
+ >
+ {
+ workflowVariableBlock?.show && (
+ <div className='p-1'>
+ <VarReferenceVars
+ searchBoxClassName='mt-1'
+ vars={workflowVariableOptions}
+ onChange={(variables: string[]) => {
+ handleSelectWorkflowVariable(variables)
+ }}
+ maxHeightClass='max-h-[34vh]'
+ isSupportFileVar={isSupportFileVar}
+ onClose={handleClose}
+ onBlur={handleClose}
+ />
+ </div>
+ )
+ }
+ {
+ workflowVariableBlock?.show && !!options.length && (
+ <div className='my-1 h-px w-full -translate-x-1 bg-divider-subtle'></div>
+ )
+ }
+ <div>
+ {
+ options.map((option, index) => (
+ <Fragment key={option.key}>
+ {
+ // Divider
+ index !== 0 && options.at(index - 1)?.group !== option.group && (
+ <div className='my-1 h-px w-full -translate-x-1 bg-divider-subtle'></div>
+ )
+ }
+ {option.renderMenuOption({
+ queryString,
+ isSelected: selectedIndex === index,
+ onSelect: () => {
+ selectOptionAndCleanUp(option)
+ },
+ onSetHighlight: () => {
+ setHighlightedIndex(index)
+ },
+ })}
+ </Fragment>
+ ))
+ }
+ </div>
+ </div>
+ </div>,
+ anchorElementRef.current,
+ )
+ }
+ </>
+ )
+ }, [allFlattenOptions.length, workflowVariableBlock?.show, refs, isPositioned, floatingStyles, queryString, workflowVariableOptions, handleSelectWorkflowVariable, handleClose, isSupportFileVar])
+
+ return (
+ <LexicalTypeaheadMenuPlugin
+ options={allFlattenOptions}
+ onQueryChange={setQueryString}
+ onSelectOption={onSelectOption}
+ // The `translate` class is used to workaround the issue that the `typeahead-menu` menu is not positioned as expected.
+ // See also https://github.com/facebook/lexical/blob/772520509308e8ba7e4a82b6cd1996a78b3298d0/packages/lexical-react/src/shared/LexicalMenu.ts#L498
+ //
+ // We no need the position function of the `LexicalTypeaheadMenuPlugin`,
+ // so the reference anchor should be positioned based on the range of the trigger string, and the menu will be positioned by the floating ui.
+ anchorClassName='z-[999999] translate-y-[calc(-100%-3px)]'
+ menuRenderFn={renderMenu}
+ triggerFn={checkForTriggerMatch}
+ />
+ )
+}
+
+export default memo(ComponentPicker)
diff --git a/app/components/base/prompt-editor/plugins/component-picker-block/menu.tsx b/app/components/base/prompt-editor/plugins/component-picker-block/menu.tsx
new file mode 100644
index 0000000..679e604
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/component-picker-block/menu.tsx
@@ -0,0 +1,31 @@
+import { MenuOption } from '@lexical/react/LexicalTypeaheadMenuPlugin'
+import { Fragment } from 'react'
+
+/**
+ * Corresponds to the `MenuRenderFn` type from `@lexical/react/LexicalTypeaheadMenuPlugin`.
+ */
+type MenuOptionRenderProps = {
+ isSelected: boolean
+ onSelect: () => void
+ onSetHighlight: () => void
+ queryString: string | null
+}
+
+export class PickerBlockMenuOption extends MenuOption {
+ public group?: string
+
+ constructor(
+ private data: {
+ key: string
+ group?: string
+ onSelect?: () => void
+ render: (menuRenderProps: MenuOptionRenderProps) => React.JSX.Element
+ },
+ ) {
+ super(data.key)
+ this.group = data.group
+ }
+
+ public onSelectMenuOption = () => this.data.onSelect?.()
+ public renderMenuOption = (menuRenderProps: MenuOptionRenderProps) => <Fragment key={this.data.key}>{this.data.render(menuRenderProps)}</Fragment>
+}
diff --git a/app/components/base/prompt-editor/plugins/component-picker-block/prompt-option.tsx b/app/components/base/prompt-editor/plugins/component-picker-block/prompt-option.tsx
new file mode 100644
index 0000000..55be781
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/component-picker-block/prompt-option.tsx
@@ -0,0 +1,45 @@
+import { memo } from 'react'
+
+type PromptMenuItemMenuItemProps = {
+ icon: React.JSX.Element
+ title: string
+ disabled?: boolean
+ isSelected: boolean
+ onClick: () => void
+ onMouseEnter: () => void
+ setRefElement?: (element: HTMLDivElement) => void
+}
+export const PromptMenuItem = memo(({
+ icon,
+ title,
+ disabled,
+ isSelected,
+ onClick,
+ onMouseEnter,
+ setRefElement,
+}: PromptMenuItemMenuItemProps) => {
+ return (
+ <div
+ className={`
+ flex h-6 cursor-pointer items-center rounded-md px-3 hover:bg-state-base-hover
+ ${isSelected && !disabled && '!bg-state-base-hover'}
+ ${disabled ? 'cursor-not-allowed opacity-30' : 'cursor-pointer hover:bg-state-base-hover'}
+ `}
+ tabIndex={-1}
+ ref={setRefElement}
+ onMouseEnter={() => {
+ if (disabled)
+ return
+ onMouseEnter()
+ }}
+ onClick={() => {
+ if (disabled)
+ return
+ onClick()
+ }}>
+ {icon}
+ <div className='ml-1 text-[13px] text-text-secondary'>{title}</div>
+ </div>
+ )
+})
+PromptMenuItem.displayName = 'PromptMenuItem'
diff --git a/app/components/base/prompt-editor/plugins/component-picker-block/variable-option.tsx b/app/components/base/prompt-editor/plugins/component-picker-block/variable-option.tsx
new file mode 100644
index 0000000..20c0376
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/component-picker-block/variable-option.tsx
@@ -0,0 +1,60 @@
+import { memo } from 'react'
+
+type VariableMenuItemProps = {
+ title: string
+ icon?: React.JSX.Element
+ extraElement?: React.JSX.Element
+ isSelected: boolean
+ queryString: string | null
+ onClick: () => void
+ onMouseEnter: () => void
+ setRefElement?: (element: HTMLDivElement) => void
+}
+export const VariableMenuItem = memo(({
+ title,
+ icon,
+ extraElement,
+ isSelected,
+ queryString,
+ onClick,
+ onMouseEnter,
+ setRefElement,
+}: VariableMenuItemProps) => {
+ let before = title
+ let middle = ''
+ let after = ''
+
+ if (queryString) {
+ const regex = new RegExp(queryString, 'i')
+ const match = regex.exec(title)
+
+ if (match) {
+ before = title.substring(0, match.index)
+ middle = match[0]
+ after = title.substring(match.index + match[0].length)
+ }
+ }
+
+ return (
+ <div
+ className={`
+ flex h-6 cursor-pointer items-center rounded-md px-3 hover:bg-state-base-hover
+ ${isSelected && 'bg-state-base-hover'}
+ `}
+ tabIndex={-1}
+ ref={setRefElement}
+ onMouseEnter={onMouseEnter}
+ onClick={onClick}>
+ <div className='mr-2'>
+ {icon}
+ </div>
+ <div className='grow truncate text-[13px] text-text-secondary' title={title}>
+ {before}
+ <span className='text-text-accent'>{middle}</span>
+ {after}
+ </div>
+ {extraElement}
+ </div>
+ )
+})
+VariableMenuItem.displayName = 'VariableMenuItem'
diff --git a/app/components/base/prompt-editor/plugins/context-block/component.tsx b/app/components/base/prompt-editor/plugins/context-block/component.tsx
new file mode 100644
index 0000000..8396478
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/context-block/component.tsx
@@ -0,0 +1,104 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiAddLine,
+} from '@remixicon/react'
+import { useSelectOrDelete, useTrigger } from '../../hooks'
+import { UPDATE_DATASETS_EVENT_EMITTER } from '../../constants'
+import type { Dataset } from './index'
+import { DELETE_CONTEXT_BLOCK_COMMAND } from './index'
+import { File05, Folder } from '@/app/components/base/icons/src/vender/solid/files'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+
+type ContextBlockComponentProps = {
+ nodeKey: string
+ datasets?: Dataset[]
+ onAddContext: () => void
+ canNotAddContext?: boolean
+}
+
+const ContextBlockComponent: FC<ContextBlockComponentProps> = ({
+ nodeKey,
+ datasets = [],
+ onAddContext,
+ canNotAddContext,
+}) => {
+ const { t } = useTranslation()
+ const [ref, isSelected] = useSelectOrDelete(nodeKey, DELETE_CONTEXT_BLOCK_COMMAND)
+ const [triggerRef, open, setOpen] = useTrigger()
+ const { eventEmitter } = useEventEmitterContextContext()
+ const [localDatasets, setLocalDatasets] = useState<Dataset[]>(datasets)
+
+ eventEmitter?.useSubscription((v: any) => {
+ if (v?.type === UPDATE_DATASETS_EVENT_EMITTER)
+ setLocalDatasets(v.payload)
+ })
+
+ return (
+ <div className={`
+ group inline-flex h-6 items-center rounded-[5px] border border-transparent bg-[#F4F3FF] pl-1 pr-0.5 text-[#6938EF] hover:bg-[#EBE9FE]
+ ${open ? 'bg-[#EBE9FE]' : 'bg-[#F4F3FF]'}
+ ${isSelected && '!border-[#9B8AFB]'}
+ `} ref={ref}>
+ <File05 className='mr-1 h-[14px] w-[14px]' />
+ <div className='mr-1 text-xs font-medium'>{t('common.promptEditor.context.item.title')}</div>
+ {!canNotAddContext && (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 3,
+ alignmentAxis: -147,
+ }}
+ >
+ <PortalToFollowElemTrigger ref={triggerRef}>
+ <div className={`
+ flex h-[18px] w-[18px] cursor-pointer items-center justify-center rounded text-[11px] font-semibold
+ ${open ? 'bg-[#6938EF] text-white' : 'bg-white/50 group-hover:bg-white group-hover:shadow-xs'}
+ `}>{localDatasets.length}</div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 100 }}>
+ <div className='w-[360px] rounded-xl bg-white shadow-lg'>
+ <div className='p-4'>
+ <div className='mb-2 text-xs font-medium text-gray-500'>
+ {t('common.promptEditor.context.modal.title', { num: localDatasets.length })}
+ </div>
+ <div className='max-h-[270px] overflow-y-auto'>
+ {
+ localDatasets.map(dataset => (
+ <div key={dataset.id} className='flex h-8 items-center'>
+ <div className='mr-2 flex h-6 w-6 shrink-0 items-center justify-center rounded-md border-[0.5px] border-[#EAECF5] bg-[#F5F8FF]'>
+ <Folder className='h-4 w-4 text-[#444CE7]' />
+ </div>
+ <div className='truncate text-sm text-gray-800' title=''>{dataset.name}</div>
+ </div>
+ ))
+ }
+ </div>
+ <div className='flex h-8 cursor-pointer items-center text-[#155EEF]' onClick={onAddContext}>
+ <div className='mr-2 flex h-6 w-6 shrink-0 items-center justify-center rounded-md border-[0.5px] border-gray-100'>
+ <RiAddLine className='h-[14px] w-[14px]' />
+ </div>
+ <div className='text-[13px] font-medium' title=''>{t('common.promptEditor.context.modal.add')}</div>
+ </div>
+ </div>
+ <div className='rounded-b-xl border-t-[0.5px] border-gray-50 bg-gray-50 px-4 py-3 text-xs text-gray-500'>
+ {t('common.promptEditor.context.modal.footer')}
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )}
+
+ </div>
+ )
+}
+
+export default ContextBlockComponent
diff --git a/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.tsx b/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.tsx
new file mode 100644
index 0000000..7d96827
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.tsx
@@ -0,0 +1,64 @@
+import {
+ memo,
+ useCallback,
+ useEffect,
+} from 'react'
+import { $applyNodeReplacement } from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { decoratorTransform } from '../../utils'
+import { CONTEXT_PLACEHOLDER_TEXT } from '../../constants'
+import type { ContextBlockType } from '../../types'
+import {
+ $createContextBlockNode,
+ ContextBlockNode,
+} from '../context-block/node'
+import { CustomTextNode } from '../custom-text/node'
+import { noop } from 'lodash-es'
+
+const REGEX = new RegExp(CONTEXT_PLACEHOLDER_TEXT)
+
+const ContextBlockReplacementBlock = ({
+ datasets = [],
+ onAddContext = noop,
+ onInsert,
+ canNotAddContext,
+}: ContextBlockType) => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ if (!editor.hasNodes([ContextBlockNode]))
+ throw new Error('ContextBlockNodePlugin: ContextBlockNode not registered on editor')
+ }, [editor])
+
+ const createContextBlockNode = useCallback((): ContextBlockNode => {
+ if (onInsert)
+ onInsert()
+ return $applyNodeReplacement($createContextBlockNode(datasets, onAddContext, canNotAddContext))
+ }, [datasets, onAddContext, onInsert, canNotAddContext])
+
+ const getMatch = useCallback((text: string) => {
+ const matchArr = REGEX.exec(text)
+
+ if (matchArr === null)
+ return null
+
+ const startOffset = matchArr.index
+ const endOffset = startOffset + CONTEXT_PLACEHOLDER_TEXT.length
+ return {
+ end: endOffset,
+ start: startOffset,
+ }
+ }, [])
+
+ useEffect(() => {
+ REGEX.lastIndex = 0
+ return mergeRegister(
+ editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createContextBlockNode)),
+ )
+ }, [])
+
+ return null
+}
+
+export default memo(ContextBlockReplacementBlock)
diff --git a/app/components/base/prompt-editor/plugins/context-block/index.tsx b/app/components/base/prompt-editor/plugins/context-block/index.tsx
new file mode 100644
index 0000000..c115065
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/context-block/index.tsx
@@ -0,0 +1,75 @@
+import {
+ memo,
+ useEffect,
+} from 'react'
+import {
+ $insertNodes,
+ COMMAND_PRIORITY_EDITOR,
+ createCommand,
+} from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import type { ContextBlockType } from '../../types'
+import {
+ $createContextBlockNode,
+ ContextBlockNode,
+} from './node'
+import { noop } from 'lodash-es'
+
+export const INSERT_CONTEXT_BLOCK_COMMAND = createCommand('INSERT_CONTEXT_BLOCK_COMMAND')
+export const DELETE_CONTEXT_BLOCK_COMMAND = createCommand('DELETE_CONTEXT_BLOCK_COMMAND')
+
+export type Dataset = {
+ id: string
+ name: string
+ type: string
+}
+
+const ContextBlock = memo(({
+ datasets = [],
+ onAddContext = noop,
+ onInsert,
+ onDelete,
+ canNotAddContext,
+}: ContextBlockType) => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ if (!editor.hasNodes([ContextBlockNode]))
+ throw new Error('ContextBlockPlugin: ContextBlock not registered on editor')
+
+ return mergeRegister(
+ editor.registerCommand(
+ INSERT_CONTEXT_BLOCK_COMMAND,
+ () => {
+ const contextBlockNode = $createContextBlockNode(datasets, onAddContext, canNotAddContext)
+
+ $insertNodes([contextBlockNode])
+
+ if (onInsert)
+ onInsert()
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ editor.registerCommand(
+ DELETE_CONTEXT_BLOCK_COMMAND,
+ () => {
+ if (onDelete)
+ onDelete()
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ )
+ }, [editor, datasets, onAddContext, onInsert, onDelete, canNotAddContext])
+
+ return null
+})
+ContextBlock.displayName = 'ContextBlock'
+
+export { ContextBlock }
+export { ContextBlockNode } from './node'
+export { default as ContextBlockReplacementBlock } from './context-block-replacement-block'
diff --git a/app/components/base/prompt-editor/plugins/context-block/node.tsx b/app/components/base/prompt-editor/plugins/context-block/node.tsx
new file mode 100644
index 0000000..227043c
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/context-block/node.tsx
@@ -0,0 +1,100 @@
+import type { LexicalNode, NodeKey, SerializedLexicalNode } from 'lexical'
+import { DecoratorNode } from 'lexical'
+import ContextBlockComponent from './component'
+import type { Dataset } from './index'
+
+export type SerializedNode = SerializedLexicalNode & { datasets: Dataset[]; onAddContext: () => void; canNotAddContext: boolean }
+
+export class ContextBlockNode extends DecoratorNode<React.JSX.Element> {
+ __datasets: Dataset[]
+ __onAddContext: () => void
+ __canNotAddContext: boolean
+
+ static getType(): string {
+ return 'context-block'
+ }
+
+ static clone(node: ContextBlockNode): ContextBlockNode {
+ return new ContextBlockNode(node.__datasets, node.__onAddContext, node.getKey(), node.__canNotAddContext)
+ }
+
+ isInline(): boolean {
+ return true
+ }
+
+ constructor(datasets: Dataset[], onAddContext: () => void, key?: NodeKey, canNotAddContext?: boolean) {
+ super(key)
+
+ this.__datasets = datasets
+ this.__onAddContext = onAddContext
+ this.__canNotAddContext = canNotAddContext || false
+ }
+
+ createDOM(): HTMLElement {
+ const div = document.createElement('div')
+ div.classList.add('inline-flex', 'items-center', 'align-middle')
+ return div
+ }
+
+ updateDOM(): false {
+ return false
+ }
+
+ decorate(): React.JSX.Element {
+ return (
+ <ContextBlockComponent
+ nodeKey={this.getKey()}
+ datasets={this.getDatasets()}
+ onAddContext={this.getOnAddContext()}
+ canNotAddContext={this.getCanNotAddContext()}
+ />
+ )
+ }
+
+ getDatasets(): Dataset[] {
+ const self = this.getLatest()
+
+ return self.__datasets
+ }
+
+ getOnAddContext(): () => void {
+ const self = this.getLatest()
+
+ return self.__onAddContext
+ }
+
+ getCanNotAddContext(): boolean {
+ const self = this.getLatest()
+
+ return self.__canNotAddContext
+ }
+
+ static importJSON(serializedNode: SerializedNode): ContextBlockNode {
+ const node = $createContextBlockNode(serializedNode.datasets, serializedNode.onAddContext, serializedNode.canNotAddContext)
+
+ return node
+ }
+
+ exportJSON(): SerializedNode {
+ return {
+ type: 'context-block',
+ version: 1,
+ datasets: this.getDatasets(),
+ onAddContext: this.getOnAddContext(),
+ canNotAddContext: this.getCanNotAddContext(),
+ }
+ }
+
+ getTextContent(): string {
+ return '{{#context#}}'
+ }
+}
+export function $createContextBlockNode(datasets: Dataset[], onAddContext: () => void, canNotAddContext?: boolean): ContextBlockNode {
+ return new ContextBlockNode(datasets, onAddContext, undefined, canNotAddContext)
+}
+
+export function $isContextBlockNode(
+ node: ContextBlockNode | LexicalNode | null | undefined,
+): boolean {
+ return node instanceof ContextBlockNode
+}
diff --git a/app/components/base/prompt-editor/plugins/custom-text/node.tsx b/app/components/base/prompt-editor/plugins/custom-text/node.tsx
new file mode 100644
index 0000000..49f4a05
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/custom-text/node.tsx
@@ -0,0 +1,52 @@
+import type { EditorConfig, SerializedTextNode } from 'lexical'
+import { $createTextNode, TextNode } from 'lexical'
+
+export class CustomTextNode extends TextNode {
+ static getType() {
+ return 'custom-text'
+ }
+
+ static clone(node: CustomTextNode) {
+ return new CustomTextNode(node.__text, node.__key)
+ }
+
+ // constructor(text: string, key?: NodeKey) {
+ // super(text, key)
+ // }
+
+ createDOM(config: EditorConfig) {
+ const dom = super.createDOM(config)
+ dom.classList.add('align-middle')
+ return dom
+ }
+
+ static importJSON(serializedNode: SerializedTextNode): TextNode {
+ const node = $createTextNode(serializedNode.text)
+ node.setFormat(serializedNode.format)
+ node.setDetail(serializedNode.detail)
+ node.setMode(serializedNode.mode)
+ node.setStyle(serializedNode.style)
+ return node
+ }
+
+ exportJSON(): SerializedTextNode {
+ return {
+ detail: this.getDetail(),
+ format: this.getFormat(),
+ mode: this.getMode(),
+ style: this.getStyle(),
+ text: this.getTextContent(),
+ type: 'custom-text',
+ version: 1,
+ }
+ }
+
+ isSimpleText() {
+ return (
+ (this.__type === 'text' || this.__type === 'custom-text') && this.__mode === 0)
+ }
+}
+
+export function $createCustomTextNode(text: string): CustomTextNode {
+ return new CustomTextNode(text)
+}
diff --git a/app/components/base/prompt-editor/plugins/history-block/component.tsx b/app/components/base/prompt-editor/plugins/history-block/component.tsx
new file mode 100644
index 0000000..dc41413
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/history-block/component.tsx
@@ -0,0 +1,92 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiMoreFill,
+} from '@remixicon/react'
+import { useSelectOrDelete, useTrigger } from '../../hooks'
+import { UPDATE_HISTORY_EVENT_EMITTER } from '../../constants'
+import type { RoleName } from './index'
+import { DELETE_HISTORY_BLOCK_COMMAND } from './index'
+import { MessageClockCircle } from '@/app/components/base/icons/src/vender/solid/general'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+
+type HistoryBlockComponentProps = {
+ nodeKey: string
+ roleName?: RoleName
+ onEditRole: () => void
+}
+
+const HistoryBlockComponent: FC<HistoryBlockComponentProps> = ({
+ nodeKey,
+ roleName = { user: '', assistant: '' },
+ onEditRole,
+}) => {
+ const { t } = useTranslation()
+ const [ref, isSelected] = useSelectOrDelete(nodeKey, DELETE_HISTORY_BLOCK_COMMAND)
+ const [triggerRef, open, setOpen] = useTrigger()
+ const { eventEmitter } = useEventEmitterContextContext()
+ const [localRoleName, setLocalRoleName] = useState<RoleName>(roleName)
+
+ eventEmitter?.useSubscription((v: any) => {
+ if (v?.type === UPDATE_HISTORY_EVENT_EMITTER)
+ setLocalRoleName(v.payload)
+ })
+
+ return (
+ <div className={`
+ group inline-flex h-6 items-center rounded-[5px] border border-transparent pl-1 pr-0.5 text-[#DD2590] hover:bg-[#FCE7F6]
+ ${open ? 'bg-[#FCE7F6]' : 'bg-[#FDF2FA]'}
+ ${isSelected && '!border-[#F670C7]'}
+ `} ref={ref}>
+ <MessageClockCircle className='mr-1 h-[14px] w-[14px]' />
+ <div className='mr-1 text-xs font-medium'>{t('common.promptEditor.history.item.title')}</div>
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='top-end'
+ offset={{
+ mainAxis: 4,
+ alignmentAxis: -148,
+ }}
+ >
+ <PortalToFollowElemTrigger ref={triggerRef}>
+ <div className={`
+ flex h-[18px] w-[18px] cursor-pointer items-center justify-center rounded
+ ${open ? 'bg-[#DD2590] text-white' : 'bg-white/50 group-hover:bg-white group-hover:shadow-xs'}
+ `}>
+ <RiMoreFill className='h-3 w-3' />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 100 }}>
+ <div className='w-[360px] rounded-xl bg-white shadow-lg'>
+ <div className='p-4'>
+ <div className='mb-2 text-xs font-medium text-gray-500'>{t('common.promptEditor.history.modal.title')}</div>
+ <div className='flex items-center text-sm text-gray-700'>
+ <div className='mr-1 w-20 text-xs font-semibold'>{localRoleName?.user}</div>
+ {t('common.promptEditor.history.modal.user')}
+ </div>
+ <div className='flex items-center text-sm text-gray-700'>
+ <div className='mr-1 w-20 text-xs font-semibold'>{localRoleName?.assistant}</div>
+ {t('common.promptEditor.history.modal.assistant')}
+ </div>
+ </div>
+ <div
+ className='cursor-pointer rounded-b-xl border-t border-black/5 px-4 py-3 text-xs text-[#155EEF]'
+ onClick={onEditRole}
+ >
+ {t('common.promptEditor.history.modal.edit')}
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ </div>
+ )
+}
+
+export default HistoryBlockComponent
diff --git a/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.tsx b/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.tsx
new file mode 100644
index 0000000..7845903
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.tsx
@@ -0,0 +1,62 @@
+import {
+ useCallback,
+ useEffect,
+} from 'react'
+import { $applyNodeReplacement } from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { decoratorTransform } from '../../utils'
+import { HISTORY_PLACEHOLDER_TEXT } from '../../constants'
+import type { HistoryBlockType } from '../../types'
+import {
+ $createHistoryBlockNode,
+ HistoryBlockNode,
+} from '../history-block/node'
+import { CustomTextNode } from '../custom-text/node'
+import { noop } from 'lodash-es'
+
+const REGEX = new RegExp(HISTORY_PLACEHOLDER_TEXT)
+
+const HistoryBlockReplacementBlock = ({
+ history = { user: '', assistant: '' },
+ onEditRole = noop,
+ onInsert,
+}: HistoryBlockType) => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ if (!editor.hasNodes([HistoryBlockNode]))
+ throw new Error('HistoryBlockNodePlugin: HistoryBlockNode not registered on editor')
+ }, [editor])
+
+ const createHistoryBlockNode = useCallback((): HistoryBlockNode => {
+ if (onInsert)
+ onInsert()
+ return $applyNodeReplacement($createHistoryBlockNode(history, onEditRole))
+ }, [history, onEditRole, onInsert])
+
+ const getMatch = useCallback((text: string) => {
+ const matchArr = REGEX.exec(text)
+
+ if (matchArr === null)
+ return null
+
+ const startOffset = matchArr.index
+ const endOffset = startOffset + HISTORY_PLACEHOLDER_TEXT.length
+ return {
+ end: endOffset,
+ start: startOffset,
+ }
+ }, [])
+
+ useEffect(() => {
+ REGEX.lastIndex = 0
+ return mergeRegister(
+ editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createHistoryBlockNode)),
+ )
+ }, [])
+
+ return null
+}
+
+export default HistoryBlockReplacementBlock
diff --git a/app/components/base/prompt-editor/plugins/history-block/index.tsx b/app/components/base/prompt-editor/plugins/history-block/index.tsx
new file mode 100644
index 0000000..d51c986
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/history-block/index.tsx
@@ -0,0 +1,80 @@
+import {
+ memo,
+ useEffect,
+} from 'react'
+import {
+ $insertNodes,
+ COMMAND_PRIORITY_EDITOR,
+ createCommand,
+} from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import type { HistoryBlockType } from '../../types'
+import {
+ $createHistoryBlockNode,
+ HistoryBlockNode,
+} from './node'
+import { noop } from 'lodash-es'
+
+export const INSERT_HISTORY_BLOCK_COMMAND = createCommand('INSERT_HISTORY_BLOCK_COMMAND')
+export const DELETE_HISTORY_BLOCK_COMMAND = createCommand('DELETE_HISTORY_BLOCK_COMMAND')
+
+export type RoleName = {
+ user: string
+ assistant: string
+}
+
+export type HistoryBlockProps = {
+ roleName: RoleName
+ onEditRole: () => void
+ onInsert?: () => void
+ onDelete?: () => void
+}
+
+const HistoryBlock = memo(({
+ history = { user: '', assistant: '' },
+ onEditRole = noop,
+ onInsert,
+ onDelete,
+}: HistoryBlockType) => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ if (!editor.hasNodes([HistoryBlockNode]))
+ throw new Error('HistoryBlockPlugin: HistoryBlock not registered on editor')
+
+ return mergeRegister(
+ editor.registerCommand(
+ INSERT_HISTORY_BLOCK_COMMAND,
+ () => {
+ const historyBlockNode = $createHistoryBlockNode(history, onEditRole)
+
+ $insertNodes([historyBlockNode])
+
+ if (onInsert)
+ onInsert()
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ editor.registerCommand(
+ DELETE_HISTORY_BLOCK_COMMAND,
+ () => {
+ if (onDelete)
+ onDelete()
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ )
+ }, [editor, history, onEditRole, onInsert, onDelete])
+
+ return null
+})
+HistoryBlock.displayName = 'HistoryBlock'
+
+export { HistoryBlock }
+export { HistoryBlockNode } from './node'
+export { default as HistoryBlockReplacementBlock } from './history-block-replacement-block'
diff --git a/app/components/base/prompt-editor/plugins/history-block/node.tsx b/app/components/base/prompt-editor/plugins/history-block/node.tsx
new file mode 100644
index 0000000..1cb33fc
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/history-block/node.tsx
@@ -0,0 +1,90 @@
+import type { LexicalNode, NodeKey, SerializedLexicalNode } from 'lexical'
+import { DecoratorNode } from 'lexical'
+import HistoryBlockComponent from './component'
+import type { RoleName } from './index'
+
+export type SerializedNode = SerializedLexicalNode & { roleName: RoleName; onEditRole: () => void }
+
+export class HistoryBlockNode extends DecoratorNode<React.JSX.Element> {
+ __roleName: RoleName
+ __onEditRole: () => void
+
+ static getType(): string {
+ return 'history-block'
+ }
+
+ static clone(node: HistoryBlockNode): HistoryBlockNode {
+ return new HistoryBlockNode(node.__roleName, node.__onEditRole, node.__key)
+ }
+
+ constructor(roleName: RoleName, onEditRole: () => void, key?: NodeKey) {
+ super(key)
+
+ this.__roleName = roleName
+ this.__onEditRole = onEditRole
+ }
+
+ isInline(): boolean {
+ return true
+ }
+
+ createDOM(): HTMLElement {
+ const div = document.createElement('div')
+ div.classList.add('inline-flex', 'items-center', 'align-middle')
+ return div
+ }
+
+ updateDOM(): false {
+ return false
+ }
+
+ decorate(): React.JSX.Element {
+ return (
+ <HistoryBlockComponent
+ nodeKey={this.getKey()}
+ roleName={this.getRoleName()}
+ onEditRole={this.getOnEditRole()}
+ />
+ )
+ }
+
+ getRoleName(): RoleName {
+ const self = this.getLatest()
+
+ return self.__roleName
+ }
+
+ getOnEditRole(): () => void {
+ const self = this.getLatest()
+
+ return self.__onEditRole
+ }
+
+ static importJSON(serializedNode: SerializedNode): HistoryBlockNode {
+ const node = $createHistoryBlockNode(serializedNode.roleName, serializedNode.onEditRole)
+
+ return node
+ }
+
+ exportJSON(): SerializedNode {
+ return {
+ type: 'history-block',
+ version: 1,
+ roleName: this.getRoleName(),
+ onEditRole: this.getOnEditRole,
+ }
+ }
+
+ getTextContent(): string {
+ return '{{#histories#}}'
+ }
+}
+export function $createHistoryBlockNode(roleName: RoleName, onEditRole: () => void): HistoryBlockNode {
+ return new HistoryBlockNode(roleName, onEditRole)
+}
+
+export function $isHistoryBlockNode(
+ node: HistoryBlockNode | LexicalNode | null | undefined,
+): node is HistoryBlockNode {
+ return node instanceof HistoryBlockNode
+}
diff --git a/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.tsx b/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.tsx
new file mode 100644
index 0000000..246fd96
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.tsx
@@ -0,0 +1,69 @@
+import type { FC } from 'react'
+import { useEffect, useRef } from 'react'
+import {
+ BLUR_COMMAND,
+ COMMAND_PRIORITY_EDITOR,
+ FOCUS_COMMAND,
+ KEY_ESCAPE_COMMAND,
+} from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { CLEAR_HIDE_MENU_TIMEOUT } from './workflow-variable-block'
+
+type OnBlurBlockProps = {
+ onBlur?: () => void
+ onFocus?: () => void
+}
+const OnBlurBlock: FC<OnBlurBlockProps> = ({
+ onBlur,
+ onFocus,
+}) => {
+ const [editor] = useLexicalComposerContext()
+
+ const ref = useRef<any>(null)
+
+ useEffect(() => {
+ return mergeRegister(
+ editor.registerCommand(
+ CLEAR_HIDE_MENU_TIMEOUT,
+ () => {
+ if (ref.current) {
+ clearTimeout(ref.current)
+ ref.current = null
+ }
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ editor.registerCommand(
+ BLUR_COMMAND,
+ (event) => {
+ // Check if the clicked target element is var-search-input
+ const target = event?.relatedTarget as HTMLElement
+ if (!target?.classList?.contains('var-search-input')) {
+ ref.current = setTimeout(() => {
+ editor.dispatchCommand(KEY_ESCAPE_COMMAND, new KeyboardEvent('keydown', { key: 'Escape' }))
+ }, 200)
+ if (onBlur)
+ onBlur()
+ }
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ editor.registerCommand(
+ FOCUS_COMMAND,
+ () => {
+ if (onFocus)
+ onFocus()
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ )
+ }, [editor, onBlur, onFocus])
+
+ return null
+}
+
+export default OnBlurBlock
diff --git a/app/components/base/prompt-editor/plugins/placeholder.tsx b/app/components/base/prompt-editor/plugins/placeholder.tsx
new file mode 100644
index 0000000..8b86913
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/placeholder.tsx
@@ -0,0 +1,27 @@
+import { memo } from 'react'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+
+const Placeholder = ({
+ compact,
+ value,
+ className,
+}: {
+ compact?: boolean
+ value?: string
+ className?: string
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={cn(
+ className,
+ 'pointer-events-none absolute left-0 top-0 h-full w-full select-none text-sm text-components-input-text-placeholder',
+ compact ? 'text-[13px] leading-5' : 'text-sm leading-6',
+ )}>
+ {value || t('common.promptEditor.placeholder')}
+ </div>
+ )
+}
+
+export default memo(Placeholder)
diff --git a/app/components/base/prompt-editor/plugins/query-block/component.tsx b/app/components/base/prompt-editor/plugins/query-block/component.tsx
new file mode 100644
index 0000000..fa46334
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/query-block/component.tsx
@@ -0,0 +1,33 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useSelectOrDelete } from '../../hooks'
+import { DELETE_QUERY_BLOCK_COMMAND } from './index'
+import { UserEdit02 } from '@/app/components/base/icons/src/vender/solid/users'
+
+type QueryBlockComponentProps = {
+ nodeKey: string
+}
+
+const QueryBlockComponent: FC<QueryBlockComponentProps> = ({
+ nodeKey,
+}) => {
+ const { t } = useTranslation()
+ const [ref, isSelected] = useSelectOrDelete(nodeKey, DELETE_QUERY_BLOCK_COMMAND)
+
+ return (
+ <div
+ className={`
+ inline-flex h-6 items-center rounded-[5px] border border-transparent bg-[#FFF6ED] pl-1 pr-0.5 hover:bg-[#FFEAD5]
+ ${isSelected && '!border-[#FD853A]'}
+ `}
+ ref={ref}
+ >
+ <UserEdit02 className='mr-1 h-[14px] w-[14px] text-[#FD853A]' />
+ <div className='text-xs font-medium text-[#EC4A0A] opacity-60'>{'{{'}</div>
+ <div className='text-xs font-medium text-[#EC4A0A]'>{t('common.promptEditor.query.item.title')}</div>
+ <div className='text-xs font-medium text-[#EC4A0A] opacity-60'>{'}}'}</div>
+ </div>
+ )
+}
+
+export default QueryBlockComponent
diff --git a/app/components/base/prompt-editor/plugins/query-block/index.tsx b/app/components/base/prompt-editor/plugins/query-block/index.tsx
new file mode 100644
index 0000000..0946153
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/query-block/index.tsx
@@ -0,0 +1,68 @@
+import {
+ memo,
+ useEffect,
+} from 'react'
+import {
+ $insertNodes,
+ COMMAND_PRIORITY_EDITOR,
+ createCommand,
+} from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import type { QueryBlockType } from '../../types'
+import {
+ $createQueryBlockNode,
+ QueryBlockNode,
+} from './node'
+
+export const INSERT_QUERY_BLOCK_COMMAND = createCommand('INSERT_QUERY_BLOCK_COMMAND')
+export const DELETE_QUERY_BLOCK_COMMAND = createCommand('DELETE_QUERY_BLOCK_COMMAND')
+
+export type QueryBlockProps = {
+ onInsert?: () => void
+ onDelete?: () => void
+}
+const QueryBlock = memo(({
+ onInsert,
+ onDelete,
+}: QueryBlockType) => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ if (!editor.hasNodes([QueryBlockNode]))
+ throw new Error('QueryBlockPlugin: QueryBlock not registered on editor')
+
+ return mergeRegister(
+ editor.registerCommand(
+ INSERT_QUERY_BLOCK_COMMAND,
+ () => {
+ const contextBlockNode = $createQueryBlockNode()
+
+ $insertNodes([contextBlockNode])
+ if (onInsert)
+ onInsert()
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ editor.registerCommand(
+ DELETE_QUERY_BLOCK_COMMAND,
+ () => {
+ if (onDelete)
+ onDelete()
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ )
+ }, [editor, onInsert, onDelete])
+
+ return null
+})
+QueryBlock.displayName = 'QueryBlock'
+
+export { QueryBlock }
+export { QueryBlockNode } from './node'
+export { default as QueryBlockReplacementBlock } from './query-block-replacement-block'
diff --git a/app/components/base/prompt-editor/plugins/query-block/node.tsx b/app/components/base/prompt-editor/plugins/query-block/node.tsx
new file mode 100644
index 0000000..fc56045
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/query-block/node.tsx
@@ -0,0 +1,59 @@
+import type { LexicalNode, SerializedLexicalNode } from 'lexical'
+import { DecoratorNode } from 'lexical'
+import QueryBlockComponent from './component'
+
+export type SerializedNode = SerializedLexicalNode
+
+export class QueryBlockNode extends DecoratorNode<React.JSX.Element> {
+ static getType(): string {
+ return 'query-block'
+ }
+
+ static clone(): QueryBlockNode {
+ return new QueryBlockNode()
+ }
+
+ isInline(): boolean {
+ return true
+ }
+
+ createDOM(): HTMLElement {
+ const div = document.createElement('div')
+ div.classList.add('inline-flex', 'items-center', 'align-middle')
+ return div
+ }
+
+ updateDOM(): false {
+ return false
+ }
+
+ decorate(): React.JSX.Element {
+ return <QueryBlockComponent nodeKey={this.getKey()} />
+ }
+
+ static importJSON(): QueryBlockNode {
+ const node = $createQueryBlockNode()
+
+ return node
+ }
+
+ exportJSON(): SerializedNode {
+ return {
+ type: 'query-block',
+ version: 1,
+ }
+ }
+
+ getTextContent(): string {
+ return '{{#query#}}'
+ }
+}
+export function $createQueryBlockNode(): QueryBlockNode {
+ return new QueryBlockNode()
+}
+
+export function $isQueryBlockNode(
+ node: QueryBlockNode | LexicalNode | null | undefined,
+): node is QueryBlockNode {
+ return node instanceof QueryBlockNode
+}
diff --git a/app/components/base/prompt-editor/plugins/query-block/query-block-replacement-block.tsx b/app/components/base/prompt-editor/plugins/query-block/query-block-replacement-block.tsx
new file mode 100644
index 0000000..484c661
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/query-block/query-block-replacement-block.tsx
@@ -0,0 +1,60 @@
+import {
+ memo,
+ useCallback,
+ useEffect,
+} from 'react'
+import { $applyNodeReplacement } from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { decoratorTransform } from '../../utils'
+import { QUERY_PLACEHOLDER_TEXT } from '../../constants'
+import type { QueryBlockType } from '../../types'
+import {
+ $createQueryBlockNode,
+ QueryBlockNode,
+} from '../query-block/node'
+import { CustomTextNode } from '../custom-text/node'
+
+const REGEX = new RegExp(QUERY_PLACEHOLDER_TEXT)
+
+const QueryBlockReplacementBlock = ({
+ onInsert,
+}: QueryBlockType) => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ if (!editor.hasNodes([QueryBlockNode]))
+ throw new Error('QueryBlockNodePlugin: QueryBlockNode not registered on editor')
+ }, [editor])
+
+ const createQueryBlockNode = useCallback((): QueryBlockNode => {
+ if (onInsert)
+ onInsert()
+ return $applyNodeReplacement($createQueryBlockNode())
+ }, [onInsert])
+
+ const getMatch = useCallback((text: string) => {
+ const matchArr = REGEX.exec(text)
+
+ if (matchArr === null)
+ return null
+
+ const startOffset = matchArr.index
+ const endOffset = startOffset + QUERY_PLACEHOLDER_TEXT.length
+ return {
+ end: endOffset,
+ start: startOffset,
+ }
+ }, [])
+
+ useEffect(() => {
+ REGEX.lastIndex = 0
+ return mergeRegister(
+ editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createQueryBlockNode)),
+ )
+ }, [])
+
+ return null
+}
+
+export default memo(QueryBlockReplacementBlock)
diff --git a/app/components/base/prompt-editor/plugins/tree-view.tsx b/app/components/base/prompt-editor/plugins/tree-view.tsx
new file mode 100644
index 0000000..29028cb
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/tree-view.tsx
@@ -0,0 +1,19 @@
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { TreeView } from '@lexical/react/LexicalTreeView'
+
+const TreeViewPlugin = () => {
+ const [editor] = useLexicalComposerContext()
+ return (
+ <TreeView
+ viewClassName="tree-view-output"
+ treeTypeButtonClassName="debug-treetype-button"
+ timeTravelPanelClassName="debug-timetravel-panel"
+ timeTravelButtonClassName="debug-timetravel-button"
+ timeTravelPanelSliderClassName="debug-timetravel-panel-slider"
+ timeTravelPanelButtonClassName="debug-timetravel-panel-button"
+ editor={editor}
+ />
+ )
+}
+
+export default TreeViewPlugin
diff --git a/app/components/base/prompt-editor/plugins/update-block.tsx b/app/components/base/prompt-editor/plugins/update-block.tsx
new file mode 100644
index 0000000..89c9374
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/update-block.tsx
@@ -0,0 +1,42 @@
+import { $insertNodes } from 'lexical'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { textToEditorState } from '../utils'
+import { CustomTextNode } from './custom-text/node'
+import { CLEAR_HIDE_MENU_TIMEOUT } from './workflow-variable-block'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+
+export const PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER = 'PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER'
+export const PROMPT_EDITOR_INSERT_QUICKLY = 'PROMPT_EDITOR_INSERT_QUICKLY'
+
+type UpdateBlockProps = {
+ instanceId?: string
+}
+const UpdateBlock = ({
+ instanceId,
+}: UpdateBlockProps) => {
+ const { eventEmitter } = useEventEmitterContextContext()
+ const [editor] = useLexicalComposerContext()
+
+ eventEmitter?.useSubscription((v: any) => {
+ if (v.type === PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER && v.instanceId === instanceId) {
+ const editorState = editor.parseEditorState(textToEditorState(v.payload))
+ editor.setEditorState(editorState)
+ }
+ })
+
+ eventEmitter?.useSubscription((v: any) => {
+ if (v.type === PROMPT_EDITOR_INSERT_QUICKLY && v.instanceId === instanceId) {
+ editor.focus()
+ editor.update(() => {
+ const textNode = new CustomTextNode('/')
+ $insertNodes([textNode])
+
+ editor.dispatchCommand(CLEAR_HIDE_MENU_TIMEOUT, undefined)
+ })
+ }
+ })
+
+ return null
+}
+
+export default UpdateBlock
diff --git a/app/components/base/prompt-editor/plugins/variable-block/index.tsx b/app/components/base/prompt-editor/plugins/variable-block/index.tsx
new file mode 100644
index 0000000..3c995d5
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/variable-block/index.tsx
@@ -0,0 +1,45 @@
+import { useEffect } from 'react'
+import {
+ $insertNodes,
+ COMMAND_PRIORITY_EDITOR,
+ createCommand,
+} from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { CustomTextNode } from '../custom-text/node'
+
+export const INSERT_VARIABLE_BLOCK_COMMAND = createCommand('INSERT_VARIABLE_BLOCK_COMMAND')
+export const INSERT_VARIABLE_VALUE_BLOCK_COMMAND = createCommand('INSERT_VARIABLE_VALUE_BLOCK_COMMAND')
+
+const VariableBlock = () => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ return mergeRegister(
+ editor.registerCommand(
+ INSERT_VARIABLE_BLOCK_COMMAND,
+ () => {
+ const textNode = new CustomTextNode('{')
+ $insertNodes([textNode])
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ editor.registerCommand(
+ INSERT_VARIABLE_VALUE_BLOCK_COMMAND,
+ (value: string) => {
+ const textNode = new CustomTextNode(value)
+ $insertNodes([textNode])
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ )
+ }, [editor])
+
+ return null
+}
+
+export default VariableBlock
diff --git a/app/components/base/prompt-editor/plugins/variable-value-block/index.tsx b/app/components/base/prompt-editor/plugins/variable-value-block/index.tsx
new file mode 100644
index 0000000..e93c0d7
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/variable-value-block/index.tsx
@@ -0,0 +1,52 @@
+import {
+ useCallback,
+ useEffect,
+} from 'react'
+import type { TextNode } from 'lexical'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { useLexicalTextEntity } from '../../hooks'
+import {
+ $createVariableValueBlockNode,
+ VariableValueBlockNode,
+} from './node'
+import { getHashtagRegexString } from './utils'
+
+const REGEX = new RegExp(getHashtagRegexString(), 'i')
+
+const VariableValueBlock = () => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ if (!editor.hasNodes([VariableValueBlockNode]))
+ throw new Error('VariableValueBlockPlugin: VariableValueNode not registered on editor')
+ }, [editor])
+
+ const createVariableValueBlockNode = useCallback((textNode: TextNode): VariableValueBlockNode => {
+ return $createVariableValueBlockNode(textNode.getTextContent())
+ }, [])
+
+ const getVariableValueMatch = useCallback((text: string) => {
+ const matchArr = REGEX.exec(text)
+
+ if (matchArr === null)
+ return null
+
+ const hashtagLength = matchArr[0].length
+ const startOffset = matchArr.index
+ const endOffset = startOffset + hashtagLength
+ return {
+ end: endOffset,
+ start: startOffset,
+ }
+ }, [])
+
+ useLexicalTextEntity<VariableValueBlockNode>(
+ getVariableValueMatch,
+ VariableValueBlockNode,
+ createVariableValueBlockNode,
+ )
+
+ return null
+}
+
+export default VariableValueBlock
diff --git a/app/components/base/prompt-editor/plugins/variable-value-block/node.tsx b/app/components/base/prompt-editor/plugins/variable-value-block/node.tsx
new file mode 100644
index 0000000..e83dd22
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/variable-value-block/node.tsx
@@ -0,0 +1,64 @@
+import type {
+ EditorConfig,
+ LexicalNode,
+ SerializedTextNode,
+} from 'lexical'
+import {
+ $applyNodeReplacement,
+ TextNode,
+} from 'lexical'
+
+export class VariableValueBlockNode extends TextNode {
+ static getType(): string {
+ return 'variable-value-block'
+ }
+
+ static clone(node: VariableValueBlockNode): VariableValueBlockNode {
+ return new VariableValueBlockNode(node.__text, node.__key)
+ }
+
+ // constructor(text: string, key?: NodeKey) {
+ // super(text, key)
+ // }
+
+ createDOM(config: EditorConfig): HTMLElement {
+ const element = super.createDOM(config)
+ element.classList.add('inline-flex', 'items-center', 'px-0.5', 'h-[22px]', 'text-text-accent', 'rounded-[5px]', 'align-middle')
+ return element
+ }
+
+ static importJSON(serializedNode: SerializedTextNode): TextNode {
+ const node = $createVariableValueBlockNode(serializedNode.text)
+ node.setFormat(serializedNode.format)
+ node.setDetail(serializedNode.detail)
+ node.setMode(serializedNode.mode)
+ node.setStyle(serializedNode.style)
+ return node
+ }
+
+ exportJSON(): SerializedTextNode {
+ return {
+ detail: this.getDetail(),
+ format: this.getFormat(),
+ mode: this.getMode(),
+ style: this.getStyle(),
+ text: this.getTextContent(),
+ type: 'variable-value-block',
+ version: 1,
+ }
+ }
+
+ canInsertTextBefore(): boolean {
+ return false
+ }
+}
+
+export function $createVariableValueBlockNode(text = ''): VariableValueBlockNode {
+ return $applyNodeReplacement(new VariableValueBlockNode(text))
+}
+
+export function $isVariableValueNodeBlock(
+ node: LexicalNode | null | undefined,
+): node is VariableValueBlockNode {
+ return node instanceof VariableValueBlockNode
+}
diff --git a/app/components/base/prompt-editor/plugins/variable-value-block/utils.ts b/app/components/base/prompt-editor/plugins/variable-value-block/utils.ts
new file mode 100644
index 0000000..4d59d41
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/variable-value-block/utils.ts
@@ -0,0 +1,5 @@
+export function getHashtagRegexString(): string {
+ const hashtag = '\\{\\{[a-zA-Z_][a-zA-Z0-9_]{0,29}\\}\\}'
+
+ return hashtag
+}
diff --git a/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx b/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx
new file mode 100644
index 0000000..50ff296
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx
@@ -0,0 +1,169 @@
+import {
+ memo,
+ useEffect,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ COMMAND_PRIORITY_EDITOR,
+} from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import {
+ RiErrorWarningFill,
+ RiMoreLine,
+} from '@remixicon/react'
+import { useSelectOrDelete } from '../../hooks'
+import type { WorkflowNodesMap } from './node'
+import { WorkflowVariableBlockNode } from './node'
+import {
+ DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND,
+ UPDATE_WORKFLOW_NODES_MAP,
+} from './index'
+import cn from '@/utils/classnames'
+import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
+import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
+import { VarBlockIcon } from '@/app/components/workflow/block-icon'
+import { Line3 } from '@/app/components/base/icons/src/public/common'
+import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
+import Tooltip from '@/app/components/base/tooltip'
+import { isExceptionVariable } from '@/app/components/workflow/utils'
+import VarFullPathPanel from '@/app/components/workflow/nodes/_base/components/variable/var-full-path-panel'
+import { Type } from '@/app/components/workflow/nodes/llm/types'
+import type { ValueSelector } from '@/app/components/workflow/types'
+
+type WorkflowVariableBlockComponentProps = {
+ nodeKey: string
+ variables: string[]
+ workflowNodesMap: WorkflowNodesMap
+ getVarType?: (payload: {
+ nodeId: string,
+ valueSelector: ValueSelector,
+ }) => Type
+}
+
+const WorkflowVariableBlockComponent = ({
+ nodeKey,
+ variables,
+ workflowNodesMap = {},
+ getVarType,
+}: WorkflowVariableBlockComponentProps) => {
+ const { t } = useTranslation()
+ const [editor] = useLexicalComposerContext()
+ const [ref, isSelected] = useSelectOrDelete(nodeKey, DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND)
+ const variablesLength = variables.length
+ const isShowAPart = variablesLength > 2
+ const varName = (
+ () => {
+ const isSystem = isSystemVar(variables)
+ const varName = variables[variablesLength - 1]
+ return `${isSystem ? 'sys.' : ''}${varName}`
+ }
+ )()
+ const [localWorkflowNodesMap, setLocalWorkflowNodesMap] = useState<WorkflowNodesMap>(workflowNodesMap)
+ const node = localWorkflowNodesMap![variables[0]]
+ const isEnv = isENV(variables)
+ const isChatVar = isConversationVar(variables)
+ const isException = isExceptionVariable(varName, node?.type)
+
+ useEffect(() => {
+ if (!editor.hasNodes([WorkflowVariableBlockNode]))
+ throw new Error('WorkflowVariableBlockPlugin: WorkflowVariableBlock not registered on editor')
+
+ return mergeRegister(
+ editor.registerCommand(
+ UPDATE_WORKFLOW_NODES_MAP,
+ (workflowNodesMap: WorkflowNodesMap) => {
+ setLocalWorkflowNodesMap(workflowNodesMap)
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ )
+ }, [editor])
+
+ const Item = (
+ <div
+ className={cn(
+ 'group/wrap relative mx-0.5 flex h-[18px] select-none items-center rounded-[5px] border pl-0.5 pr-[3px] hover:border-state-accent-solid hover:bg-state-accent-hover',
+ isSelected ? ' border-state-accent-solid bg-state-accent-hover' : ' border-components-panel-border-subtle bg-components-badge-white-to-dark',
+ !node && !isEnv && !isChatVar && '!border-state-destructive-solid !bg-state-destructive-hover',
+ )}
+ ref={ref}
+ >
+ {!isEnv && !isChatVar && (
+ <div className='flex items-center'>
+ {
+ node?.type && (
+ <div className='p-[1px]'>
+ <VarBlockIcon
+ className='!text-text-secondary'
+ type={node?.type}
+ />
+ </div>
+ )
+ }
+ <div className='mx-0.5 max-w-[60px] shrink-0 truncate text-xs font-medium text-text-secondary' title={node?.title} style={{
+ }}>{node?.title}</div>
+ <Line3 className='mr-0.5 text-divider-deep'></Line3>
+ </div>
+ )}
+ {isShowAPart && (
+ <div className='flex items-center'>
+ <RiMoreLine className='h-3 w-3 text-text-secondary' />
+ <Line3 className='mr-0.5 text-divider-deep'></Line3>
+ </div>
+ )}
+
+ <div className='flex items-center text-text-accent'>
+ {!isEnv && !isChatVar && <Variable02 className={cn('h-3.5 w-3.5 shrink-0', isException && 'text-text-warning')} />}
+ {isEnv && <Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />}
+ {isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />}
+ <div className={cn(
+ 'ml-0.5 shrink-0 truncate text-xs font-medium',
+ isEnv && 'text-util-colors-violet-violet-600',
+ isChatVar && 'text-util-colors-teal-teal-700',
+ isException && 'text-text-warning',
+ )} title={varName}>{varName}</div>
+ {
+ !node && !isEnv && !isChatVar && (
+ <RiErrorWarningFill className='ml-0.5 h-3 w-3 text-text-destructive' />
+ )
+ }
+ </div>
+ </div>
+ )
+
+ if (!node && !isEnv && !isChatVar) {
+ return (
+ <Tooltip popupContent={t('workflow.errorMsg.invalidVariable')}>
+ {Item}
+ </Tooltip>
+ )
+ }
+
+ if (!node)
+ return Item
+
+ return (
+ <Tooltip
+ noDecoration
+ popupContent={
+ <VarFullPathPanel
+ nodeName={node.title}
+ path={variables.slice(1)}
+ varType={getVarType ? getVarType({
+ nodeId: variables[0],
+ valueSelector: variables,
+ }) : Type.string}
+ nodeType={node?.type}
+ />}
+ disabled={!isShowAPart}
+ >
+ <div>{Item}</div>
+ </Tooltip>
+ )
+}
+
+export default memo(WorkflowVariableBlockComponent)
diff --git a/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx b/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx
new file mode 100644
index 0000000..479dce9
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx
@@ -0,0 +1,82 @@
+import {
+ memo,
+ useEffect,
+} from 'react'
+import {
+ $insertNodes,
+ COMMAND_PRIORITY_EDITOR,
+ createCommand,
+} from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import type { GetVarType, WorkflowVariableBlockType } from '../../types'
+import {
+ $createWorkflowVariableBlockNode,
+ WorkflowVariableBlockNode,
+} from './node'
+import type { Node } from '@/app/components/workflow/types'
+
+export const INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND = createCommand('INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND')
+export const DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND = createCommand('DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND')
+export const CLEAR_HIDE_MENU_TIMEOUT = createCommand('CLEAR_HIDE_MENU_TIMEOUT')
+export const UPDATE_WORKFLOW_NODES_MAP = createCommand('UPDATE_WORKFLOW_NODES_MAP')
+
+export type WorkflowVariableBlockProps = {
+ getWorkflowNode: (nodeId: string) => Node
+ onInsert?: () => void
+ onDelete?: () => void
+ getVarType: GetVarType
+}
+const WorkflowVariableBlock = memo(({
+ workflowNodesMap,
+ onInsert,
+ onDelete,
+ getVarType,
+}: WorkflowVariableBlockType) => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ editor.update(() => {
+ editor.dispatchCommand(UPDATE_WORKFLOW_NODES_MAP, workflowNodesMap)
+ })
+ }, [editor, workflowNodesMap])
+
+ useEffect(() => {
+ if (!editor.hasNodes([WorkflowVariableBlockNode]))
+ throw new Error('WorkflowVariableBlockPlugin: WorkflowVariableBlock not registered on editor')
+
+ return mergeRegister(
+ editor.registerCommand(
+ INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND,
+ (variables: string[]) => {
+ editor.dispatchCommand(CLEAR_HIDE_MENU_TIMEOUT, undefined)
+ const workflowVariableBlockNode = $createWorkflowVariableBlockNode(variables, workflowNodesMap, getVarType)
+
+ $insertNodes([workflowVariableBlockNode])
+ if (onInsert)
+ onInsert()
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ editor.registerCommand(
+ DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND,
+ () => {
+ if (onDelete)
+ onDelete()
+
+ return true
+ },
+ COMMAND_PRIORITY_EDITOR,
+ ),
+ )
+ }, [editor, onInsert, onDelete, workflowNodesMap, getVarType])
+
+ return null
+})
+WorkflowVariableBlock.displayName = 'WorkflowVariableBlock'
+
+export { WorkflowVariableBlock }
+export { WorkflowVariableBlockNode } from './node'
+export { default as WorkflowVariableBlockReplacementBlock } from './workflow-variable-block-replacement-block'
diff --git a/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx b/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx
new file mode 100644
index 0000000..dce636d
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx
@@ -0,0 +1,104 @@
+import type { LexicalNode, NodeKey, SerializedLexicalNode } from 'lexical'
+import { DecoratorNode } from 'lexical'
+import type { WorkflowVariableBlockType } from '../../types'
+import WorkflowVariableBlockComponent from './component'
+import type { GetVarType } from '../../types'
+
+export type WorkflowNodesMap = WorkflowVariableBlockType['workflowNodesMap']
+
+export type SerializedNode = SerializedLexicalNode & {
+ variables: string[]
+ workflowNodesMap: WorkflowNodesMap
+ getVarType?: GetVarType
+}
+
+export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element> {
+ __variables: string[]
+ __workflowNodesMap: WorkflowNodesMap
+ __getVarType?: GetVarType
+
+ static getType(): string {
+ return 'workflow-variable-block'
+ }
+
+ static clone(node: WorkflowVariableBlockNode): WorkflowVariableBlockNode {
+ return new WorkflowVariableBlockNode(node.__variables, node.__workflowNodesMap, node.__getVarType, node.__key)
+ }
+
+ isInline(): boolean {
+ return true
+ }
+
+ constructor(variables: string[], workflowNodesMap: WorkflowNodesMap, getVarType: any, key?: NodeKey) {
+ super(key)
+
+ this.__variables = variables
+ this.__workflowNodesMap = workflowNodesMap
+ this.__getVarType = getVarType
+ }
+
+ createDOM(): HTMLElement {
+ const div = document.createElement('div')
+ div.classList.add('inline-flex', 'items-center', 'align-middle')
+ return div
+ }
+
+ updateDOM(): false {
+ return false
+ }
+
+ decorate(): React.JSX.Element {
+ return (
+ <WorkflowVariableBlockComponent
+ nodeKey={this.getKey()}
+ variables={this.__variables}
+ workflowNodesMap={this.__workflowNodesMap}
+ getVarType={this.__getVarType!}
+ />
+ )
+ }
+
+ static importJSON(serializedNode: SerializedNode): WorkflowVariableBlockNode {
+ const node = $createWorkflowVariableBlockNode(serializedNode.variables, serializedNode.workflowNodesMap, serializedNode.getVarType)
+
+ return node
+ }
+
+ exportJSON(): SerializedNode {
+ return {
+ type: 'workflow-variable-block',
+ version: 1,
+ variables: this.getVariables(),
+ workflowNodesMap: this.getWorkflowNodesMap(),
+ getVarType: this.getVarType(),
+ }
+ }
+
+ getVariables(): string[] {
+ const self = this.getLatest()
+ return self.__variables
+ }
+
+ getWorkflowNodesMap(): WorkflowNodesMap {
+ const self = this.getLatest()
+ return self.__workflowNodesMap
+ }
+
+ getVarType(): any {
+ const self = this.getLatest()
+ return self.__getVarType
+ }
+
+ getTextContent(): string {
+ return `{{#${this.getVariables().join('.')}#}}`
+ }
+}
+export function $createWorkflowVariableBlockNode(variables: string[], workflowNodesMap: WorkflowNodesMap, getVarType?: GetVarType): WorkflowVariableBlockNode {
+ return new WorkflowVariableBlockNode(variables, workflowNodesMap, getVarType)
+}
+
+export function $isWorkflowVariableBlockNode(
+ node: WorkflowVariableBlockNode | LexicalNode | null | undefined,
+): node is WorkflowVariableBlockNode {
+ return node instanceof WorkflowVariableBlockNode
+}
diff --git a/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx b/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx
new file mode 100644
index 0000000..288008b
--- /dev/null
+++ b/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx
@@ -0,0 +1,66 @@
+import {
+ memo,
+ useCallback,
+ useEffect,
+} from 'react'
+import type { TextNode } from 'lexical'
+import { $applyNodeReplacement } from 'lexical'
+import { mergeRegister } from '@lexical/utils'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { decoratorTransform } from '../../utils'
+import type { WorkflowVariableBlockType } from '../../types'
+import { CustomTextNode } from '../custom-text/node'
+import { $createWorkflowVariableBlockNode } from './node'
+import { WorkflowVariableBlockNode } from './index'
+import { VAR_REGEX as REGEX, resetReg } from '@/config'
+
+const WorkflowVariableBlockReplacementBlock = ({
+ workflowNodesMap,
+ getVarType,
+ onInsert,
+}: WorkflowVariableBlockType) => {
+ const [editor] = useLexicalComposerContext()
+
+ useEffect(() => {
+ if (!editor.hasNodes([WorkflowVariableBlockNode]))
+ throw new Error('WorkflowVariableBlockNodePlugin: WorkflowVariableBlockNode not registered on editor')
+ }, [editor])
+
+ const createWorkflowVariableBlockNode = useCallback((textNode: TextNode): WorkflowVariableBlockNode => {
+ if (onInsert)
+ onInsert()
+
+ const nodePathString = textNode.getTextContent().slice(3, -3)
+ return $applyNodeReplacement($createWorkflowVariableBlockNode(nodePathString.split('.'), workflowNodesMap, getVarType))
+ }, [onInsert, workflowNodesMap, getVarType])
+
+ const getMatch = useCallback((text: string) => {
+ const matchArr = REGEX.exec(text)
+
+ if (matchArr === null)
+ return null
+
+ const startOffset = matchArr.index
+ const endOffset = startOffset + matchArr[0].length
+ return {
+ end: endOffset,
+ start: startOffset,
+ }
+ }, [])
+
+ const transformListener = useCallback((textNode: CustomTextNode) => {
+ resetReg()
+ return decoratorTransform(textNode, getMatch, createWorkflowVariableBlockNode)
+ }, [createWorkflowVariableBlockNode, getMatch])
+
+ useEffect(() => {
+ resetReg()
+ return mergeRegister(
+ editor.registerNodeTransform(CustomTextNode, transformListener),
+ )
+ }, [])
+
+ return null
+}
+
+export default memo(WorkflowVariableBlockReplacementBlock)
diff --git a/app/components/base/prompt-editor/types.ts b/app/components/base/prompt-editor/types.ts
new file mode 100644
index 0000000..0f09fb2
--- /dev/null
+++ b/app/components/base/prompt-editor/types.ts
@@ -0,0 +1,77 @@
+import type { Type } from '../../workflow/nodes/llm/types'
+import type { Dataset } from './plugins/context-block'
+import type { RoleName } from './plugins/history-block'
+import type {
+ Node,
+ NodeOutPutVar,
+ ValueSelector,
+} from '@/app/components/workflow/types'
+
+export type Option = {
+ value: string
+ name: string
+}
+
+export type ExternalToolOption = {
+ name: string
+ variableName: string
+ icon?: string
+ icon_background?: string
+}
+
+export type ContextBlockType = {
+ show?: boolean
+ selectable?: boolean
+ datasets?: Dataset[]
+ canNotAddContext?: boolean
+ onAddContext?: () => void
+ onInsert?: () => void
+ onDelete?: () => void
+}
+
+export type QueryBlockType = {
+ show?: boolean
+ selectable?: boolean
+ onInsert?: () => void
+ onDelete?: () => void
+}
+
+export type HistoryBlockType = {
+ show?: boolean
+ selectable?: boolean
+ history?: RoleName
+ onInsert?: () => void
+ onDelete?: () => void
+ onEditRole?: () => void
+}
+
+export type VariableBlockType = {
+ show?: boolean
+ variables?: Option[]
+}
+
+export type ExternalToolBlockType = {
+ show?: boolean
+ externalTools?: ExternalToolOption[]
+ onAddExternalTool?: () => void
+}
+
+export type GetVarType = (payload: {
+ nodeId: string,
+ valueSelector: ValueSelector,
+}) => Type
+
+export type WorkflowVariableBlockType = {
+ show?: boolean
+ variables?: NodeOutPutVar[]
+ workflowNodesMap?: Record<string, Pick<Node['data'], 'title' | 'type'>>
+ onInsert?: () => void
+ onDelete?: () => void
+ getVarType?: GetVarType
+}
+
+export type MenuTextMatch = {
+ leadOffset: number
+ matchingString: string
+ replaceableString: string
+}
diff --git a/app/components/base/prompt-editor/utils.ts b/app/components/base/prompt-editor/utils.ts
new file mode 100644
index 0000000..4b2570e
--- /dev/null
+++ b/app/components/base/prompt-editor/utils.ts
@@ -0,0 +1,328 @@
+import { $isAtNodeEnd } from '@lexical/selection'
+import type {
+ ElementNode,
+ Klass,
+ LexicalEditor,
+ LexicalNode,
+ RangeSelection,
+ TextNode,
+} from 'lexical'
+import {
+ $createTextNode,
+ $getSelection,
+ $isRangeSelection,
+ $isTextNode,
+} from 'lexical'
+import type { EntityMatch } from '@lexical/text'
+import { CustomTextNode } from './plugins/custom-text/node'
+import type { MenuTextMatch } from './types'
+
+export function getSelectedNode(
+ selection: RangeSelection,
+): TextNode | ElementNode {
+ const anchor = selection.anchor
+ const focus = selection.focus
+ const anchorNode = selection.anchor.getNode()
+ const focusNode = selection.focus.getNode()
+ if (anchorNode === focusNode)
+ return anchorNode
+
+ const isBackward = selection.isBackward()
+ if (isBackward)
+ return $isAtNodeEnd(focus) ? anchorNode : focusNode
+ else
+ return $isAtNodeEnd(anchor) ? anchorNode : focusNode
+}
+
+export function registerLexicalTextEntity<T extends TextNode>(
+ editor: LexicalEditor,
+ getMatch: (text: string) => null | EntityMatch,
+ targetNode: Klass<T>,
+ createNode: (textNode: TextNode) => T,
+) {
+ const isTargetNode = (node: LexicalNode | null | undefined): node is T => {
+ return node instanceof targetNode
+ }
+
+ const replaceWithSimpleText = (node: TextNode): void => {
+ const textNode = $createTextNode(node.getTextContent())
+ textNode.setFormat(node.getFormat())
+ node.replace(textNode)
+ }
+
+ const getMode = (node: TextNode): number => {
+ return node.getLatest().__mode
+ }
+
+ const textNodeTransform = (node: TextNode) => {
+ if (!node.isSimpleText())
+ return
+
+ const prevSibling = node.getPreviousSibling()
+ let text = node.getTextContent()
+ let currentNode = node
+ let match
+
+ if ($isTextNode(prevSibling)) {
+ const previousText = prevSibling.getTextContent()
+ const combinedText = previousText + text
+ const prevMatch = getMatch(combinedText)
+
+ if (isTargetNode(prevSibling)) {
+ if (prevMatch === null || getMode(prevSibling) !== 0) {
+ replaceWithSimpleText(prevSibling)
+ return
+ }
+ else {
+ const diff = prevMatch.end - previousText.length
+
+ if (diff > 0) {
+ const concatText = text.slice(0, diff)
+ const newTextContent = previousText + concatText
+ prevSibling.select()
+ prevSibling.setTextContent(newTextContent)
+
+ if (diff === text.length) {
+ node.remove()
+ }
+ else {
+ const remainingText = text.slice(diff)
+ node.setTextContent(remainingText)
+ }
+
+ return
+ }
+ }
+ }
+ else if (prevMatch === null || prevMatch.start < previousText.length) {
+ return
+ }
+ }
+
+ while (true) {
+ match = getMatch(text)
+ let nextText = match === null ? '' : text.slice(match.end)
+ text = nextText
+
+ if (nextText === '') {
+ const nextSibling = currentNode.getNextSibling()
+
+ if ($isTextNode(nextSibling)) {
+ nextText = currentNode.getTextContent() + nextSibling.getTextContent()
+ const nextMatch = getMatch(nextText)
+
+ if (nextMatch === null) {
+ if (isTargetNode(nextSibling))
+ replaceWithSimpleText(nextSibling)
+ else
+ nextSibling.markDirty()
+
+ return
+ }
+ else if (nextMatch.start !== 0) {
+ return
+ }
+ }
+ }
+ else {
+ const nextMatch = getMatch(nextText)
+
+ if (nextMatch !== null && nextMatch.start === 0)
+ return
+ }
+
+ if (match === null)
+ return
+
+ if (match.start === 0 && $isTextNode(prevSibling) && prevSibling.isTextEntity())
+ continue
+
+ let nodeToReplace
+
+ if (match.start === 0)
+ [nodeToReplace, currentNode] = currentNode.splitText(match.end)
+ else
+ [, nodeToReplace, currentNode] = currentNode.splitText(match.start, match.end)
+
+ const replacementNode = createNode(nodeToReplace)
+ replacementNode.setFormat(nodeToReplace.getFormat())
+ nodeToReplace.replace(replacementNode)
+
+ if (currentNode == null)
+ return
+ }
+ }
+
+ const reverseNodeTransform = (node: T) => {
+ const text = node.getTextContent()
+ const match = getMatch(text)
+
+ if (match === null || match.start !== 0) {
+ replaceWithSimpleText(node)
+ return
+ }
+
+ if (text.length > match.end) {
+ // This will split out the rest of the text as simple text
+ node.splitText(match.end)
+ return
+ }
+
+ const prevSibling = node.getPreviousSibling()
+
+ if ($isTextNode(prevSibling) && prevSibling.isTextEntity()) {
+ replaceWithSimpleText(prevSibling)
+ replaceWithSimpleText(node)
+ }
+
+ const nextSibling = node.getNextSibling()
+
+ if ($isTextNode(nextSibling) && nextSibling.isTextEntity()) {
+ replaceWithSimpleText(nextSibling) // This may have already been converted in the previous block
+
+ if (isTargetNode(node))
+ replaceWithSimpleText(node)
+ }
+ }
+
+ const removePlainTextTransform = editor.registerNodeTransform(CustomTextNode, textNodeTransform)
+ const removeReverseNodeTransform = editor.registerNodeTransform(targetNode, reverseNodeTransform)
+ return [removePlainTextTransform, removeReverseNodeTransform]
+}
+
+export const decoratorTransform = (
+ node: CustomTextNode,
+ getMatch: (text: string) => null | EntityMatch,
+ createNode: (textNode: TextNode) => LexicalNode,
+) => {
+ if (!node.isSimpleText())
+ return
+
+ const prevSibling = node.getPreviousSibling()
+ let text = node.getTextContent()
+ let currentNode = node
+ let match
+
+ while (true) {
+ match = getMatch(text)
+ let nextText = match === null ? '' : text.slice(match.end)
+ text = nextText
+
+ if (nextText === '') {
+ const nextSibling = currentNode.getNextSibling()
+
+ if ($isTextNode(nextSibling)) {
+ nextText = currentNode.getTextContent() + nextSibling.getTextContent()
+ const nextMatch = getMatch(nextText)
+
+ if (nextMatch === null) {
+ nextSibling.markDirty()
+ return
+ }
+ else if (nextMatch.start !== 0) {
+ return
+ }
+ }
+ }
+ else {
+ const nextMatch = getMatch(nextText)
+
+ if (nextMatch !== null && nextMatch.start === 0)
+ return
+ }
+
+ if (match === null)
+ return
+
+ if (match.start === 0 && $isTextNode(prevSibling) && prevSibling.isTextEntity())
+ continue
+
+ let nodeToReplace
+
+ if (match.start === 0)
+ [nodeToReplace, currentNode] = currentNode.splitText(match.end)
+ else
+ [, nodeToReplace, currentNode] = currentNode.splitText(match.start, match.end)
+
+ const replacementNode = createNode(nodeToReplace)
+ nodeToReplace.replace(replacementNode)
+
+ if (currentNode == null)
+ return
+ }
+}
+
+function getFullMatchOffset(
+ documentText: string,
+ entryText: string,
+ offset: number,
+): number {
+ let triggerOffset = offset
+ for (let i = triggerOffset; i <= entryText.length; i++) {
+ if (documentText.substr(-i) === entryText.substr(0, i))
+ triggerOffset = i
+ }
+ return triggerOffset
+}
+
+export function $splitNodeContainingQuery(match: MenuTextMatch): TextNode | null {
+ const selection = $getSelection()
+ if (!$isRangeSelection(selection) || !selection.isCollapsed())
+ return null
+ const anchor = selection.anchor
+ if (anchor.type !== 'text')
+ return null
+ const anchorNode = anchor.getNode()
+ if (!anchorNode.isSimpleText())
+ return null
+ const selectionOffset = anchor.offset
+ const textContent = anchorNode.getTextContent().slice(0, selectionOffset)
+ const characterOffset = match.replaceableString.length
+ const queryOffset = getFullMatchOffset(
+ textContent,
+ match.matchingString,
+ characterOffset,
+ )
+ const startOffset = selectionOffset - queryOffset
+ if (startOffset < 0)
+ return null
+ let newNode
+ if (startOffset === 0)
+ [newNode] = anchorNode.splitText(selectionOffset)
+ else
+ [, newNode] = anchorNode.splitText(startOffset, selectionOffset)
+
+ return newNode
+}
+
+export function textToEditorState(text: string) {
+ const paragraph = text && (typeof text === 'string') ? text.split('\n') : ['']
+
+ return JSON.stringify({
+ root: {
+ children: paragraph.map((p) => {
+ return {
+ children: [{
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: p,
+ type: 'custom-text',
+ version: 1,
+ }],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ type: 'paragraph',
+ version: 1,
+ }
+ }),
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ type: 'root',
+ version: 1,
+ },
+ })
+}
diff --git a/app/components/base/prompt-log-modal/card.tsx b/app/components/base/prompt-log-modal/card.tsx
new file mode 100644
index 0000000..958a8fa
--- /dev/null
+++ b/app/components/base/prompt-log-modal/card.tsx
@@ -0,0 +1,42 @@
+import type { FC } from 'react'
+import { CopyFeedbackNew } from '@/app/components/base/copy-feedback'
+
+type CardProps = {
+ log: { role: string; text: string }[]
+}
+const Card: FC<CardProps> = ({
+ log,
+}) => {
+ return (
+ <>
+ {
+ log.length === 1 && (
+ <div className='px-4 py-2'>
+ <div className='whitespace-pre-line text-text-secondary'>
+ {log[0].text}
+ </div>
+ </div>
+ )
+ }
+ {
+ log.length > 1 && (
+ <div>
+ {
+ log.map((item, index) => (
+ <div key={index} className='group/card mb-2 rounded-xl px-4 pb-4 pt-2 last-of-type:mb-0 hover:bg-state-base-hover'>
+ <div className='flex h-8 items-center justify-between'>
+ <div className='font-semibold text-[#2D31A6]'>{item.role.toUpperCase()}</div>
+ <CopyFeedbackNew className='hidden h-6 w-6 group-hover/card:block' content={item.text} />
+ </div>
+ <div className='whitespace-pre-line text-text-secondary'>{item.text}</div>
+ </div>
+ ))
+ }
+ </div>
+ )
+ }
+ </>
+ )
+}
+
+export default Card
diff --git a/app/components/base/prompt-log-modal/index.tsx b/app/components/base/prompt-log-modal/index.tsx
new file mode 100644
index 0000000..bd3097b
--- /dev/null
+++ b/app/components/base/prompt-log-modal/index.tsx
@@ -0,0 +1,72 @@
+import type { FC } from 'react'
+import { useEffect, useRef, useState } from 'react'
+import { useClickAway } from 'ahooks'
+import { RiCloseLine } from '@remixicon/react'
+import Card from './card'
+import { CopyFeedbackNew } from '@/app/components/base/copy-feedback'
+import type { IChatItem } from '@/app/components/base/chat/chat/type'
+
+type PromptLogModalProps = {
+ currentLogItem?: IChatItem
+ width: number
+ onCancel: () => void
+}
+const PromptLogModal: FC<PromptLogModalProps> = ({
+ currentLogItem,
+ width,
+ onCancel,
+}) => {
+ const ref = useRef(null)
+ const [mounted, setMounted] = useState(false)
+
+ useClickAway(() => {
+ if (mounted)
+ onCancel()
+ }, ref)
+
+ useEffect(() => {
+ setMounted(true)
+ }, [])
+
+ if (!currentLogItem || !currentLogItem.log)
+ return null
+
+ return (
+ <div
+ className='relative z-10 flex flex-col rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl'
+ style={{
+ width: 480,
+ position: 'fixed',
+ top: 56 + 8,
+ left: 8 + (width - 480),
+ bottom: 16,
+ }}
+ ref={ref}
+ >
+ <div className='flex h-14 shrink-0 items-center justify-between border-b border-divider-regular pl-6 pr-5'>
+ <div className='text-base font-semibold text-text-primary'>PROMPT LOG</div>
+ <div className='flex items-center'>
+ {
+ currentLogItem.log?.length === 1 && (
+ <>
+ <CopyFeedbackNew className='h-6 w-6' content={currentLogItem.log[0].text} />
+ <div className='mx-2.5 h-[14px] w-[1px] bg-divider-regular' />
+ </>
+ )
+ }
+ <div
+ onClick={onCancel}
+ className='flex h-6 w-6 cursor-pointer items-center justify-center'
+ >
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ <div className='grow overflow-y-auto p-2'>
+ <Card log={currentLogItem.log} />
+ </div>
+ </div>
+ )
+}
+
+export default PromptLogModal
diff --git a/app/components/base/qrcode/index.tsx b/app/components/base/qrcode/index.tsx
new file mode 100644
index 0000000..278176e
--- /dev/null
+++ b/app/components/base/qrcode/index.tsx
@@ -0,0 +1,80 @@
+'use client'
+import React, { useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiQrCodeLine,
+} from '@remixicon/react'
+import { QRCodeCanvas as QRCode } from 'qrcode.react'
+import ActionButton from '@/app/components/base/action-button'
+import Tooltip from '@/app/components/base/tooltip'
+
+type Props = {
+ content: string
+}
+
+const prefixEmbedded = 'appOverview.overview.appInfo.qrcode.title'
+
+const ShareQRCode = ({ content }: Props) => {
+ const { t } = useTranslation()
+ const [isShow, setIsShow] = useState<boolean>(false)
+ const qrCodeRef = useRef<HTMLDivElement>(null)
+
+ const toggleQRCode = (event: React.MouseEvent) => {
+ event.stopPropagation()
+ setIsShow(prev => !prev)
+ }
+
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (qrCodeRef.current && !qrCodeRef.current.contains(event.target as Node))
+ setIsShow(false)
+ }
+
+ if (isShow)
+ document.addEventListener('click', handleClickOutside)
+
+ return () => {
+ document.removeEventListener('click', handleClickOutside)
+ }
+ }, [isShow])
+
+ const downloadQR = () => {
+ const canvas = document.getElementsByTagName('canvas')[0]
+ const link = document.createElement('a')
+ link.download = 'qrcode.png'
+ link.href = canvas.toDataURL()
+ link.click()
+ }
+
+ const handlePanelClick = (event: React.MouseEvent) => {
+ event.stopPropagation()
+ }
+
+ return (
+ <Tooltip
+ popupContent={t(`${prefixEmbedded}`) || ''}
+ >
+ <div className='relative h-6 w-6' onClick={toggleQRCode}>
+ <ActionButton>
+ <RiQrCodeLine className='h-4 w-4' />
+ </ActionButton>
+ {isShow && (
+ <div
+ ref={qrCodeRef}
+ className='absolute -right-8 top-8 z-10 flex w-[232px] flex-col items-center rounded-lg bg-components-panel-bg p-4 shadow-xs'
+ onClick={handlePanelClick}
+ >
+ <QRCode size={160} value={content} className='mb-2' />
+ <div className='system-xs-regular flex items-center'>
+ <div className='text-text-tertiary'>{t('appOverview.overview.appInfo.qrcode.scan')}</div>
+ <div className='text-text-tertiary'>路</div>
+ <div className='cursor-pointer text-text-accent-secondary' onClick={downloadQR}>{t('appOverview.overview.appInfo.qrcode.download')}</div>
+ </div>
+ </div>
+ )}
+ </div>
+ </Tooltip>
+ )
+}
+
+export default ShareQRCode
diff --git a/app/components/base/radio-card/index.tsx b/app/components/base/radio-card/index.tsx
new file mode 100644
index 0000000..4178972
--- /dev/null
+++ b/app/components/base/radio-card/index.tsx
@@ -0,0 +1,68 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+type Props = {
+ className?: string
+ icon: React.ReactNode
+ iconBgClassName?: string
+ title: React.ReactNode
+ description: string
+ noRadio?: boolean
+ isChosen?: boolean
+ onChosen?: () => void
+ chosenConfig?: React.ReactNode
+ chosenConfigWrapClassName?: string
+}
+
+const RadioCard: FC<Props> = ({
+ icon,
+ iconBgClassName = 'bg-[#F5F3FF]',
+ title,
+ description,
+ noRadio,
+ isChosen,
+ onChosen = noop,
+ chosenConfig,
+ chosenConfigWrapClassName,
+ className,
+}) => {
+ return (
+ <div
+ className={cn(
+ 'relative cursor-pointer rounded-xl border-[0.5px] border-components-option-card-option-border bg-components-option-card-option-bg p-3',
+ isChosen && 'border-[1.5px] bg-components-option-card-option-selected-bg',
+ className,
+ )}
+ >
+ <div className='flex gap-x-2' onClick={onChosen}>
+ <div className={cn(iconBgClassName, 'flex size-8 shrink-0 items-center justify-center rounded-lg shadow-md')}>
+ {icon}
+ </div>
+ <div className='grow'>
+ <div className='system-sm-semibold mb-1 text-text-secondary'>{title}</div>
+ <div className='system-xs-regular text-text-tertiary'>{description}</div>
+ </div>
+ {!noRadio && (
+ <div className='absolute right-3 top-3'>
+ <div className={cn(
+ 'h-4 w-4 rounded-full border border-components-radio-border bg-components-radio-bg shadow-xs',
+ isChosen && 'border-[5px] border-components-radio-border-checked',
+ )}></div>
+ </div>
+ )}
+ </div>
+ {((isChosen && chosenConfig) || noRadio) && (
+ <div className='mt-2 flex gap-x-2'>
+ <div className='size-8 shrink-0'></div>
+ <div className={cn(chosenConfigWrapClassName, 'grow')}>
+ {chosenConfig}
+ </div>
+ </div>
+ )}
+ </div>
+ )
+}
+export default React.memo(RadioCard)
diff --git a/app/components/base/radio-card/simple/index.tsx b/app/components/base/radio-card/simple/index.tsx
new file mode 100644
index 0000000..7bb5c0f
--- /dev/null
+++ b/app/components/base/radio-card/simple/index.tsx
@@ -0,0 +1,45 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+
+type Props = {
+ className?: string
+ title: string | React.JSX.Element | null
+ description: string
+ isChosen: boolean
+ onChosen: () => void
+ chosenConfig?: React.ReactNode
+ icon?: React.JSX.Element
+ extra?: React.ReactNode
+}
+
+const RadioCard: FC<Props> = ({
+ title,
+ description,
+ isChosen,
+ onChosen,
+ icon,
+ extra,
+}) => {
+ return (
+ <div
+ className={cn(s.item, isChosen && s.active)}
+ onClick={onChosen}
+ >
+ <div className='flex px-3 py-2'>
+ {icon}
+ <div>
+ <div className='flex items-center justify-between'>
+ <div className='text-sm font-medium leading-5 text-gray-900'>{title}</div>
+ <div className={s.radio}></div>
+ </div>
+ <div className='text-xs font-normal leading-[18px] text-gray-500'>{description}</div>
+ </div>
+ </div>
+ {extra}
+ </div>
+ )
+}
+export default React.memo(RadioCard)
diff --git a/app/components/base/radio-card/simple/style.module.css b/app/components/base/radio-card/simple/style.module.css
new file mode 100644
index 0000000..93a0f43
--- /dev/null
+++ b/app/components/base/radio-card/simple/style.module.css
@@ -0,0 +1,25 @@
+.item {
+ @apply relative rounded-xl border border-gray-100 cursor-pointer;
+ background-color: #fcfcfd;
+}
+
+.item.active {
+ border-width: 1.5px;
+ border-color: #528BFF;
+ box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1), 0px 1px 2px rgba(16, 24, 40, 0.06);
+}
+
+.item:hover {
+ background-color: #ffffff;
+ border-color: #B2CCFF;
+ box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);
+}
+
+.radio {
+ @apply w-4 h-4 border-[2px] border-gray-200 rounded-full;
+}
+
+.item.active .radio {
+ border-width: 5px;
+ border-color: #155EEF;
+}
diff --git a/app/components/base/radio/component/group/index.tsx b/app/components/base/radio/component/group/index.tsx
new file mode 100644
index 0000000..088aec7
--- /dev/null
+++ b/app/components/base/radio/component/group/index.tsx
@@ -0,0 +1,24 @@
+import type { ReactNode } from 'react'
+import RadioGroupContext from '../../context'
+import s from '../../style.module.css'
+import cn from '@/utils/classnames'
+
+export type TRadioGroupProps = {
+ children?: ReactNode | ReactNode[]
+ value?: string | number
+ className?: string
+ onChange?: (value: any) => void
+}
+
+export default function Group({ children, value, onChange, className = '' }: TRadioGroupProps): React.JSX.Element {
+ const onRadioChange = (value: any) => {
+ onChange?.(value)
+ }
+ return (
+ <div className={cn('flex items-center bg-gray-50', s.container, className)}>
+ <RadioGroupContext.Provider value={{ value, onChange: onRadioChange }}>
+ {children}
+ </RadioGroupContext.Provider>
+ </div>
+ )
+}
diff --git a/app/components/base/radio/component/radio/index.tsx b/app/components/base/radio/component/radio/index.tsx
new file mode 100644
index 0000000..eddc53d
--- /dev/null
+++ b/app/components/base/radio/component/radio/index.tsx
@@ -0,0 +1,63 @@
+import type { ReactNode } from 'react'
+import { useId } from 'react'
+import { useContext } from 'use-context-selector'
+import RadioGroupContext from '../../context'
+import s from '../../style.module.css'
+import cn from '@/utils/classnames'
+
+export type IRadioProps = {
+ className?: string
+ labelClassName?: string
+ children?: string | ReactNode
+ checked?: boolean
+ value?: string | number
+ disabled?: boolean
+ onChange?: (e?: IRadioProps['value']) => void
+}
+
+export default function Radio({
+ className = '',
+ labelClassName,
+ children = '',
+ checked,
+ value,
+ disabled,
+ onChange,
+}: IRadioProps): React.JSX.Element {
+ const groupContext = useContext(RadioGroupContext)
+ const labelId = useId()
+ const handleChange = (e: IRadioProps['value']) => {
+ if (disabled)
+ return
+
+ onChange?.(e)
+ groupContext?.onChange(e)
+ }
+
+ const isChecked = groupContext ? groupContext.value === value : checked
+ const divClassName = `
+ flex items-center py-1 relative
+ px-7 cursor-pointer hover:bg-gray-200 rounded
+ `
+
+ return (
+ <div className={cn(
+ s.label,
+ disabled ? s.disabled : '',
+ isChecked ? 'bg-white shadow' : '',
+ divClassName,
+ className)}
+ onClick={() => handleChange(value)}
+ >
+ {children && (
+ <label className={
+ cn(labelClassName, 'cursor-pointer text-sm')
+ }
+ id={labelId}
+ >
+ {children}
+ </label>
+ )}
+ </div>
+ )
+}
diff --git a/app/components/base/radio/context/index.tsx b/app/components/base/radio/context/index.tsx
new file mode 100644
index 0000000..10d1193
--- /dev/null
+++ b/app/components/base/radio/context/index.tsx
@@ -0,0 +1,6 @@
+'use client'
+
+import { createContext } from 'use-context-selector'
+
+const RadioGroupContext = createContext<any>(null)
+export default RadioGroupContext
diff --git a/app/components/base/radio/index.tsx b/app/components/base/radio/index.tsx
new file mode 100644
index 0000000..9aed850
--- /dev/null
+++ b/app/components/base/radio/index.tsx
@@ -0,0 +1,15 @@
+import type React from 'react'
+import type { IRadioProps } from './component/radio'
+import RadioComps from './component/radio'
+import Group from './component/group'
+
+type CompoundedComponent = {
+ Group: typeof Group
+} & React.ForwardRefExoticComponent<IRadioProps & React.RefAttributes<HTMLElement>>
+
+const Radio = RadioComps as CompoundedComponent
+/**
+ * Radio 缁勪欢鍑虹幇涓�鑸槸浠ヤ竴缁勭殑褰㈠紡鍑虹幇
+ */
+Radio.Group = Group
+export default Radio
diff --git a/app/components/base/radio/style.module.css b/app/components/base/radio/style.module.css
new file mode 100644
index 0000000..3e6bcdf
--- /dev/null
+++ b/app/components/base/radio/style.module.css
@@ -0,0 +1,13 @@
+.container {
+ padding: 4px;
+ border-radius: 4px;
+}
+
+.label {
+ position: relative;
+ margin-right: 3px;
+}
+
+.label:last-child {
+ margin-right: 0;
+}
diff --git a/app/components/base/radio/ui.tsx b/app/components/base/radio/ui.tsx
new file mode 100644
index 0000000..178262d
--- /dev/null
+++ b/app/components/base/radio/ui.tsx
@@ -0,0 +1,18 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+
+type Props = {
+ isChecked: boolean
+}
+
+const RadioUI: FC<Props> = ({
+ isChecked,
+}) => {
+ return (
+ <div className={cn(isChecked ? 'border-[5px] border-components-radio-border-checked' : 'border-[2px] border-components-radio-border', 'h-4 w-4 rounded-full')}>
+ </div>
+ )
+}
+export default React.memo(RadioUI)
diff --git a/app/components/base/search-input/index.tsx b/app/components/base/search-input/index.tsx
new file mode 100644
index 0000000..cf9bc1c
--- /dev/null
+++ b/app/components/base/search-input/index.tsx
@@ -0,0 +1,77 @@
+import type { FC } from 'react'
+import { useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseCircleFill, RiSearchLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+
+type SearchInputProps = {
+ placeholder?: string
+ className?: string
+ value: string
+ onChange: (v: string) => void
+ white?: boolean
+}
+
+const SearchInput: FC<SearchInputProps> = ({
+ placeholder,
+ className,
+ value,
+ onChange,
+ white,
+}) => {
+ const { t } = useTranslation()
+ const [focus, setFocus] = useState<boolean>(false)
+ const isComposing = useRef<boolean>(false)
+ const [internalValue, setInternalValue] = useState<string>(value)
+
+ return (
+ <div className={cn(
+ 'group flex h-8 items-center overflow-hidden rounded-lg border-none bg-components-input-bg-normal px-2 hover:bg-components-input-bg-hover',
+ focus && '!bg-components-input-bg-active',
+ white && '!border-gray-300 !bg-white shadow-xs hover:!border-gray-300 hover:!bg-white',
+ className,
+ )}>
+ <div className="pointer-events-none mr-1.5 flex h-4 w-4 shrink-0 items-center justify-center">
+ <RiSearchLine className="h-4 w-4 text-components-input-text-placeholder" aria-hidden="true" />
+ </div>
+ <input
+ type="text"
+ name="query"
+ className={cn(
+ 'system-sm-regular caret-#295EFF block h-[18px] grow appearance-none border-0 bg-transparent text-components-input-text-filled outline-none placeholder:text-components-input-text-placeholder',
+ white && '!bg-white placeholder:!text-gray-400 hover:!bg-white group-hover:!bg-white',
+ )}
+ placeholder={placeholder || t('common.operation.search')!}
+ value={internalValue}
+ onChange={(e) => {
+ setInternalValue(e.target.value)
+ if (!isComposing.current)
+ onChange(e.target.value)
+ }}
+ onCompositionStart={() => {
+ isComposing.current = true
+ }}
+ onCompositionEnd={(e) => {
+ isComposing.current = false
+ onChange(e.data)
+ }}
+ onFocus={() => setFocus(true)}
+ onBlur={() => setFocus(false)}
+ autoComplete="off"
+ />
+ {value && (
+ <div
+ className='group/clear flex h-4 w-4 shrink-0 cursor-pointer items-center justify-center'
+ onClick={() => {
+ onChange('')
+ setInternalValue('')
+ }}
+ >
+ <RiCloseCircleFill className='h-4 w-4 text-text-quaternary group-hover/clear:text-text-tertiary' />
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default SearchInput
diff --git a/app/components/base/segmented-control/index.tsx b/app/components/base/segmented-control/index.tsx
new file mode 100644
index 0000000..bd921e4
--- /dev/null
+++ b/app/components/base/segmented-control/index.tsx
@@ -0,0 +1,68 @@
+import React from 'react'
+import classNames from '@/utils/classnames'
+import type { RemixiconComponentType } from '@remixicon/react'
+import Divider from '../divider'
+
+// Updated generic type to allow enum values
+type SegmentedControlProps<T extends string | number | symbol> = {
+ options: { Icon: RemixiconComponentType, text: string, value: T }[]
+ value: T
+ onChange: (value: T) => void
+ className?: string
+}
+
+export const SegmentedControl = <T extends string | number | symbol>({
+ options,
+ value,
+ onChange,
+ className,
+}: SegmentedControlProps<T>): JSX.Element => {
+ const selectedOptionIndex = options.findIndex(option => option.value === value)
+
+ return (
+ <div className={classNames(
+ 'flex items-center rounded-lg bg-components-segmented-control-bg-normal gap-x-[1px] p-0.5',
+ className,
+ )}>
+ {options.map((option, index) => {
+ const { Icon } = option
+ const isSelected = index === selectedOptionIndex
+ const isNextSelected = index === selectedOptionIndex - 1
+ const isLast = index === options.length - 1
+ return (
+ <button
+ type='button'
+ key={String(option.value)}
+ className={classNames(
+ 'flex items-center justify-center relative px-2 py-1 rounded-lg gap-x-0.5 group border-0.5 border-transparent',
+ isSelected
+ ? 'border-components-segmented-control-item-active-border bg-components-segmented-control-item-active-bg shadow-xs shadow-shadow-shadow-3'
+ : 'hover:bg-state-base-hover',
+ )}
+ onClick={() => onChange(option.value)}
+ >
+ <span className='flex h-5 w-5 items-center justify-center'>
+ <Icon className={classNames(
+ 'w-4 h-4 text-text-tertiary',
+ isSelected ? 'text-text-accent-light-mode-only' : 'group-hover:text-text-secondary',
+ )} />
+ </span>
+ <span className={classNames(
+ 'p-0.5 text-text-tertiary system-sm-medium',
+ isSelected ? 'text-text-accent-light-mode-only' : 'group-hover:text-text-secondary',
+ )}>
+ {option.text}
+ </span>
+ {!isLast && !isSelected && !isNextSelected && (
+ <div className='absolute right-[-1px] top-0 flex h-full items-center'>
+ <Divider type='vertical' className='mx-0 h-3.5' />
+ </div>
+ )}
+ </button>
+ )
+ })}
+ </div>
+ )
+}
+
+export default React.memo(SegmentedControl) as typeof SegmentedControl
diff --git a/app/components/base/select/index.tsx b/app/components/base/select/index.tsx
new file mode 100644
index 0000000..fa8730f
--- /dev/null
+++ b/app/components/base/select/index.tsx
@@ -0,0 +1,382 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions, Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headlessui/react'
+import { ChevronDownIcon, ChevronUpIcon, XMarkIcon } from '@heroicons/react/20/solid'
+import Badge from '../badge/index'
+import { RiCheckLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import classNames from '@/utils/classnames'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+
+const defaultItems = [
+ { value: 1, name: 'option1' },
+ { value: 2, name: 'option2' },
+ { value: 3, name: 'option3' },
+ { value: 4, name: 'option4' },
+ { value: 5, name: 'option5' },
+ { value: 6, name: 'option6' },
+ { value: 7, name: 'option7' },
+]
+
+export type Item = {
+ value: number | string
+ name: string
+} & Record<string, any>
+
+export type ISelectProps = {
+ className?: string
+ wrapperClassName?: string
+ renderTrigger?: (value: Item | null) => React.JSX.Element | null
+ items?: Item[]
+ defaultValue?: number | string
+ disabled?: boolean
+ onSelect: (value: Item) => void
+ allowSearch?: boolean
+ bgClassName?: string
+ placeholder?: string
+ overlayClassName?: string
+ optionWrapClassName?: string
+ optionClassName?: string
+ hideChecked?: boolean
+ notClearable?: boolean
+ renderOption?: ({
+ item,
+ selected,
+ }: {
+ item: Item
+ selected: boolean
+ }) => React.ReactNode
+}
+const Select: FC<ISelectProps> = ({
+ className,
+ items = defaultItems,
+ defaultValue = 1,
+ disabled = false,
+ onSelect,
+ allowSearch = true,
+ bgClassName = 'bg-components-input-bg-normal',
+ overlayClassName,
+ optionClassName,
+ renderOption,
+}) => {
+ const [query, setQuery] = useState('')
+ const [open, setOpen] = useState(false)
+
+ const [selectedItem, setSelectedItem] = useState<Item | null>(null)
+ useEffect(() => {
+ let defaultSelect = null
+ const existed = items.find((item: Item) => item.value === defaultValue)
+ if (existed)
+ defaultSelect = existed
+
+ setSelectedItem(defaultSelect)
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [defaultValue])
+
+ const filteredItems: Item[]
+ = query === ''
+ ? items
+ : items.filter((item) => {
+ return item.name.toLowerCase().includes(query.toLowerCase())
+ })
+
+ return (
+ <Combobox
+ as="div"
+ disabled={disabled}
+ value={selectedItem}
+ className={className}
+ onChange={(value: Item) => {
+ if (!disabled) {
+ setSelectedItem(value)
+ setOpen(false)
+ onSelect(value)
+ }
+ }}>
+ <div className={classNames('relative')}>
+ <div className='group text-text-secondary'>
+ {allowSearch
+ ? <ComboboxInput
+ className={`w-full rounded-lg border-0 ${bgClassName} py-1.5 pl-3 pr-10 shadow-sm focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6 ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}
+ onChange={(event) => {
+ if (!disabled)
+ setQuery(event.target.value)
+ }}
+ displayValue={(item: Item) => item?.name}
+ />
+ : <ComboboxButton onClick={
+ () => {
+ if (!disabled)
+ setOpen(!open)
+ }
+ } className={classNames(`flex items-center h-9 w-full rounded-lg border-0 ${bgClassName} py-1.5 pl-3 pr-10 shadow-sm sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-state-base-hover group-hover:bg-state-base-hover`, optionClassName)}>
+ <div className='w-0 grow truncate text-left' title={selectedItem?.name}>{selectedItem?.name}</div>
+ </ComboboxButton>}
+ <ComboboxButton className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none" onClick={
+ () => {
+ if (!disabled)
+ setOpen(!open)
+ }
+ }>
+ {open ? <ChevronUpIcon className="h-5 w-5" /> : <ChevronDownIcon className="h-5 w-5" />}
+ </ComboboxButton>
+ </div>
+
+ {(filteredItems.length > 0 && open) && (
+ <ComboboxOptions className={`absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg-blur px-1 py-1 text-base shadow-lg backdrop-blur-sm focus:outline-none sm:text-sm ${overlayClassName}`}>
+ {filteredItems.map((item: Item) => (
+ <ComboboxOption
+ key={item.value}
+ value={item}
+ className={({ active }: { active: boolean }) =>
+ classNames(
+ 'relative cursor-default select-none py-2 pl-3 pr-9 rounded-lg hover:bg-state-base-hover text-text-secondary',
+ active ? 'bg-state-base-hover' : '',
+ optionClassName,
+ )
+ }
+ >
+ {({ /* active, */ selected }) => (
+ <>
+ {renderOption
+ ? renderOption({ item, selected })
+ : (
+ <>
+ <span className={classNames('block', selected && 'font-normal')}>{item.name}</span>
+ {selected && (
+ <span
+ className={classNames(
+ 'absolute inset-y-0 right-0 flex items-center pr-4 text-text-secondary',
+ )}
+ >
+ <RiCheckLine className="h-4 w-4" aria-hidden="true" />
+ </span>
+ )}
+ </>
+ )}
+ </>
+ )}
+ </ComboboxOption>
+ ))}
+ </ComboboxOptions>
+ )}
+ </div>
+ </Combobox >
+ )
+}
+
+const SimpleSelect: FC<ISelectProps> = ({
+ className,
+ wrapperClassName = '',
+ renderTrigger,
+ items = defaultItems,
+ defaultValue = 1,
+ disabled = false,
+ onSelect,
+ placeholder,
+ optionWrapClassName,
+ optionClassName,
+ hideChecked,
+ notClearable,
+ renderOption,
+}) => {
+ const { t } = useTranslation()
+ const localPlaceholder = placeholder || t('common.placeholder.select')
+
+ const [selectedItem, setSelectedItem] = useState<Item | null>(null)
+ useEffect(() => {
+ let defaultSelect = null
+ const existed = items.find((item: Item) => item.value === defaultValue)
+ if (existed)
+ defaultSelect = existed
+
+ setSelectedItem(defaultSelect)
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [defaultValue])
+
+ return (
+ <Listbox
+ value={selectedItem}
+ onChange={(value: Item) => {
+ if (!disabled) {
+ setSelectedItem(value)
+ onSelect(value)
+ }
+ }}
+ >
+ <div className={classNames('group/simple-select relative h-9', wrapperClassName)}>
+ {renderTrigger && <ListboxButton className='w-full'>{renderTrigger(selectedItem)}</ListboxButton>}
+ {!renderTrigger && (
+ <ListboxButton className={classNames(`flex items-center w-full h-full rounded-lg border-0 bg-components-input-bg-normal pl-3 pr-10 sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-state-base-hover-alt group-hover/simple-select:bg-state-base-hover-alt ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}`, className)}>
+ <span className={classNames('block truncate text-left system-sm-regular text-components-input-text-filled', !selectedItem?.name && 'text-components-input-text-placeholder')}>{selectedItem?.name ?? localPlaceholder}</span>
+ <span className="absolute inset-y-0 right-0 flex items-center pr-2">
+ {(selectedItem && !notClearable)
+ ? (
+ <XMarkIcon
+ onClick={(e) => {
+ e.stopPropagation()
+ setSelectedItem(null)
+ onSelect({ name: '', value: '' })
+ }}
+ className="h-4 w-4 cursor-pointer text-text-quaternary"
+ aria-hidden="false"
+ />
+ )
+ : (
+ <ChevronDownIcon
+ className="h-4 w-4 text-text-quaternary group-hover/simple-select:text-text-secondary"
+ aria-hidden="true"
+ />
+ )}
+ </span>
+ </ListboxButton>
+ )}
+
+ {!disabled && (
+ <ListboxOptions className={classNames('absolute z-10 mt-1 px-1 max-h-60 w-full overflow-auto rounded-xl bg-components-panel-bg-blur backdrop-blur-sm py-1 text-base shadow-lg border-components-panel-border border-[0.5px] focus:outline-none sm:text-sm', optionWrapClassName)}>
+ {items.map((item: Item) => (
+ <ListboxOption
+ key={item.value}
+ className={
+ classNames(
+ 'relative cursor-pointer select-none py-2 pl-3 pr-9 rounded-lg hover:bg-state-base-hover text-text-secondary',
+ optionClassName,
+ )
+ }
+ value={item}
+ disabled={disabled}
+ >
+ {({ /* active, */ selected }) => (
+ <>
+ {renderOption
+ ? renderOption({ item, selected })
+ : (<>
+ <span className={classNames('block', selected && 'font-normal')}>{item.name}</span>
+ {selected && !hideChecked && (
+ <span
+ className={classNames(
+ 'absolute inset-y-0 right-0 flex items-center pr-4 text-text-accent',
+ )}
+ >
+ <RiCheckLine className="h-4 w-4" aria-hidden="true" />
+ </span>
+ )}
+ </>)}
+ </>
+ )}
+ </ListboxOption>
+ ))}
+ </ListboxOptions>
+ )}
+ </div>
+ </Listbox>
+ )
+}
+
+type PortalSelectProps = {
+ value: string | number
+ onSelect: (value: Item) => void
+ items: Item[]
+ placeholder?: string
+ installedValue?: string | number
+ renderTrigger?: (value?: Item) => React.JSX.Element | null
+ triggerClassName?: string
+ triggerClassNameFn?: (open: boolean) => string
+ popupClassName?: string
+ popupInnerClassName?: string
+ readonly?: boolean
+ hideChecked?: boolean
+}
+const PortalSelect: FC<PortalSelectProps> = ({
+ value,
+ onSelect,
+ items,
+ placeholder,
+ installedValue,
+ renderTrigger,
+ triggerClassName,
+ triggerClassNameFn,
+ popupClassName,
+ popupInnerClassName,
+ readonly,
+ hideChecked,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const localPlaceholder = placeholder || t('common.placeholder.select')
+ const selectedItem = value ? items.find(item => item.value === value) : undefined
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <PortalToFollowElemTrigger onClick={() => !readonly && setOpen(v => !v)} className='w-full'>
+ {renderTrigger
+ ? renderTrigger(selectedItem)
+ : (
+ <div
+ className={classNames(`
+ group flex items-center justify-between px-2.5 h-9 rounded-lg border-0 bg-components-input-bg-normal hover:bg-state-base-hover-alt text-sm ${readonly ? 'cursor-not-allowed' : 'cursor-pointer'}
+ `, triggerClassName, triggerClassNameFn?.(open))}
+ title={selectedItem?.name}
+ >
+ <span
+ className={`
+ grow truncate
+ ${!selectedItem?.name && 'text-components-input-text-placeholder'}
+ `}
+ >
+ {selectedItem?.name ?? localPlaceholder}
+ </span>
+ <div className='mx-0.5'>{installedValue && selectedItem && selectedItem.value !== installedValue && <Badge>{installedValue} {'->'} {selectedItem.value} </Badge>}</div>
+ <ChevronDownIcon className='h-4 w-4 shrink-0 text-text-quaternary group-hover:text-text-secondary' />
+ </div>
+ )}
+
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className={`z-20 ${popupClassName}`}>
+ <div
+ className={classNames('px-1 py-1 max-h-60 overflow-auto rounded-md text-base shadow-lg border-components-panel-border bg-components-panel-bg border-[0.5px] focus:outline-none sm:text-sm', popupInnerClassName)}
+ >
+ {items.map((item: Item) => (
+ <div
+ key={item.value}
+ className={`
+ flex h-9 cursor-pointer items-center justify-between rounded-lg px-2.5 text-text-secondary hover:bg-state-base-hover
+ ${item.value === value && 'bg-state-base-hover'}
+ `}
+ title={item.name}
+ onClick={() => {
+ onSelect(item)
+ setOpen(false)
+ }}
+ >
+ <span
+ className='w-0 grow truncate'
+ title={item.name}
+ >
+ <span className='truncate'>{item.name}</span>
+ {item.value === installedValue && (
+ <Badge uppercase={true} className='ml-1 shrink-0'>INSTALLED</Badge>
+ )}
+ </span>
+ {!hideChecked && item.value === value && (
+ <RiCheckLine className='h-4 w-4 shrink-0 text-text-accent' />
+ )}
+ </div>
+ ))}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export { SimpleSelect, PortalSelect }
+export default React.memo(Select)
diff --git a/app/components/base/select/locale.tsx b/app/components/base/select/locale.tsx
new file mode 100644
index 0000000..8981f09
--- /dev/null
+++ b/app/components/base/select/locale.tsx
@@ -0,0 +1,61 @@
+'use client'
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import { Fragment } from 'react'
+import { GlobeAltIcon } from '@heroicons/react/24/outline'
+
+type ISelectProps = {
+ items: Array<{ value: string; name: string }>
+ value?: string
+ className?: string
+ onChange?: (value: string) => void
+}
+
+export default function Select({
+ items,
+ value,
+ onChange,
+}: ISelectProps) {
+ const item = items.filter(item => item.value === value)[0]
+
+ return (
+ <div className="w-56 text-right">
+ <Menu as="div" className="relative inline-block text-left">
+ <div>
+ <MenuButton className="h-[44px]justify-center inline-flex w-full items-center rounded-lg border border-components-button-secondary-border px-[10px] py-[6px] text-[13px] font-medium text-text-primary hover:bg-state-base-hover">
+ <GlobeAltIcon className="mr-1 h-5 w-5" aria-hidden="true" />
+ {item?.name}
+ </MenuButton>
+ </div>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems className="absolute right-0 z-10 mt-2 w-[200px] origin-top-right divide-y divide-divider-regular rounded-md bg-components-panel-bg shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
+ <div className="px-1 py-1 ">
+ {items.map((item) => {
+ return <MenuItem key={item.value}>
+ <button
+ className={'group flex w-full items-center rounded-lg px-3 py-2 text-sm text-text-secondary data-[active]:bg-state-base-hover'}
+ onClick={(evt) => {
+ evt.preventDefault()
+ onChange && onChange(item.value)
+ }}
+ >
+ {item.name}
+ </button>
+ </MenuItem>
+ })}
+
+ </div>
+
+ </MenuItems>
+ </Transition>
+ </Menu>
+ </div>
+ )
+}
diff --git a/app/components/base/select/pure.tsx b/app/components/base/select/pure.tsx
new file mode 100644
index 0000000..81cc2fb
--- /dev/null
+++ b/app/components/base/select/pure.tsx
@@ -0,0 +1,157 @@
+import {
+ useCallback,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiArrowDownSLine,
+ RiCheckLine,
+} from '@remixicon/react'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import type {
+ PortalToFollowElemOptions,
+} from '@/app/components/base/portal-to-follow-elem'
+import cn from '@/utils/classnames'
+
+type Option = {
+ label: string
+ value: string
+}
+
+type PureSelectProps = {
+ options: Option[]
+ value?: string
+ onChange?: (value: string) => void
+ containerProps?: PortalToFollowElemOptions & {
+ open?: boolean
+ onOpenChange?: (open: boolean) => void
+ }
+ triggerProps?: {
+ className?: string
+ },
+ popupProps?: {
+ wrapperClassName?: string
+ className?: string
+ itemClassName?: string
+ title?: string
+ },
+}
+const PureSelect = ({
+ options,
+ value,
+ onChange,
+ containerProps,
+ triggerProps,
+ popupProps,
+}: PureSelectProps) => {
+ const { t } = useTranslation()
+ const {
+ open,
+ onOpenChange,
+ placement,
+ offset,
+ } = containerProps || {}
+ const {
+ className: triggerClassName,
+ } = triggerProps || {}
+ const {
+ wrapperClassName: popupWrapperClassName,
+ className: popupClassName,
+ itemClassName: popupItemClassName,
+ title: popupTitle,
+ } = popupProps || {}
+
+ const [localOpen, setLocalOpen] = useState(false)
+ const mergedOpen = open ?? localOpen
+
+ const handleOpenChange = useCallback((openValue: boolean) => {
+ onOpenChange?.(openValue)
+ setLocalOpen(openValue)
+ }, [onOpenChange])
+
+ const selectedOption = options.find(option => option.value === value)
+ const triggerText = selectedOption?.label || t('common.placeholder.select')
+
+ return (
+ <PortalToFollowElem
+ placement={placement || 'bottom-start'}
+ offset={offset || 4}
+ open={mergedOpen}
+ onOpenChange={handleOpenChange}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => handleOpenChange(!mergedOpen)}
+ asChild
+ >
+ <div
+ className={cn(
+ 'system-sm-regular group flex h-8 cursor-pointer items-center rounded-lg bg-components-input-bg-normal px-2 text-components-input-text-filled hover:bg-state-base-hover-alt',
+ mergedOpen && 'bg-state-base-hover-alt',
+ triggerClassName,
+ )}
+ >
+ <div
+ className='grow'
+ title={triggerText}
+ >
+ {triggerText}
+ </div>
+ <RiArrowDownSLine
+ className={cn(
+ 'h-4 w-4 shrink-0 text-text-quaternary group-hover:text-text-secondary',
+ mergedOpen && 'text-text-secondary',
+ )}
+ />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className={cn(
+ 'z-10',
+ popupWrapperClassName,
+ )}>
+ <div
+ className={cn(
+ 'rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg',
+ popupClassName,
+ )}
+ >
+ {
+ popupTitle && (
+ <div className='system-xs-medium-uppercase flex h-[22px] items-center px-3 text-text-tertiary'>
+ {popupTitle}
+ </div>
+ )
+ }
+ {
+ options.map(option => (
+ <div
+ key={option.value}
+ className={cn(
+ 'system-sm-medium flex h-8 cursor-pointer items-center rounded-lg px-2 text-text-secondary hover:bg-state-base-hover',
+ popupItemClassName,
+ )}
+ title={option.label}
+ onClick={() => {
+ onChange?.(option.value)
+ handleOpenChange(false)
+ }}
+ >
+ <div className='mr-1 grow truncate px-1'>
+ {option.label}
+ </div>
+ {
+ value === option.value && <RiCheckLine className='h-4 w-4 shrink-0 text-text-accent' />
+ }
+ </div>
+ ))
+ }
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default PureSelect
diff --git a/app/components/base/simple-pie-chart/index.module.css b/app/components/base/simple-pie-chart/index.module.css
new file mode 100644
index 0000000..827b18d
--- /dev/null
+++ b/app/components/base/simple-pie-chart/index.module.css
@@ -0,0 +1,4 @@
+.simplePieChart {
+ border-radius: 50%;
+ box-shadow: 0 0 5px -3px rgb(from var(--simple-pie-chart-color) r g b / 0.1), 0.5px 0.5px 3px 0 rgb(from var(--simple-pie-chart-color) r g b / 0.3);
+}
diff --git a/app/components/base/simple-pie-chart/index.tsx b/app/components/base/simple-pie-chart/index.tsx
new file mode 100644
index 0000000..4b987ab
--- /dev/null
+++ b/app/components/base/simple-pie-chart/index.tsx
@@ -0,0 +1,67 @@
+import type { CSSProperties } from 'react'
+import { memo, useMemo } from 'react'
+import ReactECharts from 'echarts-for-react'
+import type { EChartsOption } from 'echarts'
+import style from './index.module.css'
+import classNames from '@/utils/classnames'
+
+export type SimplePieChartProps = {
+ percentage?: number
+ fill?: string
+ stroke?: string
+ size?: number
+ animationDuration?: number
+ className?: string
+}
+
+const SimplePieChart = ({ percentage = 80, fill = '#fdb022', stroke = '#f79009', size = 12, animationDuration, className }: SimplePieChartProps) => {
+ const option: EChartsOption = useMemo(() => ({
+ series: [
+ {
+ type: 'pie',
+ radius: ['83%', '100%'],
+ animation: false,
+ data: [
+ { value: 100, itemStyle: { color: stroke } },
+ ],
+ emphasis: {
+ disabled: true,
+ },
+ labelLine: {
+ show: false,
+ },
+ cursor: 'default',
+ },
+ {
+ type: 'pie',
+ radius: '83%',
+ animationDuration: animationDuration ?? 600,
+ data: [
+ { value: percentage, itemStyle: { color: fill } },
+ { value: 100 - percentage, itemStyle: { color: '#fff' } },
+ ],
+ emphasis: {
+ disabled: true,
+ },
+ labelLine: {
+ show: false,
+ },
+ cursor: 'default',
+ },
+ ],
+ }), [stroke, fill, percentage, animationDuration])
+
+ return (
+ <ReactECharts
+ option={option}
+ className={classNames(style.simplePieChart, className)}
+ style={{
+ '--simple-pie-chart-color': fill,
+ 'width': size,
+ 'height': size,
+ } as CSSProperties}
+ />
+ )
+}
+
+export default memo(SimplePieChart)
diff --git a/app/components/base/skeleton/index.tsx b/app/components/base/skeleton/index.tsx
new file mode 100644
index 0000000..41edc26
--- /dev/null
+++ b/app/components/base/skeleton/index.tsx
@@ -0,0 +1,50 @@
+import type { ComponentProps, FC } from 'react'
+import classNames from '@/utils/classnames'
+
+type SkeletonProps = ComponentProps<'div'>
+
+export const SkeletonContainer: FC<SkeletonProps> = (props) => {
+ const { className, children, ...rest } = props
+ return (
+ <div className={classNames('flex flex-col gap-1', className)} {...rest}>
+ {children}
+ </div>
+ )
+}
+
+export const SkeletonRow: FC<SkeletonProps> = (props) => {
+ const { className, children, ...rest } = props
+ return (
+ <div className={classNames('flex items-center gap-2', className)} {...rest}>
+ {children}
+ </div>
+ )
+}
+
+export const SkeletonRectangle: FC<SkeletonProps> = (props) => {
+ const { className, children, ...rest } = props
+ return (
+ <div className={classNames('h-2 rounded-sm opacity-20 bg-text-quaternary my-1', className)} {...rest}>
+ {children}
+ </div>
+ )
+}
+
+export const SkeletonPoint: FC<SkeletonProps> = (props) => {
+ const { className, ...rest } = props
+ return (
+ <div className={classNames('text-text-quaternary text-xs font-medium', className)} {...rest}>路</div>
+ )
+}
+/** Usage
+ * <SkeletonContainer>
+ * <SkeletonRow>
+ * <SkeletonRectangle className="w-96" />
+ * <SkeletonPoint />
+ * <SkeletonRectangle className="w-96" />
+ * </SkeletonRow>
+ * <SkeletonRow>
+ * <SkeletonRectangle className="w-96" />
+ * </SkeletonRow>
+ * <SkeletonRow>
+ */
diff --git a/app/components/base/slider/index.tsx b/app/components/base/slider/index.tsx
new file mode 100644
index 0000000..2cfbf80
--- /dev/null
+++ b/app/components/base/slider/index.tsx
@@ -0,0 +1,41 @@
+import ReactSlider from 'react-slider'
+import cn from '@/utils/classnames'
+import './style.css'
+
+type ISliderProps = {
+ className?: string
+ thumbClassName?: string
+ trackClassName?: string
+ value: number
+ max?: number
+ min?: number
+ step?: number
+ disabled?: boolean
+ onChange: (value: number) => void
+}
+
+const Slider: React.FC<ISliderProps> = ({
+ className,
+ thumbClassName,
+ trackClassName,
+ max,
+ min,
+ step,
+ value,
+ disabled,
+ onChange,
+}) => {
+ return <ReactSlider
+ disabled={disabled}
+ value={isNaN(value) ? 0 : value}
+ min={min || 0}
+ max={max || 100}
+ step={step || 1}
+ className={cn('slider relative', className)}
+ thumbClassName={cn('absolute top-[-9px] h-5 w-2 rounded-[3px] border-[0.5px] border-components-slider-knob-border bg-components-slider-knob shadow-sm focus:outline-none', !disabled && 'cursor-pointer', thumbClassName)}
+ trackClassName={cn('h-0.5 rounded-full', 'slider-track', trackClassName)}
+ onChange={onChange}
+ />
+}
+
+export default Slider
diff --git a/app/components/base/slider/style.css b/app/components/base/slider/style.css
new file mode 100644
index 0000000..5d87fb0
--- /dev/null
+++ b/app/components/base/slider/style.css
@@ -0,0 +1,11 @@
+.slider.disabled {
+ opacity: 0.6;
+}
+
+.slider-track {
+ background-color: var(--color-components-slider-range);
+}
+
+.slider-track-1 {
+ background-color: var(--color-components-slider-track);
+}
diff --git a/app/components/base/sort/index.tsx b/app/components/base/sort/index.tsx
new file mode 100644
index 0000000..af90233
--- /dev/null
+++ b/app/components/base/sort/index.tsx
@@ -0,0 +1,92 @@
+import type { FC } from 'react'
+import { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowDownSLine, RiCheckLine, RiSortAsc, RiSortDesc } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+
+export type Item = {
+ value: number | string
+ name: string
+} & Record<string, any>
+
+type Props = {
+ order?: string
+ value: number | string
+ items: Item[]
+ onSelect: (item: any) => void
+}
+const Sort: FC<Props> = ({
+ order,
+ value,
+ items,
+ onSelect,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ const triggerContent = useMemo(() => {
+ return items.find(item => item.value === value)?.name || ''
+ }, [items, value])
+
+ return (
+ <div className='inline-flex items-center'>
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <div className='relative'>
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ className='block'
+ >
+ <div className={cn(
+ 'flex cursor-pointer items-center rounded-l-lg bg-components-input-bg-normal px-2 py-1 hover:bg-state-base-hover-alt',
+ open && '!bg-state-base-hover-alt hover:bg-state-base-hover-alt',
+ )}>
+ <div className='flex items-center gap-0.5 p-1'>
+ <div className='system-sm-regular text-text-tertiary'>{t('appLog.filter.sortBy')}</div>
+ <div className={cn('system-sm-regular text-text-tertiary', !!value && 'text-text-secondary')}>
+ {triggerContent}
+ </div>
+ </div>
+ <RiArrowDownSLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1002]'>
+ <div className='relative w-[240px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'>
+ <div className='max-h-72 overflow-auto p-1'>
+ {items.map(item => (
+ <div
+ key={item.value}
+ className='flex cursor-pointer items-center gap-2 rounded-lg px-2 py-[6px] pl-3 hover:bg-state-base-hover'
+ onClick={() => {
+ onSelect(`${order}${item.value}`)
+ setOpen(false)
+ }}
+ >
+ <div title={item.name} className='system-sm-medium grow truncate text-text-secondary'>{item.name}</div>
+ {value === item.value && <RiCheckLine className='h-4 w-4 shrink-0 text-util-colors-blue-light-blue-light-600' />}
+ </div>
+ ))}
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </div>
+ </PortalToFollowElem>
+ <div className='ml-px cursor-pointer rounded-r-lg bg-components-button-tertiary-bg p-2 hover:bg-components-button-tertiary-bg-hover' onClick={() => onSelect(`${order ? '' : '-'}${value}`)}>
+ {!order && <RiSortAsc className='h-4 w-4 text-components-button-tertiary-text' />}
+ {order && <RiSortDesc className='h-4 w-4 text-components-button-tertiary-text' />}
+ </div>
+ </div>
+
+ )
+}
+
+export default Sort
diff --git a/app/components/base/spinner/index.spec.tsx b/app/components/base/spinner/index.spec.tsx
new file mode 100644
index 0000000..0c4f0f6
--- /dev/null
+++ b/app/components/base/spinner/index.spec.tsx
@@ -0,0 +1,49 @@
+import React from 'react'
+import { render } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import Spinner from './index'
+
+describe('Spinner component', () => {
+ it('should render correctly when loading is true', () => {
+ const { container } = render(<Spinner loading={true} />)
+ const spinner = container.firstChild as HTMLElement
+
+ expect(spinner).toHaveClass('animate-spin')
+
+ // Check for accessibility text
+ const screenReaderText = spinner.querySelector('span')
+ expect(screenReaderText).toBeInTheDocument()
+ expect(screenReaderText).toHaveTextContent('Loading...')
+ })
+
+ it('should be hidden when loading is false', () => {
+ const { container } = render(<Spinner loading={false} />)
+ const spinner = container.firstChild as HTMLElement
+
+ expect(spinner).toHaveClass('hidden')
+ })
+
+ it('should render with custom className', () => {
+ const customClass = 'text-blue-500'
+ const { container } = render(<Spinner loading={true} className={customClass} />)
+ const spinner = container.firstChild as HTMLElement
+
+ expect(spinner).toHaveClass(customClass)
+ })
+
+ it('should render children correctly', () => {
+ const childText = 'Child content'
+ const { getByText } = render(
+ <Spinner loading={true}>{childText}</Spinner>,
+ )
+
+ expect(getByText(childText)).toBeInTheDocument()
+ })
+
+ it('should use default loading value (false) when not provided', () => {
+ const { container } = render(<Spinner />)
+ const spinner = container.firstChild as HTMLElement
+
+ expect(spinner).toHaveClass('hidden')
+ })
+})
diff --git a/app/components/base/spinner/index.tsx b/app/components/base/spinner/index.tsx
new file mode 100644
index 0000000..e1568c2
--- /dev/null
+++ b/app/components/base/spinner/index.tsx
@@ -0,0 +1,24 @@
+import type { FC } from 'react'
+import React from 'react'
+
+type Props = {
+ loading?: boolean
+ className?: string
+ children?: React.ReactNode | string
+}
+
+const Spinner: FC<Props> = ({ loading = false, children, className }) => {
+ return (
+ <div
+ className={`inline-block h-4 w-4 animate-spin rounded-full border-4 border-solid border-current border-r-transparent align-[-0.125em] text-gray-200 ${loading ? 'motion-reduce:animate-[spin_1.5s_linear_infinite]' : 'hidden'} ${className ?? ''}`}
+ role="status"
+ >
+ <span
+ className="!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]"
+ >Loading...</span>
+ {children}
+ </div>
+ )
+}
+
+export default Spinner
diff --git a/app/components/base/svg-gallery/index.tsx b/app/components/base/svg-gallery/index.tsx
new file mode 100644
index 0000000..94fc82c
--- /dev/null
+++ b/app/components/base/svg-gallery/index.tsx
@@ -0,0 +1,78 @@
+import { useEffect, useRef, useState } from 'react'
+import { SVG } from '@svgdotjs/svg.js'
+import ImagePreview from '@/app/components/base/image-uploader/image-preview'
+import DOMPurify from 'dompurify'
+
+export const SVGRenderer = ({ content }: { content: string }) => {
+ const svgRef = useRef<HTMLDivElement>(null)
+ const [imagePreview, setImagePreview] = useState('')
+ const [windowSize, setWindowSize] = useState({
+ width: typeof window !== 'undefined' ? window.innerWidth : 0,
+ height: typeof window !== 'undefined' ? window.innerHeight : 0,
+ })
+
+ const svgToDataURL = (svgElement: Element): string => {
+ const svgString = new XMLSerializer().serializeToString(svgElement)
+ const base64String = Buffer.from(svgString).toString('base64')
+ return `data:image/svg+xml;base64,${base64String}`
+ }
+
+ useEffect(() => {
+ const handleResize = () => {
+ setWindowSize({ width: window.innerWidth, height: window.innerHeight })
+ }
+
+ window.addEventListener('resize', handleResize)
+ return () => window.removeEventListener('resize', handleResize)
+ }, [])
+
+ useEffect(() => {
+ if (svgRef.current) {
+ try {
+ svgRef.current.innerHTML = ''
+ const draw = SVG().addTo(svgRef.current)
+
+ const parser = new DOMParser()
+ const svgDoc = parser.parseFromString(content, 'image/svg+xml')
+ const svgElement = svgDoc.documentElement
+
+ if (!(svgElement instanceof SVGElement))
+ throw new Error('Invalid SVG content')
+
+ const originalWidth = Number.parseInt(svgElement.getAttribute('width') || '400', 10)
+ const originalHeight = Number.parseInt(svgElement.getAttribute('height') || '600', 10)
+ draw.viewbox(0, 0, originalWidth, originalHeight)
+
+ svgRef.current.style.width = `${Math.min(originalWidth, 298)}px`
+
+ const rootElement = draw.svg(DOMPurify.sanitize(content))
+
+ rootElement.click(() => {
+ setImagePreview(svgToDataURL(svgElement as Element))
+ })
+ }
+ catch {
+ if (svgRef.current)
+ svgRef.current.innerHTML = '<span style="padding: 1rem;">Error rendering SVG. Wait for the image content to complete.</span>'
+ }
+ }
+ }, [content, windowSize])
+
+ return (
+ <>
+ <div ref={svgRef} style={{
+ maxHeight: '80vh',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ cursor: 'pointer',
+ wordBreak: 'break-word',
+ whiteSpace: 'normal',
+ margin: '0 auto',
+ }} />
+ {imagePreview && (<ImagePreview url={imagePreview} title='Preview' onCancel={() => setImagePreview('')} />)}
+ </>
+ )
+}
+
+export default SVGRenderer
diff --git a/app/components/base/svg/index.tsx b/app/components/base/svg/index.tsx
new file mode 100644
index 0000000..d29fd17
--- /dev/null
+++ b/app/components/base/svg/index.tsx
@@ -0,0 +1,22 @@
+import React from 'react'
+import s from './style.module.css'
+import ActionButton from '../action-button'
+import cn from '@/utils/classnames'
+
+type ISVGBtnProps = {
+ isSVG: boolean
+ setIsSVG: React.Dispatch<React.SetStateAction<boolean>>
+}
+
+const SVGBtn = ({
+ isSVG,
+ setIsSVG,
+}: ISVGBtnProps) => {
+ return (
+ <ActionButton onClick={() => { setIsSVG(prevIsSVG => !prevIsSVG) }}>
+ <div className={cn('h-4 w-4', isSVG ? s.svgIconed : s.svgIcon)}></div>
+ </ActionButton>
+ )
+}
+
+export default SVGBtn
diff --git a/app/components/base/svg/style.module.css b/app/components/base/svg/style.module.css
new file mode 100644
index 0000000..9258fe8
--- /dev/null
+++ b/app/components/base/svg/style.module.css
@@ -0,0 +1,11 @@
+.svgIcon {
+ background-image: url(~@/app/components/develop/secret-key/assets/svg.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.svgIconed {
+ background-image: url(~@/app/components/develop/secret-key/assets/svged.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
diff --git a/app/components/base/switch/index.tsx b/app/components/base/switch/index.tsx
new file mode 100644
index 0000000..1faf7c5
--- /dev/null
+++ b/app/components/base/switch/index.tsx
@@ -0,0 +1,87 @@
+'use client'
+import React, { useEffect, useState } from 'react'
+import { Switch as OriginalSwitch } from '@headlessui/react'
+import classNames from '@/utils/classnames'
+
+type SwitchProps = {
+ onChange?: (value: boolean) => void
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'l'
+ defaultValue?: boolean
+ disabled?: boolean
+ className?: string
+}
+
+const Switch = (
+ {
+ ref: propRef,
+ onChange,
+ size = 'md',
+ defaultValue = false,
+ disabled = false,
+ className,
+ }: SwitchProps & {
+ ref?: React.RefObject<HTMLButtonElement>;
+ },
+) => {
+ const [enabled, setEnabled] = useState(defaultValue)
+ useEffect(() => {
+ setEnabled(defaultValue)
+ }, [defaultValue])
+ const wrapStyle = {
+ lg: 'h-6 w-11',
+ l: 'h-5 w-9',
+ md: 'h-4 w-7',
+ sm: 'h-3 w-5',
+ xs: 'h-2.5 w-3.5',
+ }
+
+ const circleStyle = {
+ lg: 'h-5 w-5',
+ l: 'h-4 w-4',
+ md: 'h-3 w-3',
+ sm: 'h-2 w-2',
+ xs: 'h-1.5 w-1',
+ }
+
+ const translateLeft = {
+ lg: 'translate-x-5',
+ l: 'translate-x-4',
+ md: 'translate-x-3',
+ sm: 'translate-x-2',
+ xs: 'translate-x-1.5',
+ }
+ return (
+ <OriginalSwitch
+ ref={propRef}
+ checked={enabled}
+ onChange={(checked: boolean) => {
+ if (disabled)
+ return
+ setEnabled(checked)
+ onChange?.(checked)
+ }}
+ className={classNames(
+ wrapStyle[size],
+ enabled ? 'bg-components-toggle-bg' : 'bg-components-toggle-bg-unchecked',
+ 'relative inline-flex flex-shrink-0 cursor-pointer rounded-[5px] border-2 border-transparent transition-colors duration-200 ease-in-out',
+ disabled ? '!opacity-50 !cursor-not-allowed' : '',
+ size === 'xs' && 'rounded-sm',
+ className,
+ )}
+ >
+ <span
+ aria-hidden="true"
+ className={classNames(
+ circleStyle[size],
+ enabled ? translateLeft[size] : 'translate-x-0',
+ size === 'xs' && 'rounded-[1px]',
+ 'pointer-events-none inline-block transform rounded-[3px] bg-components-toggle-knob shadow ring-0 transition duration-200 ease-in-out',
+ )}
+ />
+ </OriginalSwitch>
+ )
+}
+
+Switch.displayName = 'Switch'
+
+export default React.memo(Switch)
diff --git a/app/components/base/tab-header/index.tsx b/app/components/base/tab-header/index.tsx
new file mode 100644
index 0000000..36dfa8c
--- /dev/null
+++ b/app/components/base/tab-header/index.tsx
@@ -0,0 +1,50 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+
+type Item = {
+ id: string
+ name: string
+ isRight?: boolean
+ icon?: React.ReactNode
+ extra?: React.ReactNode
+}
+
+export type ITabHeaderProps = {
+ items: Item[]
+ value: string
+ onChange: (value: string) => void
+}
+
+const TabHeader: FC<ITabHeaderProps> = ({
+ items,
+ value,
+ onChange,
+}) => {
+ const renderItem = ({ id, name, icon, extra }: Item) => (
+ <div
+ key={id}
+ className={cn(
+ 'system-md-semibold relative flex cursor-pointer items-center border-b-2 border-transparent pb-2 pt-2.5',
+ id === value ? 'border-components-tab-active text-text-primary' : 'text-text-tertiary',
+ )}
+ onClick={() => onChange(id)}
+ >
+ {icon || ''}
+ <div className='ml-2'>{name}</div>
+ {extra || ''}
+ </div>
+ )
+ return (
+ <div className='flex justify-between'>
+ <div className='flex space-x-4'>
+ {items.filter(item => !item.isRight).map(renderItem)}
+ </div>
+ <div className='flex space-x-4'>
+ {items.filter(item => item.isRight).map(renderItem)}
+ </div>
+ </div>
+ )
+}
+export default React.memo(TabHeader)
diff --git a/app/components/base/tab-slider-new/index.tsx b/app/components/base/tab-slider-new/index.tsx
new file mode 100644
index 0000000..fc0bc1c
--- /dev/null
+++ b/app/components/base/tab-slider-new/index.tsx
@@ -0,0 +1,40 @@
+import type { FC } from 'react'
+import cn from '@/utils/classnames'
+
+type Option = {
+ value: string
+ text: string
+ icon?: React.ReactNode
+}
+type TabSliderProps = {
+ className?: string
+ value: string
+ onChange: (v: string) => void
+ options: Option[]
+}
+const TabSliderNew: FC<TabSliderProps> = ({
+ className,
+ value,
+ onChange,
+ options,
+}) => {
+ return (
+ <div className={cn(className, 'relative flex')}>
+ {options.map(option => (
+ <div
+ key={option.value}
+ onClick={() => onChange(option.value)}
+ className={cn(
+ 'mr-1 flex h-[32px] cursor-pointer items-center rounded-lg border-[0.5px] border-transparent px-3 py-[7px] text-[13px] font-medium leading-[18px] text-text-tertiary hover:bg-components-main-nav-nav-button-bg-active',
+ value === option.value && 'border-components-main-nav-nav-button-border bg-components-main-nav-nav-button-bg-active text-components-main-nav-nav-button-text-active shadow-xs',
+ )}
+ >
+ {option.icon}
+ {option.text}
+ </div>
+ ))}
+ </div>
+ )
+}
+
+export default TabSliderNew
diff --git a/app/components/base/tab-slider-plain/index.tsx b/app/components/base/tab-slider-plain/index.tsx
new file mode 100644
index 0000000..b9b3965
--- /dev/null
+++ b/app/components/base/tab-slider-plain/index.tsx
@@ -0,0 +1,78 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+
+type Option = {
+ value: string
+ text: string | React.JSX.Element
+}
+
+type ItemProps = {
+ className?: string
+ isActive: boolean
+ onClick: (v: string) => void
+ option: Option
+ smallItem?: boolean
+}
+const Item: FC<ItemProps> = ({
+ className,
+ isActive,
+ onClick,
+ option,
+ smallItem,
+}) => {
+ return (
+ <div
+ key={option.value}
+ className={cn(
+ 'relative pb-2.5 ',
+ !isActive && 'cursor-pointer',
+ smallItem ? 'system-sm-semibold-uppercase' : 'system-xl-semibold',
+ className,
+ )}
+ onClick={() => !isActive && onClick(option.value)}
+ >
+ <div className={cn(isActive ? 'text-text-primary' : 'text-text-tertiary')}>{option.text}</div>
+ {isActive && (
+ <div className='absolute bottom-0 left-0 right-0 h-0.5 bg-util-colors-blue-brand-blue-brand-600'></div>
+ )}
+ </div>
+ )
+}
+
+type Props = {
+ className?: string
+ value: string
+ onChange: (v: string) => void
+ options: Option[]
+ noBorderBottom?: boolean
+ smallItem?: boolean
+ itemClassName?: string
+}
+
+const TabSlider: FC<Props> = ({
+ className,
+ value,
+ onChange,
+ options,
+ noBorderBottom,
+ itemClassName,
+ smallItem,
+}) => {
+ return (
+ <div className={cn(className, !noBorderBottom && 'border-b border-divider-subtle', 'flex space-x-6')}>
+ {options.map(option => (
+ <Item
+ isActive={option.value === value}
+ option={option}
+ onClick={onChange}
+ key={option.value}
+ className={itemClassName}
+ smallItem={smallItem}
+ />
+ ))}
+ </div>
+ )
+}
+export default React.memo(TabSlider)
diff --git a/app/components/base/tab-slider/index.tsx b/app/components/base/tab-slider/index.tsx
new file mode 100644
index 0000000..fd6b876
--- /dev/null
+++ b/app/components/base/tab-slider/index.tsx
@@ -0,0 +1,87 @@
+import type { FC, ReactNode } from 'react'
+import { useEffect, useState } from 'react'
+import cn from '@/utils/classnames'
+import Badge, { BadgeState } from '@/app/components/base/badge/index'
+import { useInstalledPluginList } from '@/service/use-plugins'
+type Option = {
+ value: string
+ text: ReactNode
+}
+
+type TabSliderProps = {
+ className?: string
+ value: string
+ onChange: (v: string) => void
+ options: Option[]
+}
+
+const TabSlider: FC<TabSliderProps> = ({
+ className,
+ value,
+ onChange,
+ options,
+}) => {
+ const [activeIndex, setActiveIndex] = useState(options.findIndex(option => option.value === value))
+ const [sliderStyle, setSliderStyle] = useState({})
+ const { data: pluginList } = useInstalledPluginList()
+
+ const updateSliderStyle = (index: number) => {
+ const tabElement = document.getElementById(`tab-${index}`)
+ if (tabElement) {
+ const { offsetLeft, offsetWidth } = tabElement
+ setSliderStyle({
+ transform: `translateX(${offsetLeft}px)`,
+ width: `${offsetWidth}px`,
+ })
+ }
+ }
+
+ useEffect(() => {
+ const newIndex = options.findIndex(option => option.value === value)
+ setActiveIndex(newIndex)
+ updateSliderStyle(newIndex)
+ }, [value, options, pluginList])
+
+ return (
+ <div className={cn(className, 'relative inline-flex items-center justify-center rounded-[10px] bg-components-segmented-control-bg-normal p-0.5')}>
+ <div
+ className="shadows-shadow-xs absolute bottom-0.5 left-0 right-0 top-0.5 rounded-[10px] bg-components-panel-bg transition-transform duration-300 ease-in-out"
+ style={sliderStyle}
+ />
+ {options.map((option, index) => (
+ <div
+ id={`tab-${index}`}
+ key={option.value}
+ className={cn(
+ 'relative z-10 flex cursor-pointer items-center justify-center gap-1 rounded-[10px] px-2.5 py-1.5 transition-colors duration-300 ease-in-out',
+ 'system-md-semibold',
+ index === activeIndex
+ ? 'text-text-primary'
+ : 'text-text-tertiary',
+ )}
+ onClick={() => {
+ if (index !== activeIndex) {
+ onChange(option.value)
+ updateSliderStyle(index)
+ }
+ }}
+ >
+ {option.text}
+ {/* if no plugin installed, the badge won't show */}
+ {option.value === 'plugins'
+ && (pluginList?.plugins.length ?? 0) > 0
+ && <Badge
+ size='s'
+ uppercase={true}
+ state={BadgeState.Default}
+ >
+ {pluginList?.plugins.length}
+ </Badge>
+ }
+ </div>
+ ))}
+ </div>
+ )
+}
+
+export default TabSlider
diff --git a/app/components/base/tag-input/index.tsx b/app/components/base/tag-input/index.tsx
new file mode 100644
index 0000000..2be9c5f
--- /dev/null
+++ b/app/components/base/tag-input/index.tsx
@@ -0,0 +1,121 @@
+import { useState } from 'react'
+import type { ChangeEvent, FC, KeyboardEvent } from 'react'
+import { } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import AutosizeInput from 'react-18-input-autosize'
+import { RiAddLine, RiCloseLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { useToastContext } from '@/app/components/base/toast'
+
+type TagInputProps = {
+ items: string[]
+ onChange: (items: string[]) => void
+ disableRemove?: boolean
+ disableAdd?: boolean
+ customizedConfirmKey?: 'Enter' | 'Tab'
+ isInWorkflow?: boolean
+ placeholder?: string
+}
+
+const TagInput: FC<TagInputProps> = ({
+ items,
+ onChange,
+ disableAdd,
+ disableRemove,
+ customizedConfirmKey = 'Enter',
+ isInWorkflow,
+ placeholder,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const [value, setValue] = useState('')
+ const [focused, setFocused] = useState(false)
+
+ const isSpecialMode = customizedConfirmKey === 'Tab'
+
+ const handleRemove = (index: number) => {
+ const copyItems = [...items]
+ copyItems.splice(index, 1)
+
+ onChange(copyItems)
+ }
+
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if (isSpecialMode && e.key === 'Enter')
+ setValue(`${value}鈫礰)
+
+ if (e.key === customizedConfirmKey) {
+ if (isSpecialMode)
+ e.preventDefault()
+
+ const valueTrimmed = value.trim()
+ if (!valueTrimmed || (items.find(item => item === valueTrimmed)))
+ return
+
+ if (valueTrimmed.length > 20) {
+ notify({ type: 'error', message: t('datasetDocuments.segment.keywordError') })
+ return
+ }
+
+ onChange([...items, valueTrimmed])
+ setTimeout(() => {
+ setValue('')
+ })
+ }
+ }
+
+ const handleBlur = () => {
+ setValue('')
+ setFocused(false)
+ }
+
+ return (
+ <div className={cn('flex flex-wrap', !isInWorkflow && 'min-w-[200px]', isSpecialMode ? 'rounded-lg bg-components-input-bg-normal pb-1 pl-1' : '')}>
+ {
+ (items || []).map((item, index) => (
+ <div
+ key={item}
+ className={cn('system-xs-regular mr-1 mt-1 flex items-center rounded-md border border-divider-deep bg-components-badge-white-to-dark py-1 pl-1.5 pr-1 text-text-secondary')}
+ >
+ {item}
+ {
+ !disableRemove && (
+ <div className='flex h-4 w-4 cursor-pointer items-center justify-center' onClick={() => handleRemove(index)}>
+ <RiCloseLine className='ml-0.5 h-3.5 w-3.5 text-text-tertiary' />
+ </div>
+ )
+ }
+ </div>
+ ))
+ }
+ {
+ !disableAdd && (
+ <div className={cn('group/tag-add mt-1 flex items-center gap-x-0.5', !isSpecialMode ? 'rounded-md border border-dashed border-divider-deep px-1.5' : '')}>
+ {!isSpecialMode && !focused && <RiAddLine className='h-3.5 w-3.5 text-text-placeholder group-hover/tag-add:text-text-secondary' />}
+ <AutosizeInput
+ inputClassName={cn('appearance-none caret-[#295EFF] outline-none placeholder:text-text-placeholder group-hover/tag-add:placeholder:text-text-secondary', isSpecialMode ? 'bg-transparent' : '')}
+ className={cn(
+ !isInWorkflow && 'max-w-[300px]',
+ isInWorkflow && 'max-w-[146px]',
+ `
+ system-xs-regular overflow-hidden rounded-md py-1
+ ${isSpecialMode && 'border border-transparent px-1.5'}
+ ${focused && isSpecialMode && 'border-dashed border-divider-deep'}
+ `)}
+ onFocus={() => setFocused(true)}
+ onBlur={handleBlur}
+ value={value}
+ onChange={(e: ChangeEvent<HTMLInputElement>) => {
+ setValue(e.target.value)
+ }}
+ onKeyDown={handleKeyDown}
+ placeholder={t(placeholder || (isSpecialMode ? 'common.model.params.stop_sequencesPlaceholder' : 'datasetDocuments.segment.addKeyWord'))}
+ />
+ </div>
+ )
+ }
+ </div>
+ )
+}
+
+export default TagInput
diff --git a/app/components/base/tag-management/constant.ts b/app/components/base/tag-management/constant.ts
new file mode 100644
index 0000000..3c60041
--- /dev/null
+++ b/app/components/base/tag-management/constant.ts
@@ -0,0 +1,6 @@
+export type Tag = {
+ id: string
+ name: string
+ type: string
+ binding_count: number
+}
diff --git a/app/components/base/tag-management/filter.tsx b/app/components/base/tag-management/filter.tsx
new file mode 100644
index 0000000..1ce56e8
--- /dev/null
+++ b/app/components/base/tag-management/filter.tsx
@@ -0,0 +1,147 @@
+import type { FC } from 'react'
+import { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useDebounceFn, useMount } from 'ahooks'
+import { RiArrowDownSLine } from '@remixicon/react'
+import { useStore as useTagStore } from './store'
+import cn from '@/utils/classnames'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import Input from '@/app/components/base/input'
+import { Tag01, Tag03 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
+import { Check } from '@/app/components/base/icons/src/vender/line/general'
+import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
+import type { Tag } from '@/app/components/base/tag-management/constant'
+
+import { fetchTagList } from '@/service/tag'
+
+type TagFilterProps = {
+ type: 'knowledge' | 'app'
+ value: string[]
+ onChange: (v: string[]) => void
+}
+const TagFilter: FC<TagFilterProps> = ({
+ type,
+ value,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+
+ const tagList = useTagStore(s => s.tagList)
+ const setTagList = useTagStore(s => s.setTagList)
+
+ const [keywords, setKeywords] = useState('')
+ const [searchKeywords, setSearchKeywords] = useState('')
+ const { run: handleSearch } = useDebounceFn(() => {
+ setSearchKeywords(keywords)
+ }, { wait: 500 })
+ const handleKeywordsChange = (value: string) => {
+ setKeywords(value)
+ handleSearch()
+ }
+
+ const filteredTagList = useMemo(() => {
+ return tagList.filter(tag => tag.type === type && tag.name.includes(searchKeywords))
+ }, [type, tagList, searchKeywords])
+
+ const currentTag = useMemo(() => {
+ return tagList.find(tag => tag.id === value[0])
+ }, [value, tagList])
+
+ const selectTag = (tag: Tag) => {
+ if (value.includes(tag.id))
+ onChange(value.filter(v => v !== tag.id))
+ else
+ onChange([...value, tag.id])
+ }
+
+ useMount(() => {
+ fetchTagList(type).then((res) => {
+ setTagList(res)
+ })
+ })
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <div className='relative'>
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ className='block'
+ >
+ <div className={cn(
+ 'flex h-8 cursor-pointer items-center gap-1 rounded-lg border-[0.5px] border-transparent bg-components-input-bg-normal px-2',
+ !open && !!value.length && 'shadow-xs',
+ open && !!value.length && 'shadow-xs',
+ )}>
+ <div className='p-[1px]'>
+ <Tag01 className='h-3.5 w-3.5 text-text-tertiary' />
+ </div>
+ <div className='text-[13px] leading-[18px] text-text-secondary'>
+ {!value.length && t('common.tag.placeholder')}
+ {!!value.length && currentTag?.name}
+ </div>
+ {value.length > 1 && (
+ <div className='text-xs font-medium leading-[18px] text-text-tertiary'>{`+${value.length - 1}`}</div>
+ )}
+ {!value.length && (
+ <div className='p-[1px]'>
+ <RiArrowDownSLine className='h-3.5 w-3.5 text-text-tertiary' />
+ </div>
+ )}
+ {!!value.length && (
+ <div className='group/clear cursor-pointer p-[1px]' onClick={(e) => {
+ e.stopPropagation()
+ onChange([])
+ }}>
+ <XCircle className='h-3.5 w-3.5 text-text-tertiary group-hover/clear:text-text-secondary' />
+ </div>
+ )}
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1002]'>
+ <div className='relative w-[240px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[5px]'>
+ <div className='p-2'>
+ <Input
+ showLeftIcon
+ showClearIcon
+ value={keywords}
+ onChange={e => handleKeywordsChange(e.target.value)}
+ onClear={() => handleKeywordsChange('')}
+ />
+ </div>
+ <div className='max-h-72 overflow-auto p-1'>
+ {filteredTagList.map(tag => (
+ <div
+ key={tag.id}
+ className='flex cursor-pointer items-center gap-2 rounded-lg py-[6px] pl-3 pr-2 hover:bg-state-base-hover'
+ onClick={() => selectTag(tag)}
+ >
+ <div title={tag.name} className='grow truncate text-sm leading-5 text-text-tertiary'>{tag.name}</div>
+ {value.includes(tag.id) && <Check className='h-4 w-4 shrink-0 text-text-secondary' />}
+ </div>
+ ))}
+ {!filteredTagList.length && (
+ <div className='flex flex-col items-center gap-1 p-3'>
+ <Tag03 className='h-6 w-6 text-text-tertiary' />
+ <div className='text-xs leading-[14px] text-text-tertiary'>{t('common.tag.noTag')}</div>
+ </div>
+ )}
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </div>
+ </PortalToFollowElem>
+
+ )
+}
+
+export default TagFilter
diff --git a/app/components/base/tag-management/index.tsx b/app/components/base/tag-management/index.tsx
new file mode 100644
index 0000000..d3c509b
--- /dev/null
+++ b/app/components/base/tag-management/index.tsx
@@ -0,0 +1,92 @@
+'use client'
+
+import { useEffect, useState } from 'react'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import { useStore as useTagStore } from './store'
+import TagItemEditor from './tag-item-editor'
+import Modal from '@/app/components/base/modal'
+import { ToastContext } from '@/app/components/base/toast'
+import {
+ createTag,
+ fetchTagList,
+} from '@/service/tag'
+
+type TagManagementModalProps = {
+ type: 'knowledge' | 'app'
+ show: boolean
+}
+
+const TagManagementModal = ({ show, type }: TagManagementModalProps) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const tagList = useTagStore(s => s.tagList)
+ const setTagList = useTagStore(s => s.setTagList)
+ const setShowTagManagementModal = useTagStore(s => s.setShowTagManagementModal)
+
+ const getTagList = async (type: 'knowledge' | 'app') => {
+ const res = await fetchTagList(type)
+ setTagList(res)
+ }
+
+ const [pending, setPending] = useState<boolean>(false)
+ const [name, setName] = useState<string>('')
+ const createNewTag = async () => {
+ if (!name)
+ return
+ if (pending)
+ return
+ try {
+ setPending(true)
+ const newTag = await createTag(name, type)
+ notify({ type: 'success', message: t('common.tag.created') })
+ setTagList([
+ newTag,
+ ...tagList,
+ ])
+ setName('')
+ setPending(false)
+ }
+ catch {
+ notify({ type: 'error', message: t('common.tag.failed') })
+ setPending(false)
+ }
+ }
+
+ useEffect(() => {
+ getTagList(type)
+ }, [type])
+
+ return (
+ <Modal
+ className='!w-[600px] !max-w-[600px] rounded-xl px-8 py-6'
+ isShow={show}
+ onClose={() => setShowTagManagementModal(false)}
+ >
+ <div className='relative pb-2 text-xl font-semibold leading-[30px] text-text-primary'>{t('common.tag.manageTags')}</div>
+ <div className='absolute right-4 top-4 cursor-pointer p-2' onClick={() => setShowTagManagementModal(false)}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div className='mt-3 flex flex-wrap gap-2'>
+ <input
+ className='w-[100px] shrink-0 appearance-none rounded-lg border border-dashed border-divider-regular bg-transparent px-2 py-1 text-sm leading-5 text-text-secondary caret-primary-600 outline-none placeholder:text-text-quaternary focus:border-solid'
+ placeholder={t('common.tag.addNew') || ''}
+ autoFocus
+ value={name}
+ onChange={e => setName(e.target.value)}
+ onKeyDown={e => e.key === 'Enter' && !e.nativeEvent.isComposing && createNewTag()}
+ onBlur={createNewTag}
+ />
+ {tagList.map(tag => (
+ <TagItemEditor
+ key={tag.id}
+ tag={tag}
+ />
+ ))}
+ </div>
+ </Modal>
+ )
+}
+
+export default TagManagementModal
diff --git a/app/components/base/tag-management/selector.tsx b/app/components/base/tag-management/selector.tsx
new file mode 100644
index 0000000..2678be2
--- /dev/null
+++ b/app/components/base/tag-management/selector.tsx
@@ -0,0 +1,278 @@
+import type { FC } from 'react'
+import { useMemo, useState } from 'react'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { useUnmount } from 'ahooks'
+import { RiAddLine } from '@remixicon/react'
+import { useStore as useTagStore } from './store'
+import cn from '@/utils/classnames'
+import type { HtmlContentProps } from '@/app/components/base/popover'
+import CustomPopover from '@/app/components/base/popover'
+import Divider from '@/app/components/base/divider'
+import Input from '@/app/components/base/input'
+import { Tag01, Tag03 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
+import type { Tag } from '@/app/components/base/tag-management/constant'
+import Checkbox from '@/app/components/base/checkbox'
+import { bindTag, createTag, fetchTagList, unBindTag } from '@/service/tag'
+import { ToastContext } from '@/app/components/base/toast'
+import { noop } from 'lodash-es'
+
+type TagSelectorProps = {
+ targetID: string
+ isPopover?: boolean
+ position?: 'bl' | 'br'
+ type: 'knowledge' | 'app'
+ value: string[]
+ selectedTags: Tag[]
+ onCacheUpdate: (tags: Tag[]) => void
+ onChange?: () => void
+}
+
+type PanelProps = {
+ onCreate: () => void
+} & HtmlContentProps & TagSelectorProps
+
+const Panel = (props: PanelProps) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const { targetID, type, value, selectedTags, onCacheUpdate, onChange, onCreate } = props
+ const tagList = useTagStore(s => s.tagList)
+ const setTagList = useTagStore(s => s.setTagList)
+ const setShowTagManagementModal = useTagStore(s => s.setShowTagManagementModal)
+ const [selectedTagIDs, setSelectedTagIDs] = useState<string[]>(value)
+ const [keywords, setKeywords] = useState('')
+ const handleKeywordsChange = (value: string) => {
+ setKeywords(value)
+ }
+
+ const notExisted = useMemo(() => {
+ return tagList.every(tag => tag.type === type && tag.name !== keywords)
+ }, [type, tagList, keywords])
+ const filteredSelectedTagList = useMemo(() => {
+ return selectedTags.filter(tag => tag.name.includes(keywords))
+ }, [keywords, selectedTags])
+ const filteredTagList = useMemo(() => {
+ return tagList.filter(tag => tag.type === type && !value.includes(tag.id) && tag.name.includes(keywords))
+ }, [type, tagList, value, keywords])
+
+ const [creating, setCreating] = useState<boolean>(false)
+ const createNewTag = async () => {
+ if (!keywords)
+ return
+ if (creating)
+ return
+ try {
+ setCreating(true)
+ const newTag = await createTag(keywords, type)
+ notify({ type: 'success', message: t('common.tag.created') })
+ setTagList([
+ ...tagList,
+ newTag,
+ ])
+ setKeywords('')
+ setCreating(false)
+ onCreate()
+ }
+ catch {
+ notify({ type: 'error', message: t('common.tag.failed') })
+ setCreating(false)
+ }
+ }
+ const bind = async (tagIDs: string[]) => {
+ try {
+ await bindTag(tagIDs, targetID, type)
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ }
+ }
+ const unbind = async (tagID: string) => {
+ try {
+ await unBindTag(tagID, targetID, type)
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ }
+ }
+ const selectTag = (tag: Tag) => {
+ if (selectedTagIDs.includes(tag.id))
+ setSelectedTagIDs(selectedTagIDs.filter(v => v !== tag.id))
+ else
+ setSelectedTagIDs([...selectedTagIDs, tag.id])
+ }
+
+ const valueNotChanged = useMemo(() => {
+ return value.length === selectedTagIDs.length && value.every(v => selectedTagIDs.includes(v)) && selectedTagIDs.every(v => value.includes(v))
+ }, [value, selectedTagIDs])
+ const handleValueChange = () => {
+ const addTagIDs = selectedTagIDs.filter(v => !value.includes(v))
+ const removeTagIDs = value.filter(v => !selectedTagIDs.includes(v))
+ const selectedTags = tagList.filter(tag => selectedTagIDs.includes(tag.id))
+ onCacheUpdate(selectedTags)
+ Promise.all([
+ ...(addTagIDs.length ? [bind(addTagIDs)] : []),
+ ...[removeTagIDs.length ? removeTagIDs.map(tagID => unbind(tagID)) : []],
+ ]).finally(() => {
+ if (onChange)
+ onChange()
+ })
+ }
+ useUnmount(() => {
+ if (valueNotChanged)
+ return
+ handleValueChange()
+ })
+
+ return (
+ <div className='relative w-full rounded-lg border-[0.5px] border-components-panel-border bg-components-input-bg-hover'>
+ <div className='border-b-[0.5px] border-divider-regular p-2'>
+ <Input
+ showLeftIcon
+ showClearIcon
+ value={keywords}
+ placeholder={t('common.tag.selectorPlaceholder') || ''}
+ onChange={e => handleKeywordsChange(e.target.value)}
+ onClear={() => handleKeywordsChange('')}
+ />
+ </div>
+ {keywords && notExisted && (
+ <div className='p-1'>
+ <div className='flex cursor-pointer items-center gap-2 rounded-lg py-[6px] pl-3 pr-2 hover:bg-state-base-hover' onClick={createNewTag}>
+ <RiAddLine className='h-4 w-4 text-text-tertiary' />
+ <div className='grow truncate text-sm leading-5 text-text-secondary'>
+ {`${t('common.tag.create')} `}
+ <span className='font-medium'>{`"${keywords}"`}</span>
+ </div>
+ </div>
+ </div>
+ )}
+ {keywords && notExisted && filteredTagList.length > 0 && (
+ <Divider className='!my-0 !h-[1px]' />
+ )}
+ {(filteredTagList.length > 0 || filteredSelectedTagList.length > 0) && (
+ <div className='max-h-[172px] overflow-y-auto p-1'>
+ {filteredSelectedTagList.map(tag => (
+ <div
+ key={tag.id}
+ className='flex cursor-pointer items-center gap-2 rounded-lg py-[6px] pl-3 pr-2 hover:bg-state-base-hover'
+ onClick={() => selectTag(tag)}
+ >
+ <Checkbox
+ className='shrink-0'
+ checked={selectedTagIDs.includes(tag.id)}
+ onCheck={noop}
+ />
+ <div title={tag.name} className='grow truncate text-sm leading-5 text-text-secondary'>{tag.name}</div>
+ </div>
+ ))}
+ {filteredTagList.map(tag => (
+ <div
+ key={tag.id}
+ className='flex cursor-pointer items-center gap-2 rounded-lg py-[6px] pl-3 pr-2 hover:bg-state-base-hover'
+ onClick={() => selectTag(tag)}
+ >
+ <Checkbox
+ className='shrink-0'
+ checked={selectedTagIDs.includes(tag.id)}
+ onCheck={noop}
+ />
+ <div title={tag.name} className='grow truncate text-sm leading-5 text-text-secondary'>{tag.name}</div>
+ </div>
+ ))}
+ </div>
+ )}
+ {!keywords && !filteredTagList.length && !filteredSelectedTagList.length && (
+ <div className='p-1'>
+ <div className='flex flex-col items-center gap-1 p-3'>
+ <Tag03 className='h-6 w-6 text-text-quaternary' />
+ <div className='text-xs leading-[14px] text-text-tertiary'>{t('common.tag.noTag')}</div>
+ </div>
+ </div>
+ )}
+ <Divider className='!my-0 !h-[1px]' />
+ <div className='p-1'>
+ <div className='flex cursor-pointer items-center gap-2 rounded-lg py-[6px] pl-3 pr-2 hover:bg-state-base-hover' onClick={() => setShowTagManagementModal(true)}>
+ <Tag03 className='h-4 w-4 text-text-tertiary' />
+ <div className='grow truncate text-sm leading-5 text-text-secondary'>
+ {t('common.tag.manageTags')}
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+const TagSelector: FC<TagSelectorProps> = ({
+ targetID,
+ isPopover = true,
+ position,
+ type,
+ value,
+ selectedTags,
+ onCacheUpdate,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+
+ const tagList = useTagStore(s => s.tagList)
+ const setTagList = useTagStore(s => s.setTagList)
+
+ const getTagList = async () => {
+ const res = await fetchTagList(type)
+ setTagList(res)
+ }
+
+ const triggerContent = useMemo(() => {
+ if (selectedTags?.length)
+ return selectedTags.filter(selectedTag => tagList.find(tag => tag.id === selectedTag.id)).map(tag => tag.name).join(', ')
+ return ''
+ }, [selectedTags, tagList])
+
+ const Trigger = () => {
+ return (
+ <div className={cn(
+ 'group/tip relative flex w-full cursor-pointer items-center gap-1 rounded-md px-2 py-[7px] hover:bg-state-base-hover',
+ )}>
+ <Tag01 className='h-3 w-3 shrink-0 text-components-input-text-placeholder' />
+ <div className='system-sm-regular grow truncate text-start text-components-input-text-placeholder'>
+ {!triggerContent ? t('common.tag.addTag') : triggerContent}
+ </div>
+ </div>
+ )
+ }
+ return (
+ <>
+ {isPopover && (
+ <CustomPopover
+ htmlContent={
+ <Panel
+ type={type}
+ targetID={targetID}
+ value={value}
+ selectedTags={selectedTags}
+ onCacheUpdate={onCacheUpdate}
+ onChange={onChange}
+ onCreate={getTagList}
+ />
+ }
+ position={position}
+ trigger="click"
+ btnElement={<Trigger />}
+ btnClassName={open =>
+ cn(
+ open ? '!bg-state-base-hover !text-text-secondary' : '!bg-transparent',
+ '!w-full !border-0 !p-0 !text-text-tertiary hover:!bg-state-base-hover hover:!text-text-secondary',
+ )
+ }
+ popupClassName='!w-full !ring-0'
+ className={'!z-20 h-fit !w-full'}
+ />
+ )}
+ </>
+
+ )
+}
+
+export default TagSelector
diff --git a/app/components/base/tag-management/store.ts b/app/components/base/tag-management/store.ts
new file mode 100644
index 0000000..cb92ae9
--- /dev/null
+++ b/app/components/base/tag-management/store.ts
@@ -0,0 +1,19 @@
+import { create } from 'zustand'
+import type { Tag } from './constant'
+
+type State = {
+ tagList: Tag[]
+ showTagManagementModal: boolean
+}
+
+type Action = {
+ setTagList: (tagList?: Tag[]) => void
+ setShowTagManagementModal: (showTagManagementModal: boolean) => void
+}
+
+export const useStore = create<State & Action>(set => ({
+ tagList: [],
+ setTagList: tagList => set(() => ({ tagList })),
+ showTagManagementModal: false,
+ setShowTagManagementModal: showTagManagementModal => set(() => ({ showTagManagementModal })),
+}))
diff --git a/app/components/base/tag-management/tag-item-editor.tsx b/app/components/base/tag-management/tag-item-editor.tsx
new file mode 100644
index 0000000..3264979
--- /dev/null
+++ b/app/components/base/tag-management/tag-item-editor.tsx
@@ -0,0 +1,151 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import {
+ RiDeleteBinLine,
+ RiEditLine,
+} from '@remixicon/react'
+import { useDebounceFn } from 'ahooks'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { useStore as useTagStore } from './store'
+import Confirm from '@/app/components/base/confirm'
+import cn from '@/utils/classnames'
+import type { Tag } from '@/app/components/base/tag-management/constant'
+import { ToastContext } from '@/app/components/base/toast'
+import {
+ deleteTag,
+ updateTag,
+} from '@/service/tag'
+
+type TagItemEditorProps = {
+ tag: Tag
+}
+const TagItemEditor: FC<TagItemEditorProps> = ({
+ tag,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const tagList = useTagStore(s => s.tagList)
+ const setTagList = useTagStore(s => s.setTagList)
+
+ const [isEditing, setIsEditing] = useState(false)
+ const [name, setName] = useState(tag.name)
+ const editTag = async (tagID: string, name: string) => {
+ if (name === tag.name) {
+ setIsEditing(false)
+ return
+ }
+ if (!name) {
+ notify({ type: 'error', message: 'tag name is empty' })
+ setName(tag.name)
+ setIsEditing(false)
+ return
+ }
+ try {
+ const newList = tagList.map((tag) => {
+ if (tag.id === tagID) {
+ return {
+ ...tag,
+ name,
+ }
+ }
+ return tag
+ })
+ setTagList([
+ ...newList,
+ ])
+ setIsEditing(false)
+ await updateTag(tagID, name)
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ setName(name)
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ setName(tag.name)
+ const recoverList = tagList.map((tag) => {
+ if (tag.id === tagID) {
+ return {
+ ...tag,
+ name: tag.name,
+ }
+ }
+ return tag
+ })
+ setTagList([
+ ...recoverList,
+ ])
+ setIsEditing(false)
+ }
+ }
+ const [showRemoveModal, setShowRemoveModal] = useState(false)
+ const [pending, setPending] = useState<boolean>(false)
+ const removeTag = async (tagID: string) => {
+ if (pending)
+ return
+ try {
+ setPending(true)
+ await deleteTag(tagID)
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ const newList = tagList.filter(tag => tag.id !== tagID)
+ setTagList([
+ ...newList,
+ ])
+ setPending(false)
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ setPending(false)
+ }
+ }
+ const { run: handleRemove } = useDebounceFn(() => {
+ removeTag(tag.id)
+ }, { wait: 200 })
+
+ return (
+ <>
+ <div className={cn('flex shrink-0 items-center gap-0.5 rounded-lg border border-components-panel-border py-1 pl-2 pr-1 text-sm leading-5 text-text-secondary')}>
+ {!isEditing && (
+ <>
+ <div className='text-sm leading-5 text-text-secondary'>
+ {tag.name}
+ </div>
+ <div className='leading-4.5 shrink-0 px-1 text-sm font-medium text-text-tertiary'>{tag.binding_count}</div>
+ <div className='group/edit shrink-0 cursor-pointer rounded-md p-1 hover:bg-state-base-hover' onClick={() => setIsEditing(true)}>
+ <RiEditLine className='h-3 w-3 text-text-tertiary group-hover/edit:text-text-secondary' />
+ </div>
+ <div className='group/remove shrink-0 cursor-pointer rounded-md p-1 hover:bg-state-base-hover' onClick={() => {
+ if (tag.binding_count)
+ setShowRemoveModal(true)
+ else
+ handleRemove()
+ }}>
+ <RiDeleteBinLine className='h-3 w-3 text-text-tertiary group-hover/remove:text-text-secondary' />
+ </div>
+ </>
+ )}
+ {isEditing && (
+ <input
+ className='shrink-0 appearance-none caret-primary-600 outline-none placeholder:text-text-quaternary'
+ autoFocus
+ value={name}
+ onChange={e => setName(e.target.value)}
+ onKeyDown={e => e.key === 'Enter' && editTag(tag.id, name)}
+ onBlur={() => editTag(tag.id, name)}
+ />
+ )}
+ </div>
+ <Confirm
+ title={`${t('common.tag.delete')} "${tag.name}"`}
+ isShow={showRemoveModal}
+ content={t('common.tag.deleteTip')}
+ onConfirm={() => {
+ handleRemove()
+ setShowRemoveModal(false)
+ }}
+ onCancel={() => setShowRemoveModal(false)}
+ />
+ </>
+ )
+}
+
+export default TagItemEditor
diff --git a/app/components/base/tag-management/tag-remove-modal.tsx b/app/components/base/tag-management/tag-remove-modal.tsx
new file mode 100644
index 0000000..85f1831
--- /dev/null
+++ b/app/components/base/tag-management/tag-remove-modal.tsx
@@ -0,0 +1,49 @@
+'use client'
+
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import Button from '@/app/components/base/button'
+import Modal from '@/app/components/base/modal'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
+import type { Tag } from '@/app/components/base/tag-management/constant'
+import { noop } from 'lodash-es'
+
+type TagRemoveModalProps = {
+ show: boolean
+ tag: Tag
+ onConfirm: () => void
+ onClose: () => void
+}
+
+const TagRemoveModal = ({ show, tag, onConfirm, onClose }: TagRemoveModalProps) => {
+ const { t } = useTranslation()
+
+ return (
+ <Modal
+ className={cn('w-[480px] max-w-[480px] p-8')}
+ isShow={show}
+ onClose={noop}
+ >
+ <div className='absolute right-4 top-4 cursor-pointer p-2' onClick={onClose}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div className='h-12 w-12 rounded-xl border-[0.5px] border-divider-regular bg-background-default-burn p-3 shadow-xl'>
+ <AlertTriangle className='h-6 w-6 text-[rgb(247,144,9)]' />
+ </div>
+ <div className='mt-3 text-xl font-semibold leading-[30px] text-text-primary'>
+ {`${t('common.tag.delete')} `}
+ <span>{`"${tag.name}"`}</span>
+ </div>
+ <div className='my-1 text-sm leading-5 text-text-tertiary'>
+ {t('common.tag.deleteTip')}
+ </div>
+ <div className='flex items-center justify-end pt-6'>
+ <Button className='mr-2' onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button className='border-red-700' variant="warning" onClick={onConfirm}>{t('common.operation.delete')}</Button>
+ </div>
+ </Modal>
+ )
+}
+
+export default TagRemoveModal
diff --git a/app/components/base/tag/index.tsx b/app/components/base/tag/index.tsx
new file mode 100644
index 0000000..d7b9d3e
--- /dev/null
+++ b/app/components/base/tag/index.tsx
@@ -0,0 +1,42 @@
+import React from 'react'
+import classNames from '@/utils/classnames'
+
+export type ITagProps = {
+ children: string | React.ReactNode
+ color?: keyof typeof COLOR_MAP
+ className?: string
+ bordered?: boolean
+ hideBg?: boolean
+}
+
+const COLOR_MAP = {
+ green: {
+ text: 'text-green-800',
+ bg: 'bg-green-100',
+ },
+ yellow: {
+ text: 'text-yellow-800',
+ bg: 'bg-yellow-100',
+ },
+ red: {
+ text: 'text-red-800',
+ bg: 'bg-red-100',
+ },
+ gray: {
+ text: 'text-gray-800',
+ bg: 'bg-gray-100',
+ },
+}
+
+export default function Tag({ children, color = 'green', className = '', bordered = false, hideBg = false }: ITagProps) {
+ return (
+ <div className={
+ classNames('px-2.5 py-px text-xs leading-5 rounded-md inline-flex items-center flex-shrink-0',
+ COLOR_MAP[color] ? `${COLOR_MAP[color].text} ${COLOR_MAP[color].bg}` : '',
+ bordered ? 'border-[1px]' : '',
+ hideBg ? 'bg-opacity-0' : '',
+ className)} >
+ {children}
+ </div>
+ )
+}
diff --git a/app/components/base/text-generation/hooks.ts b/app/components/base/text-generation/hooks.ts
new file mode 100644
index 0000000..3d1bae9
--- /dev/null
+++ b/app/components/base/text-generation/hooks.ts
@@ -0,0 +1,61 @@
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useToastContext } from '@/app/components/base/toast'
+import { ssePost } from '@/service/base'
+
+export const useTextGeneration = () => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const [isResponding, setIsResponding] = useState(false)
+ const [completion, setCompletion] = useState('')
+ const [messageId, setMessageId] = useState<string | null>(null)
+
+ const handleSend = async (
+ url: string,
+ data: any,
+ ) => {
+ if (isResponding) {
+ notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
+ return false
+ }
+
+ setIsResponding(true)
+ setCompletion('')
+ setMessageId('')
+ let res: string[] = []
+ ssePost(
+ url,
+ {
+ body: {
+ response_mode: 'streaming',
+ ...data,
+ },
+ },
+ {
+ onData: (data: string, _isFirstMessage: boolean, { messageId }) => {
+ res.push(data)
+ setCompletion(res.join(''))
+ setMessageId(messageId)
+ },
+ onMessageReplace: (messageReplace) => {
+ res = [messageReplace.answer]
+ setCompletion(res.join(''))
+ },
+ onCompleted() {
+ setIsResponding(false)
+ },
+ onError() {
+ setIsResponding(false)
+ },
+ })
+ return true
+ }
+
+ return {
+ completion,
+ isResponding,
+ setIsResponding,
+ handleSend,
+ messageId,
+ }
+}
diff --git a/app/components/base/text-generation/types.ts b/app/components/base/text-generation/types.ts
new file mode 100644
index 0000000..677a8e7
--- /dev/null
+++ b/app/components/base/text-generation/types.ts
@@ -0,0 +1,43 @@
+import type {
+ ModelConfig,
+ VisionFile,
+ VisionSettings,
+} from '@/types/app'
+import type { ExternalDataTool } from '@/models/common'
+export type { VisionFile } from '@/types/app'
+export { TransferMethod } from '@/types/app'
+
+export type UserInputForm = {
+ default: string
+ label: string
+ required: boolean
+ variable: string
+}
+
+export type UserInputFormTextInput = {
+ 'text-input': UserInputForm & {
+ max_length: number
+ }
+}
+
+export type UserInputFormSelect = {
+ select: UserInputForm & {
+ options: string[]
+ }
+}
+
+export type UserInputFormParagraph = {
+ paragraph: UserInputForm
+}
+
+export type VisionConfig = VisionSettings
+
+export type EnableType = {
+ enabled: boolean
+}
+
+export type TextGenerationConfig = Omit<ModelConfig, 'model'> & {
+ external_data_tools: ExternalDataTool[]
+}
+
+export type OnSend = (message: string, files?: VisionFile[]) => void
diff --git a/app/components/base/textarea/index.tsx b/app/components/base/textarea/index.tsx
new file mode 100644
index 0000000..1e27451
--- /dev/null
+++ b/app/components/base/textarea/index.tsx
@@ -0,0 +1,54 @@
+import type { CSSProperties } from 'react'
+import React from 'react'
+import { type VariantProps, cva } from 'class-variance-authority'
+import cn from '@/utils/classnames'
+
+const textareaVariants = cva(
+ '',
+ {
+ variants: {
+ size: {
+ small: 'py-1 rounded-md system-xs-regular',
+ regular: 'px-3 rounded-md system-sm-regular',
+ large: 'px-4 rounded-lg system-md-regular',
+ },
+ },
+ defaultVariants: {
+ size: 'regular',
+ },
+ },
+)
+
+export type TextareaProps = {
+ value: string
+ disabled?: boolean
+ destructive?: boolean
+ styleCss?: CSSProperties
+} & React.TextareaHTMLAttributes<HTMLTextAreaElement> & VariantProps<typeof textareaVariants>
+
+const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
+ ({ className, value, onChange, disabled, size, destructive, styleCss, ...props }, ref) => {
+ return (
+ <textarea
+ ref={ref}
+ style={styleCss}
+ className={cn(
+ 'min-h-20 w-full appearance-none border border-transparent bg-components-input-bg-normal p-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs',
+ textareaVariants({ size }),
+ disabled && 'cursor-not-allowed border-transparent bg-components-input-bg-disabled text-components-input-text-filled-disabled hover:border-transparent hover:bg-components-input-bg-disabled',
+ destructive && 'border-components-input-border-destructive bg-components-input-bg-destructive text-components-input-text-filled hover:border-components-input-border-destructive hover:bg-components-input-bg-destructive focus:border-components-input-border-destructive focus:bg-components-input-bg-destructive',
+ className,
+ )}
+ value={value}
+ onChange={onChange}
+ disabled={disabled}
+ {...props}
+ >
+ </textarea>
+ )
+ },
+)
+Textarea.displayName = 'Textarea'
+
+export default Textarea
+export { Textarea, textareaVariants }
diff --git a/app/components/base/theme-selector.tsx b/app/components/base/theme-selector.tsx
new file mode 100644
index 0000000..8dfe1d2
--- /dev/null
+++ b/app/components/base/theme-selector.tsx
@@ -0,0 +1,97 @@
+'use client'
+
+import { useState } from 'react'
+import {
+ RiCheckLine,
+ RiComputerLine,
+ RiMoonLine,
+ RiSunLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { useTheme } from 'next-themes'
+import ActionButton from '@/app/components/base/action-button'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+
+export type Theme = 'light' | 'dark' | 'system'
+
+export default function ThemeSelector() {
+ const { t } = useTranslation()
+ const { theme, setTheme } = useTheme()
+ const [open, setOpen] = useState(false)
+
+ const handleThemeChange = (newTheme: Theme) => {
+ setTheme(newTheme)
+ setOpen(false)
+ }
+
+ const getCurrentIcon = () => {
+ switch (theme) {
+ case 'light': return <RiSunLine className='h-4 w-4 text-text-tertiary' />
+ case 'dark': return <RiMoonLine className='h-4 w-4 text-text-tertiary' />
+ default: return <RiComputerLine className='h-4 w-4 text-text-tertiary' />
+ }
+ }
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{ mainAxis: 6 }}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(!open)}
+ >
+ <ActionButton
+ className={`h-8 w-8 p-[6px] ${open && 'bg-state-base-hover'}`}
+ >
+ {getCurrentIcon()}
+ </ActionButton>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1000]'>
+ <div className='flex w-[144px] flex-col items-start rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg'>
+ <button
+ className='flex w-full items-center gap-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover'
+ onClick={() => handleThemeChange('light')}
+ >
+ <RiSunLine className='h-4 w-4 text-text-tertiary' />
+ <div className='flex grow items-center justify-start px-1'>
+ <span className='system-md-regular'>{t('common.theme.light')}</span>
+ </div>
+ {theme === 'light' && <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
+ <RiCheckLine className='h-4 w-4 text-text-accent' />
+ </div>}
+ </button>
+ <button
+ className='flex w-full items-center gap-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover'
+ onClick={() => handleThemeChange('dark')}
+ >
+ <RiMoonLine className='h-4 w-4 text-text-tertiary' />
+ <div className='flex grow items-center justify-start px-1'>
+ <span className='system-md-regular'>{t('common.theme.dark')}</span>
+ </div>
+ {theme === 'dark' && <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
+ <RiCheckLine className='h-4 w-4 text-text-accent' />
+ </div>}
+ </button>
+ <button
+ className='flex w-full items-center gap-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover'
+ onClick={() => handleThemeChange('system')}
+ >
+ <RiComputerLine className='h-4 w-4 text-text-tertiary' />
+ <div className='flex grow items-center justify-start px-1'>
+ <span className='system-md-regular'>{t('common.theme.auto')}</span>
+ </div>
+ {theme === 'system' && <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
+ <RiCheckLine className='h-4 w-4 text-text-accent' />
+ </div>}
+ </button>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
diff --git a/app/components/base/theme-switcher.tsx b/app/components/base/theme-switcher.tsx
new file mode 100644
index 0000000..902d064
--- /dev/null
+++ b/app/components/base/theme-switcher.tsx
@@ -0,0 +1,58 @@
+'use client'
+import {
+ RiComputerLine,
+ RiMoonLine,
+ RiSunLine,
+} from '@remixicon/react'
+import { useTheme } from 'next-themes'
+import cn from '@/utils/classnames'
+
+export type Theme = 'light' | 'dark' | 'system'
+
+export default function ThemeSwitcher() {
+ const { theme, setTheme } = useTheme()
+
+ const handleThemeChange = (newTheme: Theme) => {
+ setTheme(newTheme)
+ }
+
+ return (
+ <div className='flex items-center rounded-[10px] bg-components-segmented-control-bg-normal p-0.5'>
+ <div
+ className={cn(
+ 'rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
+ theme === 'system' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
+ )}
+ onClick={() => handleThemeChange('system')}
+ >
+ <div className='p-0.5'>
+ <RiComputerLine className='h-4 w-4' />
+ </div>
+ </div>
+ <div className={cn('h-[14px] w-px bg-transparent', theme === 'dark' && 'bg-divider-regular')}></div>
+ <div
+ className={cn(
+ 'rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
+ theme === 'light' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
+ )}
+ onClick={() => handleThemeChange('light')}
+ >
+ <div className='p-0.5'>
+ <RiSunLine className='h-4 w-4' />
+ </div>
+ </div>
+ <div className={cn('h-[14px] w-px bg-transparent', theme === 'system' && 'bg-divider-regular')}></div>
+ <div
+ className={cn(
+ 'rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
+ theme === 'dark' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
+ )}
+ onClick={() => handleThemeChange('dark')}
+ >
+ <div className='p-0.5'>
+ <RiMoonLine className='h-4 w-4' />
+ </div>
+ </div>
+ </div>
+ )
+}
diff --git a/app/components/base/toast/index.spec.tsx b/app/components/base/toast/index.spec.tsx
new file mode 100644
index 0000000..2dac8d2
--- /dev/null
+++ b/app/components/base/toast/index.spec.tsx
@@ -0,0 +1,193 @@
+import type { ReactNode } from 'react'
+import React from 'react'
+import { act, render, screen, waitFor } from '@testing-library/react'
+import Toast, { ToastProvider, useToastContext } from '.'
+import '@testing-library/jest-dom'
+import { noop } from 'lodash-es'
+
+// Mock timers for testing timeouts
+jest.useFakeTimers()
+
+const TestComponent = () => {
+ const { notify, close } = useToastContext()
+
+ return (
+ <div>
+ <button onClick={() => notify({ message: 'Notification message', type: 'info' })}>
+ Show Toast
+ </button>
+ <button onClick={close}>Close Toast</button>
+ </div>
+ )
+}
+
+describe('Toast', () => {
+ describe('Toast Component', () => {
+ test('renders toast with correct type and message', () => {
+ render(
+ <ToastProvider>
+ <Toast type="success" message="Success message" />
+ </ToastProvider>,
+ )
+
+ expect(screen.getByText('Success message')).toBeInTheDocument()
+ })
+
+ test('renders with different types', () => {
+ const { rerender } = render(
+ <ToastProvider>
+ <Toast type="success" message="Success message" />
+ </ToastProvider>,
+ )
+
+ expect(document.querySelector('.text-text-success')).toBeInTheDocument()
+
+ rerender(
+ <ToastProvider>
+ <Toast type="error" message="Error message" />
+ </ToastProvider>,
+ )
+
+ expect(document.querySelector('.text-text-destructive')).toBeInTheDocument()
+ })
+
+ test('renders with custom component', () => {
+ render(
+ <ToastProvider>
+ <Toast
+ message="Message with custom component"
+ customComponent={<span data-testid="custom-component">Custom</span>}
+ />
+ </ToastProvider>,
+ )
+
+ expect(screen.getByTestId('custom-component')).toBeInTheDocument()
+ })
+
+ test('renders children content', () => {
+ render(
+ <ToastProvider>
+ <Toast message="Message with children">
+ <span>Additional information</span>
+ </Toast>
+ </ToastProvider>,
+ )
+
+ expect(screen.getByText('Additional information')).toBeInTheDocument()
+ })
+
+ test('does not render close button when close is undefined', () => {
+ // Create a modified context where close is undefined
+ const CustomToastContext = React.createContext({ notify: noop, close: undefined })
+
+ // Create a wrapper component using the custom context
+ const Wrapper = ({ children }: { children: ReactNode }) => (
+ <CustomToastContext.Provider value={{ notify: noop, close: undefined }}>
+ {children}
+ </CustomToastContext.Provider>
+ )
+
+ render(
+ <Wrapper>
+ <Toast message="No close button" type="info" />
+ </Wrapper>,
+ )
+
+ expect(screen.getByText('No close button')).toBeInTheDocument()
+ // Ensure the close button is not rendered
+ expect(document.querySelector('.h-4.w-4.shrink-0.text-text-tertiary')).not.toBeInTheDocument()
+ })
+ })
+
+ describe('ToastProvider and Context', () => {
+ test('shows and hides toast using context', async () => {
+ render(
+ <ToastProvider>
+ <TestComponent />
+ </ToastProvider>,
+ )
+
+ // No toast initially
+ expect(screen.queryByText('Notification message')).not.toBeInTheDocument()
+
+ // Show toast
+ act(() => {
+ screen.getByText('Show Toast').click()
+ })
+ expect(screen.getByText('Notification message')).toBeInTheDocument()
+
+ // Close toast
+ act(() => {
+ screen.getByText('Close Toast').click()
+ })
+ expect(screen.queryByText('Notification message')).not.toBeInTheDocument()
+ })
+
+ test('automatically hides toast after duration', async () => {
+ render(
+ <ToastProvider>
+ <TestComponent />
+ </ToastProvider>,
+ )
+
+ // Show toast
+ act(() => {
+ screen.getByText('Show Toast').click()
+ })
+ expect(screen.getByText('Notification message')).toBeInTheDocument()
+
+ // Fast-forward timer
+ act(() => {
+ jest.advanceTimersByTime(3000) // Default for info type is 3000ms
+ })
+
+ // Toast should be gone
+ await waitFor(() => {
+ expect(screen.queryByText('Notification message')).not.toBeInTheDocument()
+ })
+ })
+ })
+
+ describe('Toast.notify static method', () => {
+ test('creates and removes toast from DOM', async () => {
+ act(() => {
+ // Call the static method
+ Toast.notify({ message: 'Static notification', type: 'warning' })
+ })
+
+ // Toast should be in document
+ expect(screen.getByText('Static notification')).toBeInTheDocument()
+
+ // Fast-forward timer
+ act(() => {
+ jest.advanceTimersByTime(6000) // Default for warning type is 6000ms
+ })
+
+ // Toast should be removed
+ await waitFor(() => {
+ expect(screen.queryByText('Static notification')).not.toBeInTheDocument()
+ })
+ })
+
+ test('calls onClose callback after duration', async () => {
+ const onCloseMock = jest.fn()
+ act(() => {
+ Toast.notify({
+ message: 'Closing notification',
+ type: 'success',
+ onClose: onCloseMock,
+ })
+ })
+
+ // Fast-forward timer
+ act(() => {
+ jest.advanceTimersByTime(3000) // Default for success type is 3000ms
+ })
+
+ // onClose should be called
+ await waitFor(() => {
+ expect(onCloseMock).toHaveBeenCalled()
+ })
+ })
+ })
+})
diff --git a/app/components/base/toast/index.tsx b/app/components/base/toast/index.tsx
new file mode 100644
index 0000000..725c7af
--- /dev/null
+++ b/app/components/base/toast/index.tsx
@@ -0,0 +1,161 @@
+'use client'
+import type { ReactNode } from 'react'
+import React, { useEffect, useState } from 'react'
+import { createRoot } from 'react-dom/client'
+import {
+ RiAlertFill,
+ RiCheckboxCircleFill,
+ RiCloseLine,
+ RiErrorWarningFill,
+ RiInformation2Fill,
+} from '@remixicon/react'
+import { createContext, useContext } from 'use-context-selector'
+import ActionButton from '@/app/components/base/action-button'
+import classNames from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+export type IToastProps = {
+ type?: 'success' | 'error' | 'warning' | 'info'
+ size?: 'md' | 'sm'
+ duration?: number
+ message: string
+ children?: ReactNode
+ onClose?: () => void
+ className?: string
+ customComponent?: ReactNode
+}
+type IToastContext = {
+ notify: (props: IToastProps) => void
+ close: () => void
+}
+
+export const ToastContext = createContext<IToastContext>({} as IToastContext)
+export const useToastContext = () => useContext(ToastContext)
+const Toast = ({
+ type = 'info',
+ size = 'md',
+ message,
+ children,
+ className,
+ customComponent,
+}: IToastProps) => {
+ const { close } = useToastContext()
+ // sometimes message is react node array. Not handle it.
+ if (typeof message !== 'string')
+ return null
+
+ return <div className={classNames(
+ className,
+ 'fixed w-[360px] rounded-xl my-4 mx-8 flex-grow z-[9999] overflow-hidden',
+ size === 'md' ? 'p-3' : 'p-2',
+ 'border border-components-panel-border-subtle bg-components-panel-bg-blur shadow-sm',
+ 'top-0',
+ 'right-0',
+ )}>
+ <div className={`absolute inset-0 -z-10 opacity-40 ${
+ (type === 'success' && 'bg-toast-success-bg')
+ || (type === 'warning' && 'bg-toast-warning-bg')
+ || (type === 'error' && 'bg-toast-error-bg')
+ || (type === 'info' && 'bg-toast-info-bg')
+ }`}
+ />
+ <div className={`flex ${size === 'md' ? 'gap-1' : 'gap-0.5'}`}>
+ <div className={`flex items-center justify-center ${size === 'md' ? 'p-0.5' : 'p-1'}`}>
+ {type === 'success' && <RiCheckboxCircleFill className={`${size === 'md' ? 'h-5 w-5' : 'h-4 w-4'} text-text-success`} aria-hidden="true" />}
+ {type === 'error' && <RiErrorWarningFill className={`${size === 'md' ? 'h-5 w-5' : 'h-4 w-4'} text-text-destructive`} aria-hidden="true" />}
+ {type === 'warning' && <RiAlertFill className={`${size === 'md' ? 'h-5 w-5' : 'h-4 w-4'} text-text-warning-secondary`} aria-hidden="true" />}
+ {type === 'info' && <RiInformation2Fill className={`${size === 'md' ? 'h-5 w-5' : 'h-4 w-4'} text-text-accent`} aria-hidden="true" />}
+ </div>
+ <div className={`flex py-1 ${size === 'md' ? 'px-1' : 'px-0.5'} grow flex-col items-start gap-1`}>
+ <div className='flex items-center gap-1'>
+ <div className='system-sm-semibold text-text-primary [word-break:break-word]'>{message}</div>
+ {customComponent}
+ </div>
+ {children && <div className='system-xs-regular text-text-secondary'>
+ {children}
+ </div>
+ }
+ </div>
+ {close
+ && (<ActionButton className='z-[1000]' onClick={close}>
+ <RiCloseLine className='h-4 w-4 shrink-0 text-text-tertiary' />
+ </ActionButton>)
+ }
+ </div>
+ </div>
+}
+
+export const ToastProvider = ({
+ children,
+}: {
+ children: ReactNode
+}) => {
+ const placeholder: IToastProps = {
+ type: 'info',
+ message: 'Toast message',
+ duration: 6000,
+ }
+ const [params, setParams] = React.useState<IToastProps>(placeholder)
+ const defaultDuring = (params.type === 'success' || params.type === 'info') ? 3000 : 6000
+ const [mounted, setMounted] = useState(false)
+
+ useEffect(() => {
+ if (mounted) {
+ setTimeout(() => {
+ setMounted(false)
+ }, params.duration || defaultDuring)
+ }
+ }, [defaultDuring, mounted, params.duration])
+
+ return <ToastContext.Provider value={{
+ notify: (props) => {
+ setMounted(true)
+ setParams(props)
+ },
+ close: () => setMounted(false),
+ }}>
+ {mounted && <Toast {...params} />}
+ {children}
+ </ToastContext.Provider>
+}
+
+Toast.notify = ({
+ type,
+ size = 'md',
+ message,
+ duration,
+ className,
+ customComponent,
+ onClose,
+}: Pick<IToastProps, 'type' | 'size' | 'message' | 'duration' | 'className' | 'customComponent' | 'onClose'>) => {
+ const defaultDuring = (type === 'success' || type === 'info') ? 3000 : 6000
+ if (typeof window === 'object') {
+ const holder = document.createElement('div')
+ const root = createRoot(holder)
+
+ root.render(
+ <ToastContext.Provider value={{
+ notify: noop,
+ close: () => {
+ if (holder) {
+ root.unmount()
+ holder.remove()
+ }
+ onClose?.()
+ },
+ }}>
+ <Toast type={type} size={size} message={message} duration={duration} className={className} customComponent={customComponent} />
+ </ToastContext.Provider>,
+ )
+ document.body.appendChild(holder)
+ setTimeout(() => {
+ if (holder) {
+ root.unmount()
+ holder.remove()
+ }
+ onClose?.()
+ }, duration || defaultDuring)
+ }
+}
+
+export default Toast
diff --git a/app/components/base/toast/style.module.css b/app/components/base/toast/style.module.css
new file mode 100644
index 0000000..216ccf1
--- /dev/null
+++ b/app/components/base/toast/style.module.css
@@ -0,0 +1,44 @@
+.toast {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: fixed;
+ z-index: 99999999;
+ width: 1.84rem;
+ height: 1.80rem;
+ left: 50%;
+ top: 50%;
+ transform: translateX(-50%) translateY(-50%);
+ background: #000000;
+ box-shadow: 0 -.04rem .1rem 1px rgba(255, 255, 255, 0.1);
+ border-radius: .1rem .1rem .1rem .1rem;
+}
+
+.main {
+ width: 2rem;
+}
+
+.icon {
+ margin-bottom: .2rem;
+ height: .4rem;
+ background: center center no-repeat;
+ background-size: contain;
+}
+
+/* .success {
+ background-image: url('./icons/success.svg');
+}
+
+.warning {
+ background-image: url('./icons/warning.svg');
+}
+
+.error {
+ background-image: url('./icons/error.svg');
+} */
+
+.text {
+ text-align: center;
+ font-size: .2rem;
+ color: rgba(255, 255, 255, 0.86);
+}
diff --git a/app/components/base/tooltip/content.tsx b/app/components/base/tooltip/content.tsx
new file mode 100644
index 0000000..f30940a
--- /dev/null
+++ b/app/components/base/tooltip/content.tsx
@@ -0,0 +1,22 @@
+import type { FC, PropsWithChildren, ReactNode } from 'react'
+
+export type ToolTipContentProps = {
+ title?: ReactNode
+ action?: ReactNode
+} & PropsWithChildren
+
+export const ToolTipContent: FC<ToolTipContentProps> = ({
+ title,
+ action,
+ children,
+}) => {
+ return (
+ <div className='w-[180px]'>
+ {title && (
+ <div className='mb-1.5 font-semibold text-text-secondary'>{title}</div>
+ )}
+ <div className='mb-1.5 text-text-tertiary'>{children}</div>
+ {action && <div className='cursor-pointer text-text-accent'>{action}</div>}
+ </div>
+ )
+}
diff --git a/app/components/base/tooltip/index.spec.tsx b/app/components/base/tooltip/index.spec.tsx
new file mode 100644
index 0000000..1b9b7a0
--- /dev/null
+++ b/app/components/base/tooltip/index.spec.tsx
@@ -0,0 +1,116 @@
+import React from 'react'
+import { act, cleanup, fireEvent, render, screen } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import Tooltip from './index'
+
+afterEach(cleanup)
+
+describe('Tooltip', () => {
+ describe('Rendering', () => {
+ test('should render default tooltip with question icon', () => {
+ const triggerClassName = 'custom-trigger'
+ const { container } = render(<Tooltip popupContent="Tooltip content" triggerClassName={triggerClassName} />)
+ const trigger = container.querySelector(`.${triggerClassName}`)
+ expect(trigger).not.toBeNull()
+ expect(trigger?.querySelector('svg')).not.toBeNull() // question icon
+ })
+
+ test('should render with custom children', () => {
+ const { getByText } = render(
+ <Tooltip popupContent="Tooltip content">
+ <button>Hover me</button>
+ </Tooltip>,
+ )
+ expect(getByText('Hover me').textContent).toBe('Hover me')
+ })
+ })
+
+ describe('Disabled state', () => {
+ test('should not show tooltip when disabled', () => {
+ const triggerClassName = 'custom-trigger'
+ const { container } = render(<Tooltip popupContent="Tooltip content" disabled triggerClassName={triggerClassName} />)
+ const trigger = container.querySelector(`.${triggerClassName}`)
+ act(() => {
+ fireEvent.mouseEnter(trigger!)
+ })
+ expect(screen.queryByText('Tooltip content')).not.toBeInTheDocument()
+ })
+ })
+
+ describe('Trigger methods', () => {
+ test('should open on hover when triggerMethod is hover', () => {
+ const triggerClassName = 'custom-trigger'
+ const { container } = render(<Tooltip popupContent="Tooltip content" triggerClassName={triggerClassName} />)
+ const trigger = container.querySelector(`.${triggerClassName}`)
+ act(() => {
+ fireEvent.mouseEnter(trigger!)
+ })
+ expect(screen.queryByText('Tooltip content')).toBeInTheDocument()
+ })
+
+ test('should close on mouse leave when triggerMethod is hover', () => {
+ const triggerClassName = 'custom-trigger'
+ const { container } = render(<Tooltip popupContent="Tooltip content" triggerClassName={triggerClassName} />)
+ const trigger = container.querySelector(`.${triggerClassName}`)
+ act(() => {
+ fireEvent.mouseEnter(trigger!)
+ fireEvent.mouseLeave(trigger!)
+ })
+ expect(screen.queryByText('Tooltip content')).not.toBeInTheDocument()
+ })
+
+ test('should toggle on click when triggerMethod is click', () => {
+ const triggerClassName = 'custom-trigger'
+ const { container } = render(<Tooltip popupContent="Tooltip content" triggerMethod="click" triggerClassName={triggerClassName} />)
+ const trigger = container.querySelector(`.${triggerClassName}`)
+ act(() => {
+ fireEvent.click(trigger!)
+ })
+ expect(screen.queryByText('Tooltip content')).toBeInTheDocument()
+ })
+
+ test('should not close immediately on mouse leave when needsDelay is true', () => {
+ const triggerClassName = 'custom-trigger'
+ const { container } = render(<Tooltip popupContent="Tooltip content" triggerMethod="hover" needsDelay triggerClassName={triggerClassName} />)
+ const trigger = container.querySelector(`.${triggerClassName}`)
+ act(() => {
+ fireEvent.mouseEnter(trigger!)
+ fireEvent.mouseLeave(trigger!)
+ })
+ expect(screen.queryByText('Tooltip content')).toBeInTheDocument()
+ })
+ })
+
+ describe('Styling and positioning', () => {
+ test('should apply custom trigger className', () => {
+ const triggerClassName = 'custom-trigger'
+ const { container } = render(<Tooltip popupContent="Tooltip content" triggerClassName={triggerClassName} />)
+ const trigger = container.querySelector(`.${triggerClassName}`)
+ expect(trigger?.className).toContain('custom-trigger')
+ })
+
+ test('should apply custom popup className', async () => {
+ const triggerClassName = 'custom-trigger'
+ const { container } = render(<Tooltip popupContent="Tooltip content" triggerClassName={triggerClassName} popupClassName="custom-popup" />)
+ const trigger = container.querySelector(`.${triggerClassName}`)
+ act(() => {
+ fireEvent.mouseEnter(trigger!)
+ })
+ expect((await screen.findByText('Tooltip content'))?.className).toContain('custom-popup')
+ })
+
+ test('should apply noDecoration when specified', async () => {
+ const triggerClassName = 'custom-trigger'
+ const { container } = render(<Tooltip
+ popupContent="Tooltip content"
+ triggerClassName={triggerClassName}
+ noDecoration
+ />)
+ const trigger = container.querySelector(`.${triggerClassName}`)
+ act(() => {
+ fireEvent.mouseEnter(trigger!)
+ })
+ expect((await screen.findByText('Tooltip content'))?.className).not.toContain('bg-components-panel-bg')
+ })
+ })
+})
diff --git a/app/components/base/tooltip/index.tsx b/app/components/base/tooltip/index.tsx
new file mode 100644
index 0000000..e6c4de3
--- /dev/null
+++ b/app/components/base/tooltip/index.tsx
@@ -0,0 +1,116 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
+import { useBoolean } from 'ahooks'
+import type { OffsetOptions, Placement } from '@floating-ui/react'
+import { RiQuestionLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
+export type TooltipProps = {
+ position?: Placement
+ triggerMethod?: 'hover' | 'click'
+ triggerClassName?: string
+ triggerTestId?: string
+ disabled?: boolean
+ popupContent?: React.ReactNode
+ children?: React.ReactNode
+ popupClassName?: string
+ noDecoration?: boolean
+ offset?: OffsetOptions
+ needsDelay?: boolean
+ asChild?: boolean
+}
+
+const Tooltip: FC<TooltipProps> = ({
+ position = 'top',
+ triggerMethod = 'hover',
+ triggerClassName,
+ triggerTestId,
+ disabled = false,
+ popupContent,
+ children,
+ popupClassName,
+ noDecoration,
+ offset,
+ asChild = true,
+ needsDelay = false,
+}) => {
+ const [open, setOpen] = useState(false)
+ const [isHoverPopup, {
+ setTrue: setHoverPopup,
+ setFalse: setNotHoverPopup,
+ }] = useBoolean(false)
+
+ const isHoverPopupRef = useRef(isHoverPopup)
+ useEffect(() => {
+ isHoverPopupRef.current = isHoverPopup
+ }, [isHoverPopup])
+
+ const [isHoverTrigger, {
+ setTrue: setHoverTrigger,
+ setFalse: setNotHoverTrigger,
+ }] = useBoolean(false)
+
+ const isHoverTriggerRef = useRef(isHoverTrigger)
+ useEffect(() => {
+ isHoverTriggerRef.current = isHoverTrigger
+ }, [isHoverTrigger])
+
+ const handleLeave = (isTrigger: boolean) => {
+ if (isTrigger)
+ setNotHoverTrigger()
+
+ else
+ setNotHoverPopup()
+
+ // give time to move to the popup
+ if (needsDelay) {
+ setTimeout(() => {
+ if (!isHoverPopupRef.current && !isHoverTriggerRef.current)
+ setOpen(false)
+ }, 500)
+ }
+ else {
+ setOpen(false)
+ }
+ }
+
+ return (
+ <PortalToFollowElem
+ open={disabled ? false : open}
+ onOpenChange={setOpen}
+ placement={position}
+ offset={offset ?? 8}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => triggerMethod === 'click' && setOpen(v => !v)}
+ onMouseEnter={() => {
+ if (triggerMethod === 'hover') {
+ setHoverTrigger()
+ setOpen(true)
+ }
+ }}
+ onMouseLeave={() => triggerMethod === 'hover' && handleLeave(true)}
+ asChild={asChild}
+ >
+ {children || <div data-testid={triggerTestId} className={triggerClassName || 'h-3.5 w-3.5 shrink-0 p-[1px]'}><RiQuestionLine className='h-full w-full text-text-quaternary hover:text-text-tertiary' /></div>}
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent
+ className="z-[9999]"
+ >
+ {popupContent && (<div
+ className={cn(
+ !noDecoration && 'system-xs-regular relative break-words rounded-md bg-components-panel-bg px-3 py-2 text-text-tertiary shadow-lg',
+ popupClassName,
+ )}
+ onMouseEnter={() => triggerMethod === 'hover' && setHoverPopup()}
+ onMouseLeave={() => triggerMethod === 'hover' && handleLeave(false)}
+ >
+ {popupContent}
+ </div>)}
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default React.memo(Tooltip)
diff --git a/app/components/base/video-gallery/VideoPlayer.module.css b/app/components/base/video-gallery/VideoPlayer.module.css
new file mode 100644
index 0000000..04c4a36
--- /dev/null
+++ b/app/components/base/video-gallery/VideoPlayer.module.css
@@ -0,0 +1,188 @@
+.videoPlayer {
+ position: relative;
+ width: 100%;
+ max-width: 800px;
+ margin: 0 auto;
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+.video {
+ width: 100%;
+ display: block;
+}
+
+.controls {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ transition: opacity 0.3s ease;
+}
+
+.controls.hidden {
+ opacity: 0;
+}
+
+.controls.visible {
+ opacity: 1;
+}
+
+.overlay {
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.7) 0%, transparent 100%);
+ padding: 20px;
+ display: flex;
+ flex-direction: column;
+}
+
+.progressBarContainer {
+ width: 100%;
+ margin-bottom: 10px;
+}
+
+.controlsContent {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.leftControls, .rightControls {
+ display: flex;
+ align-items: center;
+}
+
+.playPauseButton, .muteButton, .fullscreenButton {
+ background: none;
+ border: none;
+ color: white;
+ cursor: pointer;
+ padding: 4px;
+ margin-right: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.playPauseButton:hover, .muteButton:hover, .fullscreenButton:hover {
+ background-color: rgba(255, 255, 255, 0.1);
+ border-radius: 50%;
+}
+
+.time {
+ color: white;
+ font-size: 14px;
+ margin-left: 8px;
+}
+
+.volumeControl {
+ display: flex;
+ align-items: center;
+ margin-right: 16px;
+}
+
+.volumeSlider {
+ width: 60px;
+ height: 4px;
+ background: rgba(255, 255, 255, 0.3);
+ border-radius: 2px;
+ cursor: pointer;
+ margin-left: 12px;
+ position: relative;
+}
+
+.volumeLevel {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ background: #ffffff;
+ border-radius: 2px;
+}
+
+.progressBar {
+ position: relative;
+ width: 100%;
+ height: 4px;
+ background: rgba(255, 255, 255, 0.3);
+ cursor: pointer;
+ border-radius: 2px;
+ overflow: visible;
+ transition: height 0.2s ease;
+}
+
+.progressBar:hover {
+ height: 6px;
+}
+
+.progress {
+ height: 100%;
+ background: #ffffff;
+ transition: width 0.1s ease-in-out;
+}
+
+.hoverTimeIndicator {
+ position: absolute;
+ bottom: 100%;
+ transform: translateX(-50%);
+ background-color: rgba(0, 0, 0, 0.7);
+ color: white;
+ padding: 4px 8px;
+ border-radius: 4px;
+ font-size: 12px;
+ pointer-events: none;
+ white-space: nowrap;
+ margin-bottom: 8px;
+}
+
+.hoverTimeIndicator::after {
+ content: '';
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ margin-left: -4px;
+ border-width: 4px;
+ border-style: solid;
+ border-color: rgba(0, 0, 0, 0.7) transparent transparent transparent;
+}
+
+.controls.smallSize .controlsContent {
+ justify-content: space-between;
+}
+
+.controls.smallSize .leftControls,
+.controls.smallSize .rightControls {
+ flex: 0 0 auto;
+ display: flex;
+ align-items: center;
+}
+
+.controls.smallSize .rightControls {
+ justify-content: flex-end;
+}
+
+.controls.smallSize .progressBarContainer {
+ margin-bottom: 4px;
+}
+
+.controls.smallSize .playPauseButton,
+.controls.smallSize .muteButton,
+.controls.smallSize .fullscreenButton {
+ padding: 2px;
+ margin-right: 4px;
+}
+
+.controls.smallSize .playPauseButton svg,
+.controls.smallSize .muteButton svg,
+.controls.smallSize .fullscreenButton svg {
+ width: 16px;
+ height: 16px;
+}
+
+.controls.smallSize .muteButton {
+ order: -1;
+}
diff --git a/app/components/base/video-gallery/VideoPlayer.tsx b/app/components/base/video-gallery/VideoPlayer.tsx
new file mode 100644
index 0000000..d7c86a1
--- /dev/null
+++ b/app/components/base/video-gallery/VideoPlayer.tsx
@@ -0,0 +1,278 @@
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import styles from './VideoPlayer.module.css'
+
+type VideoPlayerProps = {
+ src: string
+}
+
+const PlayIcon = () => (
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M8 5V19L19 12L8 5Z" fill="currentColor"/>
+ </svg>
+)
+
+const PauseIcon = () => (
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M6 19H10V5H6V19ZM14 5V19H18V5H14Z" fill="currentColor"/>
+ </svg>
+)
+
+const MuteIcon = () => (
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M3 9V15H7L12 20V4L7 9H3ZM16.5 12C16.5 10.23 15.48 8.71 14 7.97V16.02C15.48 15.29 16.5 13.77 16.5 12ZM14 3.23V5.29C16.89 6.15 19 8.83 19 12C19 15.17 16.89 17.85 14 18.71V20.77C18.01 19.86 21 16.28 21 12C21 7.72 18.01 4.14 14 3.23Z" fill="currentColor"/>
+ </svg>
+)
+
+const UnmuteIcon = () => (
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M4.34 2.93L2.93 4.34L7.29 8.7L7 9H3V15H7L12 20V13.41L16.18 17.59C15.69 17.96 15.16 18.27 14.58 18.5V20.58C15.94 20.22 17.15 19.56 18.13 18.67L19.66 20.2L21.07 18.79L4.34 2.93ZM10 15.17L7.83 13H5V11H7.83L10 8.83V15.17ZM19 12C19 12.82 18.85 13.61 18.59 14.34L20.12 15.87C20.68 14.7 21 13.39 21 12C21 7.72 18.01 4.14 14 3.23V5.29C16.89 6.15 19 8.83 19 12ZM12 4L10.12 5.88L12 7.76V4ZM16.5 12C16.5 10.23 15.48 8.71 14 7.97V10.18L16.45 12.63C16.48 12.43 16.5 12.22 16.5 12Z" fill="currentColor"/>
+ </svg>
+)
+
+const FullscreenIcon = () => (
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M7 14H5V19H10V17H7V14ZM5 10H7V7H10V5H5V10ZM17 17H14V19H19V14H17V17ZM14 5V7H17V10H19V5H14Z" fill="currentColor"/>
+ </svg>
+)
+
+const VideoPlayer: React.FC<VideoPlayerProps> = ({ src }) => {
+ const [isPlaying, setIsPlaying] = useState(false)
+ const [currentTime, setCurrentTime] = useState(0)
+ const [duration, setDuration] = useState(0)
+ const [isMuted, setIsMuted] = useState(false)
+ const [volume, setVolume] = useState(1)
+ const [isDragging, setIsDragging] = useState(false)
+ const [isControlsVisible, setIsControlsVisible] = useState(true)
+ const [hoverTime, setHoverTime] = useState<number | null>(null)
+ const videoRef = useRef<HTMLVideoElement>(null)
+ const progressRef = useRef<HTMLDivElement>(null)
+ const volumeRef = useRef<HTMLDivElement>(null)
+ const controlsTimeoutRef = useRef<NodeJS.Timeout | null>(null)
+ const [isSmallSize, setIsSmallSize] = useState(false)
+ const containerRef = useRef<HTMLDivElement>(null)
+
+ useEffect(() => {
+ const video = videoRef.current
+ if (!video)
+ return
+
+ const setVideoData = () => {
+ setDuration(video.duration)
+ setVolume(video.volume)
+ }
+
+ const setVideoTime = () => {
+ setCurrentTime(video.currentTime)
+ }
+
+ const handleEnded = () => {
+ setIsPlaying(false)
+ }
+
+ video.addEventListener('loadedmetadata', setVideoData)
+ video.addEventListener('timeupdate', setVideoTime)
+ video.addEventListener('ended', handleEnded)
+
+ return () => {
+ video.removeEventListener('loadedmetadata', setVideoData)
+ video.removeEventListener('timeupdate', setVideoTime)
+ video.removeEventListener('ended', handleEnded)
+ }
+ }, [src])
+
+ useEffect(() => {
+ return () => {
+ if (controlsTimeoutRef.current)
+ clearTimeout(controlsTimeoutRef.current)
+ }
+ }, [])
+
+ const showControls = useCallback(() => {
+ setIsControlsVisible(true)
+ if (controlsTimeoutRef.current)
+ clearTimeout(controlsTimeoutRef.current)
+
+ controlsTimeoutRef.current = setTimeout(() => setIsControlsVisible(false), 3000)
+ }, [])
+
+ const togglePlayPause = useCallback(() => {
+ const video = videoRef.current
+ if (video) {
+ if (isPlaying)
+ video.pause()
+ else video.play().catch(error => console.error('Error playing video:', error))
+ setIsPlaying(!isPlaying)
+ }
+ }, [isPlaying])
+
+ const toggleMute = useCallback(() => {
+ const video = videoRef.current
+ if (video) {
+ const newMutedState = !video.muted
+ video.muted = newMutedState
+ setIsMuted(newMutedState)
+ setVolume(newMutedState ? 0 : (video.volume > 0 ? video.volume : 1))
+ video.volume = newMutedState ? 0 : (video.volume > 0 ? video.volume : 1)
+ }
+ }, [])
+
+ const toggleFullscreen = useCallback(() => {
+ const video = videoRef.current
+ if (video) {
+ if (document.fullscreenElement)
+ document.exitFullscreen()
+ else video.requestFullscreen()
+ }
+ }, [])
+
+ const formatTime = (time: number) => {
+ const minutes = Math.floor(time / 60)
+ const seconds = Math.floor(time % 60)
+ return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
+ }
+
+ const updateVideoProgress = useCallback((clientX: number) => {
+ const progressBar = progressRef.current
+ const video = videoRef.current
+ if (progressBar && video) {
+ const rect = progressBar.getBoundingClientRect()
+ const pos = (clientX - rect.left) / rect.width
+ const newTime = pos * video.duration
+ if (newTime >= 0 && newTime <= video.duration) {
+ setHoverTime(newTime)
+ if (isDragging)
+ video.currentTime = newTime
+ }
+ }
+ }, [isDragging])
+
+ const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
+ updateVideoProgress(e.clientX)
+ }, [updateVideoProgress])
+
+ const handleMouseLeave = useCallback(() => {
+ if (!isDragging)
+ setHoverTime(null)
+ }, [isDragging])
+
+ const handleMouseDown = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
+ e.preventDefault()
+ setIsDragging(true)
+ updateVideoProgress(e.clientX)
+ }, [updateVideoProgress])
+
+ useEffect(() => {
+ const handleGlobalMouseMove = (e: MouseEvent) => {
+ if (isDragging)
+ updateVideoProgress(e.clientX)
+ }
+
+ const handleGlobalMouseUp = () => {
+ setIsDragging(false)
+ setHoverTime(null)
+ }
+
+ if (isDragging) {
+ document.addEventListener('mousemove', handleGlobalMouseMove)
+ document.addEventListener('mouseup', handleGlobalMouseUp)
+ }
+
+ return () => {
+ document.removeEventListener('mousemove', handleGlobalMouseMove)
+ document.removeEventListener('mouseup', handleGlobalMouseUp)
+ }
+ }, [isDragging, updateVideoProgress])
+
+ const checkSize = useCallback(() => {
+ if (containerRef.current)
+ setIsSmallSize(containerRef.current.offsetWidth < 400)
+ }, [])
+
+ useEffect(() => {
+ checkSize()
+ window.addEventListener('resize', checkSize)
+ return () => window.removeEventListener('resize', checkSize)
+ }, [checkSize])
+
+ const handleVolumeChange = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
+ const volumeBar = volumeRef.current
+ const video = videoRef.current
+ if (volumeBar && video) {
+ const rect = volumeBar.getBoundingClientRect()
+ const newVolume = (e.clientX - rect.left) / rect.width
+ const clampedVolume = Math.max(0, Math.min(1, newVolume))
+ video.volume = clampedVolume
+ setVolume(clampedVolume)
+ setIsMuted(clampedVolume === 0)
+ }
+ }, [])
+
+ return (
+ <div ref={containerRef} className={styles.videoPlayer} onMouseMove={showControls} onMouseEnter={showControls}>
+ <video ref={videoRef} src={src} className={styles.video} />
+ <div className={`${styles.controls} ${isControlsVisible ? styles.visible : styles.hidden} ${isSmallSize ? styles.smallSize : ''}`}>
+ <div className={styles.overlay}>
+ <div className={styles.progressBarContainer}>
+ <div
+ ref={progressRef}
+ className={styles.progressBar}
+ onClick={handleMouseDown}
+ onMouseMove={handleMouseMove}
+ onMouseLeave={handleMouseLeave}
+ onMouseDown={handleMouseDown}
+ >
+ <div className={styles.progress} style={{ width: `${(currentTime / duration) * 100}%` }} />
+ {hoverTime !== null && (
+ <div
+ className={styles.hoverTimeIndicator}
+ style={{ left: `${(hoverTime / duration) * 100}%` }}
+ >
+ {formatTime(hoverTime)}
+ </div>
+ )}
+ </div>
+ </div>
+ <div className={styles.controlsContent}>
+ <div className={styles.leftControls}>
+ <button className={styles.playPauseButton} onClick={togglePlayPause}>
+ {isPlaying ? <PauseIcon /> : <PlayIcon />}
+ </button>
+ {!isSmallSize && (<span className={styles.time}>{formatTime(currentTime)} / {formatTime(duration)}</span>)}
+ </div>
+ <div className={styles.rightControls}>
+ <button className={styles.muteButton} onClick={toggleMute}>
+ {isMuted ? <UnmuteIcon /> : <MuteIcon />}
+ </button>
+ {!isSmallSize && (
+ <div className={styles.volumeControl}>
+ <div
+ ref={volumeRef}
+ className={styles.volumeSlider}
+ onClick={handleVolumeChange}
+ onMouseDown={(e) => {
+ handleVolumeChange(e)
+ const handleMouseMove = (e: MouseEvent) => handleVolumeChange(e as unknown as React.MouseEvent<HTMLDivElement>)
+ const handleMouseUp = () => {
+ document.removeEventListener('mousemove', handleMouseMove)
+ document.removeEventListener('mouseup', handleMouseUp)
+ }
+ document.addEventListener('mousemove', handleMouseMove)
+ document.addEventListener('mouseup', handleMouseUp)
+ }}
+ >
+ <div className={styles.volumeLevel} style={{ width: `${volume * 100}%` }} />
+ </div>
+ </div>
+ )}
+ <button className={styles.fullscreenButton} onClick={toggleFullscreen}>
+ <FullscreenIcon />
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default VideoPlayer
diff --git a/app/components/base/video-gallery/index.tsx b/app/components/base/video-gallery/index.tsx
new file mode 100644
index 0000000..ae2fab8
--- /dev/null
+++ b/app/components/base/video-gallery/index.tsx
@@ -0,0 +1,12 @@
+import React from 'react'
+import VideoPlayer from './VideoPlayer'
+
+type Props = {
+ srcs: string[]
+}
+
+const VideoGallery: React.FC<Props> = ({ srcs }) => {
+ return (<><br/>{srcs.map((src, index) => (<React.Fragment key={`video_${index}`}><br/><VideoPlayer src={src}/></React.Fragment>))}</>)
+}
+
+export default React.memo(VideoGallery)
diff --git a/app/components/base/voice-input/index.module.css b/app/components/base/voice-input/index.module.css
new file mode 100644
index 0000000..8286f9d
--- /dev/null
+++ b/app/components/base/voice-input/index.module.css
@@ -0,0 +1,10 @@
+.wrapper {
+ background: linear-gradient(131deg, #2250F2 0%, #0EBCF3 100%);
+ box-shadow: 0px 4px 6px -2px rgba(16, 24, 40, 0.03), 0px 12px 16px -4px rgba(16, 24, 40, 0.08);
+}
+
+.convert {
+ background: linear-gradient(91.92deg, #104AE1 -1.74%, #0098EE 75.74%);
+ background-clip: text;
+ color: transparent;
+}
diff --git a/app/components/base/voice-input/index.tsx b/app/components/base/voice-input/index.tsx
new file mode 100644
index 0000000..5a5400a
--- /dev/null
+++ b/app/components/base/voice-input/index.tsx
@@ -0,0 +1,216 @@
+import { useCallback, useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useParams, usePathname } from 'next/navigation'
+import {
+ RiCloseLine,
+ RiLoader2Line,
+} from '@remixicon/react'
+import Recorder from 'js-audio-recorder'
+import { useRafInterval } from 'ahooks'
+import { convertToMp3 } from './utils'
+import s from './index.module.css'
+import cn from '@/utils/classnames'
+import { StopCircle } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
+import { audioToText } from '@/service/share'
+
+type VoiceInputTypes = {
+ onConverted: (text: string) => void
+ onCancel: () => void
+ wordTimestamps?: string
+}
+
+const VoiceInput = ({
+ onCancel,
+ onConverted,
+ wordTimestamps,
+}: VoiceInputTypes) => {
+ const { t } = useTranslation()
+ const recorder = useRef(new Recorder({
+ sampleBits: 16,
+ sampleRate: 16000,
+ numChannels: 1,
+ compiling: false,
+ }))
+ const canvasRef = useRef<HTMLCanvasElement | null>(null)
+ const ctxRef = useRef<CanvasRenderingContext2D | null>(null)
+ const drawRecordId = useRef<number | null>(null)
+ const [originDuration, setOriginDuration] = useState(0)
+ const [startRecord, setStartRecord] = useState(false)
+ const [startConvert, setStartConvert] = useState(false)
+ const pathname = usePathname()
+ const params = useParams()
+ const clearInterval = useRafInterval(() => {
+ setOriginDuration(originDuration + 1)
+ }, 1000)
+
+ const drawRecord = useCallback(() => {
+ drawRecordId.current = requestAnimationFrame(drawRecord)
+ const canvas = canvasRef.current!
+ const ctx = ctxRef.current!
+ const dataUnit8Array = recorder.current.getRecordAnalyseData()
+ const dataArray = [].slice.call(dataUnit8Array)
+ const lineLength = Number.parseInt(`${canvas.width / 3}`)
+ const gap = Number.parseInt(`${1024 / lineLength}`)
+
+ ctx.clearRect(0, 0, canvas.width, canvas.height)
+ ctx.beginPath()
+ let x = 0
+ for (let i = 0; i < lineLength; i++) {
+ let v = dataArray.slice(i * gap, i * gap + gap).reduce((prev: number, next: number) => {
+ return prev + next
+ }, 0) / gap
+
+ if (v < 128)
+ v = 128
+ if (v > 178)
+ v = 178
+ const y = (v - 128) / 50 * canvas.height
+
+ ctx.moveTo(x, 16)
+ if (ctx.roundRect)
+ ctx.roundRect(x, 16 - y, 2, y, [1, 1, 0, 0])
+ else
+ ctx.rect(x, 16 - y, 2, y)
+ ctx.fill()
+ x += 3
+ }
+ ctx.closePath()
+ }, [])
+ const handleStopRecorder = useCallback(async () => {
+ clearInterval()
+ setStartRecord(false)
+ setStartConvert(true)
+ recorder.current.stop()
+ drawRecordId.current && cancelAnimationFrame(drawRecordId.current)
+ drawRecordId.current = null
+ const canvas = canvasRef.current!
+ const ctx = ctxRef.current!
+ ctx.clearRect(0, 0, canvas.width, canvas.height)
+ const mp3Blob = convertToMp3(recorder.current)
+ const mp3File = new File([mp3Blob], 'temp.mp3', { type: 'audio/mp3' })
+ const formData = new FormData()
+ formData.append('file', mp3File)
+ formData.append('word_timestamps', wordTimestamps || 'disabled')
+
+ let url = ''
+ let isPublic = false
+
+ if (params.token) {
+ url = '/audio-to-text'
+ isPublic = true
+ }
+ else if (params.appId) {
+ if (pathname.search('explore/installed') > -1)
+ url = `/installed-apps/${params.appId}/audio-to-text`
+ else
+ url = `/apps/${params.appId}/audio-to-text`
+ }
+
+ try {
+ const audioResponse = await audioToText(url, isPublic, formData)
+ onConverted(audioResponse.text)
+ onCancel()
+ }
+ catch {
+ onConverted('')
+ onCancel()
+ }
+ }, [clearInterval, onCancel, onConverted, params.appId, params.token, pathname, wordTimestamps])
+ const handleStartRecord = async () => {
+ try {
+ await recorder.current.start()
+ setStartRecord(true)
+ setStartConvert(false)
+
+ if (canvasRef.current && ctxRef.current)
+ drawRecord()
+ }
+ catch {
+ onCancel()
+ }
+ }
+
+ const initCanvas = () => {
+ const dpr = window.devicePixelRatio || 1
+ const canvas = document.getElementById('voice-input-record') as HTMLCanvasElement
+
+ if (canvas) {
+ const { width: cssWidth, height: cssHeight } = canvas.getBoundingClientRect()
+
+ canvas.width = dpr * cssWidth
+ canvas.height = dpr * cssHeight
+ canvasRef.current = canvas
+
+ const ctx = canvas.getContext('2d')
+ if (ctx) {
+ ctx.scale(dpr, dpr)
+ ctx.fillStyle = 'rgba(209, 224, 255, 1)'
+ ctxRef.current = ctx
+ }
+ }
+ }
+ if (originDuration >= 600 && startRecord)
+ handleStopRecorder()
+
+ useEffect(() => {
+ initCanvas()
+ handleStartRecord()
+ const recorderRef = recorder?.current
+ return () => {
+ recorderRef?.stop()
+ }
+ }, [])
+
+ const minutes = Number.parseInt(`${Number.parseInt(`${originDuration}`) / 60}`)
+ const seconds = Number.parseInt(`${originDuration}`) % 60
+
+ return (
+ <div className={cn(s.wrapper, 'absolute inset-0 rounded-xl')}>
+ <div className='absolute inset-[1.5px] flex items-center overflow-hidden rounded-[10.5px] bg-primary-25 py-[14px] pl-[14.5px] pr-[6.5px]'>
+ <canvas id='voice-input-record' className='absolute bottom-0 left-0 h-4 w-full' />
+ {
+ startConvert && <RiLoader2Line className='mr-2 h-4 w-4 animate-spin text-primary-700' />
+ }
+ <div className='grow'>
+ {
+ startRecord && (
+ <div className='text-sm text-gray-500'>
+ {t('common.voiceInput.speaking')}
+ </div>
+ )
+ }
+ {
+ startConvert && (
+ <div className={cn(s.convert, 'text-sm')}>
+ {t('common.voiceInput.converting')}
+ </div>
+ )
+ }
+ </div>
+ {
+ startRecord && (
+ <div
+ className='mr-1 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg hover:bg-primary-100'
+ onClick={handleStopRecorder}
+ >
+ <StopCircle className='h-5 w-5 text-primary-600' />
+ </div>
+ )
+ }
+ {
+ startConvert && (
+ <div
+ className='mr-1 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg hover:bg-gray-200'
+ onClick={onCancel}
+ >
+ <RiCloseLine className='h-4 w-4 text-gray-500' />
+ </div>
+ )
+ }
+ <div className={`w-[45px] pl-1 text-xs font-medium ${originDuration > 500 ? 'text-[#F04438]' : 'text-gray-700'}`}>{`0${minutes.toFixed(0)}:${seconds >= 10 ? seconds : `0${seconds}`}`}</div>
+ </div>
+ </div>
+ )
+}
+
+export default VoiceInput
diff --git a/app/components/base/voice-input/utils.ts b/app/components/base/voice-input/utils.ts
new file mode 100644
index 0000000..70133f4
--- /dev/null
+++ b/app/components/base/voice-input/utils.ts
@@ -0,0 +1,47 @@
+import lamejs from 'lamejs'
+import MPEGMode from 'lamejs/src/js/MPEGMode'
+import Lame from 'lamejs/src/js/Lame'
+import BitStream from 'lamejs/src/js/BitStream'
+
+if (globalThis) {
+ (globalThis as any).MPEGMode = MPEGMode
+ ;(globalThis as any).Lame = Lame
+ ;(globalThis as any).BitStream = BitStream
+}
+
+export const convertToMp3 = (recorder: any) => {
+ const wav = lamejs.WavHeader.readHeader(recorder.getWAV())
+ const { channels, sampleRate } = wav
+ const mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128)
+ const result = recorder.getChannelData()
+ const buffer = []
+
+ const leftData = result.left && new Int16Array(result.left.buffer, 0, result.left.byteLength / 2)
+ const rightData = result.right && new Int16Array(result.right.buffer, 0, result.right.byteLength / 2)
+ const remaining = leftData.length + (rightData ? rightData.length : 0)
+
+ const maxSamples = 1152
+ for (let i = 0; i < remaining; i += maxSamples) {
+ const left = leftData.subarray(i, i + maxSamples)
+ let right = null
+ let mp3buf = null
+
+ if (channels === 2) {
+ right = rightData.subarray(i, i + maxSamples)
+ mp3buf = mp3enc.encodeBuffer(left, right)
+ }
+ else {
+ mp3buf = mp3enc.encodeBuffer(left)
+ }
+
+ if (mp3buf.length > 0)
+ buffer.push(mp3buf)
+ }
+
+ const enc = mp3enc.flush()
+
+ if (enc.length > 0)
+ buffer.push(enc)
+
+ return new Blob(buffer, { type: 'audio/mp3' })
+}
diff --git a/app/components/base/with-input-validation/index.spec.tsx b/app/components/base/with-input-validation/index.spec.tsx
new file mode 100644
index 0000000..732a16d
--- /dev/null
+++ b/app/components/base/with-input-validation/index.spec.tsx
@@ -0,0 +1,41 @@
+import { render, screen } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import { z } from 'zod'
+import withValidation from '.'
+import { noop } from 'lodash-es'
+
+describe('withValidation HOC', () => {
+ // schema for validation
+ const schema = z.object({ name: z.string() })
+ type Props = z.infer<typeof schema> & {
+ age: number
+ }
+
+ const TestComponent = ({ name, age }: Props) => (
+ <div>{name} - {age}</div>
+ )
+ const WrappedComponent = withValidation(TestComponent, schema)
+
+ beforeAll(() => {
+ jest.spyOn(console, 'error').mockImplementation(noop)
+ })
+
+ afterAll(() => {
+ jest.restoreAllMocks()
+ })
+
+ it('renders the component when validation passes', () => {
+ render(<WrappedComponent name='Valid Name' age={30} />)
+ expect(screen.getByText('Valid Name - 30')).toBeInTheDocument()
+ })
+
+ it('renders the component when props is invalid but not in schema ', () => {
+ render(<WrappedComponent name='Valid Name' age={'aaa' as any} />)
+ expect(screen.getByText('Valid Name - aaa')).toBeInTheDocument()
+ })
+
+ it('does not render the component when validation fails', () => {
+ render(<WrappedComponent name={123 as any} age={30} />)
+ expect(screen.queryByText('123 - 30')).toBeNull()
+ })
+})
diff --git a/app/components/base/with-input-validation/index.tsx b/app/components/base/with-input-validation/index.tsx
new file mode 100644
index 0000000..6036b79
--- /dev/null
+++ b/app/components/base/with-input-validation/index.tsx
@@ -0,0 +1,24 @@
+'use client'
+import React from 'react'
+import type { ZodSchema } from 'zod'
+
+function withValidation<T extends Record<string, unknown>, K extends keyof T>(
+ WrappedComponent: React.ComponentType<T>,
+ schema: ZodSchema<Pick<T, K>>,
+) {
+ return function EnsuredComponent(props: T) {
+ const partialProps = Object.fromEntries(
+ Object.entries(props).filter(([key]) => key in (schema._def as any).shape),
+ ) as Pick<T, K>
+
+ const checkRes = schema.safeParse(partialProps)
+ if (!checkRes.success) {
+ console.error(checkRes.error)
+ // Maybe there is a better way to handle this, like error logic placeholder
+ return null
+ }
+ return <WrappedComponent {...props} />
+ }
+}
+
+export default withValidation
diff --git a/app/components/billing/annotation-full/index.tsx b/app/components/billing/annotation-full/index.tsx
new file mode 100644
index 0000000..88ed5f1
--- /dev/null
+++ b/app/components/billing/annotation-full/index.tsx
@@ -0,0 +1,31 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import UpgradeBtn from '../upgrade-btn'
+import Usage from './usage'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import GridMask from '@/app/components/base/grid-mask'
+
+const AnnotationFull: FC = () => {
+ const { t } = useTranslation()
+
+ return (
+ <GridMask wrapperClassName='rounded-lg' canvasClassName='rounded-lg' gradientClassName='rounded-lg'>
+ <div className='mt-6 flex cursor-pointer flex-col rounded-lg border-2 border-solid border-transparent px-3.5 py-4 shadow-md transition-all duration-200 ease-in-out'>
+ <div className='flex items-center justify-between'>
+ <div className={cn(s.textGradient, 'text-base font-semibold leading-[24px]')}>
+ <div>{t('billing.annotatedResponse.fullTipLine1')}</div>
+ <div>{t('billing.annotatedResponse.fullTipLine2')}</div>
+ </div>
+ <div className='flex'>
+ <UpgradeBtn loc={'annotation-create'} />
+ </div>
+ </div>
+ <Usage className='mt-4' />
+ </div>
+ </GridMask>
+ )
+}
+export default React.memo(AnnotationFull)
diff --git a/app/components/billing/annotation-full/modal.tsx b/app/components/billing/annotation-full/modal.tsx
new file mode 100644
index 0000000..324a4dc
--- /dev/null
+++ b/app/components/billing/annotation-full/modal.tsx
@@ -0,0 +1,47 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import UpgradeBtn from '../upgrade-btn'
+import Modal from '../../base/modal'
+import Usage from './usage'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import GridMask from '@/app/components/base/grid-mask'
+
+type Props = {
+ show: boolean
+ onHide: () => void
+}
+const AnnotationFullModal: FC<Props> = ({
+ show,
+ onHide,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <Modal
+ isShow={show}
+ onClose={onHide}
+ closable
+ className='!p-0'
+ >
+ <GridMask wrapperClassName='rounded-lg' canvasClassName='rounded-lg' gradientClassName='rounded-lg'>
+ <div className='mt-6 flex cursor-pointer flex-col rounded-lg border-2 border-solid border-transparent px-7 py-6 shadow-md transition-all duration-200 ease-in-out'>
+ <div className='flex items-center justify-between'>
+ <div className={cn(s.textGradient, 'text-[18px] font-semibold leading-[27px]')}>
+ <div>{t('billing.annotatedResponse.fullTipLine1')}</div>
+ <div>{t('billing.annotatedResponse.fullTipLine2')}</div>
+ </div>
+
+ </div>
+ <Usage className='mt-4' />
+ <div className='mt-7 flex justify-end'>
+ <UpgradeBtn loc={'annotation-create'} />
+ </div>
+ </div>
+ </GridMask>
+ </Modal>
+ )
+}
+export default React.memo(AnnotationFullModal)
diff --git a/app/components/billing/annotation-full/style.module.css b/app/components/billing/annotation-full/style.module.css
new file mode 100644
index 0000000..15bedd8
--- /dev/null
+++ b/app/components/billing/annotation-full/style.module.css
@@ -0,0 +1,7 @@
+.textGradient {
+ background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ text-fill-color: transparent;
+}
diff --git a/app/components/billing/annotation-full/usage.tsx b/app/components/billing/annotation-full/usage.tsx
new file mode 100644
index 0000000..44a97de
--- /dev/null
+++ b/app/components/billing/annotation-full/usage.tsx
@@ -0,0 +1,32 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { MessageFastPlus } from '../../base/icons/src/vender/line/communication'
+import UsageInfo from '../usage-info'
+import { useProviderContext } from '@/context/provider-context'
+
+type Props = {
+ className?: string
+}
+
+const Usage: FC<Props> = ({
+ className,
+}) => {
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+ const {
+ usage,
+ total,
+ } = plan
+ return (
+ <UsageInfo
+ className={className}
+ Icon={MessageFastPlus}
+ name={t('billing.annotatedResponse.quotaTitle')}
+ usage={usage.annotatedResponse}
+ total={total.annotatedResponse}
+ />
+ )
+}
+export default React.memo(Usage)
diff --git a/app/components/billing/apps-full-in-dialog/index.tsx b/app/components/billing/apps-full-in-dialog/index.tsx
new file mode 100644
index 0000000..b721b94
--- /dev/null
+++ b/app/components/billing/apps-full-in-dialog/index.tsx
@@ -0,0 +1,84 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import UpgradeBtn from '../upgrade-btn'
+import ProgressBar from '@/app/components/billing/progress-bar'
+import Button from '@/app/components/base/button'
+import { mailToSupport } from '@/app/components/header/utils/util'
+import { useProviderContext } from '@/context/provider-context'
+import { useAppContext } from '@/context/app-context'
+import { Plan } from '@/app/components/billing/type'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+
+const LOW = 50
+const MIDDLE = 80
+
+const AppsFull: FC<{ loc: string; className?: string; }> = ({
+ loc,
+ className,
+}) => {
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+ const { userProfile, langeniusVersionInfo } = useAppContext()
+ const isTeam = plan.type === Plan.team
+ const usage = plan.usage.buildApps
+ const total = plan.total.buildApps
+ const percent = usage / total * 100
+ const color = (() => {
+ if (percent < LOW)
+ return 'bg-components-progress-bar-progress-solid'
+
+ if (percent < MIDDLE)
+ return 'bg-components-progress-warning-progress'
+
+ return 'bg-components-progress-error-progress'
+ })()
+ return (
+ <div className={cn(
+ 'flex flex-col gap-3 rounded-xl border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg p-4 shadow-xs backdrop-blur-sm',
+ className,
+ )}>
+ <div className='flex justify-between'>
+ {!isTeam && (
+ <div>
+ <div className={cn('title-xl-semi-bold mb-1', s.textGradient)}>
+ {t('billing.apps.fullTip1')}
+ </div>
+ <div className='system-xs-regular text-text-tertiary'>{t('billing.apps.fullTip1des')}</div>
+ </div>
+ )}
+ {isTeam && (
+ <div>
+ <div className={cn('title-xl-semi-bold mb-1', s.textGradient)}>
+ {t('billing.apps.fullTip2')}
+ </div>
+ <div className='system-xs-regular text-text-tertiary'>{t('billing.apps.fullTip2des')}</div>
+ </div>
+ )}
+ {(plan.type === Plan.sandbox || plan.type === Plan.professional) && (
+ <UpgradeBtn isShort loc={loc} />
+ )}
+ {plan.type !== Plan.sandbox && plan.type !== Plan.professional && (
+ <Button variant='secondary-accent'>
+ <a target='_blank' rel='noopener noreferrer' href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)}>
+ {t('billing.apps.contactUs')}
+ </a>
+ </Button>
+ )}
+ </div>
+ <div className='flex flex-col gap-2'>
+ <div className='system-xs-medium flex items-center justify-between text-text-secondary'>
+ <div>{t('billing.usagePage.buildApps')}</div>
+ <div>{usage}/{total}</div>
+ </div>
+ <ProgressBar
+ percent={percent}
+ color={color}
+ />
+ </div>
+ </div>
+ )
+}
+export default React.memo(AppsFull)
diff --git a/app/components/billing/apps-full-in-dialog/style.module.css b/app/components/billing/apps-full-in-dialog/style.module.css
new file mode 100644
index 0000000..1f68e66
--- /dev/null
+++ b/app/components/billing/apps-full-in-dialog/style.module.css
@@ -0,0 +1,7 @@
+.textGradient {
+ background: linear-gradient(92deg, #0EBCF3 -29.55%, #2250F2 75.22%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ text-fill-color: transparent;
+}
diff --git a/app/components/billing/billing-page/index.tsx b/app/components/billing/billing-page/index.tsx
new file mode 100644
index 0000000..43e80f4
--- /dev/null
+++ b/app/components/billing/billing-page/index.tsx
@@ -0,0 +1,40 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import {
+ RiArrowRightUpLine,
+} from '@remixicon/react'
+import PlanComp from '../plan'
+import Divider from '@/app/components/base/divider'
+import { fetchBillingUrl } from '@/service/billing'
+import { useAppContext } from '@/context/app-context'
+import { useProviderContext } from '@/context/provider-context'
+
+const Billing: FC = () => {
+ const { t } = useTranslation()
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const { enableBilling } = useProviderContext()
+ const { data: billingUrl } = useSWR(
+ (!enableBilling || !isCurrentWorkspaceManager) ? null : ['/billing/invoices'],
+ () => fetchBillingUrl().then(data => data.url),
+ )
+
+ return (
+ <div>
+ <PlanComp loc={'billing-page'} />
+ {enableBilling && isCurrentWorkspaceManager && billingUrl && (
+ <>
+ <Divider className='my-4' />
+ <a className='system-xs-medium flex cursor-pointer items-center text-text-accent-light-mode-only' href={billingUrl} target='_blank' rel='noopener noreferrer'>
+ <span className='pr-0.5'>{t('billing.viewBilling')}</span>
+ <RiArrowRightUpLine className='h-4 w-4' />
+ </a>
+ </>
+ )}
+ </div>
+ )
+}
+
+export default React.memo(Billing)
diff --git a/app/components/billing/config.ts b/app/components/billing/config.ts
new file mode 100644
index 0000000..1d5fbc7
--- /dev/null
+++ b/app/components/billing/config.ts
@@ -0,0 +1,86 @@
+import type { BasicPlan } from '@/app/components/billing/type'
+import { Plan, type PlanInfo, Priority } from '@/app/components/billing/type'
+
+const supportModelProviders = 'OpenAI/Anthropic/Llama2/Azure OpenAI/Hugging Face/Replicate'
+
+export const NUM_INFINITE = 99999999
+export const contractSales = 'contractSales'
+export const unAvailable = 'unAvailable'
+
+export const contactSalesUrl = 'https://vikgc6bnu1s.typeform.com/dify-business'
+export const getStartedWithCommunityUrl = 'https://github.com/langgenius/dify'
+export const getWithPremiumUrl = 'https://aws.amazon.com/marketplace/pp/prodview-t22mebxzwjhu6'
+
+export const ALL_PLANS: Record<BasicPlan, PlanInfo> = {
+ sandbox: {
+ level: 1,
+ price: 0,
+ modelProviders: supportModelProviders,
+ teamWorkspace: 1,
+ teamMembers: 1,
+ buildApps: 5,
+ documents: 50,
+ vectorSpace: '50MB',
+ documentsUploadQuota: 0,
+ documentsRequestQuota: 10,
+ apiRateLimit: 5000,
+ documentProcessingPriority: Priority.standard,
+ messageRequest: 200,
+ annotatedResponse: 10,
+ logHistory: 30,
+ },
+ professional: {
+ level: 2,
+ price: 59,
+ modelProviders: supportModelProviders,
+ teamWorkspace: 1,
+ teamMembers: 3,
+ buildApps: 50,
+ documents: 500,
+ vectorSpace: '5GB',
+ documentsUploadQuota: 0,
+ documentsRequestQuota: 100,
+ apiRateLimit: NUM_INFINITE,
+ documentProcessingPriority: Priority.priority,
+ messageRequest: 5000,
+ annotatedResponse: 2000,
+ logHistory: NUM_INFINITE,
+ },
+ team: {
+ level: 3,
+ price: 159,
+ modelProviders: supportModelProviders,
+ teamWorkspace: 1,
+ teamMembers: 50,
+ buildApps: 200,
+ documents: 1000,
+ vectorSpace: '20GB',
+ documentsUploadQuota: 0,
+ documentsRequestQuota: 1000,
+ apiRateLimit: NUM_INFINITE,
+ documentProcessingPriority: Priority.topPriority,
+ messageRequest: 10000,
+ annotatedResponse: 5000,
+ logHistory: NUM_INFINITE,
+ },
+}
+
+export const defaultPlan = {
+ type: Plan.sandbox as BasicPlan,
+ usage: {
+ documents: 50,
+ vectorSpace: 1,
+ buildApps: 1,
+ teamMembers: 1,
+ annotatedResponse: 1,
+ documentsUploadQuota: 0,
+ },
+ total: {
+ documents: 50,
+ vectorSpace: 10,
+ buildApps: 10,
+ teamMembers: 1,
+ annotatedResponse: 10,
+ documentsUploadQuota: 0,
+ },
+}
diff --git a/app/components/billing/header-billing-btn/index.tsx b/app/components/billing/header-billing-btn/index.tsx
new file mode 100644
index 0000000..f34fa0b
--- /dev/null
+++ b/app/components/billing/header-billing-btn/index.tsx
@@ -0,0 +1,60 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import UpgradeBtn from '../upgrade-btn'
+import { Plan } from '../type'
+import cn from '@/utils/classnames'
+import { useProviderContext } from '@/context/provider-context'
+
+type Props = {
+ onClick?: () => void
+ isDisplayOnly?: boolean
+}
+
+const HeaderBillingBtn: FC<Props> = ({
+ onClick,
+ isDisplayOnly = false,
+}) => {
+ const { plan, enableBilling, isFetchedPlan } = useProviderContext()
+ const {
+ type,
+ } = plan
+
+ const name = (() => {
+ if (type === Plan.professional)
+ return 'pro'
+ return type
+ })()
+ const classNames = (() => {
+ if (type === Plan.professional)
+ return `border-[#E0F2FE] ${!isDisplayOnly ? 'hover:border-[#B9E6FE]' : ''} bg-[#E0F2FE] text-[#026AA2]`
+ if (type === Plan.team)
+ return `border-[#E0EAFF] ${!isDisplayOnly ? 'hover:border-[#C7D7FE]' : ''} bg-[#E0EAFF] text-[#3538CD]`
+ return ''
+ })()
+
+ if (!enableBilling || !isFetchedPlan)
+ return null
+
+ if (type === Plan.sandbox)
+ return <UpgradeBtn onClick={isDisplayOnly ? undefined : onClick} isShort />
+
+ const handleClick = () => {
+ if (!isDisplayOnly && onClick)
+ onClick()
+ }
+
+ return (
+ <div
+ onClick={handleClick}
+ className={cn(
+ classNames,
+ 'flex h-[22px] items-center rounded-md border px-2 text-xs font-semibold uppercase',
+ isDisplayOnly ? 'cursor-default' : 'cursor-pointer',
+ )}
+ >
+ {name}
+ </div>
+ )
+}
+export default React.memo(HeaderBillingBtn)
diff --git a/app/components/billing/plan/index.tsx b/app/components/billing/plan/index.tsx
new file mode 100644
index 0000000..7badb36
--- /dev/null
+++ b/app/components/billing/plan/index.tsx
@@ -0,0 +1,137 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { useRouter } from 'next/navigation'
+import {
+ RiBook2Line,
+ RiBox3Line,
+ RiFileEditLine,
+ RiGraduationCapLine,
+ RiGroup3Line,
+ RiGroupLine,
+ RiSquareLine,
+} from '@remixicon/react'
+import { Plan, SelfHostedPlan } from '../type'
+import VectorSpaceInfo from '../usage-info/vector-space-info'
+import AppsInfo from '../usage-info/apps-info'
+import UpgradeBtn from '../upgrade-btn'
+import { useProviderContext } from '@/context/provider-context'
+import { useAppContext } from '@/context/app-context'
+import Button from '@/app/components/base/button'
+import UsageInfo from '@/app/components/billing/usage-info'
+import VerifyStateModal from '@/app/education-apply/verify-state-modal'
+import { EDUCATION_VERIFYING_LOCALSTORAGE_ITEM } from '@/app/education-apply/constants'
+import { useEducationVerify } from '@/service/use-education'
+import { useModalContextSelector } from '@/context/modal-context'
+
+type Props = {
+ loc: string
+}
+
+const PlanComp: FC<Props> = ({
+ loc,
+}) => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const { userProfile } = useAppContext()
+ const { plan, enableEducationPlan, isEducationAccount } = useProviderContext()
+ const {
+ type,
+ } = plan
+
+ const {
+ usage,
+ total,
+ } = plan
+
+ const [showModal, setShowModal] = React.useState(false)
+ const { mutateAsync } = useEducationVerify()
+ const setShowAccountSettingModal = useModalContextSelector(s => s.setShowAccountSettingModal)
+ const handleVerify = () => {
+ mutateAsync().then((res) => {
+ localStorage.removeItem(EDUCATION_VERIFYING_LOCALSTORAGE_ITEM)
+ router.push(`/education-apply?token=${res.token}`)
+ setShowAccountSettingModal(null)
+ }).catch(() => {
+ setShowModal(true)
+ })
+ }
+ return (
+ <div className='rounded-2xl border-[0.5px] border-effects-highlight-lightmode-off bg-background-section-burn'>
+ <div className='p-6 pb-2'>
+ {plan.type === Plan.sandbox && (
+ <RiBox3Line className='h-7 w-7 text-text-primary'/>
+ )}
+ {plan.type === Plan.professional && (
+ <RiSquareLine className='h-7 w-7 rotate-90 text-util-colors-blue-brand-blue-brand-600'/>
+ )}
+ {plan.type === Plan.team && (
+ <RiGroup3Line className='h-7 w-7 text-util-colors-indigo-indigo-600'/>
+ )}
+ {(plan.type as any) === SelfHostedPlan.enterprise && (
+ <RiGroup3Line className='h-7 w-7 text-util-colors-indigo-indigo-600'/>
+ )}
+ <div className='mt-1 flex items-center'>
+ <div className='grow'>
+ <div className='mb-1 flex items-center gap-1'>
+ <div className='system-md-semibold-uppercase text-text-primary'>{t(`billing.plans.${type}.name`)}</div>
+ <div className='system-2xs-medium-uppercase rounded-[5px] border border-divider-deep px-1 py-0.5 text-text-tertiary'>{t('billing.currentPlan')}</div>
+ </div>
+ <div className='system-xs-regular text-util-colors-gray-gray-600'>{t(`billing.plans.${type}.for`)}</div>
+ </div>
+ <div className='flex shrink-0 items-center gap-1'>
+ {enableEducationPlan && !isEducationAccount && (
+ <Button variant='ghost' onClick={handleVerify}>
+ <RiGraduationCapLine className='mr-1 h-4 w-4'/>
+ {t('education.toVerified')}
+ </Button>
+ )}
+ {(plan.type as any) !== SelfHostedPlan.enterprise && (
+ <UpgradeBtn
+ className='shrink-0'
+ isPlain={type === Plan.team}
+ isShort
+ loc={loc}
+ />
+ )}
+ </div>
+ </div>
+ </div>
+ {/* Plan detail */}
+ <div className='grid grid-cols-3 content-start gap-1 p-2'>
+ <AppsInfo />
+ <UsageInfo
+ Icon={RiGroupLine}
+ name={t('billing.usagePage.teamMembers')}
+ usage={usage.teamMembers}
+ total={total.teamMembers}
+ />
+ <UsageInfo
+ Icon={RiBook2Line}
+ name={t('billing.usagePage.documentsUploadQuota')}
+ usage={usage.documentsUploadQuota}
+ total={total.documentsUploadQuota}
+ />
+ <VectorSpaceInfo />
+ <UsageInfo
+ Icon={RiFileEditLine}
+ name={t('billing.usagePage.annotationQuota')}
+ usage={usage.annotatedResponse}
+ total={total.annotatedResponse}
+ />
+
+ </div>
+ <VerifyStateModal
+ showLink
+ email={userProfile.email}
+ isShow={showModal}
+ title={t('education.rejectTitle')}
+ content={t('education.rejectContent')}
+ onConfirm={() => setShowModal(false)}
+ onCancel={() => setShowModal(false)}
+ />
+ </div>
+ )
+}
+export default React.memo(PlanComp)
diff --git a/app/components/billing/pricing/index.tsx b/app/components/billing/pricing/index.tsx
new file mode 100644
index 0000000..0516794
--- /dev/null
+++ b/app/components/billing/pricing/index.tsx
@@ -0,0 +1,146 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { createPortal } from 'react-dom'
+import { useTranslation } from 'react-i18next'
+import { RiArrowRightUpLine, RiCloseLine, RiCloudFill, RiTerminalBoxFill } from '@remixicon/react'
+import Link from 'next/link'
+import { useKeyPress } from 'ahooks'
+import { Plan, SelfHostedPlan } from '../type'
+import TabSlider from '../../base/tab-slider'
+import SelectPlanRange, { PlanRange } from './select-plan-range'
+import PlanItem from './plan-item'
+import SelfHostedPlanItem from './self-hosted-plan-item'
+import { useProviderContext } from '@/context/provider-context'
+import GridMask from '@/app/components/base/grid-mask'
+import { useAppContext } from '@/context/app-context'
+import classNames from '@/utils/classnames'
+import { useGetPricingPageLanguage } from '@/context/i18n'
+
+type Props = {
+ onCancel: () => void
+}
+
+const Pricing: FC<Props> = ({
+ onCancel,
+}) => {
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const canPay = isCurrentWorkspaceManager
+ const [planRange, setPlanRange] = React.useState<PlanRange>(PlanRange.monthly)
+
+ const [currentPlan, setCurrentPlan] = React.useState<string>('cloud')
+
+ useKeyPress(['esc'], onCancel)
+
+ const pricingPageLanguage = useGetPricingPageLanguage()
+ const pricingPageURL = pricingPageLanguage
+ ? `https://dify.ai/${pricingPageLanguage}/pricing#plans-and-features`
+ : 'https://dify.ai/pricing#plans-and-features'
+
+ return createPortal(
+ <div
+ className='fixed inset-0 bottom-0 left-0 right-0 top-0 z-[1000] bg-background-overlay-backdrop p-4 backdrop-blur-[6px]'
+ onClick={e => e.stopPropagation()}
+ >
+ <div className='relative h-full w-full overflow-auto rounded-2xl border border-effects-highlight bg-saas-background'>
+ <div
+ className='fixed right-7 top-7 z-[1001] flex h-9 w-9 cursor-pointer items-center justify-center rounded-[10px] bg-components-button-tertiary-bg hover:bg-components-button-tertiary-bg-hover'
+ onClick={onCancel}
+ >
+ <RiCloseLine className='size-5 text-components-button-tertiary-text' />
+ </div>
+ <GridMask wrapperClassName='w-full min-h-full' canvasClassName='min-h-full'>
+ <div className='flex flex-col items-center px-8 pb-7 pt-12'>
+ <div className='title-5xl-bold mb-2 text-text-primary'>
+ {t('billing.plansCommon.title')}
+ </div>
+ <div className='system-sm-regular text-text-secondary'>
+ <span>{t('billing.plansCommon.freeTrialTipPrefix')}</span>
+ <span className='text-gradient font-semibold'>{t('billing.plansCommon.freeTrialTip')}</span>
+ <span>{t('billing.plansCommon.freeTrialTipSuffix')}</span>
+ </div>
+ </div>
+ <div className='mx-auto w-[1152px]'>
+ <div className='flex h-[64px] items-center justify-between py-2'>
+ <TabSlider
+ value={currentPlan}
+ className='inline-flex'
+ options={[
+ {
+ value: 'cloud',
+ text: <div className={
+ classNames('inline-flex items-center system-md-semibold-uppercase text-text-secondary',
+ currentPlan === 'cloud' && 'text-text-accent-light-mode-only')} >
+ <RiCloudFill className='mr-2 size-4' />{t('billing.plansCommon.cloud')}</div>,
+ },
+ {
+ value: 'self',
+ text: <div className={
+ classNames('inline-flex items-center system-md-semibold-uppercase text-text-secondary',
+ currentPlan === 'self' && 'text-text-accent-light-mode-only')}>
+ <RiTerminalBoxFill className='mr-2 size-4' />{t('billing.plansCommon.self')}</div>,
+ }]}
+ onChange={v => setCurrentPlan(v)} />
+
+ {currentPlan === 'cloud' && <SelectPlanRange
+ value={planRange}
+ onChange={setPlanRange}
+ />}
+ </div>
+ <div className='pb-8 pt-3'>
+ <div className='flex flex-nowrap justify-center gap-x-4'>
+ {currentPlan === 'cloud' && <>
+ <PlanItem
+ currentPlan={plan.type}
+ plan={Plan.sandbox}
+ planRange={planRange}
+ canPay={canPay}
+ />
+ <PlanItem
+ currentPlan={plan.type}
+ plan={Plan.professional}
+ planRange={planRange}
+ canPay={canPay}
+ />
+ <PlanItem
+ currentPlan={plan.type}
+ plan={Plan.team}
+ planRange={planRange}
+ canPay={canPay}
+ />
+ </>}
+ {currentPlan === 'self' && <>
+ <SelfHostedPlanItem
+ plan={SelfHostedPlan.community}
+ planRange={planRange}
+ canPay={canPay}
+ />
+ <SelfHostedPlanItem
+ plan={SelfHostedPlan.premium}
+ planRange={planRange}
+ canPay={canPay}
+ />
+ <SelfHostedPlanItem
+ plan={SelfHostedPlan.enterprise}
+ planRange={planRange}
+ canPay={canPay}
+ />
+ </>}
+ </div>
+ </div>
+ </div>
+ <div className='flex items-center justify-center py-4'>
+ <div className='flex items-center justify-center gap-x-0.5 rounded-lg px-3 py-2 text-components-button-secondary-accent-text hover:cursor-pointer hover:bg-state-accent-hover'>
+ <Link href={pricingPageURL} className='system-sm-medium'>{t('billing.plansCommon.comparePlanAndFeatures')}</Link>
+ <RiArrowRightUpLine className='size-4' />
+ </div>
+ </div>
+ </GridMask>
+ </div >
+ </div >,
+ document.body,
+ )
+}
+export default React.memo(Pricing)
diff --git a/app/components/billing/pricing/plan-item.tsx b/app/components/billing/pricing/plan-item.tsx
new file mode 100644
index 0000000..07af0ff
--- /dev/null
+++ b/app/components/billing/pricing/plan-item.tsx
@@ -0,0 +1,235 @@
+'use client'
+import type { FC, ReactNode } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiApps2Line, RiBook2Line, RiBrain2Line, RiChatAiLine, RiFileEditLine, RiFolder6Line, RiGroupLine, RiHardDrive3Line, RiHistoryLine, RiProgress3Line, RiQuestionLine, RiSeoLine, RiTerminalBoxLine } from '@remixicon/react'
+import type { BasicPlan } from '../type'
+import { Plan } from '../type'
+import { ALL_PLANS, NUM_INFINITE } from '../config'
+import Toast from '../../base/toast'
+import Tooltip from '../../base/tooltip'
+import Divider from '../../base/divider'
+import { ArCube1, Group2, Keyframe, SparklesSoft } from '../../base/icons/src/public/billing'
+import { PlanRange } from './select-plan-range'
+import cn from '@/utils/classnames'
+import { useAppContext } from '@/context/app-context'
+import { fetchSubscriptionUrls } from '@/service/billing'
+
+type Props = {
+ currentPlan: BasicPlan
+ plan: BasicPlan
+ planRange: PlanRange
+ canPay: boolean
+}
+
+const KeyValue = ({ icon, label, tooltip }: { icon: ReactNode; label: string; tooltip?: ReactNode }) => {
+ return (
+ <div className='flex text-text-tertiary'>
+ <div className='flex size-4 items-center justify-center'>
+ {icon}
+ </div>
+ <div className='system-sm-regular ml-2 mr-0.5 text-text-primary'>{label}</div>
+ {tooltip && (
+ <Tooltip
+ asChild
+ popupContent={tooltip}
+ popupClassName='w-[200px]'
+ >
+ <div className='flex size-4 items-center justify-center'>
+ <RiQuestionLine className='text-text-quaternary' />
+ </div>
+ </Tooltip>
+ )}
+ </div>
+ )
+}
+
+const priceClassName = 'leading-[125%] text-[28px] font-bold text-text-primary'
+const style = {
+ [Plan.sandbox]: {
+ icon: <ArCube1 className='size-7 text-text-primary' />,
+ description: 'text-util-colors-gray-gray-600',
+ btnStyle: 'bg-components-button-secondary-bg hover:bg-components-button-secondary-bg-hover border-[0.5px] border-components-button-secondary-border text-text-primary',
+ btnDisabledStyle: 'bg-components-button-secondary-bg-disabled hover:bg-components-button-secondary-bg-disabled border-components-button-secondary-border-disabled text-components-button-secondary-text-disabled',
+ },
+ [Plan.professional]: {
+ icon: <Keyframe className='size-7 text-util-colors-blue-brand-blue-brand-600' />,
+ description: 'text-util-colors-blue-brand-blue-brand-600',
+ btnStyle: 'bg-components-button-primary-bg hover:bg-components-button-primary-bg-hover border border-components-button-primary-border text-components-button-primary-text',
+ btnDisabledStyle: 'bg-components-button-primary-bg-disabled hover:bg-components-button-primary-bg-disabled border-components-button-primary-border-disabled text-components-button-primary-text-disabled',
+ },
+ [Plan.team]: {
+ icon: <Group2 className='size-7 text-util-colors-indigo-indigo-600' />,
+ description: 'text-util-colors-indigo-indigo-600',
+ btnStyle: 'bg-components-button-indigo-bg hover:bg-components-button-indigo-bg-hover border border-components-button-primary-border text-components-button-primary-text',
+ btnDisabledStyle: 'bg-components-button-indigo-bg-disabled hover:bg-components-button-indigo-bg-disabled border-components-button-indigo-border-disabled text-components-button-primary-text-disabled',
+ },
+}
+const PlanItem: FC<Props> = ({
+ plan,
+ currentPlan,
+ planRange,
+}) => {
+ const { t } = useTranslation()
+ const [loading, setLoading] = React.useState(false)
+ const i18nPrefix = `billing.plans.${plan}`
+ const isFreePlan = plan === Plan.sandbox
+ const isMostPopularPlan = plan === Plan.professional
+ const planInfo = ALL_PLANS[plan]
+ const isYear = planRange === PlanRange.yearly
+ const isCurrent = plan === currentPlan
+ const isPlanDisabled = planInfo.level <= ALL_PLANS[currentPlan].level
+ const { isCurrentWorkspaceManager } = useAppContext()
+
+ const btnText = (() => {
+ if (isCurrent)
+ return t('billing.plansCommon.currentPlan')
+
+ return ({
+ [Plan.sandbox]: t('billing.plansCommon.startForFree'),
+ [Plan.professional]: t('billing.plansCommon.getStarted'),
+ [Plan.team]: t('billing.plansCommon.getStarted'),
+ })[plan]
+ })()
+
+ const handleGetPayUrl = async () => {
+ if (loading)
+ return
+
+ if (isPlanDisabled)
+ return
+
+ if (isFreePlan)
+ return
+
+ // Only workspace manager can buy plan
+ if (!isCurrentWorkspaceManager) {
+ Toast.notify({
+ type: 'error',
+ message: t('billing.buyPermissionDeniedTip'),
+ className: 'z-[1001]',
+ })
+ return
+ }
+ setLoading(true)
+ try {
+ const res = await fetchSubscriptionUrls(plan, isYear ? 'year' : 'month')
+ // Adb Block additional tracking block the gtag, so we need to redirect directly
+ window.location.href = res.url
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+ return (
+ <div className={cn('flex w-[373px] flex-col rounded-2xl border-[0.5px] border-effects-highlight-lightmode-off bg-background-section-burn p-6',
+ isMostPopularPlan ? 'border-effects-highlight shadow-lg backdrop-blur-[5px]' : 'hover:border-effects-highlight hover:shadow-lg hover:backdrop-blur-[5px]',
+ )}>
+ <div className='flex flex-col gap-y-1'>
+ {style[plan].icon}
+ <div className='flex items-center'>
+ <div className='grow text-lg font-semibold uppercase leading-[125%] text-text-primary'>{t(`${i18nPrefix}.name`)}</div>
+ {isMostPopularPlan && <div className='ml-1 flex shrink-0 items-center justify-center rounded-full border-[0.5px] bg-price-premium-badge-background px-1 py-[3px] text-components-premium-badge-grey-text-stop-0 shadow-xs'>
+ <div className='pl-0.5'>
+ <SparklesSoft className='size-3' />
+ </div>
+ <span className='system-2xs-semibold-uppercase bg-price-premium-text-background bg-clip-text px-0.5 text-transparent'>{t('billing.plansCommon.mostPopular')}</span>
+ </div>}
+ </div>
+ <div className={cn(style[plan].description, 'system-sm-regular')}>{t(`${i18nPrefix}.description`)}</div>
+ </div>
+ <div className='my-5'>
+ {/* Price */}
+ {isFreePlan && (
+ <div className={priceClassName}>{t('billing.plansCommon.free')}</div>
+ )}
+ {!isFreePlan && (
+ <div className='flex items-end'>
+ <div className={priceClassName}>${isYear ? planInfo.price * 10 : planInfo.price}</div>
+ <div className='ml-1 flex flex-col'>
+ {isYear && <div className='text-[14px] font-normal italic leading-[14px] text-text-warning'>{t('billing.plansCommon.save')}${planInfo.price * 2}</div>}
+ <div className='text-[14px] font-normal leading-normal text-text-tertiary'>
+ {t('billing.plansCommon.priceTip')}
+ {t(`billing.plansCommon.${!isYear ? 'month' : 'year'}`)}</div>
+ </div>
+ </div>
+ )}
+ </div>
+
+ <div
+ className={cn('flex h-[42px] items-center justify-center rounded-full px-5 py-3',
+ style[plan].btnStyle,
+ isPlanDisabled && style[plan].btnDisabledStyle,
+ isPlanDisabled ? 'cursor-not-allowed' : 'cursor-pointer')}
+ onClick={handleGetPayUrl}
+ >
+ {btnText}
+ </div>
+ <div className='mt-6 flex flex-col gap-y-3'>
+ <KeyValue
+ icon={<RiChatAiLine />}
+ label={isFreePlan
+ ? t('billing.plansCommon.messageRequest.title', { count: planInfo.messageRequest })
+ : t('billing.plansCommon.messageRequest.titlePerMonth', { count: planInfo.messageRequest })}
+ tooltip={t('billing.plansCommon.messageRequest.tooltip') as string}
+ />
+ <KeyValue
+ icon={<RiBrain2Line />}
+ label={t('billing.plansCommon.modelProviders')}
+ />
+ <KeyValue
+ icon={<RiFolder6Line />}
+ label={t('billing.plansCommon.teamWorkspace', { count: planInfo.teamWorkspace })}
+ />
+ <KeyValue
+ icon={<RiGroupLine />}
+ label={t('billing.plansCommon.teamMember', { count: planInfo.teamMembers })}
+ />
+ <KeyValue
+ icon={<RiApps2Line />}
+ label={t('billing.plansCommon.buildApps', { count: planInfo.buildApps })}
+ />
+ <Divider bgStyle='gradient' />
+ <KeyValue
+ icon={<RiBook2Line />}
+ label={t('billing.plansCommon.documents', { count: planInfo.documents })}
+ tooltip={t('billing.plansCommon.documentsTooltip') as string}
+ />
+ <KeyValue
+ icon={<RiHardDrive3Line />}
+ label={t('billing.plansCommon.vectorSpace', { size: planInfo.vectorSpace })}
+ tooltip={t('billing.plansCommon.vectorSpaceTooltip') as string}
+ />
+
+ <KeyValue
+ icon={<RiSeoLine />}
+ label={t('billing.plansCommon.documentsRequestQuota', { count: planInfo.documentsRequestQuota })}
+ tooltip={t('billing.plansCommon.documentsRequestQuotaTooltip')}
+ />
+ <KeyValue
+ icon={<RiTerminalBoxLine />}
+ label={
+ planInfo.apiRateLimit === NUM_INFINITE ? `${t('billing.plansCommon.unlimitedApiRate')}`
+ : `${t('billing.plansCommon.apiRateLimitUnit', { count: planInfo.apiRateLimit })} ${t('billing.plansCommon.apiRateLimit')}`
+ }
+ tooltip={planInfo.apiRateLimit === NUM_INFINITE ? null : t('billing.plansCommon.apiRateLimitTooltip') as string}
+ />
+ <KeyValue
+ icon={<RiProgress3Line />}
+ label={[t(`billing.plansCommon.priority.${planInfo.documentProcessingPriority}`), t('billing.plansCommon.documentProcessingPriority')].join('')}
+ />
+ <Divider bgStyle='gradient' />
+ <KeyValue
+ icon={<RiFileEditLine />}
+ label={t('billing.plansCommon.annotatedResponse.title', { count: planInfo.annotatedResponse })}
+ tooltip={t('billing.plansCommon.annotatedResponse.tooltip') as string}
+ />
+ <KeyValue
+ icon={<RiHistoryLine />}
+ label={t('billing.plansCommon.logsHistory', { days: planInfo.logHistory === NUM_INFINITE ? t('billing.plansCommon.unlimited') as string : `${planInfo.logHistory} ${t('billing.plansCommon.days')}` })}
+ />
+ </div>
+ </div>
+ )
+}
+export default React.memo(PlanItem)
diff --git a/app/components/billing/pricing/select-plan-range.tsx b/app/components/billing/pricing/select-plan-range.tsx
new file mode 100644
index 0000000..e7b06cb
--- /dev/null
+++ b/app/components/billing/pricing/select-plan-range.tsx
@@ -0,0 +1,54 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Switch from '../../base/switch'
+export enum PlanRange {
+ monthly = 'monthly',
+ yearly = 'yearly',
+}
+
+type Props = {
+ value: PlanRange
+ onChange: (value: PlanRange) => void
+}
+
+const ArrowIcon = (
+ <svg xmlns="http://www.w3.org/2000/svg" width="22" height="29" viewBox="0 0 22 29" fill="none">
+ <g clipPath="url(#clip0_394_43518)">
+ <path d="M2.11312 1.64777C2.11312 1.64777 2.10178 1.64849 2.09045 1.6492C2.06211 1.65099 2.08478 1.64956 2.11312 1.64777ZM9.047 20.493C9.43106 19.9965 8.97268 19.2232 8.35639 19.2848C7.72208 19.4215 6.27243 20.3435 5.13995 20.8814C4.2724 21.3798 3.245 21.6892 2.54015 22.4221C1.87751 23.2831 2.70599 23.9706 3.47833 24.3088C4.73679 24.9578 6.00624 25.6004 7.25975 26.2611C8.4424 26.8807 9.57833 27.5715 10.7355 28.2383C10.9236 28.3345 11.1464 28.3489 11.3469 28.2794C11.9886 28.0796 12.0586 27.1137 11.4432 26.8282C9.83391 25.8485 8.17365 24.9631 6.50314 24.0955C8.93023 24.2384 11.3968 24.1058 13.5161 22.7945C16.6626 20.8097 19.0246 17.5714 20.2615 14.0854C22.0267 8.96164 18.9313 4.08153 13.9897 2.40722C10.5285 1.20289 6.76599 0.996166 3.14837 1.46306C2.50624 1.56611 2.68616 1.53201 2.10178 1.64849C2.12445 1.64706 2.14712 1.64563 2.16979 1.6442C2.01182 1.66553 1.86203 1.72618 1.75582 1.84666C1.48961 2.13654 1.58903 2.63096 1.9412 2.80222C2.19381 2.92854 2.4835 2.83063 2.74986 2.81385C3.7267 2.69541 4.70711 2.63364 5.69109 2.62853C8.30015 2.58932 10.5052 2.82021 13.2684 3.693C21.4149 6.65607 20.7135 14.2162 14.6733 20.0304C12.4961 22.2272 9.31209 22.8944 6.11128 22.4816C5.92391 22.4877 5.72342 22.4662 5.52257 22.439C6.35474 22.011 7.20002 21.6107 8.01305 21.1498C8.35227 20.935 8.81233 20.8321 9.05266 20.4926L9.047 20.493Z" fill="url(#paint0_linear_394_43518)" />
+ </g>
+ <defs>
+ <linearGradient id="paint0_linear_394_43518" x1="11" y1="-48.5001" x2="12.2401" y2="28.2518" gradientUnits="userSpaceOnUse">
+ <stop stopColor="#FDB022" />
+ <stop offset="1" stopColor="#F79009" />
+ </linearGradient>
+ <clipPath id="clip0_394_43518">
+ <rect width="19.1928" height="27.3696" fill="white" transform="translate(21.8271 27.6475) rotate(176.395)" />
+ </clipPath>
+ </defs>
+ </svg>
+)
+
+const SelectPlanRange: FC<Props> = ({
+ value,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='relative flex flex-col items-end pr-6'>
+ <div className='bg-premium-yearly-tip-text-background bg-clip-text text-sm italic text-transparent'>{t('billing.plansCommon.yearlyTip')}</div>
+ <div className='flex items-center py-1'>
+ <span className='mr-2 text-[13px]'>{t('billing.plansCommon.annualBilling')}</span>
+ <Switch size='l' defaultValue={value === PlanRange.yearly} onChange={(v) => {
+ onChange(v ? PlanRange.yearly : PlanRange.monthly)
+ }} />
+ </div>
+ <div className='absolute right-0 top-2'>
+ {ArrowIcon}
+ </div>
+ </div>
+ )
+}
+export default React.memo(SelectPlanRange)
diff --git a/app/components/billing/pricing/self-hosted-plan-item.tsx b/app/components/billing/pricing/self-hosted-plan-item.tsx
new file mode 100644
index 0000000..491fdfe
--- /dev/null
+++ b/app/components/billing/pricing/self-hosted-plan-item.tsx
@@ -0,0 +1,176 @@
+'use client'
+import type { FC, ReactNode } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowRightUpLine, RiBrain2Line, RiCheckLine, RiQuestionLine } from '@remixicon/react'
+import { SelfHostedPlan } from '../type'
+import { contactSalesUrl, getStartedWithCommunityUrl, getWithPremiumUrl } from '../config'
+import Toast from '../../base/toast'
+import Tooltip from '../../base/tooltip'
+import { Asterisk, AwsMarketplace, Azure, Buildings, Diamond, GoogleCloud } from '../../base/icons/src/public/billing'
+import type { PlanRange } from './select-plan-range'
+import cn from '@/utils/classnames'
+import { useAppContext } from '@/context/app-context'
+
+type Props = {
+ plan: SelfHostedPlan
+ planRange: PlanRange
+ canPay: boolean
+}
+
+const KeyValue = ({ label, tooltip, textColor, tooltipIconColor }: { icon: ReactNode; label: string; tooltip?: string; textColor: string; tooltipIconColor: string }) => {
+ return (
+ <div className={cn('flex', textColor)}>
+ <div className='flex size-4 items-center justify-center'>
+ <RiCheckLine />
+ </div>
+ <div className={cn('system-sm-regular ml-2 mr-0.5', textColor)}>{label}</div>
+ {tooltip && (
+ <Tooltip
+ asChild
+ popupContent={tooltip}
+ popupClassName='w-[200px]'
+ >
+ <div className='flex size-4 items-center justify-center'>
+ <RiQuestionLine className={cn(tooltipIconColor)} />
+ </div>
+ </Tooltip>
+ )}
+ </div>
+ )
+}
+
+const style = {
+ [SelfHostedPlan.community]: {
+ icon: <Asterisk className='size-7 text-text-primary' />,
+ title: 'text-text-primary',
+ price: 'text-text-primary',
+ priceTip: 'text-text-tertiary',
+ description: 'text-util-colors-gray-gray-600',
+ bg: 'border-effects-highlight-lightmode-off bg-background-section-burn',
+ btnStyle: 'bg-components-button-secondary-bg hover:bg-components-button-secondary-bg-hover border-[0.5px] border-components-button-secondary-border text-text-primary',
+ values: 'text-text-secondary',
+ tooltipIconColor: 'text-text-tertiary',
+ },
+ [SelfHostedPlan.premium]: {
+ icon: <Diamond className='size-7 text-text-warning' />,
+ title: 'text-text-primary',
+ price: 'text-text-primary',
+ priceTip: 'text-text-tertiary',
+ description: 'text-text-warning',
+ bg: 'border-effects-highlight bg-background-section-burn',
+ btnStyle: 'bg-third-party-aws hover:bg-third-party-aws-hover border border-components-button-primary-border text-text-primary-on-surface shadow-xs',
+ values: 'text-text-secondary',
+ tooltipIconColor: 'text-text-tertiary',
+ },
+ [SelfHostedPlan.enterprise]: {
+ icon: <Buildings className='size-7 text-text-primary-on-surface' />,
+ title: 'text-text-primary-on-surface',
+ price: 'text-text-primary-on-surface',
+ priceTip: 'text-text-primary-on-surface',
+ description: 'text-text-primary-on-surface',
+ bg: 'border-effects-highlight bg-[#155AEF] text-text-primary-on-surface',
+ btnStyle: 'bg-white bg-opacity-96 hover:opacity-85 border-[0.5px] border-components-button-secondary-border text-[#155AEF] shadow-xs',
+ values: 'text-text-primary-on-surface',
+ tooltipIconColor: 'text-text-primary-on-surface',
+ },
+}
+const SelfHostedPlanItem: FC<Props> = ({
+ plan,
+}) => {
+ const { t } = useTranslation()
+ const isFreePlan = plan === SelfHostedPlan.community
+ const isPremiumPlan = plan === SelfHostedPlan.premium
+ const i18nPrefix = `billing.plans.${plan}`
+ const isEnterprisePlan = plan === SelfHostedPlan.enterprise
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const features = t(`${i18nPrefix}.features`, { returnObjects: true }) as string[]
+ const handleGetPayUrl = () => {
+ // Only workspace manager can buy plan
+ if (!isCurrentWorkspaceManager) {
+ Toast.notify({
+ type: 'error',
+ message: t('billing.buyPermissionDeniedTip'),
+ className: 'z-[1001]',
+ })
+ return
+ }
+ if (isFreePlan) {
+ window.location.href = getStartedWithCommunityUrl
+ return
+ }
+ if (isPremiumPlan) {
+ window.location.href = getWithPremiumUrl
+ return
+ }
+
+ if (isEnterprisePlan)
+ window.location.href = contactSalesUrl
+ }
+ return (
+ <div className={cn(`relative flex w-[374px] flex-col overflow-hidden rounded-2xl
+ border-[0.5px] hover:border-effects-highlight hover:shadow-lg hover:backdrop-blur-[5px]`, style[plan].bg)}>
+ <div>
+ <div className={cn(isEnterprisePlan ? 'z-1 absolute bottom-0 left-0 right-0 top-0 bg-price-enterprise-background' : '')} >
+ </div>
+ {isEnterprisePlan && <div className='z-15 absolute -left-[90px] -top-[104px] size-[341px] rounded-full bg-[#09328c] opacity-15 mix-blend-plus-darker blur-[80px]'></div>}
+ {isEnterprisePlan && <div className='z-15 absolute -bottom-[72px] -right-[40px] size-[341px] rounded-full bg-[#e2eafb] opacity-15 mix-blend-plus-darker blur-[80px]'></div>}
+ </div>
+ <div className='relative z-10 min-h-[559px] w-full p-6'>
+ <div className=' flex min-h-[108px] flex-col gap-y-1'>
+ {style[plan].icon}
+ <div className='flex items-center'>
+ <div className={cn('system-md-semibold uppercase leading-[125%]', style[plan].title)}>{t(`${i18nPrefix}.name`)}</div>
+ </div>
+ <div className={cn(style[plan].description, 'system-sm-regular')}>{t(`${i18nPrefix}.description`)}</div>
+ </div>
+ <div className='my-3'>
+ <div className='flex items-end'>
+ <div className={cn('shrink-0 text-[28px] font-bold leading-[125%]', style[plan].price)}>{t(`${i18nPrefix}.price`)}</div>
+ {!isFreePlan
+ && <span className={cn('ml-2 py-1 text-[14px] font-normal leading-normal', style[plan].priceTip)}>
+ {t(`${i18nPrefix}.priceTip`)}
+ </span>}
+ </div>
+ </div>
+
+ <div
+ className={cn('system-md-semibold flex h-[44px] cursor-pointer items-center justify-center rounded-full px-5 py-3',
+ style[plan].btnStyle)}
+ onClick={handleGetPayUrl}
+ >
+ {t(`${i18nPrefix}.btnText`)}
+ {isPremiumPlan
+ && <>
+ <div className='mx-1 pt-[6px]'>
+ <AwsMarketplace className='h-6' />
+ </div>
+ <RiArrowRightUpLine className='size-4' />
+ </>}
+ </div>
+ <div className={cn('system-sm-semibold mb-2 mt-6', style[plan].values)}>{t(`${i18nPrefix}.includesTitle`)}</div>
+ <div className='flex flex-col gap-y-3'>
+ {features.map(v =>
+ <KeyValue key={`${plan}-${v}`}
+ textColor={style[plan].values}
+ tooltipIconColor={style[plan].tooltipIconColor}
+ icon={<RiBrain2Line />}
+ label={v}
+ />)}
+ </div>
+ {isPremiumPlan && <div className='mt-[68px]'>
+ <div className='flex items-center gap-x-1'>
+ <div className='flex size-8 items-center justify-center rounded-lg border-[0.5px] border-components-panel-border-subtle bg-background-default shadow-xs'>
+ <Azure />
+ </div>
+ <div className='flex size-8 items-center justify-center rounded-lg border-[0.5px] border-components-panel-border-subtle bg-background-default shadow-xs'>
+ <GoogleCloud />
+ </div>
+ </div>
+ <span className={cn('system-xs-regular mt-2', style[plan].tooltipIconColor)}>{t('billing.plans.premium.comingSoon')}</span>
+ </div>}
+ </div>
+ </div>
+ )
+}
+export default React.memo(SelfHostedPlanItem)
diff --git a/app/components/billing/priority-label/index.tsx b/app/components/billing/priority-label/index.tsx
new file mode 100644
index 0000000..d63d7ba
--- /dev/null
+++ b/app/components/billing/priority-label/index.tsx
@@ -0,0 +1,65 @@
+import { useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ DocumentProcessingPriority,
+ Plan,
+} from '../type'
+import cn from '@/utils/classnames'
+import { useProviderContext } from '@/context/provider-context'
+import {
+ ZapFast,
+ ZapNarrow,
+} from '@/app/components/base/icons/src/vender/solid/general'
+import Tooltip from '@/app/components/base/tooltip'
+
+type PriorityLabelProps = {
+ className?: string
+}
+
+const PriorityLabel = ({ className }: PriorityLabelProps) => {
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+
+ const priority = useMemo(() => {
+ if (plan.type === Plan.sandbox)
+ return DocumentProcessingPriority.standard
+
+ if (plan.type === Plan.professional)
+ return DocumentProcessingPriority.priority
+
+ if (plan.type === Plan.team || plan.type === Plan.enterprise)
+ return DocumentProcessingPriority.topPriority
+ }, [plan])
+
+ return (
+ <Tooltip popupContent={
+ <div>
+ <div className='mb-1 text-xs font-semibold text-gray-700'>{`${t('billing.plansCommon.documentProcessingPriority')}: ${t(`billing.plansCommon.priority.${priority}`)}`}</div>
+ {
+ priority !== DocumentProcessingPriority.topPriority && (
+ <div className='text-xs text-gray-500'>{t('billing.plansCommon.documentProcessingPriorityTip')}</div>
+ )
+ }
+ </div>
+ }>
+ <span className={cn(`
+ ml-1 flex h-[18px] shrink-0 items-center rounded-[5px] border border-text-accent-secondary px-1
+ text-2xs font-medium text-text-accent-secondary
+ `, className)}>
+ {
+ plan.type === Plan.professional && (
+ <ZapNarrow className='mr-0.5 size-3' />
+ )
+ }
+ {
+ (plan.type === Plan.team || plan.type === Plan.enterprise) && (
+ <ZapFast className='mr-0.5 size-3' />
+ )
+ }
+ {t(`billing.plansCommon.priority.${priority}`)}
+ </span>
+ </Tooltip>
+ )
+}
+
+export default PriorityLabel
diff --git a/app/components/billing/progress-bar/index.tsx b/app/components/billing/progress-bar/index.tsx
new file mode 100644
index 0000000..6397b43
--- /dev/null
+++ b/app/components/billing/progress-bar/index.tsx
@@ -0,0 +1,24 @@
+import cn from '@/utils/classnames'
+
+type ProgressBarProps = {
+ percent: number
+ color: string
+}
+
+const ProgressBar = ({
+ percent = 0,
+ color = '#2970FF',
+}: ProgressBarProps) => {
+ return (
+ <div className='overflow-hidden rounded-[6px] bg-components-progress-bar-bg'>
+ <div
+ className={cn('h-1 rounded-[6px]', color)}
+ style={{
+ width: `${Math.min(percent, 100)}%`,
+ }}
+ />
+ </div>
+ )
+}
+
+export default ProgressBar
diff --git a/app/components/billing/type.ts b/app/components/billing/type.ts
new file mode 100644
index 0000000..2f5728c
--- /dev/null
+++ b/app/components/billing/type.ts
@@ -0,0 +1,107 @@
+export enum Plan {
+ sandbox = 'sandbox',
+ professional = 'professional',
+ team = 'team',
+ enterprise = 'enterprise',
+}
+export enum Priority {
+ standard = 'standard',
+ priority = 'priority',
+ topPriority = 'top-priority',
+}
+
+export type BasicPlan = Plan.sandbox | Plan.professional | Plan.team
+
+export type PlanInfo = {
+ level: number
+ price: number
+ modelProviders: string
+ teamWorkspace: number
+ teamMembers: number
+ buildApps: number
+ documents: number
+ vectorSpace: string
+ documentsUploadQuota: number
+ documentsRequestQuota: number
+ apiRateLimit: number
+ documentProcessingPriority: Priority
+ logHistory: number
+ messageRequest: number
+ annotatedResponse: number
+}
+
+export enum SelfHostedPlan {
+ community = 'community',
+ premium = 'premium',
+ enterprise = 'enterprise',
+}
+
+export type SelfHostedPlanInfo = {
+ level: number
+ price: number
+ modelProviders: string
+ teamWorkspace: number
+ teamMembers: number
+ buildApps: number
+ documents: number
+ vectorSpace: string
+ documentsRequestQuota: number
+ documentProcessingPriority: Priority
+ logHistory: number
+ messageRequest: number
+ annotatedResponse: number
+}
+
+export type UsagePlanInfo = Pick<PlanInfo, 'buildApps' | 'teamMembers' | 'annotatedResponse' | 'documentsUploadQuota'> & { vectorSpace: number }
+
+export enum DocumentProcessingPriority {
+ standard = 'standard',
+ priority = 'priority',
+ topPriority = 'top-priority',
+}
+
+export type CurrentPlanInfoBackend = {
+ billing: {
+ enabled: boolean
+ subscription: {
+ plan: BasicPlan
+ }
+ }
+ members: {
+ size: number
+ limit: number // total. 0 means unlimited
+ }
+ apps: {
+ size: number
+ limit: number // total. 0 means unlimited
+ }
+ vector_space: {
+ size: number
+ limit: number // total. 0 means unlimited
+ }
+ annotation_quota_limit: {
+ size: number
+ limit: number // total. 0 means unlimited
+ }
+ documents_upload_quota: {
+ size: number
+ limit: number // total. 0 means unlimited
+ }
+ docs_processing: DocumentProcessingPriority
+ can_replace_logo: boolean
+ model_load_balancing_enabled: boolean
+ dataset_operator_enabled: boolean
+ education: {
+ enabled: boolean
+ activated: boolean
+ }
+}
+
+export type SubscriptionItem = {
+ plan: Plan
+ url: string
+}
+
+export type SubscriptionUrlsBackend = {
+ url: string
+}
diff --git a/app/components/billing/upgrade-btn/index.tsx b/app/components/billing/upgrade-btn/index.tsx
new file mode 100644
index 0000000..45f4d44
--- /dev/null
+++ b/app/components/billing/upgrade-btn/index.tsx
@@ -0,0 +1,67 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import PremiumBadge from '../../base/premium-badge'
+import Button from '@/app/components/base/button'
+import { SparklesSoft } from '@/app/components/base/icons/src/public/common'
+import { useModalContext } from '@/context/modal-context'
+
+type Props = {
+ className?: string
+ isFull?: boolean
+ size?: 'md' | 'lg'
+ isPlain?: boolean
+ isShort?: boolean
+ onClick?: () => void
+ loc?: string
+}
+
+const UpgradeBtn: FC<Props> = ({
+ isPlain = false,
+ isShort = false,
+ onClick: _onClick,
+ loc,
+}) => {
+ const { t } = useTranslation()
+ const { setShowPricingModal } = useModalContext()
+ const handleClick = () => {
+ if (_onClick)
+ _onClick()
+ else
+ (setShowPricingModal as any)()
+ }
+ const onClick = () => {
+ handleClick()
+ if (loc && (window as any).gtag) {
+ (window as any).gtag('event', 'click_upgrade_btn', {
+ loc,
+ })
+ }
+ }
+
+ if (isPlain) {
+ return (
+ <Button onClick={onClick}>
+ {t('billing.upgradeBtn.plain')}
+ </Button>
+ )
+ }
+
+ return (
+ <PremiumBadge
+ size="m"
+ color="blue"
+ allowHover={true}
+ onClick={onClick}
+ >
+ <SparklesSoft className='flex h-3.5 w-3.5 items-center py-[1px] pl-[3px] text-components-premium-badge-indigo-text-stop-0' />
+ <div className='system-xs-medium'>
+ <span className='p-1'>
+ {t(`billing.upgradeBtn.${isShort ? 'encourageShort' : 'encourage'}`)}
+ </span>
+ </div>
+ </PremiumBadge>
+ )
+}
+export default React.memo(UpgradeBtn)
diff --git a/app/components/billing/upgrade-btn/style.module.css b/app/components/billing/upgrade-btn/style.module.css
new file mode 100644
index 0000000..ab8c30e
--- /dev/null
+++ b/app/components/billing/upgrade-btn/style.module.css
@@ -0,0 +1,9 @@
+.upgradeBtn {
+ background: linear-gradient(99deg, rgba(255, 255, 255, 0.12) 7.16%, rgba(255, 255, 255, 0.00) 85.47%), linear-gradient(280deg, #00B2FF 12.96%, #132BFF 90.95%);
+ box-shadow: 0px 2px 4px -2px rgba(16, 24, 40, 0.06), 0px 4px 8px -2px rgba(0, 162, 253, 0.12);
+
+}
+.upgradeBtn:hover {
+ background: linear-gradient(99deg, rgba(255, 255, 255, 0.12) 7.16%, rgba(255, 255, 255, 0.00) 85.47%), linear-gradient(280deg, #02C2FF 12.96%, #001AFF 90.95%);
+ box-shadow: 0px 4px 6px -2px rgba(16, 18, 40, 0.08), 0px 12px 16px -4px rgba(0, 209, 255, 0.08);
+}
diff --git a/app/components/billing/usage-info/apps-info.tsx b/app/components/billing/usage-info/apps-info.tsx
new file mode 100644
index 0000000..2601bbc
--- /dev/null
+++ b/app/components/billing/usage-info/apps-info.tsx
@@ -0,0 +1,34 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiApps2Line,
+} from '@remixicon/react'
+import UsageInfo from '../usage-info'
+import { useProviderContext } from '@/context/provider-context'
+
+type Props = {
+ className?: string
+}
+
+const AppsInfo: FC<Props> = ({
+ className,
+}) => {
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+ const {
+ usage,
+ total,
+ } = plan
+ return (
+ <UsageInfo
+ className={className}
+ Icon={RiApps2Line}
+ name={t('billing.usagePage.buildApps')}
+ usage={usage.buildApps}
+ total={total.buildApps}
+ />
+ )
+}
+export default React.memo(AppsInfo)
diff --git a/app/components/billing/usage-info/index.tsx b/app/components/billing/usage-info/index.tsx
new file mode 100644
index 0000000..30b4bca
--- /dev/null
+++ b/app/components/billing/usage-info/index.tsx
@@ -0,0 +1,71 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import ProgressBar from '../progress-bar'
+import { NUM_INFINITE } from '../config'
+import Tooltip from '@/app/components/base/tooltip'
+import cn from '@/utils/classnames'
+
+type Props = {
+ className?: string
+ Icon: any
+ name: string
+ tooltip?: string
+ usage: number
+ total: number
+ unit?: string
+}
+
+const LOW = 50
+const MIDDLE = 80
+
+const UsageInfo: FC<Props> = ({
+ className,
+ Icon,
+ name,
+ tooltip,
+ usage,
+ total,
+ unit = '',
+}) => {
+ const { t } = useTranslation()
+
+ const percent = usage / total * 100
+ const color = (() => {
+ if (percent < LOW)
+ return 'bg-components-progress-bar-progress-solid'
+
+ if (percent < MIDDLE)
+ return 'bg-components-progress-warning-progress'
+
+ return 'bg-components-progress-error-progress'
+ })()
+ return (
+ <div className={cn('flex flex-col gap-2 rounded-xl bg-components-panel-bg p-4', className)}>
+ <Icon className='h-4 w-4 text-text-tertiary' />
+ <div className='flex items-center gap-1'>
+ <div className='system-xs-medium text-text-tertiary'>{name}</div>
+ {tooltip && (
+ <Tooltip
+ popupContent={
+ <div className='w-[180px]'>
+ {tooltip}
+ </div>
+ }
+ />
+ )}
+ </div>
+ <div className='system-md-semibold flex items-center gap-1 text-text-primary'>
+ {usage}
+ <div className='system-md-regular text-text-quaternary'>/</div>
+ <div>{total === NUM_INFINITE ? t('billing.plansCommon.unlimited') : `${total}${unit}`}</div>
+ </div>
+ <ProgressBar
+ percent={percent}
+ color={color}
+ />
+ </div>
+ )
+}
+export default React.memo(UsageInfo)
diff --git a/app/components/billing/usage-info/vector-space-info.tsx b/app/components/billing/usage-info/vector-space-info.tsx
new file mode 100644
index 0000000..e578280
--- /dev/null
+++ b/app/components/billing/usage-info/vector-space-info.tsx
@@ -0,0 +1,36 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import {
+ RiHardDrive3Line,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import UsageInfo from '../usage-info'
+import { useProviderContext } from '@/context/provider-context'
+
+type Props = {
+ className?: string
+}
+
+const VectorSpaceInfo: FC<Props> = ({
+ className,
+}) => {
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+ const {
+ usage,
+ total,
+ } = plan
+ return (
+ <UsageInfo
+ className={className}
+ Icon={RiHardDrive3Line}
+ name={t('billing.usagePage.vectorSpace')}
+ tooltip={t('billing.usagePage.vectorSpaceTooltip') as string}
+ usage={usage.vectorSpace}
+ total={total.vectorSpace}
+ unit='MB'
+ />
+ )
+}
+export default React.memo(VectorSpaceInfo)
diff --git a/app/components/billing/utils/index.ts b/app/components/billing/utils/index.ts
new file mode 100644
index 0000000..111f02e
--- /dev/null
+++ b/app/components/billing/utils/index.ts
@@ -0,0 +1,29 @@
+import type { CurrentPlanInfoBackend } from '../type'
+import { NUM_INFINITE } from '@/app/components/billing/config'
+
+const parseLimit = (limit: number) => {
+ if (limit === 0)
+ return NUM_INFINITE
+
+ return limit
+}
+
+export const parseCurrentPlan = (data: CurrentPlanInfoBackend) => {
+ return {
+ type: data.billing.subscription.plan,
+ usage: {
+ vectorSpace: data.vector_space.size,
+ buildApps: data.apps?.size || 0,
+ teamMembers: data.members.size,
+ annotatedResponse: data.annotation_quota_limit.size,
+ documentsUploadQuota: data.documents_upload_quota.size,
+ },
+ total: {
+ vectorSpace: parseLimit(data.vector_space.limit),
+ buildApps: parseLimit(data.apps?.limit) || 0,
+ teamMembers: parseLimit(data.members.limit),
+ annotatedResponse: parseLimit(data.annotation_quota_limit.limit),
+ documentsUploadQuota: parseLimit(data.documents_upload_quota.limit),
+ },
+ }
+}
diff --git a/app/components/billing/vector-space-full/index.tsx b/app/components/billing/vector-space-full/index.tsx
new file mode 100644
index 0000000..58d9db0
--- /dev/null
+++ b/app/components/billing/vector-space-full/index.tsx
@@ -0,0 +1,29 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import UpgradeBtn from '../upgrade-btn'
+import VectorSpaceInfo from '../usage-info/vector-space-info'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import GridMask from '@/app/components/base/grid-mask'
+
+const VectorSpaceFull: FC = () => {
+ const { t } = useTranslation()
+
+ return (
+ <GridMask wrapperClassName='border border-gray-200 rounded-xl' canvasClassName='rounded-xl' gradientClassName='rounded-xl'>
+ <div className='px-6 py-5'>
+ <div className='flex items-center justify-between'>
+ <div className={cn(s.textGradient, 'text-base font-semibold leading-[24px]')}>
+ <div>{t('billing.vectorSpace.fullTip')}</div>
+ <div>{t('billing.vectorSpace.fullSolution')}</div>
+ </div>
+ <UpgradeBtn loc='knowledge-add-file' />
+ </div>
+ <VectorSpaceInfo className='pt-4' />
+ </div>
+ </GridMask>
+ )
+}
+export default React.memo(VectorSpaceFull)
diff --git a/app/components/billing/vector-space-full/style.module.css b/app/components/billing/vector-space-full/style.module.css
new file mode 100644
index 0000000..15bedd8
--- /dev/null
+++ b/app/components/billing/vector-space-full/style.module.css
@@ -0,0 +1,7 @@
+.textGradient {
+ background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ text-fill-color: transparent;
+}
diff --git a/app/components/browser-initor.tsx b/app/components/browser-initor.tsx
new file mode 100644
index 0000000..f2f4b02
--- /dev/null
+++ b/app/components/browser-initor.tsx
@@ -0,0 +1,52 @@
+'use client'
+
+class StorageMock {
+ data: Record<string, string>
+
+ constructor() {
+ this.data = {} as Record<string, string>
+ }
+
+ setItem(name: string, value: string) {
+ this.data[name] = value
+ }
+
+ getItem(name: string) {
+ return this.data[name] || null
+ }
+
+ removeItem(name: string) {
+ delete this.data[name]
+ }
+
+ clear() {
+ this.data = {}
+ }
+}
+
+let localStorage, sessionStorage
+
+try {
+ localStorage = globalThis.localStorage
+ sessionStorage = globalThis.sessionStorage
+}
+catch {
+ localStorage = new StorageMock()
+ sessionStorage = new StorageMock()
+}
+
+Object.defineProperty(globalThis, 'localStorage', {
+ value: localStorage,
+})
+
+Object.defineProperty(globalThis, 'sessionStorage', {
+ value: sessionStorage,
+})
+
+const BrowserInitor = ({
+ children,
+}: { children: React.ReactNode }) => {
+ return children
+}
+
+export default BrowserInitor
diff --git a/app/components/custom/custom-page/index.tsx b/app/components/custom/custom-page/index.tsx
new file mode 100644
index 0000000..90ce16b
--- /dev/null
+++ b/app/components/custom/custom-page/index.tsx
@@ -0,0 +1,38 @@
+import { useTranslation } from 'react-i18next'
+import CustomWebAppBrand from '../custom-web-app-brand'
+import { useProviderContext } from '@/context/provider-context'
+import { Plan } from '@/app/components/billing/type'
+import { contactSalesUrl } from '@/app/components/billing/config'
+import { useModalContext } from '@/context/modal-context'
+
+const CustomPage = () => {
+ const { t } = useTranslation()
+ const { plan, enableBilling } = useProviderContext()
+ const { setShowPricingModal } = useModalContext()
+ const showBillingTip = enableBilling && plan.type === Plan.sandbox
+ const showContact = enableBilling && (plan.type === Plan.professional || plan.type === Plan.team)
+
+ return (
+ <div className='flex flex-col'>
+ {showBillingTip && (
+ <div className='mb-1 flex justify-between rounded-xl bg-gradient-to-r from-components-input-border-active-prompt-1 to-components-input-border-active-prompt-2 p-4 pl-6 shadow-lg backdrop-blur-sm'>
+ <div className='space-y-1 text-text-primary-on-surface'>
+ <div className='title-xl-semi-bold'>{t('custom.upgradeTip.title')}</div>
+ <div className='system-sm-regular'>{t('custom.upgradeTip.des')}</div>
+ </div>
+ <div className='system-md-semibold flex h-10 w-[120px] cursor-pointer items-center justify-center rounded-3xl bg-white text-text-accent shadow-xs hover:opacity-95' onClick={() => setShowPricingModal()}>{t('billing.upgradeBtn.encourageShort')}</div>
+ </div>
+ )}
+ <CustomWebAppBrand />
+ {showContact && (
+ <div className='absolute bottom-0 h-[50px] text-xs leading-[50px] text-text-quaternary'>
+ {t('custom.customize.prefix')}
+ <a className='text-text-accent' href={contactSalesUrl} target='_blank' rel='noopener noreferrer'>{t('custom.customize.contactUs')}</a>
+ {t('custom.customize.suffix')}
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default CustomPage
diff --git a/app/components/custom/custom-web-app-brand/index.tsx b/app/components/custom/custom-web-app-brand/index.tsx
new file mode 100644
index 0000000..444df98
--- /dev/null
+++ b/app/components/custom/custom-web-app-brand/index.tsx
@@ -0,0 +1,319 @@
+import type { ChangeEvent } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiEditBoxLine,
+ RiEqualizer2Line,
+ RiExchange2Fill,
+ RiImageAddLine,
+ RiLayoutLeft2Line,
+ RiLoader2Line,
+ RiPlayLargeLine,
+} from '@remixicon/react'
+import DifyLogo from '@/app/components/base/logo/dify-logo'
+import Switch from '@/app/components/base/switch'
+import Button from '@/app/components/base/button'
+import Divider from '@/app/components/base/divider'
+import { useProviderContext } from '@/context/provider-context'
+import { Plan } from '@/app/components/billing/type'
+import { imageUpload } from '@/app/components/base/image-uploader/utils'
+import { useToastContext } from '@/app/components/base/toast'
+import { BubbleTextMod } from '@/app/components/base/icons/src/vender/solid/communication'
+import {
+ updateCurrentWorkspace,
+} from '@/service/common'
+import { useAppContext } from '@/context/app-context'
+import cn from '@/utils/classnames'
+
+const ALLOW_FILE_EXTENSIONS = ['svg', 'png']
+
+const CustomWebAppBrand = () => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const { plan, enableBilling } = useProviderContext()
+ const {
+ currentWorkspace,
+ mutateCurrentWorkspace,
+ isCurrentWorkspaceManager,
+ } = useAppContext()
+ const [fileId, setFileId] = useState('')
+ const [imgKey, setImgKey] = useState(Date.now())
+ const [uploadProgress, setUploadProgress] = useState(0)
+ const isSandbox = enableBilling && plan.type === Plan.sandbox
+ const uploading = uploadProgress > 0 && uploadProgress < 100
+ const webappLogo = currentWorkspace.custom_config?.replace_webapp_logo || ''
+ const webappBrandRemoved = currentWorkspace.custom_config?.remove_webapp_brand
+ const uploadDisabled = isSandbox || webappBrandRemoved || !isCurrentWorkspaceManager
+
+ const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
+ const file = e.target.files?.[0]
+
+ if (!file)
+ return
+
+ if (file.size > 5 * 1024 * 1024) {
+ notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerLimit', { size: 5 }) })
+ return
+ }
+
+ imageUpload({
+ file,
+ onProgressCallback: (progress) => {
+ setUploadProgress(progress)
+ },
+ onSuccessCallback: (res) => {
+ setUploadProgress(100)
+ setFileId(res.id)
+ },
+ onErrorCallback: () => {
+ notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerUploadError') })
+ setUploadProgress(-1)
+ },
+ }, false, '/workspaces/custom-config/webapp-logo/upload')
+ }
+
+ const handleApply = async () => {
+ await updateCurrentWorkspace({
+ url: '/workspaces/custom-config',
+ body: {
+ remove_webapp_brand: webappBrandRemoved,
+ replace_webapp_logo: fileId,
+ },
+ })
+ mutateCurrentWorkspace()
+ setFileId('')
+ setImgKey(Date.now())
+ }
+
+ const handleRestore = async () => {
+ await updateCurrentWorkspace({
+ url: '/workspaces/custom-config',
+ body: {
+ remove_webapp_brand: false,
+ replace_webapp_logo: '',
+ },
+ })
+ mutateCurrentWorkspace()
+ }
+
+ const handleSwitch = async (checked: boolean) => {
+ await updateCurrentWorkspace({
+ url: '/workspaces/custom-config',
+ body: {
+ remove_webapp_brand: checked,
+ },
+ })
+ mutateCurrentWorkspace()
+ }
+
+ const handleCancel = () => {
+ setFileId('')
+ setUploadProgress(0)
+ }
+
+ return (
+ <div className='py-4'>
+ <div className='system-md-medium mb-2 flex items-center justify-between rounded-xl bg-background-section-burn p-4 text-text-primary'>
+ {t('custom.webapp.removeBrand')}
+ <Switch
+ size='l'
+ defaultValue={webappBrandRemoved}
+ disabled={isSandbox || !isCurrentWorkspaceManager}
+ onChange={handleSwitch}
+ />
+ </div>
+ <div className={cn('flex h-14 items-center justify-between rounded-xl bg-background-section-burn px-4', webappBrandRemoved && 'opacity-30')}>
+ <div>
+ <div className='system-md-medium text-text-primary'>{t('custom.webapp.changeLogo')}</div>
+ <div className='system-xs-regular text-text-tertiary'>{t('custom.webapp.changeLogoTip')}</div>
+ </div>
+ <div className='flex items-center'>
+ {(uploadDisabled || (!webappLogo && !webappBrandRemoved)) && (
+ <>
+ <Button
+ variant='ghost'
+ disabled={uploadDisabled || (!webappLogo && !webappBrandRemoved)}
+ onClick={handleRestore}
+ >
+ {t('custom.restore')}
+ </Button>
+ <div className='mx-2 h-5 w-[1px] bg-divider-regular'></div>
+ </>
+ )}
+ {
+ !uploading && (
+ <Button
+ className='relative mr-2'
+ disabled={uploadDisabled}
+ >
+ <RiImageAddLine className='mr-1 h-4 w-4' />
+ {
+ (webappLogo || fileId)
+ ? t('custom.change')
+ : t('custom.upload')
+ }
+ <input
+ className={cn('absolute inset-0 block w-full text-[0] opacity-0', uploadDisabled ? 'cursor-not-allowed' : 'cursor-pointer')}
+ onClick={e => (e.target as HTMLInputElement).value = ''}
+ type='file'
+ accept={ALLOW_FILE_EXTENSIONS.map(ext => `.${ext}`).join(',')}
+ onChange={handleChange}
+ disabled={uploadDisabled}
+ />
+ </Button>
+ )
+ }
+ {
+ uploading && (
+ <Button
+ className='relative mr-2'
+ disabled={true}
+ >
+ <RiLoader2Line className='mr-1 h-4 w-4 animate-spin' />
+ {t('custom.uploading')}
+ </Button>
+ )
+ }
+ {
+ fileId && (
+ <>
+ <Button
+ className='mr-2'
+ onClick={handleCancel}
+ disabled={webappBrandRemoved || !isCurrentWorkspaceManager}
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ className='mr-2'
+ onClick={handleApply}
+ disabled={webappBrandRemoved || !isCurrentWorkspaceManager}
+ >
+ {t('custom.apply')}
+ </Button>
+ </>
+ )
+ }
+ </div>
+ </div>
+ {uploadProgress === -1 && (
+ <div className='mt-2 text-xs text-[#D92D20]'>{t('custom.uploadedFail')}</div>
+ )}
+ <div className='mb-2 mt-5 flex items-center gap-2'>
+ <div className='system-xs-medium-uppercase shrink-0 text-text-tertiary'>{t('appOverview.overview.appInfo.preview')}</div>
+ <Divider bgStyle='gradient' className='grow' />
+ </div>
+ <div className='relative mb-2 flex items-center gap-3'>
+ {/* chat card */}
+ <div className='flex h-[320px] grow basis-1/2 overflow-hidden rounded-2xl border-[0.5px] border-components-panel-border-subtle bg-background-default-burn'>
+ <div className='flex h-full w-[232px] shrink-0 flex-col p-1 pr-0'>
+ <div className='flex items-center gap-3 p-3 pr-2'>
+ <div className={cn('inline-flex h-8 w-8 items-center justify-center rounded-lg border border-divider-regular', 'bg-components-icon-bg-blue-light-solid')}>
+ <BubbleTextMod className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
+ </div>
+ <div className='system-md-semibold grow text-text-secondary'>Chatflow App</div>
+ <div className='p-1.5'>
+ <RiLayoutLeft2Line className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ <div className='shrink-0 px-4 py-3'>
+ <Button variant='secondary-accent' className='w-full justify-center'>
+ <RiEditBoxLine className='mr-1 h-4 w-4' />
+ <div className='p-1 opacity-20'>
+ <div className='h-2 w-[94px] rounded-sm bg-text-accent-light-mode-only'></div>
+ </div>
+ </Button>
+ </div>
+ <div className='grow px-3 pt-5'>
+ <div className='flex h-8 items-center px-3 py-1'>
+ <div className='h-2 w-14 rounded-sm bg-text-quaternary opacity-20'></div>
+ </div>
+ <div className='flex h-8 items-center px-3 py-1'>
+ <div className='h-2 w-[168px] rounded-sm bg-text-quaternary opacity-20'></div>
+ </div>
+ <div className='flex h-8 items-center px-3 py-1'>
+ <div className='h-2 w-[128px] rounded-sm bg-text-quaternary opacity-20'></div>
+ </div>
+ </div>
+ <div className='flex shrink-0 items-center justify-between p-3'>
+ <div className='p-1.5'>
+ <RiEqualizer2Line className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div className='flex items-center gap-1.5'>
+ {!webappBrandRemoved && (
+ <>
+ <div className='system-2xs-medium-uppercase text-text-tertiary'>POWERED BY</div>
+ {webappLogo
+ ? <img src={`${webappLogo}?hash=${imgKey}`} alt='logo' className='block h-5 w-auto' />
+ : <DifyLogo size='small' />
+ }
+ </>
+ )}
+ </div>
+ </div>
+ </div>
+ <div className='flex w-[138px] grow flex-col justify-between p-2 pr-0'>
+ <div className='flex grow flex-col justify-between rounded-l-2xl border-[0.5px] border-r-0 border-components-panel-border-subtle bg-chatbot-bg pb-4 pl-[22px] pt-16'>
+ <div className='w-[720px] rounded-2xl border border-divider-subtle bg-chat-bubble-bg px-4 py-3'>
+ <div className='body-md-regular mb-1 text-text-primary'>Hello! How can I assist you today?</div>
+ <Button size='small'>
+ <div className='h-2 w-[144px] rounded-sm bg-text-quaternary opacity-20'></div>
+ </Button>
+ </div>
+ <div className='body-lg-regular flex h-[52px] w-[578px] items-center rounded-xl border border-components-chat-input-border bg-components-panel-bg-blur pl-3.5 text-text-placeholder shadow-md backdrop-blur-sm'>Talk to Dify</div>
+ </div>
+ </div>
+ </div>
+ {/* workflow card */}
+ <div className='flex h-[320px] grow basis-1/2 flex-col overflow-hidden rounded-2xl border-[0.5px] border-components-panel-border-subtle bg-background-default-burn'>
+ <div className='w-full border-b-[0.5px] border-divider-subtle p-4 pb-0'>
+ <div className='mb-2 flex items-center gap-3'>
+ <div className={cn('inline-flex h-8 w-8 items-center justify-center rounded-lg border border-divider-regular', 'bg-components-icon-bg-indigo-solid')}>
+ <RiExchange2Fill className='h-4 w-4 text-components-avatar-shape-fill-stop-100' />
+ </div>
+ <div className='system-md-semibold grow text-text-secondary'>Workflow App</div>
+ <div className='p-1.5'>
+ <RiLayoutLeft2Line className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ <div className='flex items-center gap-4'>
+ <div className='system-md-semibold-uppercase flex h-10 shrink-0 items-center border-b-2 border-components-tab-active text-text-primary'>RUN ONCE</div>
+ <div className='system-md-semibold-uppercase flex h-10 grow items-center border-b-2 border-transparent text-text-tertiary'>RUN BATCH</div>
+ </div>
+ </div>
+ <div className='grow bg-components-panel-bg'>
+ <div className='p-4 pb-1'>
+ <div className='mb-1 py-2'>
+ <div className='h-2 w-20 rounded-sm bg-text-quaternary opacity-20'></div>
+ </div>
+ <div className='h-16 w-full rounded-lg bg-components-input-bg-normal '></div>
+ </div>
+ <div className='flex items-center justify-between px-4 py-3'>
+ <Button size='small'>
+ <div className='h-2 w-10 rounded-sm bg-text-quaternary opacity-20'></div>
+ </Button>
+ <Button variant='primary' size='small' disabled>
+ <RiPlayLargeLine className='mr-1 h-4 w-4' />
+ <span>Execute</span>
+ </Button>
+ </div>
+ </div>
+ <div className='flex h-12 shrink-0 items-center gap-1.5 bg-components-panel-bg p-4 pt-3'>
+ {!webappBrandRemoved && (
+ <>
+ <div className='system-2xs-medium-uppercase text-text-tertiary'>POWERED BY</div>
+ {webappLogo
+ ? <img src={`${webappLogo}?hash=${imgKey}`} alt='logo' className='block h-5 w-auto' />
+ : <DifyLogo size='small' />
+ }
+ </>
+ )}
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default CustomWebAppBrand
diff --git a/app/components/custom/custom-web-app-brand/style.module.css b/app/components/custom/custom-web-app-brand/style.module.css
new file mode 100644
index 0000000..bdc7d7c
--- /dev/null
+++ b/app/components/custom/custom-web-app-brand/style.module.css
@@ -0,0 +1,3 @@
+.mask {
+ background: linear-gradient(273deg, rgba(255, 255, 255, 0.00) 51.75%, rgba(255, 255, 255, 0.80) 115.32%);
+}
diff --git a/app/components/custom/style.module.css b/app/components/custom/style.module.css
new file mode 100644
index 0000000..0a839f6
--- /dev/null
+++ b/app/components/custom/style.module.css
@@ -0,0 +1,6 @@
+.textGradient {
+ background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
diff --git a/app/components/datasets/api/index.tsx b/app/components/datasets/api/index.tsx
new file mode 100644
index 0000000..3ca84c3
--- /dev/null
+++ b/app/components/datasets/api/index.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const index = () => {
+ return (
+ <div>index</div>
+ )
+}
+
+export default index
diff --git a/app/components/datasets/chunk.tsx b/app/components/datasets/chunk.tsx
new file mode 100644
index 0000000..eb36c20
--- /dev/null
+++ b/app/components/datasets/chunk.tsx
@@ -0,0 +1,56 @@
+import type { FC, PropsWithChildren } from 'react'
+import { SelectionMod } from '../base/icons/src/public/knowledge'
+import type { QA } from '@/models/datasets'
+
+export type ChunkLabelProps = {
+ label: string
+ characterCount: number
+}
+
+export const ChunkLabel: FC<ChunkLabelProps> = (props) => {
+ const { label, characterCount } = props
+ return <div className='flex items-center text-xs font-medium text-text-tertiary'>
+ <SelectionMod className='size-[10px]' />
+ <p className='ml-0.5 flex gap-2'>
+ <span>
+ {label}
+ </span>
+ <span>
+ 路
+ </span>
+ <span>
+ {`${characterCount} characters`}
+ </span>
+ </p>
+ </div>
+}
+
+export type ChunkContainerProps = ChunkLabelProps & PropsWithChildren
+
+export const ChunkContainer: FC<ChunkContainerProps> = (props) => {
+ const { label, characterCount, children } = props
+ return <div className='space-y-2'>
+ <ChunkLabel label={label} characterCount={characterCount} />
+ <div className='body-md-regular text-text-secondary'>
+ {children}
+ </div>
+ </div>
+}
+
+export type QAPreviewProps = {
+ qa: QA
+}
+
+export const QAPreview: FC<QAPreviewProps> = (props) => {
+ const { qa } = props
+ return <div className='flex flex-col gap-y-2'>
+ <div className='flex gap-x-1'>
+ <label className='shrink-0 text-[13px] font-medium leading-[20px] text-text-tertiary'>Q</label>
+ <p className='body-md-regular text-text-secondary'>{qa.question}</p>
+ </div>
+ <div className='flex gap-x-1'>
+ <label className='shrink-0 text-[13px] font-medium leading-[20px] text-text-tertiary'>A</label>
+ <p className='body-md-regular text-text-secondary'>{qa.answer}</p>
+ </div>
+ </div>
+}
diff --git a/app/components/datasets/common/check-rerank-model.ts b/app/components/datasets/common/check-rerank-model.ts
new file mode 100644
index 0000000..ccb8c45
--- /dev/null
+++ b/app/components/datasets/common/check-rerank-model.ts
@@ -0,0 +1,70 @@
+import { RETRIEVE_METHOD, type RetrievalConfig } from '@/types/app'
+import type {
+ DefaultModelResponse,
+ Model,
+} from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { RerankingModeEnum } from '@/models/datasets'
+
+export const isReRankModelSelected = ({
+ retrievalConfig,
+ rerankModelList,
+ indexMethod,
+}: {
+ retrievalConfig: RetrievalConfig
+ rerankModelList: Model[]
+ indexMethod?: string
+}) => {
+ const rerankModelSelected = (() => {
+ if (retrievalConfig.reranking_model?.reranking_model_name) {
+ const provider = rerankModelList.find(({ provider }) => provider === retrievalConfig.reranking_model?.reranking_provider_name)
+
+ return provider?.models.find(({ model }) => model === retrievalConfig.reranking_model?.reranking_model_name)
+ }
+
+ return false
+ })()
+
+ if (
+ indexMethod === 'high_quality'
+ && ([RETRIEVE_METHOD.semantic, RETRIEVE_METHOD.fullText].includes(retrievalConfig.search_method))
+ && retrievalConfig.reranking_enable
+ && !rerankModelSelected
+ )
+ return false
+
+ if (
+ indexMethod === 'high_quality'
+ && (retrievalConfig.search_method === RETRIEVE_METHOD.hybrid && retrievalConfig.reranking_mode !== RerankingModeEnum.WeightedScore)
+ && !rerankModelSelected
+ )
+ return false
+
+ return true
+}
+
+export const ensureRerankModelSelected = ({
+ rerankDefaultModel,
+ indexMethod,
+ retrievalConfig,
+}: {
+ rerankDefaultModel: DefaultModelResponse
+ retrievalConfig: RetrievalConfig
+ indexMethod?: string
+}) => {
+ const rerankModel = retrievalConfig.reranking_model?.reranking_model_name ? retrievalConfig.reranking_model : undefined
+ if (
+ indexMethod === 'high_quality'
+ && (retrievalConfig.reranking_enable || retrievalConfig.search_method === RETRIEVE_METHOD.hybrid)
+ && !rerankModel
+ && rerankDefaultModel
+ ) {
+ return {
+ ...retrievalConfig,
+ reranking_model: {
+ reranking_provider_name: rerankDefaultModel.provider.provider,
+ reranking_model_name: rerankDefaultModel.model,
+ },
+ }
+ }
+ return retrievalConfig
+}
diff --git a/app/components/datasets/common/chunking-mode-label.tsx b/app/components/datasets/common/chunking-mode-label.tsx
new file mode 100644
index 0000000..ced0f44
--- /dev/null
+++ b/app/components/datasets/common/chunking-mode-label.tsx
@@ -0,0 +1,29 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Badge from '@/app/components/base/badge'
+import { GeneralType, ParentChildType } from '@/app/components/base/icons/src/public/knowledge'
+
+type Props = {
+ isGeneralMode: boolean
+ isQAMode: boolean
+}
+
+const ChunkingModeLabel: FC<Props> = ({
+ isGeneralMode,
+ isQAMode,
+}) => {
+ const { t } = useTranslation()
+ const TypeIcon = isGeneralMode ? GeneralType : ParentChildType
+
+ return (
+ <Badge>
+ <div className='flex h-full items-center space-x-0.5 text-text-tertiary'>
+ <TypeIcon className='h-3 w-3' />
+ <span className='system-2xs-medium-uppercase'>{isGeneralMode ? `${t('dataset.chunkingMode.general')}${isQAMode ? ' 路 QA' : ''}` : t('dataset.chunkingMode.parentChild')}</span>
+ </div>
+ </Badge>
+ )
+}
+export default React.memo(ChunkingModeLabel)
diff --git a/app/components/datasets/common/document-file-icon.tsx b/app/components/datasets/common/document-file-icon.tsx
new file mode 100644
index 0000000..5842cbb
--- /dev/null
+++ b/app/components/datasets/common/document-file-icon.tsx
@@ -0,0 +1,40 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import FileTypeIcon from '../../base/file-uploader/file-type-icon'
+import type { FileAppearanceType } from '@/app/components/base/file-uploader/types'
+import { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types'
+
+const extendToFileTypeMap: { [key: string]: FileAppearanceType } = {
+ pdf: FileAppearanceTypeEnum.pdf,
+ json: FileAppearanceTypeEnum.document,
+ html: FileAppearanceTypeEnum.document,
+ txt: FileAppearanceTypeEnum.document,
+ markdown: FileAppearanceTypeEnum.markdown,
+ md: FileAppearanceTypeEnum.markdown,
+ xlsx: FileAppearanceTypeEnum.excel,
+ xls: FileAppearanceTypeEnum.excel,
+ csv: FileAppearanceTypeEnum.excel,
+ doc: FileAppearanceTypeEnum.word,
+ docx: FileAppearanceTypeEnum.word,
+}
+
+type Props = {
+ extension?: string
+ name?: string
+ size?: 'sm' | 'lg' | 'md'
+ className?: string
+}
+
+const DocumentFileIcon: FC<Props> = ({
+ extension,
+ name,
+ size = 'md',
+ className,
+}) => {
+ const localExtension = extension?.toLowerCase() || name?.split('.')?.pop()?.toLowerCase()
+ return (
+ <FileTypeIcon type={extendToFileTypeMap[localExtension!] || FileAppearanceTypeEnum.document} size={size} className={className} />
+ )
+}
+export default React.memo(DocumentFileIcon)
diff --git a/app/components/datasets/common/document-picker/document-list.tsx b/app/components/datasets/common/document-picker/document-list.tsx
new file mode 100644
index 0000000..5ac98b9
--- /dev/null
+++ b/app/components/datasets/common/document-picker/document-list.tsx
@@ -0,0 +1,42 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import FileIcon from '../document-file-icon'
+import cn from '@/utils/classnames'
+import type { DocumentItem } from '@/models/datasets'
+
+type Props = {
+ className?: string
+ list: DocumentItem[]
+ onChange: (value: DocumentItem) => void
+}
+
+const DocumentList: FC<Props> = ({
+ className,
+ list,
+ onChange,
+}) => {
+ const handleChange = useCallback((item: DocumentItem) => {
+ return () => onChange(item)
+ }, [onChange])
+
+ return (
+ <div className={cn(className)}>
+ {list.map((item) => {
+ const { id, name, extension } = item
+ return (
+ <div
+ key={id}
+ className='flex h-8 cursor-pointer items-center space-x-2 rounded-lg px-2 hover:bg-state-base-hover'
+ onClick={handleChange(item)}
+ >
+ <FileIcon name={item.name} extension={extension} size='md' />
+ <div className='truncate text-sm text-text-secondary'>{name}</div>
+ </div>
+ )
+ })}
+ </div>
+ )
+}
+
+export default React.memo(DocumentList)
diff --git a/app/components/datasets/common/document-picker/index.tsx b/app/components/datasets/common/document-picker/index.tsx
new file mode 100644
index 0000000..d1a6a37
--- /dev/null
+++ b/app/components/datasets/common/document-picker/index.tsx
@@ -0,0 +1,118 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { useBoolean } from 'ahooks'
+import { RiArrowDownSLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import FileIcon from '../document-file-icon'
+import DocumentList from './document-list'
+import type { DocumentItem, ParentMode, SimpleDocumentDetail } from '@/models/datasets'
+import { ProcessMode } from '@/models/datasets'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import cn from '@/utils/classnames'
+import SearchInput from '@/app/components/base/search-input'
+import { GeneralType, ParentChildType } from '@/app/components/base/icons/src/public/knowledge'
+import { useDocumentList } from '@/service/knowledge/use-document'
+import Loading from '@/app/components/base/loading'
+
+type Props = {
+ datasetId: string
+ value: {
+ name?: string
+ extension?: string
+ processMode?: ProcessMode
+ parentMode?: ParentMode
+ }
+ onChange: (value: SimpleDocumentDetail) => void
+}
+
+const DocumentPicker: FC<Props> = ({
+ datasetId,
+ value,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const {
+ name,
+ extension,
+ processMode,
+ parentMode,
+ } = value
+ const [query, setQuery] = useState('')
+
+ const { data } = useDocumentList({
+ datasetId,
+ query: {
+ keyword: query,
+ page: 1,
+ limit: 20,
+ },
+ })
+ const documentsList = data?.data
+ const isParentChild = processMode === ProcessMode.parentChild
+ const TypeIcon = isParentChild ? ParentChildType : GeneralType
+
+ const [open, {
+ set: setOpen,
+ toggle: togglePopup,
+ }] = useBoolean(false)
+ const ArrowIcon = RiArrowDownSLine
+
+ const handleChange = useCallback(({ id }: DocumentItem) => {
+ onChange(documentsList?.find(item => item.id === id) as SimpleDocumentDetail)
+ setOpen(false)
+ }, [documentsList, onChange, setOpen])
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ >
+ <PortalToFollowElemTrigger onClick={togglePopup}>
+ <div className={cn('ml-1 flex cursor-pointer select-none items-center rounded-lg px-2 py-0.5 hover:bg-state-base-hover', open && 'bg-state-base-hover')}>
+ <FileIcon name={name} extension={extension} size='lg' />
+ <div className='ml-1 mr-0.5 flex flex-col items-start'>
+ <div className='flex items-center space-x-0.5'>
+ <span className={cn('system-md-semibold text-text-primary')}> {name || '--'}</span>
+ <ArrowIcon className={'h-4 w-4 text-text-primary'} />
+ </div>
+ <div className='flex h-3 items-center space-x-0.5 text-text-tertiary'>
+ <TypeIcon className='h-3 w-3' />
+ <span className={cn('system-2xs-medium-uppercase', isParentChild && 'mt-0.5' /* to icon problem cause not ver align */)}>
+ {isParentChild ? t('dataset.chunkingMode.parentChild') : t('dataset.chunkingMode.general')}
+ {isParentChild && ` 路 ${!parentMode ? '--' : parentMode === 'paragraph' ? t('dataset.parentMode.paragraph') : t('dataset.parentMode.fullDoc')}`}
+ </span>
+ </div>
+ </div>
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[11]'>
+ <div className='w-[360px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 pt-2 shadow-lg backdrop-blur-[5px]'>
+ <SearchInput value={query} onChange={setQuery} className='mx-1' />
+ {documentsList
+ ? (
+ <DocumentList
+ className='mt-2'
+ list={documentsList.map(d => ({
+ id: d.id,
+ name: d.name,
+ extension: d.data_source_detail_dict?.upload_file?.extension || '',
+ }))}
+ onChange={handleChange}
+ />
+ )
+ : (<div className='mt-2 flex h-[100px] w-[360px] items-center justify-center'>
+ <Loading />
+ </div>)}
+ </div>
+
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(DocumentPicker)
diff --git a/app/components/datasets/common/document-picker/preview-document-picker.tsx b/app/components/datasets/common/document-picker/preview-document-picker.tsx
new file mode 100644
index 0000000..a6de0c3
--- /dev/null
+++ b/app/components/datasets/common/document-picker/preview-document-picker.tsx
@@ -0,0 +1,82 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useBoolean } from 'ahooks'
+import { RiArrowDownSLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import FileIcon from '../document-file-icon'
+import DocumentList from './document-list'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import cn from '@/utils/classnames'
+import Loading from '@/app/components/base/loading'
+import type { DocumentItem } from '@/models/datasets'
+
+type Props = {
+ className?: string
+ value: DocumentItem
+ files: DocumentItem[]
+ onChange: (value: DocumentItem) => void
+}
+
+const PreviewDocumentPicker: FC<Props> = ({
+ className,
+ value,
+ files,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const { name, extension } = value
+
+ const [open, {
+ set: setOpen,
+ toggle: togglePopup,
+ }] = useBoolean(false)
+ const ArrowIcon = RiArrowDownSLine
+
+ const handleChange = useCallback((item: DocumentItem) => {
+ onChange(item)
+ setOpen(false)
+ }, [onChange, setOpen])
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <PortalToFollowElemTrigger onClick={togglePopup}>
+ <div className={cn('flex h-6 select-none items-center rounded-md px-1 hover:bg-state-base-hover', open && 'bg-state-base-hover', className)}>
+ <FileIcon name={name} extension={extension} size='md' />
+ <div className='ml-1 flex flex-col items-start'>
+ <div className='flex items-center space-x-0.5'>
+ <span className={cn('system-md-semibold max-w-[200px] truncate text-text-primary')}> {name || '--'}</span>
+ <ArrowIcon className={'h-[18px] w-[18px] text-text-primary'} />
+ </div>
+ </div>
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[11]'>
+ <div className='w-[392px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-[5px]'>
+ {files?.length > 1 && <div className='system-xs-medium-uppercase flex h-8 items-center pl-2 text-text-tertiary'>{t('dataset.preprocessDocument', { num: files.length })}</div>}
+ {files?.length > 0
+ ? (
+ <DocumentList
+ list={files}
+ onChange={handleChange}
+ />
+ )
+ : (<div className='mt-2 flex h-[100px] w-[360px] items-center justify-center'>
+ <Loading />
+ </div>)}
+ </div>
+
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(PreviewDocumentPicker)
diff --git a/app/components/datasets/common/document-status-with-action/auto-disabled-document.tsx b/app/components/datasets/common/document-status-with-action/auto-disabled-document.tsx
new file mode 100644
index 0000000..b687c00
--- /dev/null
+++ b/app/components/datasets/common/document-status-with-action/auto-disabled-document.tsx
@@ -0,0 +1,38 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import StatusWithAction from './status-with-action'
+import { useAutoDisabledDocuments, useDocumentEnable, useInvalidDisabledDocument } from '@/service/knowledge/use-document'
+import Toast from '@/app/components/base/toast'
+type Props = {
+ datasetId: string
+}
+
+const AutoDisabledDocument: FC<Props> = ({
+ datasetId,
+}) => {
+ const { t } = useTranslation()
+ const { data, isLoading } = useAutoDisabledDocuments(datasetId)
+ const invalidDisabledDocument = useInvalidDisabledDocument()
+ const documentIds = data?.document_ids
+ const hasDisabledDocument = documentIds && documentIds.length > 0
+ const { mutateAsync: enableDocument } = useDocumentEnable()
+ const handleEnableDocuments = useCallback(async () => {
+ await enableDocument({ datasetId, documentIds })
+ invalidDisabledDocument()
+ Toast.notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ }, [])
+ if (!hasDisabledDocument || isLoading)
+ return null
+
+ return (
+ <StatusWithAction
+ type='info'
+ description={t('dataset.documentsDisabled', { num: documentIds?.length })}
+ actionText={t('dataset.enable')}
+ onAction={handleEnableDocuments}
+ />
+ )
+}
+export default React.memo(AutoDisabledDocument)
diff --git a/app/components/datasets/common/document-status-with-action/index-failed.tsx b/app/components/datasets/common/document-status-with-action/index-failed.tsx
new file mode 100644
index 0000000..802e3d8
--- /dev/null
+++ b/app/components/datasets/common/document-status-with-action/index-failed.tsx
@@ -0,0 +1,70 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useReducer } from 'react'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import StatusWithAction from './status-with-action'
+import { getErrorDocs, retryErrorDocs } from '@/service/datasets'
+import type { IndexingStatusResponse } from '@/models/datasets'
+import { noop } from 'lodash-es'
+
+type Props = {
+ datasetId: string
+}
+type IIndexState = {
+ value: string
+}
+type ActionType = 'retry' | 'success' | 'error'
+
+type IAction = {
+ type: ActionType
+}
+const indexStateReducer = (state: IIndexState, action: IAction) => {
+ const actionMap = {
+ retry: 'retry',
+ success: 'success',
+ error: 'error',
+ }
+
+ return {
+ ...state,
+ value: actionMap[action.type] || state.value,
+ }
+}
+
+const RetryButton: FC<Props> = ({ datasetId }) => {
+ const { t } = useTranslation()
+ const [indexState, dispatch] = useReducer(indexStateReducer, { value: 'success' })
+ const { data: errorDocs, isLoading } = useSWR({ datasetId }, getErrorDocs)
+
+ const onRetryErrorDocs = async () => {
+ dispatch({ type: 'retry' })
+ const document_ids = errorDocs?.data.map((doc: IndexingStatusResponse) => doc.id) || []
+ const res = await retryErrorDocs({ datasetId, document_ids })
+ if (res.result === 'success')
+ dispatch({ type: 'success' })
+ else
+ dispatch({ type: 'error' })
+ }
+
+ useEffect(() => {
+ if (errorDocs?.total === 0)
+ dispatch({ type: 'success' })
+ else
+ dispatch({ type: 'error' })
+ }, [errorDocs?.total])
+
+ if (isLoading || indexState.value === 'success')
+ return null
+
+ return (
+ <StatusWithAction
+ type='warning'
+ description={`${errorDocs?.total} ${t('dataset.docsFailedNotice')}`}
+ actionText={t('dataset.retry')}
+ disabled={indexState.value === 'retry'}
+ onAction={indexState.value === 'error' ? onRetryErrorDocs : noop}
+ />
+ )
+}
+export default RetryButton
diff --git a/app/components/datasets/common/document-status-with-action/status-with-action.tsx b/app/components/datasets/common/document-status-with-action/status-with-action.tsx
new file mode 100644
index 0000000..0314b26
--- /dev/null
+++ b/app/components/datasets/common/document-status-with-action/status-with-action.tsx
@@ -0,0 +1,70 @@
+'use client'
+import { RiAlertFill, RiCheckboxCircleFill, RiErrorWarningFill, RiInformation2Fill } from '@remixicon/react'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import Divider from '@/app/components/base/divider'
+
+type Status = 'success' | 'error' | 'warning' | 'info'
+type Props = {
+ type?: Status
+ description: string
+ actionText?: string
+ onAction?: () => void
+ disabled?: boolean
+}
+
+const IconMap = {
+ success: {
+ Icon: RiCheckboxCircleFill,
+ color: 'text-text-success',
+ },
+ error: {
+ Icon: RiErrorWarningFill,
+ color: 'text-text-destructive',
+ },
+ warning: {
+ Icon: RiAlertFill,
+ color: 'text-text-warning-secondary',
+ },
+ info: {
+ Icon: RiInformation2Fill,
+ color: 'text-text-accent',
+ },
+}
+
+const getIcon = (type: Status) => {
+ return IconMap[type]
+}
+
+const StatusAction: FC<Props> = ({
+ type = 'info',
+ description,
+ actionText,
+ onAction,
+ disabled,
+}) => {
+ const { Icon, color } = getIcon(type)
+ return (
+ <div className='relative flex h-[34px] items-center rounded-lg border border-components-panel-border bg-components-panel-bg-blur pl-2 pr-3 shadow-xs'>
+ <div className={
+ `absolute inset-0 rounded-lg opacity-40 ${(type === 'success' && 'bg-[linear-gradient(92deg,rgba(23,178,106,0.25)_0%,rgba(255,255,255,0.00)_100%)]')
+ || (type === 'warning' && 'bg-[linear-gradient(92deg,rgba(247,144,9,0.25)_0%,rgba(255,255,255,0.00)_100%)]')
+ || (type === 'error' && 'bg-[linear-gradient(92deg,rgba(240,68,56,0.25)_0%,rgba(255,255,255,0.00)_100%)]')
+ || (type === 'info' && 'bg-[linear-gradient(92deg,rgba(11,165,236,0.25)_0%,rgba(255,255,255,0.00)_100%)]')
+ }`}
+ />
+ <div className='relative z-10 flex h-full items-center space-x-2'>
+ <Icon className={cn('h-4 w-4', color)} />
+ <div className='text-[13px] font-normal text-text-secondary'>{description}</div>
+ {onAction && (
+ <>
+ <Divider type='vertical' className='!h-4' />
+ <div onClick={onAction} className={cn('cursor-pointer text-[13px] font-semibold text-text-accent', disabled && 'cursor-not-allowed text-text-disabled')}>{actionText}</div>
+ </>
+ )}
+ </div>
+ </div>
+ )
+}
+export default React.memo(StatusAction)
diff --git a/app/components/datasets/common/economical-retrieval-method-config/index.tsx b/app/components/datasets/common/economical-retrieval-method-config/index.tsx
new file mode 100644
index 0000000..17cb3ef
--- /dev/null
+++ b/app/components/datasets/common/economical-retrieval-method-config/index.tsx
@@ -0,0 +1,42 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Image from 'next/image'
+import RetrievalParamConfig from '../retrieval-param-config'
+import { OptionCard } from '../../create/step-two/option-card'
+import { retrievalIcon } from '../../create/icons'
+import { RETRIEVE_METHOD } from '@/types/app'
+import type { RetrievalConfig } from '@/types/app'
+
+type Props = {
+ disabled?: boolean
+ value: RetrievalConfig
+ onChange: (value: RetrievalConfig) => void
+}
+
+const EconomicalRetrievalMethodConfig: FC<Props> = ({
+ disabled = false,
+ value,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='space-y-2'>
+ <OptionCard
+ disabled={disabled} icon={<Image className='h-4 w-4' src={retrievalIcon.vector} alt='' />}
+ title={t('dataset.retrieval.invertedIndex.title')}
+ description={t('dataset.retrieval.invertedIndex.description')} isActive
+ activeHeaderClassName='bg-dataset-option-card-purple-gradient'
+ >
+ <RetrievalParamConfig
+ type={RETRIEVE_METHOD.invertedIndex}
+ value={value}
+ onChange={onChange}
+ />
+ </OptionCard>
+ </div>
+ )
+}
+export default React.memo(EconomicalRetrievalMethodConfig)
diff --git a/app/components/datasets/common/retrieval-method-config/index.tsx b/app/components/datasets/common/retrieval-method-config/index.tsx
new file mode 100644
index 0000000..f979447
--- /dev/null
+++ b/app/components/datasets/common/retrieval-method-config/index.tsx
@@ -0,0 +1,157 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import Image from 'next/image'
+import RetrievalParamConfig from '../retrieval-param-config'
+import { OptionCard } from '../../create/step-two/option-card'
+import Effect from '../../create/assets/option-card-effect-purple.svg'
+import { retrievalIcon } from '../../create/icons'
+import type { RetrievalConfig } from '@/types/app'
+import { RETRIEVE_METHOD } from '@/types/app'
+import { useProviderContext } from '@/context/provider-context'
+import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import {
+ DEFAULT_WEIGHTED_SCORE,
+ RerankingModeEnum,
+ WeightedScoreEnum,
+} from '@/models/datasets'
+import Badge from '@/app/components/base/badge'
+
+type Props = {
+ disabled?: boolean
+ value: RetrievalConfig
+ onChange: (value: RetrievalConfig) => void
+}
+
+const RetrievalMethodConfig: FC<Props> = ({
+ disabled = false,
+ value,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const { supportRetrievalMethods } = useProviderContext()
+ const {
+ defaultModel: rerankDefaultModel,
+ currentModel: isRerankDefaultModelValid,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
+
+ const onSwitch = useCallback((retrieveMethod: RETRIEVE_METHOD) => {
+ if ([RETRIEVE_METHOD.semantic, RETRIEVE_METHOD.fullText].includes(retrieveMethod)) {
+ onChange({
+ ...value,
+ search_method: retrieveMethod,
+ ...(!value.reranking_model.reranking_model_name
+ ? {
+ reranking_model: {
+ reranking_provider_name: isRerankDefaultModelValid ? rerankDefaultModel?.provider?.provider ?? '' : '',
+ reranking_model_name: isRerankDefaultModelValid ? rerankDefaultModel?.model ?? '' : '',
+ },
+ reranking_enable: !!isRerankDefaultModelValid,
+ }
+ : {
+ reranking_enable: true,
+ }),
+ })
+ }
+ if (retrieveMethod === RETRIEVE_METHOD.hybrid) {
+ onChange({
+ ...value,
+ search_method: retrieveMethod,
+ ...(!value.reranking_model.reranking_model_name
+ ? {
+ reranking_model: {
+ reranking_provider_name: isRerankDefaultModelValid ? rerankDefaultModel?.provider?.provider ?? '' : '',
+ reranking_model_name: isRerankDefaultModelValid ? rerankDefaultModel?.model ?? '' : '',
+ },
+ reranking_enable: !!isRerankDefaultModelValid,
+ reranking_mode: isRerankDefaultModelValid ? RerankingModeEnum.RerankingModel : RerankingModeEnum.WeightedScore,
+ }
+ : {
+ reranking_enable: true,
+ reranking_mode: RerankingModeEnum.RerankingModel,
+ }),
+ ...(!value.weights
+ ? {
+ weights: {
+ weight_type: WeightedScoreEnum.Customized,
+ vector_setting: {
+ vector_weight: DEFAULT_WEIGHTED_SCORE.other.semantic,
+ embedding_provider_name: '',
+ embedding_model_name: '',
+ },
+ keyword_setting: {
+ keyword_weight: DEFAULT_WEIGHTED_SCORE.other.keyword,
+ },
+ },
+ }
+ : {}),
+ })
+ }
+ }, [value, rerankDefaultModel, isRerankDefaultModelValid, onChange])
+
+ return (
+ <div className='space-y-2'>
+ {supportRetrievalMethods.includes(RETRIEVE_METHOD.semantic) && (
+ <OptionCard disabled={disabled} icon={<Image className='h-4 w-4' src={retrievalIcon.vector} alt='' />}
+ title={t('dataset.retrieval.semantic_search.title')}
+ description={t('dataset.retrieval.semantic_search.description')}
+ isActive={
+ value.search_method === RETRIEVE_METHOD.semantic
+ }
+ onSwitched={() => onSwitch(RETRIEVE_METHOD.semantic)}
+ effectImg={Effect.src}
+ activeHeaderClassName='bg-dataset-option-card-purple-gradient'
+ >
+ <RetrievalParamConfig
+ type={RETRIEVE_METHOD.semantic}
+ value={value}
+ onChange={onChange}
+ />
+ </OptionCard>
+ )}
+ {supportRetrievalMethods.includes(RETRIEVE_METHOD.fullText) && (
+ <OptionCard disabled={disabled} icon={<Image className='h-4 w-4' src={retrievalIcon.fullText} alt='' />}
+ title={t('dataset.retrieval.full_text_search.title')}
+ description={t('dataset.retrieval.full_text_search.description')}
+ isActive={
+ value.search_method === RETRIEVE_METHOD.fullText
+ }
+ onSwitched={() => onSwitch(RETRIEVE_METHOD.fullText)}
+ effectImg={Effect.src}
+ activeHeaderClassName='bg-dataset-option-card-purple-gradient'
+ >
+ <RetrievalParamConfig
+ type={RETRIEVE_METHOD.fullText}
+ value={value}
+ onChange={onChange}
+ />
+ </OptionCard>
+ )}
+ {supportRetrievalMethods.includes(RETRIEVE_METHOD.hybrid) && (
+ <OptionCard disabled={disabled} icon={<Image className='h-4 w-4' src={retrievalIcon.hybrid} alt='' />}
+ title={
+ <div className='flex items-center space-x-1'>
+ <div>{t('dataset.retrieval.hybrid_search.title')}</div>
+ <Badge text={t('dataset.retrieval.hybrid_search.recommend')!} className='ml-1 h-[18px] border-text-accent-secondary text-text-accent-secondary' uppercase />
+ </div>
+ }
+ description={t('dataset.retrieval.hybrid_search.description')} isActive={
+ value.search_method === RETRIEVE_METHOD.hybrid
+ }
+ onSwitched={() => onSwitch(RETRIEVE_METHOD.hybrid)}
+ effectImg={Effect.src}
+ activeHeaderClassName='bg-dataset-option-card-purple-gradient'
+ >
+ <RetrievalParamConfig
+ type={RETRIEVE_METHOD.hybrid}
+ value={value}
+ onChange={onChange}
+ />
+ </OptionCard>
+ )}
+ </div>
+ )
+}
+export default React.memo(RetrievalMethodConfig)
diff --git a/app/components/datasets/common/retrieval-method-info/index.tsx b/app/components/datasets/common/retrieval-method-info/index.tsx
new file mode 100644
index 0000000..066cfd9
--- /dev/null
+++ b/app/components/datasets/common/retrieval-method-info/index.tsx
@@ -0,0 +1,64 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Image from 'next/image'
+import { retrievalIcon } from '../../create/icons'
+import type { RetrievalConfig } from '@/types/app'
+import { RETRIEVE_METHOD } from '@/types/app'
+import RadioCard from '@/app/components/base/radio-card'
+
+type Props = {
+ value: RetrievalConfig
+}
+
+export const getIcon = (type: RETRIEVE_METHOD) => {
+ return ({
+ [RETRIEVE_METHOD.semantic]: retrievalIcon.vector,
+ [RETRIEVE_METHOD.fullText]: retrievalIcon.fullText,
+ [RETRIEVE_METHOD.hybrid]: retrievalIcon.hybrid,
+ [RETRIEVE_METHOD.invertedIndex]: retrievalIcon.vector,
+ [RETRIEVE_METHOD.keywordSearch]: retrievalIcon.vector,
+ })[type] || retrievalIcon.vector
+}
+
+const EconomicalRetrievalMethodConfig: FC<Props> = ({
+ // type,
+ value,
+}) => {
+ const { t } = useTranslation()
+ const type = value.search_method
+ const icon = <Image className='size-3.5 text-util-colors-purple-purple-600' src={getIcon(type)} alt='' />
+ return (
+ <div className='space-y-2'>
+ <RadioCard
+ icon={icon}
+ title={t(`dataset.retrieval.${type}.title`)}
+ description={t(`dataset.retrieval.${type}.description`)}
+ noRadio
+ chosenConfigWrapClassName='!pb-3'
+ chosenConfig={
+ <div className='flex flex-wrap text-xs font-normal leading-[18px]'>
+ {value.reranking_model.reranking_model_name && (
+ <div className='mr-8 flex space-x-1'>
+ <div className='text-gray-500'>{t('common.modelProvider.rerankModel.key')}</div>
+ <div className='font-medium text-gray-800'>{value.reranking_model.reranking_model_name}</div>
+ </div>
+ )}
+
+ <div className='mr-8 flex space-x-1'>
+ <div className='text-gray-500'>{t('appDebug.datasetConfig.top_k')}</div>
+ <div className='font-medium text-gray-800'>{value.top_k}</div>
+ </div>
+
+ <div className='mr-8 flex space-x-1'>
+ <div className='text-gray-500'>{t('appDebug.datasetConfig.score_threshold')}</div>
+ <div className='font-medium text-gray-800'>{value.score_threshold}</div>
+ </div>
+ </div>
+ }
+ />
+ </div>
+ )
+}
+export default React.memo(EconomicalRetrievalMethodConfig)
diff --git a/app/components/datasets/common/retrieval-param-config/index.tsx b/app/components/datasets/common/retrieval-param-config/index.tsx
new file mode 100644
index 0000000..97e0a7f
--- /dev/null
+++ b/app/components/datasets/common/retrieval-param-config/index.tsx
@@ -0,0 +1,295 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+
+import Image from 'next/image'
+import ProgressIndicator from '../../create/assets/progress-indicator.svg'
+import Reranking from '../../create/assets/rerank.svg'
+import cn from '@/utils/classnames'
+import TopKItem from '@/app/components/base/param-item/top-k-item'
+import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item'
+import { RETRIEVE_METHOD } from '@/types/app'
+import Switch from '@/app/components/base/switch'
+import Tooltip from '@/app/components/base/tooltip'
+import type { RetrievalConfig } from '@/types/app'
+import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
+import { useCurrentProviderAndModel, useModelListAndDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import {
+ DEFAULT_WEIGHTED_SCORE,
+ RerankingModeEnum,
+ WeightedScoreEnum,
+} from '@/models/datasets'
+import WeightedScore from '@/app/components/app/configuration/dataset-config/params-config/weighted-score'
+import Toast from '@/app/components/base/toast'
+import RadioCard from '@/app/components/base/radio-card'
+
+type Props = {
+ type: RETRIEVE_METHOD
+ value: RetrievalConfig
+ onChange: (value: RetrievalConfig) => void
+}
+
+const RetrievalParamConfig: FC<Props> = ({
+ type,
+ value,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const canToggleRerankModalEnable = type !== RETRIEVE_METHOD.hybrid
+ const isEconomical = type === RETRIEVE_METHOD.invertedIndex
+ const isHybridSearch = type === RETRIEVE_METHOD.hybrid
+ const {
+ modelList: rerankModelList,
+ } = useModelListAndDefaultModel(ModelTypeEnum.rerank)
+
+ const {
+ currentModel,
+ } = useCurrentProviderAndModel(
+ rerankModelList,
+ {
+ provider: value.reranking_model?.reranking_provider_name ?? '',
+ model: value.reranking_model?.reranking_model_name ?? '',
+ },
+ )
+
+ const handleDisabledSwitchClick = useCallback((enable: boolean) => {
+ if (enable && !currentModel)
+ Toast.notify({ type: 'error', message: t('workflow.errorMsg.rerankModelRequired') })
+ onChange({
+ ...value,
+ reranking_enable: enable,
+ })
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [currentModel, onChange, value])
+
+ const rerankModel = useMemo(() => {
+ return {
+ provider_name: value.reranking_model.reranking_provider_name,
+ model_name: value.reranking_model.reranking_model_name,
+ }
+ }, [value.reranking_model])
+
+ const handleChangeRerankMode = (v: RerankingModeEnum) => {
+ if (v === value.reranking_mode)
+ return
+
+ const result = {
+ ...value,
+ reranking_mode: v,
+ }
+
+ if (!result.weights && v === RerankingModeEnum.WeightedScore) {
+ result.weights = {
+ weight_type: WeightedScoreEnum.Customized,
+ vector_setting: {
+ vector_weight: DEFAULT_WEIGHTED_SCORE.other.semantic,
+ embedding_provider_name: '',
+ embedding_model_name: '',
+ },
+ keyword_setting: {
+ keyword_weight: DEFAULT_WEIGHTED_SCORE.other.keyword,
+ },
+ }
+ }
+ if (v === RerankingModeEnum.RerankingModel && !currentModel)
+ Toast.notify({ type: 'error', message: t('workflow.errorMsg.rerankModelRequired') })
+ onChange(result)
+ }
+
+ const rerankingModeOptions = [
+ {
+ value: RerankingModeEnum.WeightedScore,
+ label: t('dataset.weightedScore.title'),
+ tips: t('dataset.weightedScore.description'),
+ },
+ {
+ value: RerankingModeEnum.RerankingModel,
+ label: t('common.modelProvider.rerankModel.key'),
+ tips: t('common.modelProvider.rerankModel.tip'),
+ },
+ ]
+
+ return (
+ <div>
+ {!isEconomical && !isHybridSearch && (
+ <div>
+ <div className='mb-2 flex items-center space-x-2'>
+ {canToggleRerankModalEnable && (
+ <Switch
+ size='md'
+ defaultValue={value.reranking_enable}
+ onChange={handleDisabledSwitchClick}
+ />
+ )}
+ <div className='flex items-center'>
+ <span className='system-sm-semibold mr-0.5 text-text-secondary'>{t('common.modelProvider.rerankModel.key')}</span>
+ <Tooltip
+ popupContent={
+ <div className="w-[200px]">{t('common.modelProvider.rerankModel.tip')}</div>
+ }
+ />
+ </div>
+ </div>
+ {
+ value.reranking_enable && (
+ <ModelSelector
+ defaultModel={rerankModel && { provider: rerankModel.provider_name, model: rerankModel.model_name }}
+ modelList={rerankModelList}
+ onSelect={(v) => {
+ onChange({
+ ...value,
+ reranking_model: {
+ reranking_provider_name: v.provider,
+ reranking_model_name: v.model,
+ },
+ })
+ }}
+ />
+ )
+ }
+ </div>
+ )}
+ {
+ !isHybridSearch && (
+ <div className={cn(!isEconomical && 'mt-4', 'space-between flex space-x-4')}>
+ <TopKItem
+ className='grow'
+ value={value.top_k}
+ onChange={(_key, v) => {
+ onChange({
+ ...value,
+ top_k: v,
+ })
+ }}
+ enable={true}
+ />
+ {(!isEconomical && !(value.search_method === RETRIEVE_METHOD.fullText && !value.reranking_enable)) && (
+ <ScoreThresholdItem
+ className='grow'
+ value={value.score_threshold}
+ onChange={(_key, v) => {
+ onChange({
+ ...value,
+ score_threshold: v,
+ })
+ }}
+ enable={value.score_threshold_enabled}
+ hasSwitch={true}
+ onSwitchChange={(_key, v) => {
+ onChange({
+ ...value,
+ score_threshold_enabled: v,
+ })
+ }}
+ />
+ )}
+ </div>
+ )
+ }
+ {
+ isHybridSearch && (
+ <>
+ <div className='mb-4 flex gap-2'>
+ {
+ rerankingModeOptions.map(option => (
+ <RadioCard
+ key={option.value}
+ isChosen={value.reranking_mode === option.value}
+ onChosen={() => handleChangeRerankMode(option.value)}
+ icon={<Image src={
+ option.value === RerankingModeEnum.WeightedScore
+ ? ProgressIndicator
+ : Reranking
+ } alt=''/>}
+ title={option.label}
+ description={option.tips}
+ className='flex-1'
+ />
+ ))
+ }
+ </div>
+ {
+ value.reranking_mode === RerankingModeEnum.WeightedScore && (
+ <WeightedScore
+ value={{
+ value: [
+ value.weights!.vector_setting.vector_weight,
+ value.weights!.keyword_setting.keyword_weight,
+ ],
+ }}
+ onChange={(v) => {
+ onChange({
+ ...value,
+ weights: {
+ ...value.weights!,
+ vector_setting: {
+ ...value.weights!.vector_setting,
+ vector_weight: v.value[0],
+ },
+ keyword_setting: {
+ ...value.weights!.keyword_setting,
+ keyword_weight: v.value[1],
+ },
+ },
+ })
+ }}
+ />
+ )
+ }
+ {
+ value.reranking_mode !== RerankingModeEnum.WeightedScore && (
+ <ModelSelector
+ defaultModel={rerankModel && { provider: rerankModel.provider_name, model: rerankModel.model_name }}
+ modelList={rerankModelList}
+ onSelect={(v) => {
+ onChange({
+ ...value,
+ reranking_model: {
+ reranking_provider_name: v.provider,
+ reranking_model_name: v.model,
+ },
+ })
+ }}
+ />
+ )
+ }
+ <div className={cn(!isEconomical && 'mt-4', 'space-between flex space-x-6')}>
+ <TopKItem
+ className='grow'
+ value={value.top_k}
+ onChange={(_key, v) => {
+ onChange({
+ ...value,
+ top_k: v,
+ })
+ }}
+ enable={true}
+ />
+ <ScoreThresholdItem
+ className='grow'
+ value={value.score_threshold}
+ onChange={(_key, v) => {
+ onChange({
+ ...value,
+ score_threshold: v,
+ })
+ }}
+ enable={value.score_threshold_enabled}
+ hasSwitch={true}
+ onSwitchChange={(_key, v) => {
+ onChange({
+ ...value,
+ score_threshold_enabled: v,
+ })
+ }}
+ />
+ </div>
+ </>
+ )
+ }
+ </div>
+ )
+}
+export default React.memo(RetrievalParamConfig)
diff --git a/app/components/datasets/create/assets/Icon-3-dots.svg b/app/components/datasets/create/assets/Icon-3-dots.svg
new file mode 100644
index 0000000..0955e5d
--- /dev/null
+++ b/app/components/datasets/create/assets/Icon-3-dots.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103" stroke="#374151" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/create/assets/Loading.svg b/app/components/datasets/create/assets/Loading.svg
new file mode 100644
index 0000000..9bce91e
--- /dev/null
+++ b/app/components/datasets/create/assets/Loading.svg
@@ -0,0 +1,16 @@
+<svg width="464" height="180" viewBox="0 0 464 180" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="464" height="180" rx="12" fill="#F9FAFB"/>
+<rect y="6" width="464" height="8" rx="3" fill="#EAECF0"/>
+<rect y="26" width="464" height="8" rx="3" fill="#EAECF0"/>
+<rect y="46" width="464" height="8" rx="3" fill="#EAECF0"/>
+<rect y="66" width="464" height="8" rx="3" fill="#EAECF0"/>
+<rect y="86" width="464" height="8" rx="3" fill="#EAECF0"/>
+<rect y="106" width="256" height="8" rx="3" fill="#EAECF0"/>
+<path d="M0 60H464V168C464 174.627 458.627 180 452 180H12C5.3726 180 0 174.627 0 168V60Z" fill="url(#paint0_linear_2131_10881)"/>
+<defs>
+<linearGradient id="paint0_linear_2131_10881" x1="232" y1="60" x2="232" y2="180" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FCFCFD" stop-opacity="0"/>
+<stop offset="0.741486" stop-color="#FCFCFD"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/alert-triangle.svg b/app/components/datasets/create/assets/alert-triangle.svg
new file mode 100644
index 0000000..5ba0731
--- /dev/null
+++ b/app/components/datasets/create/assets/alert-triangle.svg
@@ -0,0 +1,3 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.40616 0.834307C6.14751 0.719294 5.85222 0.719294 5.59356 0.834307C5.3938 0.923133 5.26403 1.07959 5.17373 1.20708C5.08495 1.33242 4.9899 1.49664 4.88536 1.67723L0.751783 8.81705C0.646828 8.9983 0.551451 9.16302 0.486781 9.3028C0.421056 9.44487 0.349754 9.63584 0.372478 9.85381C0.401884 10.1359 0.549654 10.3922 0.779012 10.5589C0.956259 10.6878 1.15726 10.7218 1.31314 10.7361C1.46651 10.7501 1.65684 10.7501 1.86628 10.7501H10.1334C10.3429 10.7501 10.5332 10.7501 10.6866 10.7361C10.8425 10.7218 11.0435 10.6878 11.2207 10.5589C11.4501 10.3922 11.5978 10.1359 11.6272 9.85381C11.65 9.63584 11.5787 9.44487 11.5129 9.3028C11.4483 9.16303 11.3529 8.99833 11.248 8.81709L7.11436 1.67722C7.00983 1.49663 6.91477 1.33242 6.82599 1.20708C6.73569 1.07959 6.60593 0.923133 6.40616 0.834307ZM6.49988 4.50012C6.49988 4.22398 6.27602 4.00012 5.99988 4.00012C5.72374 4.00012 5.49988 4.22398 5.49988 4.50012V6.50012C5.49988 6.77626 5.72374 7.00012 5.99988 7.00012C6.27602 7.00012 6.49988 6.77626 6.49988 6.50012V4.50012ZM5.99988 8.00012C5.72374 8.00012 5.49988 8.22398 5.49988 8.50012C5.49988 8.77626 5.72374 9.00012 5.99988 9.00012H6.00488C6.28102 9.00012 6.50488 8.77626 6.50488 8.50012C6.50488 8.22398 6.28102 8.00012 6.00488 8.00012H5.99988Z" fill="#F79009"/>
+</svg>
diff --git a/app/components/datasets/create/assets/annotation-info.svg b/app/components/datasets/create/assets/annotation-info.svg
new file mode 100644
index 0000000..2ffbc24
--- /dev/null
+++ b/app/components/datasets/create/assets/annotation-info.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16.2413 2H7.7587C6.95374 1.99999 6.28937 1.99998 5.74818 2.04419C5.18608 2.09012 4.66937 2.18868 4.18404 2.43598C3.43139 2.81947 2.81947 3.43139 2.43598 4.18404C2.18868 4.66937 2.09012 5.18608 2.04419 5.74818C1.99998 6.28937 1.99999 6.95372 2 7.75869V13.5343C1.99999 14.2041 1.99999 14.7569 2.03087 15.2095C2.06289 15.6788 2.13142 16.1129 2.30448 16.5307C2.71046 17.5108 3.48916 18.2895 4.46927 18.6955C4.88708 18.8686 5.32118 18.9371 5.79046 18.9691C6.24307 19 6.79594 19 7.46573 19H7.5C8.03656 19 8.14307 19.0063 8.22975 19.0268C8.38085 19.0624 8.52156 19.1328 8.64075 19.2322C8.70913 19.2893 8.77806 19.3708 9.1 19.8L10.5769 21.7692C10.6703 21.8938 10.7758 22.0346 10.8774 22.1476C10.9894 22.2721 11.1756 22.4555 11.4563 22.5647C11.806 22.7007 12.194 22.7007 12.5437 22.5647C12.8244 22.4555 13.0106 22.2721 13.1226 22.1476C13.2242 22.0346 13.3297 21.8938 13.4231 21.7692L14.9 19.8C15.2219 19.3708 15.2909 19.2893 15.3593 19.2322C15.4784 19.1328 15.6192 19.0624 15.7702 19.0268C15.8569 19.0063 15.9634 19 16.5 19H16.5343C17.2041 19 17.7569 19 18.2095 18.9691C18.6788 18.9371 19.1129 18.8686 19.5307 18.6955C20.5108 18.2895 21.2895 17.5108 21.6955 16.5307C21.8686 16.1129 21.9371 15.6788 21.9691 15.2095C22 14.7569 22 14.2041 22 13.5343V7.75868C22 6.95372 22 6.28937 21.9558 5.74818C21.9099 5.18608 21.8113 4.66937 21.564 4.18404C21.1805 3.43139 20.5686 2.81947 19.816 2.43598C19.3306 2.18868 18.8139 2.09012 18.2518 2.04419C17.7106 1.99998 17.0463 1.99999 16.2413 2ZM12 6C11.4477 6 11 6.44772 11 7C11 7.55229 11.4477 8 12 8H12.01C12.5623 8 13.01 7.55229 13.01 7C13.01 6.44772 12.5623 6 12.01 6H12ZM13 10.5C13 9.94772 12.5523 9.5 12 9.5C11.4477 9.5 11 9.94772 11 10.5V14C11 14.5523 11.4477 15 12 15C12.5523 15 13 14.5523 13 14V10.5Z" fill="#155EEF"/>
+</svg>
diff --git a/app/components/datasets/create/assets/arrow-narrow-left.svg b/app/components/datasets/create/assets/arrow-narrow-left.svg
new file mode 100644
index 0000000..5c37df2
--- /dev/null
+++ b/app/components/datasets/create/assets/arrow-narrow-left.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M13.3332 8H2.6665M2.6665 8L6.6665 12M2.6665 8L6.6665 4" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/create/assets/book-open-01.svg b/app/components/datasets/create/assets/book-open-01.svg
new file mode 100644
index 0000000..2f43afc
--- /dev/null
+++ b/app/components/datasets/create/assets/book-open-01.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.12" d="M1.33337 4.13333C1.33337 3.3866 1.33337 3.01323 1.4787 2.72801C1.60653 2.47713 1.8105 2.27316 2.06139 2.14532C2.3466 2 2.71997 2 3.46671 2H3.73337C5.22685 2 5.97358 2 6.54401 2.29065C7.04578 2.54631 7.45373 2.95426 7.70939 3.45603C8.00004 4.02646 8.00004 4.77319 8.00004 6.26667V14L7.93334 13.8999C7.47024 13.2053 7.2387 12.858 6.93277 12.6065C6.66195 12.3839 6.34988 12.2169 6.01444 12.1151C5.63554 12 5.21811 12 4.38326 12H3.46671C2.71997 12 2.3466 12 2.06139 11.8547C1.8105 11.7268 1.60653 11.5229 1.4787 11.272C1.33337 10.9868 1.33337 10.6134 1.33337 9.86667V4.13333Z" fill="#155EEF"/>
+<path d="M8.00004 14L7.93334 13.8999C7.47024 13.2053 7.2387 12.858 6.93278 12.6065C6.66195 12.3839 6.34988 12.2169 6.01444 12.1151C5.63554 12 5.21811 12 4.38326 12H3.46671C2.71997 12 2.3466 12 2.06139 11.8547C1.8105 11.7268 1.60653 11.5229 1.4787 11.272C1.33337 10.9868 1.33337 10.6134 1.33337 9.86667V4.13333C1.33337 3.3866 1.33337 3.01323 1.4787 2.72801C1.60653 2.47713 1.8105 2.27316 2.06139 2.14532C2.3466 2 2.71997 2 3.46671 2H3.73337C5.22685 2 5.97358 2 6.54402 2.29065C7.04578 2.54631 7.45373 2.95426 7.70939 3.45603C8.00004 4.02646 8.00004 4.77319 8.00004 6.26667M8.00004 14V6.26667M8.00004 14L8.06674 13.8999C8.52984 13.2053 8.76139 12.858 9.06731 12.6065C9.33814 12.3839 9.6502 12.2169 9.98564 12.1151C10.3645 12 10.782 12 11.6168 12H12.5334C13.2801 12 13.6535 12 13.9387 11.8547C14.1896 11.7268 14.3936 11.5229 14.5214 11.272C14.6667 10.9868 14.6667 10.6134 14.6667 9.86667V4.13333C14.6667 3.3866 14.6667 3.01323 14.5214 2.72801C14.3936 2.47713 14.1896 2.27316 13.9387 2.14532C13.6535 2 13.2801 2 12.5334 2H12.2667C10.7732 2 10.0265 2 9.45607 2.29065C8.9543 2.54631 8.54635 2.95426 8.29069 3.45603C8.00004 4.02646 8.00004 4.77319 8.00004 6.26667" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/create/assets/check.svg b/app/components/datasets/create/assets/check.svg
new file mode 100644
index 0000000..ae91c47
--- /dev/null
+++ b/app/components/datasets/create/assets/check.svg
@@ -0,0 +1,3 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10 3L4.5 8.5L2 6" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/create/assets/close.svg b/app/components/datasets/create/assets/close.svg
new file mode 100644
index 0000000..7a8ef6b
--- /dev/null
+++ b/app/components/datasets/create/assets/close.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12 4L4 12M4 4L12 12" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/create/assets/csv.svg b/app/components/datasets/create/assets/csv.svg
new file mode 100644
index 0000000..82a5efa
--- /dev/null
+++ b/app/components/datasets/create/assets/csv.svg
@@ -0,0 +1,22 @@
+<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_5938_919)">
+<path d="M3 5.8C3 4.11984 3 3.27976 3.32698 2.63803C3.6146 2.07354 4.07354 1.6146 4.63803 1.32698C5.27976 1 6.11984 1 7.8 1H14L21 8V18.2C21 19.8802 21 20.7202 20.673 21.362C20.3854 21.9265 19.9265 22.3854 19.362 22.673C18.7202 23 17.8802 23 16.2 23H7.8C6.11984 23 5.27976 23 4.63803 22.673C4.07354 22.3854 3.6146 21.9265 3.32698 21.362C3 20.7202 3 19.8802 3 18.2V5.8Z" fill="#169951"/>
+</g>
+<g opacity="0.96">
+<path d="M9.81332 16.4181C9.63132 17.5171 8.86832 18.0421 7.92332 18.0421C7.34232 18.0421 6.90132 17.8461 6.53732 17.4821C6.01232 16.9571 6.03332 16.2571 6.03332 15.5081C6.03332 14.7591 6.01232 14.0591 6.53732 13.5341C6.90132 13.1701 7.34232 12.9741 7.92332 12.9741C8.86832 12.9741 9.63132 13.4991 9.81332 14.5981H8.56732C8.49032 14.3181 8.33632 14.0661 7.93032 14.0661C7.70632 14.0661 7.53832 14.1571 7.44732 14.2761C7.33532 14.4231 7.25832 14.5981 7.25832 15.5081C7.25832 16.4181 7.33532 16.5931 7.44732 16.7401C7.53832 16.8591 7.70632 16.9501 7.93032 16.9501C8.33632 16.9501 8.49032 16.6981 8.56732 16.4181H9.81332Z" fill="white"/>
+<path d="M13.8059 16.4741C13.8059 17.4891 12.9309 18.0421 11.8809 18.0421C11.1179 18.0421 10.4949 17.9021 9.99094 17.3841L10.7749 16.6001C11.0339 16.8591 11.4889 16.9501 11.8879 16.9501C12.3709 16.9501 12.6019 16.7891 12.6019 16.5021C12.6019 16.3831 12.5739 16.2851 12.5039 16.2081C12.4409 16.1451 12.3359 16.0961 12.1749 16.0751L11.5729 15.9911C11.1319 15.9281 10.7959 15.7811 10.5719 15.5501C10.3409 15.3121 10.2289 14.9761 10.2289 14.5491C10.2289 13.6391 10.9149 12.9741 12.0489 12.9741C12.7629 12.9741 13.3019 13.1421 13.7289 13.5691L12.9589 14.3391C12.6439 14.0241 12.2309 14.0451 12.0139 14.0451C11.5869 14.0451 11.4119 14.2901 11.4119 14.5071C11.4119 14.5701 11.4329 14.6611 11.5099 14.7381C11.5729 14.8011 11.6779 14.8641 11.8529 14.8851L12.4549 14.9691C12.9029 15.0321 13.2249 15.1721 13.4349 15.3821C13.7009 15.6411 13.8059 16.0121 13.8059 16.4741Z" fill="white"/>
+<path d="M18.3124 13.0161L16.6604 18.0001H15.7504L14.1054 13.0161H15.3724L16.2124 15.8021L17.0384 13.0161H18.3124Z" fill="white"/>
+</g>
+<path opacity="0.5" d="M14 1L21 8H16C14.8954 8 14 7.10457 14 6V1Z" fill="white"/>
+<defs>
+<filter id="filter0_d_5938_919" x="1" y="0" width="22" height="26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5938_919"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5938_919" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/doc.svg b/app/components/datasets/create/assets/doc.svg
new file mode 100644
index 0000000..9a8aef5
--- /dev/null
+++ b/app/components/datasets/create/assets/doc.svg
@@ -0,0 +1,22 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_17194_49206)">
+<path d="M4 7.73301C4 5.4928 4 4.37269 4.43597 3.51705C4.81947 2.7644 5.43139 2.15248 6.18404 1.76898C7.03969 1.33301 8.15979 1.33301 10.4 1.33301H18.6667L28 10.6663V24.2663C28 26.5066 28 27.6267 27.564 28.4823C27.1805 29.2349 26.5686 29.8469 25.816 30.2304C24.9603 30.6663 23.8402 30.6663 21.6 30.6663H10.4C8.15979 30.6663 7.03969 30.6663 6.18404 30.2304C5.43139 29.8469 4.81947 29.2349 4.43597 28.4823C4 27.6267 4 26.5066 4 24.2663V7.73301Z" fill="#2349A9"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.33301L27.9998 10.6663H21.3332C19.8604 10.6663 18.6665 9.47243 18.6665 7.99967V1.33301Z" fill="white"/>
+<g opacity="0.96">
+<path d="M13.6329 21.4112C13.6329 22.2603 13.7059 22.9501 13.0326 23.5793C12.6351 23.9508 12.0754 24.11 11.4751 24.11H9.3335V18.7125H11.4751C12.0754 18.7125 12.6351 18.8717 13.0326 19.2431C13.7059 19.8723 13.6329 20.5622 13.6329 21.4112ZM12.2133 21.4112C12.2133 20.5015 12.1727 20.3499 12.0591 20.1983C11.9293 20.0164 11.7347 19.8951 11.3777 19.8951H10.7531V22.9274H11.3777C11.7347 22.9274 11.9293 22.8061 12.0591 22.6242C12.1727 22.4725 12.2133 22.3285 12.2133 21.4112Z" fill="white"/>
+<path d="M18.8275 21.4112C18.8275 22.2224 18.8519 22.9805 18.2435 23.549C17.8217 23.9432 17.3349 24.1555 16.6292 24.1555C15.9234 24.1555 15.4367 23.9432 15.0149 23.549C14.4065 22.9805 14.4308 22.2224 14.4308 21.4112C14.4308 20.6001 14.4065 19.842 15.0149 19.2735C15.4367 18.8793 15.9234 18.667 16.6292 18.667C17.3349 18.667 17.8217 18.8793 18.2435 19.2735C18.8519 19.842 18.8275 20.6001 18.8275 21.4112ZM17.4079 21.4112C17.4079 20.4257 17.3268 20.2438 17.197 20.0846C17.0916 19.9557 16.8888 19.8496 16.6292 19.8496C16.3696 19.8496 16.1668 19.9557 16.0613 20.0846C15.9316 20.2438 15.8504 20.4257 15.8504 21.4112C15.8504 22.3967 15.9316 22.5711 16.0613 22.7303C16.1668 22.8592 16.3696 22.9729 16.6292 22.9729C16.8888 22.9729 17.0916 22.8592 17.197 22.7303C17.3268 22.5711 17.4079 22.3967 17.4079 21.4112Z" fill="white"/>
+<path d="M24.0002 22.3967C23.7893 23.5869 22.905 24.1555 21.8099 24.1555C21.1366 24.1555 20.6256 23.9432 20.2037 23.549C19.5953 22.9805 19.6197 22.2224 19.6197 21.4112C19.6197 20.6001 19.5953 19.842 20.2037 19.2735C20.6256 18.8793 21.1366 18.667 21.8099 18.667C22.905 18.667 23.7893 19.2356 24.0002 20.4257H22.5562C22.467 20.1225 22.2885 19.8496 21.818 19.8496C21.5584 19.8496 21.3638 19.9481 21.2583 20.077C21.1285 20.2362 21.0393 20.4257 21.0393 21.4112C21.0393 22.3967 21.1285 22.5863 21.2583 22.7455C21.3638 22.8743 21.5584 22.9729 21.818 22.9729C22.2885 22.9729 22.467 22.7 22.5562 22.3967H24.0002Z" fill="white"/>
+</g>
+<defs>
+<filter id="filter0_d_17194_49206" x="2" y="0.333008" width="28" height="33.333" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_17194_49206"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_17194_49206" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/docx.svg b/app/components/datasets/create/assets/docx.svg
new file mode 100644
index 0000000..5f8fa51
--- /dev/null
+++ b/app/components/datasets/create/assets/docx.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_10291_62253)">
+<path d="M4 7.73301C4 5.4928 4 4.37269 4.43597 3.51705C4.81947 2.7644 5.43139 2.15248 6.18404 1.76898C7.03969 1.33301 8.15979 1.33301 10.4 1.33301H18.6667L28 10.6663V24.2663C28 26.5065 28 27.6267 27.564 28.4823C27.1805 29.2349 26.5686 29.8469 25.816 30.2304C24.9603 30.6663 23.8402 30.6663 21.6 30.6663H10.4C8.15979 30.6663 7.03969 30.6663 6.18404 30.2304C5.43139 29.8469 4.81947 29.2349 4.43597 28.4823C4 27.6267 4 26.5065 4 24.2663V7.73301Z" fill="#2349A9"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.33301L27.9998 10.6663H21.3332C19.8604 10.6663 18.6665 9.47243 18.6665 7.99967V1.33301Z" fill="white"/>
+<g opacity="0.96">
+<path d="M10.8443 21.3337C10.8443 22.1587 10.9153 22.8291 10.261 23.4405C9.87477 23.8014 9.33086 23.9561 8.74754 23.9561H6.6665V18.7112H8.74754C9.33086 18.7112 9.87477 18.8659 10.261 19.2268C10.9153 19.8383 10.8443 20.5086 10.8443 21.3337ZM9.46487 21.3337C9.46487 20.4497 9.42545 20.3024 9.31509 20.155C9.18897 19.9782 8.99979 19.8604 8.65295 19.8604H8.04598V22.807H8.65295C8.99979 22.807 9.18897 22.6891 9.31509 22.5123C9.42545 22.365 9.46487 22.225 9.46487 21.3337Z" fill="white"/>
+<path d="M15.8922 21.3337C15.8922 22.1219 15.9158 22.8585 15.3246 23.411C14.9147 23.7941 14.4418 24.0003 13.756 24.0003C13.0702 24.0003 12.5972 23.7941 12.1873 23.411C11.5961 22.8585 11.6197 22.1219 11.6197 21.3337C11.6197 20.5454 11.5961 19.8088 12.1873 19.2563C12.5972 18.8733 13.0702 18.667 13.756 18.667C14.4418 18.667 14.9147 18.8733 15.3246 19.2563C15.9158 19.8088 15.8922 20.5454 15.8922 21.3337ZM14.5127 21.3337C14.5127 20.376 14.4339 20.1992 14.3077 20.0445C14.2053 19.9193 14.0082 19.8162 13.756 19.8162C13.5037 19.8162 13.3066 19.9193 13.2042 20.0445C13.078 20.1992 12.9992 20.376 12.9992 21.3337C12.9992 22.2913 13.078 22.4607 13.2042 22.6154C13.3066 22.7407 13.5037 22.8512 13.756 22.8512C14.0082 22.8512 14.2053 22.7407 14.3077 22.6154C14.4339 22.4607 14.5127 22.2913 14.5127 21.3337Z" fill="white"/>
+<path d="M20.9186 22.2913C20.7136 23.4478 19.8544 24.0003 18.7902 24.0003C18.136 24.0003 17.6394 23.7941 17.2295 23.411C16.6383 22.8585 16.6619 22.1219 16.6619 21.3337C16.6619 20.5454 16.6383 19.8088 17.2295 19.2563C17.6394 18.8733 18.136 18.667 18.7902 18.667C19.8544 18.667 20.7136 19.2195 20.9186 20.376H19.5154C19.4287 20.0814 19.2553 19.8162 18.7981 19.8162C18.5459 19.8162 18.3567 19.9119 18.2542 20.0372C18.1281 20.1919 18.0414 20.376 18.0414 21.3337C18.0414 22.2913 18.1281 22.4755 18.2542 22.6302C18.3567 22.7554 18.5459 22.8512 18.7981 22.8512C19.2553 22.8512 19.4287 22.586 19.5154 22.2913H20.9186Z" fill="white"/>
+<path d="M25.9998 23.9561H24.4233L23.501 22.3429L22.5787 23.9561H21.0022L22.7522 21.2674L21.1126 18.7112H22.6812L23.501 20.1919L24.3208 18.7112H25.8895L24.2499 21.2674L25.9998 23.9561Z" fill="white"/>
+</g>
+<defs>
+<filter id="filter0_d_10291_62253" x="2" y="0.333008" width="28" height="33.333" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_10291_62253"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_10291_62253" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/family-mod.svg b/app/components/datasets/create/assets/family-mod.svg
new file mode 100644
index 0000000..b1c4e6f
--- /dev/null
+++ b/app/components/datasets/create/assets/family-mod.svg
@@ -0,0 +1,6 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M6.18055 6.45828C7.52291 6.45828 8.61111 5.37008 8.61111 4.02772C8.61111 2.68536 7.52291 1.59717 6.18055 1.59717C4.8382 1.59717 3.75 2.68536 3.75 4.02772C3.75 5.37008 4.8382 6.45828 6.18055 6.45828Z" fill="#EF6820"/>
+ <path d="M13.8192 6.45828C15.1616 6.45828 16.2498 5.37008 16.2498 4.02772C16.2498 2.68536 15.1616 1.59717 13.8192 1.59717C12.4769 1.59717 11.3887 2.68536 11.3887 4.02772C11.3887 5.37008 12.4769 6.45828 13.8192 6.45828Z" fill="#EF6820"/>
+ <path d="M13.8193 7.84719C13.0627 7.84805 12.3185 8.03933 11.6552 8.40341C10.992 8.7675 10.4311 9.29267 10.0241 9.93053C10.5745 9.93695 11.1 10.1609 11.4858 10.5535C11.8716 10.9461 12.0864 11.4755 12.0831 12.0259C12.0799 12.5763 11.859 13.1031 11.4687 13.4911C11.0783 13.8792 10.5503 14.097 9.99984 14.097C9.44942 14.097 8.92135 13.8792 8.53101 13.4911C8.14066 13.1031 7.91976 12.5763 7.91655 12.0259C7.91334 11.4755 8.12808 10.9461 8.51387 10.5535C8.89966 10.1609 9.42515 9.93695 9.97554 9.93053C9.45127 9.10686 8.67371 8.47572 7.75983 8.13205C6.84596 7.78839 5.84519 7.75078 4.9081 8.0249C3.97101 8.29902 3.14828 8.87003 2.56368 9.65203C1.97908 10.434 1.66424 11.3847 1.66652 12.3611V16.875C1.66652 17.0591 1.73968 17.2358 1.86991 17.366C2.00015 17.4962 2.17678 17.5694 2.36096 17.5694H7.22207V15.8333L4.72207 13.9583C4.64911 13.9036 4.58765 13.835 4.54118 13.7566C4.49472 13.6781 4.46417 13.5912 4.45127 13.501C4.42522 13.3186 4.47267 13.1334 4.58318 12.9861C4.69369 12.8387 4.8582 12.7413 5.04053 12.7153C5.22285 12.6892 5.40806 12.7367 5.5554 12.8472L8.14776 14.7916H11.8519L14.4443 12.8472C14.5916 12.7367 14.7768 12.6892 14.9592 12.7153C15.1415 12.7413 15.306 12.8387 15.4165 12.9861C15.527 13.1334 15.5745 13.3186 15.5484 13.501C15.5224 13.6833 15.425 13.8478 15.2776 13.9583L12.7776 15.8333V17.5694H17.6387C17.8229 17.5694 17.9995 17.4962 18.1298 17.366C18.26 17.2358 18.3332 17.0591 18.3332 16.875V12.3611C18.3317 11.1644 17.8557 10.0171 17.0095 9.17091C16.1633 8.32471 15.016 7.84867 13.8193 7.84719Z" fill="#EF6820"/>
+ </svg>
+
\ No newline at end of file
diff --git a/app/components/datasets/create/assets/file-list-3-fill.svg b/app/components/datasets/create/assets/file-list-3-fill.svg
new file mode 100644
index 0000000..a4e6c4d
--- /dev/null
+++ b/app/components/datasets/create/assets/file-list-3-fill.svg
@@ -0,0 +1,5 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="file-list-3-fill">
+<path id="Vector" d="M15.8332 18.3333H4.1665C2.7858 18.3333 1.6665 17.2141 1.6665 15.8333V2.50001C1.6665 2.03977 2.0396 1.66667 2.49984 1.66667H14.1665C14.6268 1.66667 14.9998 2.03977 14.9998 2.50001V12.5H18.3332V15.8333C18.3332 17.2141 17.2139 18.3333 15.8332 18.3333ZM14.9998 14.1667V15.8333C14.9998 16.2936 15.3729 16.6667 15.8332 16.6667C16.2934 16.6667 16.6665 16.2936 16.6665 15.8333V14.1667H14.9998ZM4.99984 5.83334V7.50001H11.6665V5.83334H4.99984ZM4.99984 9.16667V10.8333H11.6665V9.16667H4.99984ZM4.99984 12.5V14.1667H9.1665V12.5H4.99984Z" fill="#1570EF"/>
+</g>
+</svg>
diff --git a/app/components/datasets/create/assets/file.svg b/app/components/datasets/create/assets/file.svg
new file mode 100644
index 0000000..137086a
--- /dev/null
+++ b/app/components/datasets/create/assets/file.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.66667 1.34356C8.66667 1.32602 8.66667 1.31725 8.66591 1.30135C8.65018 0.972168 8.3607 0.682824 8.03151 0.667251C8.01562 0.666499 8.0104 0.666501 8.00001 0.666504H5.8391C5.30248 0.666497 4.85957 0.666491 4.49878 0.695968C4.12405 0.726585 3.77958 0.792295 3.45603 0.957155C2.95426 1.21282 2.54631 1.62077 2.29065 2.12253C2.12579 2.44609 2.06008 2.79056 2.02946 3.16529C1.99999 3.52608 1.99999 3.96899 2 4.50562V11.494C1.99999 12.0307 1.99999 12.4736 2.02946 12.8344C2.06008 13.2091 2.12579 13.5536 2.29065 13.8771C2.54631 14.3789 2.95426 14.7869 3.45603 15.0425C3.77958 15.2074 4.12405 15.2731 4.49878 15.3037C4.85958 15.3332 5.30248 15.3332 5.83912 15.3332H10.1609C10.6975 15.3332 11.1404 15.3332 11.5012 15.3037C11.8759 15.2731 12.2204 15.2074 12.544 15.0425C13.0457 14.7869 13.4537 14.3789 13.7093 13.8771C13.8742 13.5536 13.9399 13.2091 13.9705 12.8344C14 12.4736 14 12.0307 14 11.4941V6.66646C14 6.65611 14 6.65093 13.9993 6.63505C13.9837 6.30583 13.6943 6.01631 13.3651 6.0006C13.3492 5.99985 13.3405 5.99985 13.323 5.99985L10.3787 5.99985C10.2105 5.99987 10.0466 5.99989 9.90785 5.98855C9.75545 5.9761 9.57563 5.94672 9.39468 5.85452C9.1438 5.72669 8.93983 5.52272 8.81199 5.27183C8.7198 5.09088 8.69042 4.91106 8.67797 4.75867C8.66663 4.61989 8.66665 4.45603 8.66667 4.28778L8.66667 1.34356ZM5.33333 8.6665C4.96514 8.6665 4.66667 8.96498 4.66667 9.33317C4.66667 9.70136 4.96514 9.99984 5.33333 9.99984H10.6667C11.0349 9.99984 11.3333 9.70136 11.3333 9.33317C11.3333 8.96498 11.0349 8.6665 10.6667 8.6665H5.33333ZM5.33333 11.3332C4.96514 11.3332 4.66667 11.6316 4.66667 11.9998C4.66667 12.368 4.96514 12.6665 5.33333 12.6665H9.33333C9.70152 12.6665 10 12.368 10 11.9998C10 11.6316 9.70152 11.3332 9.33333 11.3332H5.33333Z" fill="#444CE7"/>
+<path d="M12.6053 4.6665C12.8011 4.6665 12.8989 4.6665 12.9791 4.61735C13.0923 4.54794 13.16 4.3844 13.129 4.25526C13.107 4.16382 13.0432 4.10006 12.9155 3.97253L10.694 1.75098C10.5664 1.62333 10.5027 1.5595 10.4112 1.53752C10.2821 1.50648 10.1186 1.57417 10.0492 1.6874C10 1.76757 10 1.86545 10 2.0612L10 4.13315C10 4.31982 10 4.41316 10.0363 4.48446C10.0683 4.54718 10.1193 4.59818 10.182 4.63014C10.2533 4.66647 10.3466 4.66647 10.5333 4.66647L12.6053 4.6665Z" fill="#444CE7"/>
+</svg>
diff --git a/app/components/datasets/create/assets/folder-plus.svg b/app/components/datasets/create/assets/folder-plus.svg
new file mode 100644
index 0000000..c63a58b
--- /dev/null
+++ b/app/components/datasets/create/assets/folder-plus.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.66683 4.66667L7.92314 3.17928C7.7091 2.7512 7.60207 2.53715 7.44241 2.38078C7.30122 2.24249 7.13105 2.13732 6.94421 2.07287C6.73294 2 6.49363 2 6.01502 2H3.46683C2.72009 2 2.34672 2 2.06151 2.14532C1.81063 2.27316 1.60665 2.47713 1.47882 2.72801C1.3335 3.01323 1.3335 3.3866 1.3335 4.13333V4.66667M1.3335 4.66667H11.4668C12.5869 4.66667 13.147 4.66667 13.5748 4.88465C13.9511 5.0764 14.2571 5.38236 14.4488 5.75869C14.6668 6.18651 14.6668 6.74656 14.6668 7.86667V10.8C14.6668 11.9201 14.6668 12.4802 14.4488 12.908C14.2571 13.2843 13.9511 13.5903 13.5748 13.782C13.147 14 12.5869 14 11.4668 14H4.5335C3.41339 14 2.85334 14 2.42552 13.782C2.04919 13.5903 1.74323 13.2843 1.55148 12.908C1.3335 12.4802 1.3335 11.9201 1.3335 10.8V4.66667ZM8.00016 11.3333V7.33333M6.00016 9.33333H10.0002" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/create/assets/gold.svg b/app/components/datasets/create/assets/gold.svg
new file mode 100644
index 0000000..b48ac0e
--- /dev/null
+++ b/app/components/datasets/create/assets/gold.svg
@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M9.99984 1.66663C8.35166 1.66663 6.7405 2.15537 5.37009 3.07105C3.99968 3.98672 2.93157 5.28821 2.30084 6.81093C1.67011 8.33365 1.50509 10.0092 1.82663 11.6257C2.14817 13.2422 2.94185 14.7271 4.10728 15.8925C5.27272 17.058 6.75758 17.8516 8.37409 18.1732C9.9906 18.4947 11.6662 18.3297 13.1889 17.699C14.7116 17.0682 16.0131 16.0001 16.9288 14.6297C17.8444 13.2593 18.3332 11.6481 18.3332 9.99996C18.3332 7.78982 17.4552 5.67021 15.8924 4.1074C14.3296 2.5446 12.21 1.66663 9.99984 1.66663ZM12.295 5.65899L13.1116 4.53538C13.1653 4.46155 13.2329 4.39901 13.3107 4.35133C13.3885 4.30365 13.4749 4.27175 13.565 4.25747C13.6551 4.24319 13.7472 4.24679 13.8359 4.26809C13.9246 4.28938 14.0083 4.32793 14.0821 4.38156C14.156 4.43518 14.2185 4.50282 14.2662 4.58061C14.3139 4.6584 14.3458 4.74482 14.36 4.83494C14.3743 4.92506 14.3707 5.01711 14.3494 5.10583C14.3281 5.19456 14.2896 5.27822 14.236 5.35204L13.4193 6.47565C13.311 6.62474 13.1479 6.72471 12.9659 6.75356C12.7839 6.7824 12.5979 6.73777 12.4488 6.62947C12.2997 6.52118 12.1997 6.35809 12.1709 6.17609C12.142 5.99408 12.1867 5.80808 12.295 5.65899ZM5.9179 4.3819C5.99174 4.32795 6.07551 4.28911 6.1644 4.26761C6.25329 4.24612 6.34556 4.2424 6.43589 4.25666C6.52623 4.27092 6.61286 4.30288 6.69081 4.35071C6.76875 4.39854 6.83649 4.4613 6.89012 4.53538L7.70817 5.65899C7.81647 5.80854 7.86092 5.99499 7.83175 6.17731C7.80258 6.35964 7.70217 6.52291 7.55262 6.63121C7.40307 6.73951 7.21662 6.78396 7.03429 6.75478C6.85196 6.72561 6.68869 6.62521 6.5804 6.47565L5.76373 5.35204C5.71013 5.27823 5.6716 5.19457 5.65034 5.10586C5.62908 5.01715 5.62551 4.92512 5.63983 4.83503C5.65414 4.74494 5.68607 4.65855 5.73378 4.5808C5.78149 4.50306 5.84406 4.43547 5.9179 4.3819ZM5.59151 12.1597L4.27206 12.5888C4.18433 12.6215 4.0909 12.6361 3.99739 12.6317C3.90388 12.6273 3.81222 12.6041 3.72791 12.5634C3.64361 12.5227 3.56841 12.4654 3.50682 12.3949C3.44524 12.3244 3.39854 12.2421 3.36954 12.1531C3.34055 12.0641 3.32984 11.9702 3.33808 11.8769C3.34631 11.7837 3.37332 11.693 3.41747 11.6105C3.46162 11.528 3.522 11.4552 3.59499 11.3966C3.66798 11.3379 3.75207 11.2947 3.8422 11.2694L5.16165 10.8402C5.24947 10.8072 5.34308 10.7924 5.43681 10.7965C5.53054 10.8007 5.62245 10.8238 5.707 10.8645C5.79154 10.9052 5.86697 10.9626 5.92872 11.0332C5.99047 11.1039 6.03727 11.1863 6.06629 11.2755C6.09531 11.3647 6.10595 11.4589 6.09757 11.5524C6.08919 11.6458 6.06195 11.7366 6.01752 11.8192C5.97308 11.9018 5.91236 11.9746 5.83902 12.0331C5.76568 12.0916 5.68194 12.1347 5.59151 12.1597ZM10.6943 16.25C10.6943 16.4341 10.6211 16.6108 10.4909 16.741C10.3607 16.8712 10.184 16.9444 9.99984 16.9444C9.81566 16.9444 9.63903 16.8712 9.50879 16.741C9.37856 16.6108 9.3054 16.4341 9.3054 16.25V14.8611C9.3054 14.6769 9.37856 14.5003 9.50879 14.37C9.63903 14.2398 9.81566 14.1666 9.99984 14.1666C10.184 14.1666 10.3607 14.2398 10.4909 14.37C10.6211 14.5003 10.6943 14.6769 10.6943 14.8611V16.25ZM9.99984 12.2222L7.38595 13.5972L7.88526 10.6868L5.77067 8.62565L8.6929 8.20135L9.99984 5.55551L11.3068 8.20135L14.229 8.62565L12.1144 10.6868L12.6137 13.5972L9.99984 12.2222ZM15.729 12.5902L14.4096 12.1611C14.3191 12.1361 14.2347 12.093 14.1614 12.0345C14.088 11.976 14.0273 11.9032 13.9829 11.8206C13.9384 11.738 13.9112 11.6472 13.9028 11.5537C13.8944 11.4603 13.9051 11.3661 13.9341 11.2769C13.9631 11.1877 14.0099 11.1053 14.0717 11.0346C14.1334 10.964 14.2088 10.9066 14.2934 10.8659C14.3779 10.8252 14.4698 10.8021 14.5636 10.7979C14.6573 10.7938 14.7509 10.8086 14.8387 10.8416L16.1582 11.2708C16.2483 11.2961 16.3324 11.3393 16.4054 11.398C16.4784 11.4566 16.5388 11.5293 16.5829 11.6119C16.6271 11.6944 16.6541 11.7851 16.6623 11.8783C16.6705 11.9716 16.6598 12.0655 16.6308 12.1545C16.6018 12.2435 16.5551 12.3258 16.4936 12.3963C16.432 12.4668 16.3568 12.5241 16.2725 12.5648C16.1882 12.6055 16.0965 12.6287 16.003 12.6331C15.9095 12.6375 15.8167 12.6229 15.729 12.5902Z" fill="#EF6820"/>
+ </svg>
+
\ No newline at end of file
diff --git a/app/components/datasets/create/assets/html.svg b/app/components/datasets/create/assets/html.svg
new file mode 100644
index 0000000..f4db500
--- /dev/null
+++ b/app/components/datasets/create/assets/html.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14424)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#EC5B27"/>
+</g>
+<g opacity="0.96">
+<path d="M10.2704 24.0002V18.3042H8.87042V20.4962H7.38242V18.3042H5.98242V24.0002H7.38242V21.7442H8.87042V24.0002H10.2704Z" fill="white"/>
+<path d="M15.2839 19.5522V18.3042H11.0839V19.5522H12.4839V24.0002H13.8839V19.5522H15.2839Z" fill="white"/>
+<path d="M21.4116 24.0002V18.3042H20.0356L18.7556 20.8162L17.4756 18.3042H16.0996V24.0002H17.4996V21.2722L18.3076 22.6802H19.2036L20.0116 21.2722V24.0002H21.4116Z" fill="white"/>
+<path d="M26.3525 24.0002V22.7522H23.9605V18.3042H22.5605V24.0002H26.3525Z" fill="white"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14424" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14424"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14424" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/jina.png b/app/components/datasets/create/assets/jina.png
new file mode 100644
index 0000000..b4beeaf
--- /dev/null
+++ b/app/components/datasets/create/assets/jina.png
Binary files differ
diff --git a/app/components/datasets/create/assets/json.svg b/app/components/datasets/create/assets/json.svg
new file mode 100644
index 0000000..0876828
--- /dev/null
+++ b/app/components/datasets/create/assets/json.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14428)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#2D2D2E"/>
+</g>
+<g opacity="0.96">
+<path d="M9.83907 22.0479V18.3039H8.43907V22.0159C8.43907 22.5599 8.12707 22.7999 7.69507 22.7999C7.38307 22.7999 7.23907 22.6879 7.06307 22.5119L6.14307 23.4239C6.60707 23.8879 7.03107 24.0479 7.69507 24.0479C8.76707 24.0479 9.83907 23.3999 9.83907 22.0479Z" fill="white"/>
+<path d="M14.7321 22.2559C14.7321 21.7279 14.6121 21.3039 14.3081 21.0079C14.0681 20.7679 13.7001 20.6079 13.1881 20.5359L12.5001 20.4399C12.3001 20.4159 12.1801 20.3439 12.1081 20.2719C12.0201 20.1839 11.9961 20.0799 11.9961 20.0079C11.9961 19.7599 12.1961 19.4799 12.6841 19.4799C12.9321 19.4799 13.4041 19.4559 13.7641 19.8159L14.6441 18.9359C14.1561 18.4479 13.5401 18.2559 12.7241 18.2559C11.4281 18.2559 10.6441 19.0159 10.6441 20.0559C10.6441 20.5439 10.7721 20.9279 11.0361 21.1999C11.2921 21.4639 11.6761 21.6319 12.1801 21.7039L12.8681 21.7999C13.0521 21.8239 13.1721 21.8799 13.2441 21.9519C13.3241 22.0399 13.3561 22.1519 13.3561 22.2879C13.3561 22.6159 13.0921 22.7999 12.5401 22.7999C12.0841 22.7999 11.5641 22.6959 11.2681 22.3999L10.3721 23.2959C10.9481 23.8879 11.6601 24.0479 12.5321 24.0479C13.7321 24.0479 14.7321 23.4159 14.7321 22.2559Z" fill="white"/>
+<path d="M19.8023 21.1519C19.8023 20.2959 19.8263 19.4959 19.2263 18.8959C18.8103 18.4799 18.3303 18.2559 17.6343 18.2559C16.9383 18.2559 16.4583 18.4799 16.0423 18.8959C15.4423 19.4959 15.4663 20.2959 15.4663 21.1519C15.4663 22.0079 15.4423 22.8079 16.0423 23.4079C16.4583 23.8239 16.9383 24.0479 17.6343 24.0479C18.3303 24.0479 18.8103 23.8239 19.2263 23.4079C19.8263 22.8079 19.8023 22.0079 19.8023 21.1519ZM18.4023 21.1519C18.4023 22.1919 18.3223 22.3759 18.1943 22.5439C18.0903 22.6799 17.8903 22.7999 17.6343 22.7999C17.3783 22.7999 17.1783 22.6799 17.0743 22.5439C16.9463 22.3759 16.8663 22.1919 16.8663 21.1519C16.8663 20.1119 16.9463 19.9199 17.0743 19.7519C17.1783 19.6159 17.3783 19.5039 17.6343 19.5039C17.8903 19.5039 18.0903 19.6159 18.1943 19.7519C18.3223 19.9199 18.4023 20.1119 18.4023 21.1519Z" fill="white"/>
+<path d="M25.2154 23.9999V18.3039H23.8154V21.1679L21.9914 18.3039H20.7674V23.9999H22.1674V21.1359L23.9914 23.9999H25.2154Z" fill="white"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14428" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14428"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14428" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/md.svg b/app/components/datasets/create/assets/md.svg
new file mode 100644
index 0000000..d730b5a
--- /dev/null
+++ b/app/components/datasets/create/assets/md.svg
@@ -0,0 +1,18 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3777_37339)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#309BEC"/>
+</g>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M21.9904 25.3335H10.0096C9.45202 25.3335 9 24.9138 9 24.396V18.271C9 17.7532 9.45202 17.3335 10.0096 17.3335H21.9904C22.548 17.3335 23 17.7532 23 18.271V24.396C23 24.9138 22.548 25.3335 21.9904 25.3335ZM12.3654 23.4585V21.021L13.7115 22.5835L15.0577 21.021V23.4585H16.4038V19.2085H15.0577L13.7115 20.771L12.3654 19.2085H11.0192V23.4585H12.3654ZM20.0385 21.3335H21.3846L19.3654 23.521L17.3462 21.3335H18.6923V19.2085H20.0385V21.3335Z" fill="white"/>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3777_37339" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3777_37339"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3777_37339" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/normal.svg b/app/components/datasets/create/assets/normal.svg
new file mode 100644
index 0000000..1d94adf
--- /dev/null
+++ b/app/components/datasets/create/assets/normal.svg
@@ -0,0 +1,4 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.75 4.5C6.7165 4.5 7.5 3.7165 7.5 2.75C7.5 1.7835 6.7165 1 5.75 1C4.7835 1 4 1.7835 4 2.75C4 3.7165 4.7835 4.5 5.75 4.5Z" fill="#444CE7"/>
+<path d="M3.48775 4.314C3.36842 4.14172 3.30875 4.05558 3.24448 4.02712C3.18679 4.00157 3.12605 3.99844 3.06603 4.01794C2.99918 4.03965 2.94661 4.10099 2.84146 4.22367C2.41951 4.71598 2.13172 5.32705 2.03543 6.00009H2C1.72386 6.00009 1.5 5.77623 1.5 5.50009C1.5 5.31565 1.59961 5.15388 1.75036 5.06668C1.98939 4.9284 2.07107 4.62254 1.9328 4.38351C1.79453 4.14448 1.48867 4.0628 1.24964 4.20107C0.802591 4.45967 0.5 4.94425 0.5 5.50009C0.5 6.32852 1.17157 7.00009 2 7.00009H2.03545C2.14342 7.75422 2.49192 8.43113 2.99997 8.94961L2.99997 10.1117C2.99994 10.1712 2.99992 10.2424 3.00504 10.305C3.01097 10.3776 3.02619 10.4816 3.08171 10.5906C3.15362 10.7317 3.26835 10.8465 3.40948 10.9184C3.51845 10.9739 3.62245 10.9891 3.69505 10.9951C3.7577 11.0002 3.82881 11.0001 3.88836 11.0001H4.86154C4.92109 11.0001 4.99224 11.0002 5.05488 10.9951C5.12749 10.9891 5.23149 10.9739 5.34046 10.9184C5.48158 10.8465 5.59632 10.7317 5.66822 10.5906C5.72375 10.4816 5.73897 10.3776 5.7449 10.305C5.75002 10.2424 5.75 10.1712 5.74997 10.1117L5.74997 10.0001H6.24998L6.24997 10.1115C6.24995 10.1711 6.24992 10.2422 6.25504 10.3048C6.26097 10.3775 6.2762 10.4815 6.33172 10.5904C6.40363 10.7315 6.51836 10.8463 6.65948 10.9182C6.76846 10.9737 6.87245 10.9889 6.94506 10.9949C7.0077 11 7.0788 11 7.13835 10.9999H8.11159C8.17113 11 8.24229 11 8.30493 10.9949C8.37753 10.9889 8.48153 10.9737 8.5905 10.9182C8.73162 10.8463 8.84636 10.7315 8.91827 10.5904C8.97379 10.4815 8.98901 10.3775 8.99494 10.3048C9.00006 10.2422 9.00004 10.1711 9.00001 10.1115L9.00001 9.66299C9.55312 9.40029 10.0258 8.99721 10.3726 8.49993L10.6116 8.49994C10.6711 8.49996 10.7423 8.49999 10.8049 8.49487C10.8775 8.48893 10.9815 8.47371 11.0905 8.41819C11.2316 8.34628 11.3464 8.23155 11.4183 8.09043C11.4738 7.98145 11.489 7.87746 11.4949 7.80485C11.5001 7.74221 11.5 7.67109 11.5 7.61154V5.88181C11.5 5.82509 11.5001 5.75735 11.4954 5.69761C11.49 5.62851 11.4763 5.5294 11.4257 5.42448C11.352 5.27143 11.2285 5.14794 11.0755 5.07422C10.9705 5.02369 10.8714 5.00992 10.8023 5.00454C10.7577 5.00106 10.7087 5.0002 10.6631 4.99999C10.4953 4.64662 10.2702 4.32616 10 4.05044L10 3.51615C10 3.43874 10.0001 3.35111 9.99335 3.27574C9.98593 3.19252 9.96656 3.06385 9.88754 2.93633C9.78902 2.77733 9.63465 2.66089 9.4547 2.60984C9.31038 2.56889 9.18134 2.58561 9.09929 2.60134C9.02497 2.61559 8.94073 2.63969 8.8663 2.66098L8.78839 2.68324C8.6859 2.71252 8.63465 2.72716 8.59861 2.75356C8.5638 2.77904 8.54252 2.80415 8.52309 2.84266C8.50297 2.88255 8.49603 2.94339 8.48215 3.06506C8.32585 4.43546 7.16224 5.5 5.75 5.5C4.81225 5.5 3.98413 5.03063 3.48775 4.314Z" fill="#444CE7"/>
+</svg>
diff --git a/app/components/datasets/create/assets/note-mod.svg b/app/components/datasets/create/assets/note-mod.svg
new file mode 100644
index 0000000..b9e81f6
--- /dev/null
+++ b/app/components/datasets/create/assets/note-mod.svg
@@ -0,0 +1,5 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="note-mod">
+<path id="Vector" d="M17.6387 3.05555H2.36095C1.97762 3.05555 1.6665 3.36666 1.6665 3.74999V16.25C1.6665 16.6333 1.97762 16.9444 2.36095 16.9444H17.6387C18.0221 16.9444 18.3332 16.6333 18.3332 16.25V3.74999C18.3332 3.36666 18.0221 3.05555 17.6387 3.05555ZM9.30539 14.1667H5.13873C4.75539 14.1667 4.44428 13.8555 4.44428 13.4722C4.44428 13.0889 4.75539 12.7778 5.13873 12.7778H9.30539C9.68873 12.7778 9.99984 13.0889 9.99984 13.4722C9.99984 13.8555 9.68873 14.1667 9.30539 14.1667ZM14.8609 10.6944H5.13873C4.75539 10.6944 4.44428 10.3833 4.44428 9.99999C4.44428 9.61666 4.75539 9.30555 5.13873 9.30555H14.8609C15.2443 9.30555 15.5554 9.61666 15.5554 9.99999C15.5554 10.3833 15.2443 10.6944 14.8609 10.6944ZM14.8609 7.22221H5.13873C4.75539 7.22221 4.44428 6.9111 4.44428 6.52777C4.44428 6.14443 4.75539 5.83332 5.13873 5.83332H14.8609C15.2443 5.83332 15.5554 6.14443 15.5554 6.52777C15.5554 6.9111 15.2443 7.22221 14.8609 7.22221Z" fill="#1570EF"/>
+</g>
+</svg>
diff --git a/app/components/datasets/create/assets/notion.svg b/app/components/datasets/create/assets/notion.svg
new file mode 100644
index 0000000..84a45b9
--- /dev/null
+++ b/app/components/datasets/create/assets/notion.svg
@@ -0,0 +1,12 @@
+<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_2942_529)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.90599 18.2611L1.75639 15.5832C1.2392 14.9389 0.958496 14.1466 0.958496 13.3312V3.63437C0.958496 2.4129 1.93574 1.39936 3.19644 1.31328L13.1661 0.632614C13.8904 0.583164 14.6103 0.775682 15.2052 1.17794L18.708 3.5462C19.335 3.97012 19.7085 4.66312 19.7085 5.40266V16.427C19.7085 17.6223 18.7476 18.6121 17.5133 18.688L6.44808 19.3692C5.46308 19.4298 4.51099 19.0148 3.90599 18.2611Z" fill="white"/>
+<path d="M7.36355 8.48663V8.35968C7.36355 8.03787 7.62129 7.77098 7.95347 7.7488L10.3731 7.58726L13.7191 12.5146V8.19003L12.8579 8.07522V8.01492C12.8579 7.68933 13.1215 7.42068 13.4579 7.40344L15.6595 7.29066V7.60749C15.6595 7.75622 15.5489 7.88343 15.3973 7.90907L14.8675 7.99868V15.0022L14.2026 15.2309C13.6471 15.4219 13.0287 15.2174 12.7107 14.7376L9.46228 9.83568V14.5143L10.4622 14.7056L10.4482 14.7984C10.4046 15.0889 10.1538 15.3086 9.85036 15.3221L7.36355 15.4328C7.33068 15.1204 7.56481 14.8409 7.88781 14.807L8.21492 14.7726V8.53447L7.36355 8.48663Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M13.2553 1.85418L3.28567 2.53485C2.68849 2.57562 2.22559 3.05572 2.22559 3.63431V13.3311C2.22559 13.8748 2.41272 14.4029 2.75752 14.8325L4.90712 17.5104C5.25467 17.9433 5.80161 18.1817 6.36747 18.1469L17.4326 17.4658C17.9998 17.4309 18.4413 16.9761 18.4413 16.4269V5.4026C18.4413 5.06281 18.2697 4.74441 17.9816 4.54963L14.4788 2.18137C14.1218 1.94002 13.6899 1.82451 13.2553 1.85418ZM3.78004 3.78556C3.64138 3.6829 3.70737 3.46903 3.88156 3.45654L13.3224 2.77938C13.6232 2.75781 13.9221 2.84064 14.1653 3.01299L16.0595 4.35502C16.1315 4.40597 16.0977 4.51596 16.0087 4.5208L6.01092 5.06454C5.70835 5.081 5.4097 4.99211 5.16913 4.814L3.78004 3.78556ZM5.54198 6.76913C5.54198 6.44433 5.80438 6.17604 6.13991 6.15777L16.7104 5.5821C17.0374 5.56429 17.3127 5.81577 17.3127 6.13232V15.6782C17.3127 16.0024 17.0512 16.2705 16.7164 16.2895L6.2128 16.8871C5.84887 16.9079 5.54198 16.6282 5.54198 16.2759V6.76913Z" fill="black"/>
+</g>
+<defs>
+<clipPath id="clip0_2942_529">
+<rect width="20" height="20" fill="white" transform="translate(0.333496)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/option-card-effect-blue.svg b/app/components/datasets/create/assets/option-card-effect-blue.svg
new file mode 100644
index 0000000..00a8afa
--- /dev/null
+++ b/app/components/datasets/create/assets/option-card-effect-blue.svg
@@ -0,0 +1,12 @@
+<svg width="220" height="220" viewBox="0 0 220 220" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Effect" opacity="0.8" filter="url(#filter0_f_1328_28605)">
+<circle cx="32" cy="32" r="28" fill="#444CE7"/>
+</g>
+<defs>
+<filter id="filter0_f_1328_28605" x="-156" y="-156" width="376" height="376" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feGaussianBlur stdDeviation="80" result="effect1_foregroundBlur_1328_28605"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/option-card-effect-orange.svg b/app/components/datasets/create/assets/option-card-effect-orange.svg
new file mode 100644
index 0000000..d833764
--- /dev/null
+++ b/app/components/datasets/create/assets/option-card-effect-orange.svg
@@ -0,0 +1,12 @@
+<svg width="220" height="220" viewBox="0 0 220 220" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Effect" opacity="0.8" filter="url(#filter0_f_481_16338)">
+<circle cx="32" cy="32" r="28" fill="#EF6820"/>
+</g>
+<defs>
+<filter id="filter0_f_481_16338" x="-156" y="-156" width="376" height="376" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feGaussianBlur stdDeviation="80" result="effect1_foregroundBlur_481_16338"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/option-card-effect-purple.svg b/app/components/datasets/create/assets/option-card-effect-purple.svg
new file mode 100644
index 0000000..a7857f8
--- /dev/null
+++ b/app/components/datasets/create/assets/option-card-effect-purple.svg
@@ -0,0 +1,12 @@
+<svg width="220" height="220" viewBox="0 0 220 220" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Effect" opacity="0.8" filter="url(#filter0_f_481_16453)">
+<circle cx="32" cy="32" r="28" fill="#6938EF"/>
+</g>
+<defs>
+<filter id="filter0_f_481_16453" x="-156" y="-156" width="376" height="376" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feGaussianBlur stdDeviation="80" result="effect1_foregroundBlur_481_16453"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/pattern-recognition-mod.svg b/app/components/datasets/create/assets/pattern-recognition-mod.svg
new file mode 100644
index 0000000..1083e88
--- /dev/null
+++ b/app/components/datasets/create/assets/pattern-recognition-mod.svg
@@ -0,0 +1,12 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M3.93923 18.3333C3.48973 18.3333 3.05032 18.2 2.67657 17.9503C2.30282 17.7006 2.01152 17.3456 1.83951 16.9303C1.66749 16.515 1.62248 16.0581 1.71017 15.6172C1.79787 15.1763 2.01432 14.7714 2.33217 14.4535C2.65002 14.1357 3.05498 13.9192 3.49584 13.8315C3.93671 13.7438 4.39368 13.7889 4.80897 13.9609C5.22425 14.1329 5.5792 14.4242 5.82894 14.7979C6.07867 15.1717 6.21196 15.6111 6.21196 16.0606C6.21196 16.6634 5.97251 17.2414 5.54629 17.6677C5.12007 18.0939 4.542 18.3333 3.93923 18.3333Z" fill="#6938EF"/>
+ <path d="M9.99978 7.72726C9.55028 7.72726 9.11087 7.86056 8.73712 8.11029C8.36337 8.36002 8.07207 8.71497 7.90005 9.13026C7.72804 9.54554 7.68303 10.0025 7.77072 10.4434C7.85842 10.8842 8.07487 11.2892 8.39272 11.6071C8.71056 11.9249 9.11553 12.1414 9.55639 12.229C9.99726 12.3167 10.4542 12.2717 10.8695 12.0997C11.2848 11.9277 11.6398 11.6364 11.8895 11.2627C12.1392 10.8889 12.2725 10.4495 12.2725 9.99999C12.2725 9.39723 12.0331 8.81915 11.6068 8.39293C11.1806 7.96671 10.6025 7.72726 9.99978 7.72726Z" fill="#6938EF"/>
+ <path d="M3.93923 1.66666C3.48973 1.66666 3.05032 1.79995 2.67657 2.04968C2.30282 2.29941 2.01152 2.65436 1.83951 3.06965C1.66749 3.48494 1.62248 3.9419 1.71017 4.38277C1.79787 4.82364 2.01432 5.2286 2.33217 5.54644C2.65002 5.86429 3.05498 6.08075 3.49585 6.16844C3.93671 6.25613 4.39368 6.21113 4.80897 6.03911C5.22425 5.86709 5.57921 5.57579 5.82894 5.20204C6.07867 4.8283 6.21196 4.38889 6.21196 3.93938C6.21196 3.33662 5.97251 2.75854 5.54629 2.33232C5.12007 1.9061 4.542 1.66666 3.93923 1.66666Z" fill="#6938EF"/>
+ <path d="M16.0603 1.66666C15.6108 1.66666 15.1714 1.79995 14.7977 2.04968C14.4239 2.29941 14.1326 2.65436 13.9606 3.06965C13.7886 3.48494 13.7436 3.9419 13.8313 4.38277C13.919 4.82364 14.1354 5.2286 14.4533 5.54644C14.7711 5.86429 15.1761 6.08075 15.6169 6.16844C16.0578 6.25613 16.5148 6.21113 16.9301 6.03911C17.3453 5.86709 17.7003 5.57579 17.95 5.20204C18.1998 4.8283 18.3331 4.38889 18.3331 3.93938C18.3331 3.33662 18.0936 2.75854 17.6674 2.33232C17.2412 1.9061 16.6631 1.66666 16.0603 1.66666Z" fill="#6938EF"/>
+ <path d="M16.0603 13.7879C15.6108 13.7879 15.1714 13.9212 14.7977 14.1709C14.4239 14.4206 14.1326 14.7756 13.9606 15.1909C13.7886 15.6062 13.7436 16.0631 13.8313 16.504C13.919 16.9449 14.1354 17.3498 14.4533 17.6677C14.7711 17.9855 15.1761 18.202 15.6169 18.2897C16.0578 18.3774 16.5148 18.3323 16.9301 18.1603C17.3453 17.9883 17.7003 17.697 17.95 17.3233C18.1998 16.9495 18.3331 16.5101 18.3331 16.0606C18.3331 15.4578 18.0936 14.8798 17.6674 14.4535C17.2412 14.0273 16.6631 13.7879 16.0603 13.7879Z" fill="#6938EF"/>
+ <path d="M6.21196 7.72726H1.6665V12.2727H6.21196V7.72726Z" fill="#6938EF"/>
+ <path d="M18.3331 7.72726H13.7876V12.2727H18.3331V7.72726Z" fill="#6938EF"/>
+ <path d="M12.2725 1.66666H7.72705V6.21211H12.2725V1.66666Z" fill="#6938EF"/>
+ <path d="M12.2725 13.7879H7.72705V18.3333H12.2725V13.7879Z" fill="#6938EF"/>
+ </svg>
+
\ No newline at end of file
diff --git a/app/components/datasets/create/assets/pdf.svg b/app/components/datasets/create/assets/pdf.svg
new file mode 100644
index 0000000..bc63229
--- /dev/null
+++ b/app/components/datasets/create/assets/pdf.svg
@@ -0,0 +1,22 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14420)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#DD3633"/>
+</g>
+<g opacity="0.96">
+<path d="M13.2801 20.1362C13.2801 19.2002 12.6001 18.3042 11.3361 18.3042H9.08008V24.0002H10.4801V21.9682H11.3361C12.6001 21.9682 13.2801 21.0722 13.2801 20.1362ZM11.8801 20.1362C11.8801 20.4322 11.6561 20.7122 11.2721 20.7122H10.4801V19.5602H11.2721C11.6561 19.5602 11.8801 19.8402 11.8801 20.1362Z" fill="white"/>
+<path d="M18.3357 21.1522C18.3357 20.2562 18.4077 19.5282 17.7437 18.8642C17.3517 18.4722 16.7997 18.3042 16.2077 18.3042H14.0957V24.0002H16.2077C16.7997 24.0002 17.3517 23.8322 17.7437 23.4402C18.4077 22.7762 18.3357 22.0482 18.3357 21.1522ZM16.9357 21.1522C16.9357 22.1202 16.8957 22.2722 16.7837 22.4322C16.6557 22.6242 16.4637 22.7522 16.1117 22.7522H15.4957V19.5522H16.1117C16.4637 19.5522 16.6557 19.6802 16.7837 19.8722C16.8957 20.0322 16.9357 20.1922 16.9357 21.1522Z" fill="white"/>
+<path d="M23.1786 19.5522V18.3042H19.3066V24.0002H20.7066V21.8002H22.8186V20.5522H20.7066V19.5522H23.1786Z" fill="white"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14420" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14420"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14420" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/piggy-bank-01.svg b/app/components/datasets/create/assets/piggy-bank-01.svg
new file mode 100644
index 0000000..f598586
--- /dev/null
+++ b/app/components/datasets/create/assets/piggy-bank-01.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.66675 6.00004C8.95541 6.00004 10.0001 4.95537 10.0001 3.66671C10.0001 2.37804 8.95541 1.33337 7.66675 1.33337C6.37808 1.33337 5.33341 2.37804 5.33341 3.66671C5.33341 4.95537 6.37808 6.00004 7.66675 6.00004Z" fill="#444CE7"/>
+<path d="M4.65042 5.75205C4.49131 5.52233 4.41175 5.40747 4.32605 5.36953C4.24913 5.33547 4.16814 5.3313 4.08813 5.35729C3.99899 5.38624 3.92889 5.46803 3.78869 5.6316C3.22609 6.28801 2.84238 7.10277 2.71398 8.00016H2.66675C2.29856 8.00016 2.00008 7.70168 2.00008 7.33349C2.00008 7.08757 2.13289 6.87188 2.3339 6.75561C2.65261 6.57125 2.76151 6.16343 2.57715 5.84472C2.39279 5.52601 1.98497 5.4171 1.66626 5.60147C1.0702 5.94627 0.666748 6.59237 0.666748 7.33349C0.666748 8.43806 1.56218 9.33349 2.66675 9.33349H2.71402C2.85798 10.339 3.32264 11.2416 4.00004 11.9329L4.00004 13.4823C4.00001 13.5617 3.99997 13.6565 4.0068 13.7401C4.01471 13.8369 4.035 13.9756 4.10903 14.1209C4.20491 14.309 4.35789 14.462 4.54605 14.5579C4.69135 14.6319 4.83001 14.6522 4.92682 14.6601C5.01034 14.6669 5.10517 14.6669 5.18456 14.6669H6.48214C6.56153 14.6669 6.6564 14.6669 6.73993 14.6601C6.83674 14.6522 6.9754 14.6319 7.1207 14.5579C7.30886 14.462 7.46184 14.309 7.55771 14.1209C7.63175 13.9756 7.65204 13.8369 7.65995 13.7401C7.66678 13.6565 7.66674 13.5617 7.66671 13.4823L7.66671 13.3335H8.33338L8.33338 13.482C8.33335 13.5615 8.33331 13.6563 8.34014 13.7398C8.34805 13.8366 8.36834 13.9753 8.44238 14.1206C8.53825 14.3088 8.69123 14.4618 8.87939 14.5576C9.02469 14.6317 9.16335 14.652 9.26016 14.6599C9.34368 14.6667 9.43849 14.6667 9.51788 14.6666H10.8155C10.8949 14.6667 10.9898 14.6667 11.0733 14.6599C11.1701 14.652 11.3088 14.6317 11.4541 14.5576C11.6422 14.4618 11.7952 14.3088 11.8911 14.1206C11.9651 13.9753 11.9854 13.8366 11.9933 13.7398C12.0002 13.6563 12.0001 13.5615 12.0001 13.482L12.0001 12.884C12.7376 12.5338 13.3679 11.9963 13.8302 11.3333L14.1488 11.3333C14.2283 11.3333 14.3231 11.3334 14.4066 11.3265C14.5035 11.3186 14.6421 11.2983 14.7874 11.2243C14.9756 11.1284 15.1286 10.9754 15.2244 10.7873C15.2985 10.642 15.3188 10.5033 15.3267 10.4065C15.3335 10.323 15.3335 10.2282 15.3334 10.1488V7.84245C15.3335 7.76683 15.3335 7.67651 15.3273 7.59685C15.3201 7.50472 15.3017 7.37257 15.2344 7.23269C15.1361 7.02862 14.9714 6.86396 14.7674 6.76567C14.6275 6.6983 14.4953 6.67993 14.4032 6.67276C14.3437 6.66813 14.2783 6.66697 14.2175 6.66669C13.9938 6.19554 13.6937 5.76825 13.3334 5.40063L13.3334 4.68824C13.3335 4.58502 13.3335 4.46819 13.3245 4.36769C13.3147 4.25673 13.2888 4.08518 13.1835 3.91515C13.0521 3.70315 12.8463 3.54789 12.6064 3.47982C12.4139 3.42523 12.2419 3.44753 12.1325 3.4685C12.0334 3.48749 11.921 3.51963 11.8218 3.54801L11.7179 3.57769C11.5813 3.61674 11.513 3.63626 11.4649 3.67145C11.4185 3.70542 11.3901 3.73891 11.3642 3.79026C11.3374 3.84344 11.3281 3.92456 11.3096 4.08678C11.1012 5.91399 9.54973 7.33337 7.66675 7.33337C6.41642 7.33337 5.31225 6.70755 4.65042 5.75205Z" fill="#444CE7"/>
+</svg>
diff --git a/app/components/datasets/create/assets/piggy-bank-mod.svg b/app/components/datasets/create/assets/piggy-bank-mod.svg
new file mode 100644
index 0000000..b1120ad
--- /dev/null
+++ b/app/components/datasets/create/assets/piggy-bank-mod.svg
@@ -0,0 +1,7 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M7.91672 15.2028V17.9805H6.52783V15.2028H7.91672Z" fill="#444CE7"/>
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M14.1667 15.2028V17.9805H12.7778V15.2028H14.1667Z" fill="#444CE7"/>
+ <path d="M14.1666 2.0083C14.1666 3.54243 12.923 4.78608 11.3889 4.78608C9.85476 4.78608 8.61108 3.54243 8.61108 2.0083L14.1666 2.0083Z" fill="#444CE7"/>
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M5.8864 5.23918C6.9718 4.92907 8.12598 5.30791 8.81883 6.17498H13.1251C16.0015 6.17498 18.3334 8.50683 18.3334 11.3833C18.3334 14.2598 16.0015 16.5916 13.1251 16.5916H7.39252C6.14908 16.5916 4.97062 16.0363 4.1791 15.0773L3.32342 14.0407L1.66675 13.3448V9.93061L3.65692 9.40957L4.44453 8.40703V5.65114L5.8864 5.23918ZM8.61119 8.25831H14.1667V9.64721H8.61119V8.25831ZM6.52786 9.99443C6.52786 10.5697 6.06149 11.0361 5.48619 11.0361C4.91089 11.0361 4.44453 10.5697 4.44453 9.99443C4.44453 9.41915 4.91089 8.95276 5.48619 8.95276C6.06149 8.95276 6.52786 9.41915 6.52786 9.99443Z" fill="#444CE7"/>
+ </svg>
+
\ No newline at end of file
diff --git a/app/components/datasets/create/assets/progress-indicator.svg b/app/components/datasets/create/assets/progress-indicator.svg
new file mode 100644
index 0000000..3c99713
--- /dev/null
+++ b/app/components/datasets/create/assets/progress-indicator.svg
@@ -0,0 +1,8 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="progress-indicator">
+<g id="Vector">
+<path d="M18.4029 10.7639H1.59738C1.17572 10.7639 0.833496 11.1061 0.833496 11.5278V16.1111C0.833496 16.5328 1.17572 16.875 1.59738 16.875H18.4029C18.8246 16.875 19.1668 16.5328 19.1668 16.1111V11.5278C19.1668 11.1061 18.8246 10.7639 18.4029 10.7639ZM17.6391 15.3472H10.0002V12.2917H17.6391V15.3472Z" fill="#1570EF"/>
+<path d="M9.716 7.58153C9.78933 7.66174 9.89169 7.70833 10.0002 7.70833C10.1086 7.70833 10.211 7.6625 10.2843 7.58153L13.7218 3.76208C13.8227 3.64979 13.8479 3.48937 13.7868 3.35111C13.7249 3.21361 13.5881 3.125 13.4377 3.125H6.56266C6.41218 3.125 6.27544 3.21361 6.21356 3.35111C6.15245 3.48937 6.17766 3.64979 6.2785 3.76208L9.716 7.58153Z" fill="#1570EF"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/datasets/create/assets/rerank.svg b/app/components/datasets/create/assets/rerank.svg
new file mode 100644
index 0000000..409b52e
--- /dev/null
+++ b/app/components/datasets/create/assets/rerank.svg
@@ -0,0 +1,13 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="rerank">
+<g id="Vector">
+<path d="M18.3333 4.58329C18.3333 5.73389 17.4005 6.66663 16.2499 6.66663C15.0993 6.66663 14.1666 5.73389 14.1666 4.58329C14.1666 3.4327 15.0993 2.49996 16.2499 2.49996C17.4005 2.49996 18.3333 3.4327 18.3333 4.58329Z" fill="#0E9384"/>
+<path d="M13.3333 15.4166C13.3333 16.5672 12.4005 17.5 11.2499 17.5C10.0993 17.5 9.16658 16.5672 9.16658 15.4166C9.16658 14.266 10.0993 13.3333 11.2499 13.3333C12.4005 13.3333 13.3333 14.266 13.3333 15.4166Z" fill="#0E9384"/>
+<path d="M12.0833 4.58329C12.0833 5.27365 11.5236 5.83329 10.8333 5.83329C10.1429 5.83329 9.58325 5.27365 9.58325 4.58329C9.58325 3.89294 10.1429 3.33329 10.8333 3.33329C11.5236 3.33329 12.0833 3.89294 12.0833 4.58329Z" fill="#0E9384"/>
+<path d="M17.4999 15.4166C17.4999 16.107 16.9403 16.6666 16.2499 16.6666C15.5596 16.6666 14.9999 16.107 14.9999 15.4166C14.9999 14.7263 15.5596 14.1666 16.2499 14.1666C16.9403 14.1666 17.4999 14.7263 17.4999 15.4166Z" fill="#0E9384"/>
+<path d="M7.49992 15.4166C7.49992 17.0275 6.19408 18.3333 4.58325 18.3333C2.97242 18.3333 1.66659 17.0275 1.66659 15.4166C1.66659 13.8058 2.97242 12.5 4.58325 12.5C6.19408 12.5 7.49992 13.8058 7.49992 15.4166Z" fill="#0E9384"/>
+<path d="M7.49992 4.58329C7.49992 6.19412 6.19408 7.49996 4.58325 7.49996C2.97242 7.49996 1.66659 6.19412 1.66659 4.58329C1.66659 2.97246 2.97242 1.66663 4.58325 1.66663C6.19408 1.66663 7.49992 2.97246 7.49992 4.58329Z" fill="#0E9384"/>
+<path d="M0.833252 9.99996C0.833252 9.53972 1.20635 9.16663 1.66659 9.16663H18.3333C18.7935 9.16663 19.1666 9.53972 19.1666 9.99996C19.1666 10.4602 18.7935 10.8333 18.3333 10.8333H1.66659C1.20635 10.8333 0.833252 10.4602 0.833252 9.99996Z" fill="#0E9384"/>
+</g>
+</g>
+</svg>
diff --git a/app/components/datasets/create/assets/research-mod.svg b/app/components/datasets/create/assets/research-mod.svg
new file mode 100644
index 0000000..1f0bb34
--- /dev/null
+++ b/app/components/datasets/create/assets/research-mod.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M13.6752 4.83333H9.91553V1.07361L13.6752 4.83333Z" fill="#6938EF"/>
+ <path d="M7.2003 13.8611H2.62391C2.53183 13.8611 2.44351 13.8245 2.37839 13.7594C2.31327 13.6943 2.27669 13.606 2.27669 13.5139V12.8195C2.27669 12.7274 2.31327 12.6391 2.37839 12.5739C2.44351 12.5088 2.53183 12.4722 2.62391 12.4722H7.2003C7.33176 11.6964 7.68097 10.9739 8.20725 10.3889H2.62391C2.53183 10.3889 2.44351 10.3523 2.37839 10.2872C2.31327 10.2221 2.27669 10.1338 2.27669 10.0417V9.34724C2.27669 9.25515 2.31327 9.16684 2.37839 9.10172C2.44351 9.0366 2.53183 9.00002 2.62391 9.00002H11.3045C12.3309 9.0003 13.3207 9.38137 14.0822 10.0695V6.22224H9.22114C9.03696 6.22224 8.86032 6.14908 8.73009 6.01884C8.59986 5.88861 8.52669 5.71198 8.52669 5.5278V0.666687H0.887804C0.703626 0.666687 0.526991 0.739851 0.396757 0.870085C0.266524 1.00032 0.193359 1.17695 0.193359 1.36113V16.6389C0.193359 16.8231 0.266524 16.9997 0.396757 17.13C0.526991 17.2602 0.703626 17.3334 0.887804 17.3334H10.61C9.73337 17.224 8.91945 16.8214 8.30046 16.1911C7.68146 15.5607 7.29375 14.7396 7.2003 13.8611ZM2.62391 5.5278H6.09614C6.18823 5.5278 6.27654 5.56438 6.34166 5.6295C6.40678 5.69461 6.44336 5.78293 6.44336 5.87502V6.56947C6.44336 6.66155 6.40678 6.74987 6.34166 6.81499C6.27654 6.88011 6.18823 6.91669 6.09614 6.91669H2.62391C2.53183 6.91669 2.44351 6.88011 2.37839 6.81499C2.31327 6.74987 2.27669 6.66155 2.27669 6.56947V5.87502C2.27669 5.78293 2.31327 5.69461 2.37839 5.6295C2.44351 5.56438 2.53183 5.5278 2.62391 5.5278Z" fill="#6938EF"/>
+ <path d="M15.2678 16.1479L13.6887 14.5688C13.9439 14.1455 14.08 13.661 14.0824 13.1667C14.0824 12.6173 13.9195 12.0802 13.6143 11.6234C13.309 11.1666 12.8752 10.8106 12.3676 10.6004C11.8601 10.3901 11.3016 10.3351 10.7627 10.4423C10.2239 10.5495 9.72893 10.814 9.34045 11.2025C8.95197 11.591 8.68741 12.0859 8.58023 12.6248C8.47305 13.1636 8.52806 13.7221 8.7383 14.2297C8.94855 14.7373 9.30458 15.1711 9.76138 15.4763C10.2182 15.7816 10.7552 15.9445 11.3046 15.9445C11.799 15.9421 12.2834 15.806 12.7067 15.5507L14.2859 17.1299C14.4169 17.2564 14.5923 17.3264 14.7744 17.3248C14.9564 17.3232 15.1306 17.2502 15.2594 17.1214C15.3881 16.9927 15.4612 16.8185 15.4627 16.6364C15.4643 16.4543 15.3943 16.2789 15.2678 16.1479ZM9.91575 13.1667C9.91575 12.892 9.9972 12.6235 10.1498 12.3951C10.3024 12.1667 10.5193 11.9887 10.7731 11.8835C11.0269 11.7784 11.3062 11.7509 11.5756 11.8045C11.845 11.8581 12.0925 11.9904 12.2867 12.1846C12.481 12.3788 12.6132 12.6263 12.6668 12.8957C12.7204 13.1652 12.6929 13.4444 12.5878 13.6982C12.4827 13.952 12.3047 14.1689 12.0763 14.3215C11.8479 14.4741 11.5793 14.5556 11.3046 14.5556C10.9363 14.5556 10.583 14.4093 10.3225 14.1488C10.0621 13.8883 9.91575 13.5351 9.91575 13.1667Z" fill="#6938EF"/>
+ </svg>
+
\ No newline at end of file
diff --git a/app/components/datasets/create/assets/selection-mod.svg b/app/components/datasets/create/assets/selection-mod.svg
new file mode 100644
index 0000000..2d0dd3b
--- /dev/null
+++ b/app/components/datasets/create/assets/selection-mod.svg
@@ -0,0 +1,12 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M5.83317 18.3334H1.6665V14.1667H5.83317V18.3334Z" fill="#6938EF"/>
+ <path d="M12.0832 12.0834H7.9165V7.91669H12.0832V12.0834Z" fill="#6938EF"/>
+ <path d="M5.83317 12.0834H1.6665V7.91669H5.83317V12.0834Z" fill="#6938EF"/>
+ <path d="M12.0832 5.83335H7.9165V1.66669H12.0832V5.83335Z" fill="#6938EF"/>
+ <path d="M5.83317 5.83335H1.6665V1.66669H5.83317V5.83335Z" fill="#6938EF"/>
+ <path d="M18.3332 5.83335H14.1665V1.66669H18.3332V5.83335Z" fill="#6938EF"/>
+ <path d="M17.6386 14.8611H14.8608V17.6389H17.6386V14.8611Z" fill="#6938EF"/>
+ <path d="M17.6386 8.61115H14.8608V11.3889H17.6386V8.61115Z" fill="#6938EF"/>
+ <path d="M11.3886 14.8611H8.61084V17.6389H11.3886V14.8611Z" fill="#6938EF"/>
+ </svg>
+
\ No newline at end of file
diff --git a/app/components/datasets/create/assets/setting-gear-mod.svg b/app/components/datasets/create/assets/setting-gear-mod.svg
new file mode 100644
index 0000000..c782caa
--- /dev/null
+++ b/app/components/datasets/create/assets/setting-gear-mod.svg
@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M10.0002 0.833374C10.4604 0.833374 10.8335 1.20647 10.8335 1.66671V2.54597C11.5977 2.63056 12.328 2.8301 13.0061 3.12703L13.4452 2.36666C13.6752 1.96808 14.1849 1.83152 14.5835 2.06164C14.9821 2.29176 15.1186 2.80142 14.8885 3.2L14.4488 3.96146C15.0552 4.40877 15.5915 4.94516 16.0388 5.55143L16.8003 5.11177C17.1989 4.88165 17.7086 5.01821 17.9387 5.41679C18.1688 5.81537 18.0322 6.32502 17.6337 6.55514L16.8732 6.99418C17.1702 7.67226 17.3697 8.40254 17.4543 9.16679H18.3335C18.7937 9.16679 19.1668 9.53987 19.1668 10.0001C19.1668 10.4604 18.7937 10.8335 18.3335 10.8335H17.4543C17.3697 11.5977 17.1702 12.328 16.8732 13.0061L17.6337 13.4452C18.0322 13.6753 18.1688 14.185 17.9387 14.5835C17.7086 14.9821 17.1989 15.1187 16.8003 14.8885L16.0388 14.4489C15.5915 15.0551 15.0551 15.5915 14.4488 16.0388L14.8885 16.8004C15.1186 17.1989 14.9821 17.7085 14.5835 17.9387C14.1849 18.1688 13.6752 18.0322 13.4452 17.6337L13.0061 16.8732C12.328 17.1701 11.5977 17.3697 10.8335 17.4543V18.3334C10.8335 18.7936 10.4604 19.1667 10.0002 19.1667C9.53991 19.1667 9.16683 18.7936 9.16683 18.3334V17.4543C8.40258 17.3697 7.6723 17.1701 6.99424 16.8732L6.55516 17.6337C6.32505 18.0323 5.81539 18.1689 5.41681 17.9388C5.01824 17.7086 4.88167 17.199 5.11179 16.8005L5.55149 16.0388C4.94519 15.5915 4.40878 15.0551 3.96145 14.4488L3.19993 14.8885C2.80135 15.1186 2.2917 14.982 2.06158 14.5835C1.83145 14.1849 1.96802 13.6752 2.3666 13.4451L3.12704 13.006C2.83011 12.328 2.63056 11.5977 2.54598 10.8335L1.66679 10.8334C1.20655 10.8334 0.833474 10.4602 0.833496 10C0.833521 9.53979 1.20663 9.16671 1.66687 9.16671L2.54599 9.16679C2.63058 8.40254 2.8301 7.67229 3.12701 6.99424L2.3666 6.55523C1.96802 6.32512 1.83145 5.81546 2.06157 5.41687C2.29169 5.0183 2.80135 4.88173 3.19992 5.11185L3.96142 5.55148C4.40874 4.94518 4.94515 4.40877 5.55145 3.96144L5.11179 3.19991C4.88167 2.80133 5.01823 2.29167 5.41681 2.06156C5.81539 1.83144 6.32505 1.968 6.55516 2.36657L6.9942 3.12702C7.67228 2.83009 8.40258 2.63055 9.16683 2.54597V1.66671C9.16683 1.20647 9.53991 0.833374 10.0002 0.833374ZM6.39156 5.41655C5.81089 5.87442 5.31917 6.44029 4.94695 7.08361C4.45095 7.94087 4.16681 8.93604 4.16681 10.0001C4.16681 11.0642 4.45096 12.0594 4.94698 12.9167C5.3192 13.56 5.81091 14.1259 6.39159 14.5837L8.1 11.6246C7.72651 11.1881 7.50015 10.6208 7.50015 10.0001C7.50015 9.37946 7.72651 8.81212 8.09999 8.37562L6.39156 5.41655ZM9.54316 7.54194L7.83418 4.5819C8.50325 4.31416 9.23383 4.16679 10.0002 4.16679C11.0642 4.16679 12.0594 4.45095 12.9167 4.94697C13.8022 5.45932 14.541 6.19807 15.0533 7.08357C15.4173 7.71277 15.6673 8.41629 15.7745 9.16679H12.3579C12.0147 8.19579 11.0887 7.50012 10.0002 7.50012C9.84433 7.50012 9.69149 7.51446 9.54316 7.54194ZM12.3579 10.8335C12.0147 11.8045 11.0887 12.5001 10.0002 12.5001C9.84433 12.5001 9.69149 12.4858 9.54316 12.4583L7.8342 15.4184C8.50325 15.6861 9.23383 15.8335 10.0002 15.8335C11.0642 15.8335 12.0594 15.5493 12.9167 15.0533C13.8022 14.541 14.5409 13.8022 15.0532 12.9167C15.4173 12.2875 15.6673 11.584 15.7745 10.8335H12.3579Z" fill="#444CE7"/>
+ </svg>
+
\ No newline at end of file
diff --git a/app/components/datasets/create/assets/sliders-02.svg b/app/components/datasets/create/assets/sliders-02.svg
new file mode 100644
index 0000000..ed05e97
--- /dev/null
+++ b/app/components/datasets/create/assets/sliders-02.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1.33325 12.6666C1.33325 12.2984 1.63173 12 1.99992 12H4.66659C5.03478 12 5.33325 12.2984 5.33325 12.6666C5.33325 13.0348 5.03478 13.3333 4.66659 13.3333H1.99992C1.63173 13.3333 1.33325 13.0348 1.33325 12.6666Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5528 12C10.2782 11.2232 9.5374 10.6666 8.66659 10.6666C7.56202 10.6666 6.66659 11.5621 6.66659 12.6666C6.66659 13.7712 7.56202 14.6666 8.66659 14.6666C9.5374 14.6666 10.2782 14.1101 10.5528 13.3333L13.9999 13.3333C14.3681 13.3333 14.6666 13.0348 14.6666 12.6666C14.6666 12.2984 14.3681 12 13.9999 12L10.5528 12Z" fill="#155EEF"/>
+<path d="M9.99992 7.33329C9.63173 7.33329 9.33325 7.63177 9.33325 7.99996C9.33325 8.36815 9.63173 8.66663 9.99992 8.66663H13.9999C14.3681 8.66663 14.6666 8.36815 14.6666 7.99996C14.6666 7.63177 14.3681 7.33329 13.9999 7.33329H9.99992Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.33325 7.99996C1.33325 7.63177 1.63173 7.33329 1.99992 7.33329H4.11372C4.38828 6.5565 5.12911 5.99996 5.99992 5.99996C7.10449 5.99996 7.99992 6.89539 7.99992 7.99996C7.99992 9.10453 7.10449 9.99996 5.99992 9.99996C5.12911 9.99996 4.38828 9.44342 4.11372 8.66663H1.99992C1.63173 8.66663 1.33325 8.36815 1.33325 7.99996Z" fill="#155EEF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.99992 1.33329C10.8707 1.33329 11.6116 1.88983 11.8861 2.66663H13.9999C14.3681 2.66663 14.6666 2.9651 14.6666 3.33329C14.6666 3.70148 14.3681 3.99996 13.9999 3.99996H11.8861C11.6116 4.77675 10.8707 5.33329 9.99992 5.33329C8.89535 5.33329 7.99992 4.43786 7.99992 3.33329C7.99992 2.22872 8.89535 1.33329 9.99992 1.33329Z" fill="#155EEF"/>
+<path d="M1.33325 3.33329C1.33325 2.9651 1.63173 2.66663 1.99992 2.66663H5.99992C6.36811 2.66663 6.66659 2.9651 6.66659 3.33329C6.66659 3.70148 6.36811 3.99996 5.99992 3.99996H1.99992C1.63173 3.99996 1.33325 3.70148 1.33325 3.33329Z" fill="#155EEF"/>
+</svg>
diff --git a/app/components/datasets/create/assets/star-07.svg b/app/components/datasets/create/assets/star-07.svg
new file mode 100644
index 0000000..f043ae6
--- /dev/null
+++ b/app/components/datasets/create/assets/star-07.svg
@@ -0,0 +1,11 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.00008 0.666626C8.36827 0.666626 8.66675 0.965103 8.66675 1.33329V2.66663C8.66675 3.03482 8.36827 3.33329 8.00008 3.33329C7.63189 3.33329 7.33341 3.03482 7.33341 2.66663V1.33329C7.33341 0.965103 7.63189 0.666626 8.00008 0.666626Z" fill="#FB6514"/>
+<path d="M3.75729 2.81452C3.49694 2.55418 3.07483 2.55418 2.81448 2.81452C2.55413 3.07487 2.55413 3.49698 2.81448 3.75733L3.75729 4.70014C4.01764 4.96049 4.43975 4.96049 4.7001 4.70014C4.96045 4.43979 4.96045 4.01768 4.7001 3.75733L3.75729 2.81452Z" fill="#FB6514"/>
+<path d="M0.666748 7.99996C0.666748 7.63177 0.965225 7.33329 1.33341 7.33329H2.66675C3.03494 7.33329 3.33341 7.63177 3.33341 7.99996C3.33341 8.36815 3.03494 8.66663 2.66675 8.66663H1.33341C0.965225 8.66663 0.666748 8.36815 0.666748 7.99996Z" fill="#FB6514"/>
+<path d="M13.3334 7.33329C12.9652 7.33329 12.6667 7.63177 12.6667 7.99996C12.6667 8.36815 12.9652 8.66663 13.3334 8.66663H14.6667C15.0349 8.66663 15.3334 8.36815 15.3334 7.99996C15.3334 7.63177 15.0349 7.33329 14.6667 7.33329H13.3334Z" fill="#FB6514"/>
+<path d="M12.2426 11.2997C11.9823 11.0394 11.5602 11.0394 11.2998 11.2997C11.0395 11.5601 11.0395 11.9822 11.2998 12.2425L12.2426 13.1853C12.503 13.4457 12.9251 13.4457 13.1855 13.1853C13.4458 12.925 13.4458 12.5029 13.1855 12.2425L12.2426 11.2997Z" fill="#FB6514"/>
+<path d="M13.1855 3.75733C13.4458 3.49698 13.4458 3.07487 13.1855 2.81452C12.9251 2.55418 12.503 2.55418 12.2426 2.81452L11.2998 3.75733C11.0395 4.01768 11.0395 4.43979 11.2998 4.70014C11.5602 4.96049 11.9823 4.96049 12.2426 4.70014L13.1855 3.75733Z" fill="#FB6514"/>
+<path d="M8.00008 12.6666C8.36827 12.6666 8.66675 12.9651 8.66675 13.3333V14.6666C8.66675 15.0348 8.36827 15.3333 8.00008 15.3333C7.63189 15.3333 7.33341 15.0348 7.33341 14.6666V13.3333C7.33341 12.9651 7.63189 12.6666 8.00008 12.6666Z" fill="#FB6514"/>
+<path d="M4.7001 12.2425C4.96045 11.9822 4.96045 11.5601 4.7001 11.2997C4.43975 11.0394 4.01764 11.0394 3.75729 11.2997L2.81448 12.2425C2.55413 12.5029 2.55413 12.925 2.81448 13.1853C3.07483 13.4457 3.49694 13.4457 3.75729 13.1853L4.7001 12.2425Z" fill="#FB6514"/>
+<path d="M8.59791 4.37154C8.48559 4.14401 8.25385 3.99996 8.0001 3.99996C7.74635 3.99996 7.51461 4.14401 7.4023 4.37154L6.52726 6.14427L4.57035 6.4303C4.31931 6.46699 4.11085 6.643 4.0326 6.88434C3.95435 7.12567 4.01987 7.39051 4.20161 7.56753L5.61709 8.9462L5.28303 10.8939C5.24013 11.1441 5.34296 11.3968 5.54828 11.546C5.7536 11.6951 6.02579 11.7148 6.2504 11.5967L8.0001 10.6765L9.7498 11.5967C9.97441 11.7148 10.2466 11.6951 10.4519 11.546C10.6572 11.3968 10.7601 11.1441 10.7172 10.8939L10.3831 8.9462L11.7986 7.56753C11.9803 7.39051 12.0458 7.12567 11.9676 6.88434C11.8893 6.643 11.6809 6.46699 11.4299 6.4303L9.47294 6.14427L8.59791 4.37154Z" fill="#FB6514"/>
+</svg>
diff --git a/app/components/datasets/create/assets/star.svg b/app/components/datasets/create/assets/star.svg
new file mode 100644
index 0000000..3ffda57
--- /dev/null
+++ b/app/components/datasets/create/assets/star.svg
@@ -0,0 +1,11 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6 0.5C6.27614 0.5 6.5 0.723858 6.5 1V2C6.5 2.27614 6.27614 2.5 6 2.5C5.72386 2.5 5.5 2.27614 5.5 2V1C5.5 0.723858 5.72386 0.5 6 0.5Z" fill="#FB6514"/>
+<path d="M2.81791 2.11092C2.62265 1.91566 2.30606 1.91566 2.1108 2.11092C1.91554 2.30619 1.91554 2.62277 2.1108 2.81803L2.81791 3.52514C3.01317 3.7204 3.32975 3.7204 3.52502 3.52514C3.72028 3.32988 3.72028 3.01329 3.52502 2.81803L2.81791 2.11092Z" fill="#FB6514"/>
+<path d="M0.5 6C0.5 5.72386 0.723858 5.5 1 5.5H2C2.27614 5.5 2.5 5.72386 2.5 6C2.5 6.27614 2.27614 6.5 2 6.5H1C0.723858 6.5 0.5 6.27614 0.5 6Z" fill="#FB6514"/>
+<path d="M10 5.5C9.72386 5.5 9.5 5.72386 9.5 6C9.5 6.27614 9.72386 6.5 10 6.5H11C11.2761 6.5 11.5 6.27614 11.5 6C11.5 5.72386 11.2761 5.5 11 5.5H10Z" fill="#FB6514"/>
+<path d="M9.18192 8.47482C8.98666 8.27955 8.67008 8.27955 8.47482 8.47482C8.27955 8.67008 8.27955 8.98666 8.47482 9.18192L9.18192 9.88903C9.37718 10.0843 9.69377 10.0843 9.88903 9.88903C10.0843 9.69377 10.0843 9.37718 9.88903 9.18192L9.18192 8.47482Z" fill="#FB6514"/>
+<path d="M9.88903 2.81803C10.0843 2.62277 10.0843 2.30619 9.88903 2.11092C9.69377 1.91566 9.37718 1.91566 9.18192 2.11092L8.47482 2.81803C8.27955 3.01329 8.27955 3.32988 8.47482 3.52514C8.67008 3.7204 8.98666 3.7204 9.18192 3.52514L9.88903 2.81803Z" fill="#FB6514"/>
+<path d="M6 9.5C6.27614 9.5 6.5 9.72386 6.5 10V11C6.5 11.2761 6.27614 11.5 6 11.5C5.72386 11.5 5.5 11.2761 5.5 11V10C5.5 9.72386 5.72386 9.5 6 9.5Z" fill="#FB6514"/>
+<path d="M3.52502 9.18192C3.72028 8.98666 3.72028 8.67008 3.52502 8.47482C3.32975 8.27955 3.01317 8.27955 2.81791 8.47482L2.1108 9.18192C1.91554 9.37718 1.91554 9.69377 2.1108 9.88903C2.30606 10.0843 2.62265 10.0843 2.81791 9.88903L3.52502 9.18192Z" fill="#FB6514"/>
+<path d="M6.44837 3.27869C6.36413 3.10804 6.19032 3 6.00001 3C5.8097 3 5.6359 3.10804 5.55166 3.27869L4.89538 4.60823L3.4277 4.82276C3.23942 4.85028 3.08308 4.98228 3.02439 5.16328C2.9657 5.34429 3.01484 5.54291 3.15115 5.67568L4.21275 6.70968L3.96221 8.17048C3.93004 8.35807 4.00716 8.54766 4.16115 8.65953C4.31514 8.77139 4.51928 8.78613 4.68774 8.69754L6.00001 8.00742L7.31229 8.69754C7.48075 8.78613 7.68489 8.77139 7.83888 8.65953C7.99287 8.54766 8.06999 8.35807 8.03782 8.17048L7.78728 6.70968L8.84888 5.67568C8.98519 5.54291 9.03433 5.34429 8.97564 5.16328C8.91695 4.98228 8.76061 4.85028 8.57233 4.82276L7.10465 4.60823L6.44837 3.27869Z" fill="#FB6514"/>
+</svg>
diff --git a/app/components/datasets/create/assets/trash.svg b/app/components/datasets/create/assets/trash.svg
new file mode 100644
index 0000000..00c2989
--- /dev/null
+++ b/app/components/datasets/create/assets/trash.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6 2H10M2 4H14M12.6667 4L12.1991 11.0129C12.129 12.065 12.0939 12.5911 11.8667 12.99C11.6666 13.3412 11.3648 13.6235 11.0011 13.7998C10.588 14 10.0607 14 9.00623 14H6.99377C5.93927 14 5.41202 14 4.99889 13.7998C4.63517 13.6235 4.33339 13.3412 4.13332 12.99C3.90607 12.5911 3.871 12.065 3.80086 11.0129L3.33333 4M6.66667 7V10.3333M9.33333 7V10.3333" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/create/assets/txt.svg b/app/components/datasets/create/assets/txt.svg
new file mode 100644
index 0000000..d1b6a8c
--- /dev/null
+++ b/app/components/datasets/create/assets/txt.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14432)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#E3E5E8"/>
+<path d="M4.25 7.73349C4.25 6.60926 4.25019 5.78113 4.30367 5.12666C4.3569 4.47511 4.46169 4.01774 4.65873 3.63103C5.01825 2.92542 5.59193 2.35175 6.29754 1.99222C6.68424 1.79518 7.14162 1.6904 7.79317 1.63716C8.44763 1.58369 9.27577 1.5835 10.4 1.5835H18.5631L27.75 10.7704V24.2668C27.75 25.3911 27.7498 26.2192 27.6963 26.8737C27.6431 27.5252 27.5383 27.9826 27.3413 28.3693C26.9817 29.0749 26.4081 29.6486 25.7025 30.0081C25.3158 30.2051 24.8584 30.3099 24.2068 30.3632C23.5524 30.4166 22.7242 30.4168 21.6 30.4168H10.4C9.27577 30.4168 8.44763 30.4166 7.79317 30.3632C7.14162 30.3099 6.68424 30.2051 6.29754 30.0081C5.59193 29.6486 5.01825 29.0749 4.65873 28.3693C4.46169 27.9826 4.3569 27.5252 4.30367 26.8737C4.25019 26.2192 4.25 25.3911 4.25 24.2668V7.73349Z" stroke="black" stroke-opacity="0.03" stroke-width="0.5"/>
+</g>
+<g opacity="0.96">
+<path d="M13.2254 19.5522V18.3042H9.02539V19.5522H10.4254V24.0002H11.8254V19.5522H13.2254Z" fill="#667085"/>
+<path d="M18.5371 24.0002L16.7611 21.0802L18.4251 18.3042H16.8331L16.0011 19.9122L15.1691 18.3042H13.5771L15.2411 21.0802L13.4651 24.0002H15.0651L16.0011 22.2482L16.9371 24.0002H18.5371Z" fill="#667085"/>
+<path d="M22.9754 19.5522V18.3042H18.7754V19.5522H20.1754V24.0002H21.5754V19.5522H22.9754Z" fill="#667085"/>
+</g>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14432" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14432"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14432" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/unknown.svg b/app/components/datasets/create/assets/unknown.svg
new file mode 100644
index 0000000..6daa243
--- /dev/null
+++ b/app/components/datasets/create/assets/unknown.svg
@@ -0,0 +1,23 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_3055_14436)">
+<path d="M4 7.73349C4 5.49329 4 4.37318 4.43597 3.51753C4.81947 2.76489 5.43139 2.15296 6.18404 1.76947C7.03969 1.3335 8.15979 1.3335 10.4 1.3335H18.6667L28 10.6668V24.2668C28 26.507 28 27.6271 27.564 28.4828C27.1805 29.2354 26.5686 29.8474 25.816 30.2309C24.9603 30.6668 23.8402 30.6668 21.6 30.6668H10.4C8.15979 30.6668 7.03969 30.6668 6.18404 30.2309C5.43139 29.8474 4.81947 29.2354 4.43597 28.4828C4 27.6271 4 26.507 4 24.2668V7.73349Z" fill="#E3E5E8"/>
+<path d="M4.25 7.73349C4.25 6.60926 4.25019 5.78113 4.30367 5.12666C4.3569 4.47511 4.46169 4.01774 4.65873 3.63103C5.01825 2.92542 5.59193 2.35175 6.29754 1.99222C6.68424 1.79518 7.14162 1.6904 7.79317 1.63716C8.44763 1.58369 9.27577 1.5835 10.4 1.5835H18.5631L27.75 10.7704V24.2668C27.75 25.3911 27.7498 26.2192 27.6963 26.8737C27.6431 27.5252 27.5383 27.9826 27.3413 28.3693C26.9817 29.0749 26.4081 29.6486 25.7025 30.0081C25.3158 30.2051 24.8584 30.3099 24.2068 30.3632C23.5524 30.4166 22.7242 30.4168 21.6 30.4168H10.4C9.27577 30.4168 8.44763 30.4166 7.79317 30.3632C7.14162 30.3099 6.68424 30.2051 6.29754 30.0081C5.59193 29.6486 5.01825 29.0749 4.65873 28.3693C4.46169 27.9826 4.3569 27.5252 4.30367 26.8737C4.25019 26.2192 4.25 25.3911 4.25 24.2668V7.73349Z" stroke="black" stroke-opacity="0.03" stroke-width="0.5"/>
+</g>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9998 23.1992C15.8014 23.1992 15.6039 23.1968 15.4077 23.1924V24.0549C15.4077 24.3819 15.6728 24.647 15.9998 24.647C16.3268 24.647 16.592 24.3819 16.592 24.0549V23.1924C16.3957 23.1968 16.1983 23.1992 15.9998 23.1992Z" fill="#98A2B3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0984 22.8838L11.757 23.8593C11.649 24.168 11.8117 24.5058 12.1203 24.6138C12.185 24.6364 12.251 24.6472 12.3159 24.6472C12.5605 24.6472 12.7894 24.4944 12.8747 24.2505L13.2936 23.0534C12.8807 23.0073 12.481 22.9506 12.0984 22.8838Z" fill="#98A2B3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M20.2431 23.8593L19.9018 22.8838C19.5192 22.9506 19.1195 23.0073 18.7065 23.0534L19.1254 24.2505C19.2108 24.4944 19.4396 24.6472 19.6843 24.6472C19.7491 24.6472 19.8151 24.6364 19.8798 24.6138C20.1885 24.5058 20.3511 24.168 20.2431 23.8593Z" fill="#98A2B3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M20.1624 17.2634C20.2697 17.6416 20.3254 18.0369 20.3254 18.4409C20.3254 18.9087 20.05 19.3327 19.6226 19.5228C19.5564 19.5522 17.9801 20.2436 16.0359 20.2436C14.0917 20.2436 12.5153 19.5522 12.4492 19.5228C12.0218 19.3327 11.7464 18.9086 11.7464 18.4409C11.7464 18.0312 11.8037 17.6305 11.914 17.2476C10.3343 17.5645 8.5 18.2009 8.5 19.4464C8.5 20.2859 9.32512 20.9477 10.9525 21.4134C11.4194 21.547 11.9381 21.66 12.4949 21.7506C12.8783 21.813 13.28 21.8648 13.6953 21.9056C14.2455 21.9597 14.8197 21.9942 15.4079 22.0082C15.6039 22.0128 15.8013 22.0153 16 22.0153C16.1987 22.0153 16.3962 22.0128 16.5921 22.0082C17.1803 21.9943 17.7545 21.9596 18.3047 21.9056C18.72 21.8648 19.1217 21.8131 19.5051 21.7506C20.062 21.66 20.5807 21.547 21.0476 21.4134C22.6749 20.9477 23.5 20.2859 23.5 19.4464C23.5 18.2187 21.7108 17.5833 20.1624 17.2634Z" fill="#98A2B3"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M18.8441 17.1144C18.7585 16.9335 18.6559 16.7622 18.5384 16.6025C18.4174 16.4382 18.2809 16.286 18.1307 16.1486C17.5784 15.6437 16.8433 15.3354 16.036 15.3354C15.2318 15.3354 14.499 15.6411 13.9476 16.1426C13.7974 16.2791 13.6609 16.4303 13.5399 16.5937C13.4217 16.753 13.3185 16.924 13.2322 17.1048C13.039 17.5095 12.9307 17.9624 12.9307 18.4407C12.9307 18.4407 14.321 19.0592 16.036 19.0592C17.751 19.0592 19.1412 18.4407 19.1412 18.4407C19.1412 17.9662 19.0344 17.5167 18.8441 17.1144Z" fill="#98A2B3"/>
+<path opacity="0.5" d="M18.6665 1.3335L27.9998 10.6668H21.3332C19.8604 10.6668 18.6665 9.47292 18.6665 8.00016V1.3335Z" fill="white"/>
+<defs>
+<filter id="filter0_d_3055_14436" x="2" y="0.333496" width="28" height="33.3335" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3055_14436"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3055_14436" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/upload-cloud-01.svg b/app/components/datasets/create/assets/upload-cloud-01.svg
new file mode 100644
index 0000000..4df53cf
--- /dev/null
+++ b/app/components/datasets/create/assets/upload-cloud-01.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.4" d="M4 16.2422C2.79401 15.435 2 14.0602 2 12.5C2 10.1564 3.79151 8.23129 6.07974 8.01937C6.54781 5.17213 9.02024 3 12 3C14.9798 3 17.4522 5.17213 17.9203 8.01937C20.2085 8.23129 22 10.1564 22 12.5C22 14.0602 21.206 15.435 20 16.2422" stroke="#344054" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M8 16L12 12M12 12L16 16M12 12L12 21" stroke="#344054" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/create/assets/watercrawl.svg b/app/components/datasets/create/assets/watercrawl.svg
new file mode 100644
index 0000000..bd4e6ba
--- /dev/null
+++ b/app/components/datasets/create/assets/watercrawl.svg
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
+ <path style="fill: rgb(0, 23, 87); stroke: rgb(13, 14, 52);" d="M 247.794 213.903 L 246.81 76.976 L 254.345 76.963 L 254.592 213.989 L 247.794 213.903 Z"/>
+ <ellipse style="fill: rgb(0, 23, 87); stroke: rgb(0, 23, 87);" cx="250.025" cy="43.859" rx="33.966" ry="33.906"/>
+ <path style="fill: rgb(30, 141, 166); stroke: rgb(30, 141, 166);" d="M 282.472 260.389 L 414.181 330.253 L 410.563 336.234 L 279.38 265.739 L 282.472 260.389 Z"/>
+ <path style="fill: rgb(15, 17, 57); stroke: rgb(13, 14, 52);" d="M 255.105 281.394 L 254.485 417.656 L 246.156 417.691 L 246.688 280.51 L 255.105 281.394 Z"/>
+ <path style="paint-order: fill; fill: rgb(30, 141, 166); stroke: rgb(30, 141, 166);" d="M 279.486 229.517 L 410.351 160.07 L 413.923 167.04 L 283.727 235.998 L 279.486 229.517 Z"/>
+ <path style="fill: rgb(15, 164, 161); stroke: rgb(15, 164, 161);" d="M 88.545 164.884 L 219.797 236.07 L 222.867 229.568 L 90.887 159.47 L 88.545 164.884 Z"/>
+ <path style="fill: rgb(15, 164, 161); stroke: rgb(15, 164, 161);" d="M 224.76 266.9 L 95.55 334.829 L 92.878 328.37 L 219.955 261.275 L 224.76 266.9 Z"/>
+ <ellipse style="paint-order: fill; fill: rgb(2, 181, 225); stroke: rgb(2, 181, 225);" cx="251.242" cy="247.466" rx="33.966" ry="33.906"/>
+ <path style="fill: rgb(13, 14, 52); stroke: rgb(13, 14, 52);" d="M 279.502 433.617 L 408.666 359.443 C 408.666 359.443 412.398 366.965 412.398 366.916 C 412.398 366.867 281.544 440.217 281.544 440.217 L 279.502 433.617 Z"/>
+ <path style="fill: rgb(13, 14, 52); stroke: rgb(13, 14, 52);" d="M 223.119 431.408 L 96.643 361.068 L 93.265 368.047 L 218.895 438.099 L 223.119 431.408 Z"/>
+ <ellipse style="fill: rgb(0, 23, 87); stroke: rgb(0, 23, 87);" cx="250.504" cy="451.168" rx="33.966" ry="33.906"/>
+ <path style="fill: rgb(90, 191, 187); stroke: rgb(90, 191, 187);" d="M 435.665 180.895 L 435.859 316.869 L 443.103 315.579 L 442.56 180.697 L 435.665 180.895 Z"/>
+ <ellipse style="fill: rgb(0, 23, 87); stroke: rgb(0, 23, 87);" cx="441.06" cy="349.665" rx="33.966" ry="33.906"/>
+ <ellipse style="fill: rgb(2, 181, 225); stroke: rgb(2, 181, 225);" cx="441.512" cy="147.767" rx="33.966" ry="33.906"/>
+ <path style="fill: rgb(84, 187, 181); stroke: rgb(84, 187, 181);" d="M 64.755 314.523 L 57.928 315.006 L 58.307 182.961 L 65.169 182.865 L 64.755 314.523 Z"/>
+ <ellipse style="fill: rgb(0, 23, 87); stroke: rgb(0, 23, 87);" cx="58.177" cy="149.757" rx="33.966" ry="33.906"/>
+ <ellipse style="fill: rgb(61, 224, 203); stroke: rgb(61, 224, 203);" cx="65.909" cy="348.17" rx="33.966" ry="33.906"/>
+</svg>
diff --git a/app/components/datasets/create/assets/web.svg b/app/components/datasets/create/assets/web.svg
new file mode 100644
index 0000000..a9bac51
--- /dev/null
+++ b/app/components/datasets/create/assets/web.svg
@@ -0,0 +1,4 @@
+<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.06124 2.21694C7.57213 2.07545 8.11041 1.99984 8.66634 1.99984C9.97432 1.99984 11.1845 2.41837 12.1704 3.12881C11.6459 3.4755 11.2546 3.85196 10.9834 4.25446C10.569 4.86947 10.4628 5.50546 10.5486 6.08575C10.632 6.64928 10.8907 7.13053 11.1627 7.48656C11.4265 7.83177 11.7501 8.12048 12.0351 8.26293C12.7526 8.62164 13.5806 8.80129 14.1996 8.89387C14.7596 8.97762 15.9468 9.2579 15.9907 8.36596C15.9967 8.24461 15.9997 8.12255 15.9997 7.99984C15.9997 3.94975 12.7164 0.666504 8.66634 0.666504C4.61625 0.666504 1.33301 3.94975 1.33301 7.99984C1.33301 12.0499 4.61625 15.3332 8.66634 15.3332C8.78906 15.3332 8.91112 15.3301 9.03246 15.3242C9.40021 15.3061 9.68364 14.9933 9.66553 14.6255C9.64743 14.2578 9.33463 13.9743 8.96689 13.9925C8.86737 13.9974 8.76717 13.9998 8.66634 13.9998C6.32676 13.9998 4.29993 12.6608 3.31046 10.7073L3.95617 10.3345L6.33797 10.7803C6.95507 10.8958 7.52471 10.4207 7.52192 9.79289L7.51258 7.69081L8.72983 5.60684C8.92705 5.2692 8.90938 4.84758 8.68459 4.52762L7.06124 2.21694Z" fill="#1570EF"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M9.96344 8.43724C9.71815 8.3442 9.4411 8.40367 9.2556 8.58917C9.07009 8.77467 9.01063 9.05172 9.10367 9.29701L11.2149 14.8629C11.3123 15.1198 11.5575 15.2906 11.8323 15.2931C12.1071 15.2955 12.3552 15.1291 12.4572 14.8739L13.3377 12.6713L15.5403 11.7908C15.7955 11.6888 15.9619 11.4407 15.9595 11.1659C15.9571 10.891 15.7862 10.6459 15.5293 10.5484L9.96344 8.43724Z" fill="#1570EF"/>
+</svg>
diff --git a/app/components/datasets/create/assets/xlsx.svg b/app/components/datasets/create/assets/xlsx.svg
new file mode 100644
index 0000000..2cdf42c
--- /dev/null
+++ b/app/components/datasets/create/assets/xlsx.svg
@@ -0,0 +1,18 @@
+<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_5938_927)">
+<path d="M3 5.8C3 4.11984 3 3.27976 3.32698 2.63803C3.6146 2.07354 4.07354 1.6146 4.63803 1.32698C5.27976 1 6.11984 1 7.8 1H14L21 8V18.2C21 19.8802 21 20.7202 20.673 21.362C20.3854 21.9265 19.9265 22.3854 19.362 22.673C18.7202 23 17.8802 23 16.2 23H7.8C6.11984 23 5.27976 23 4.63803 22.673C4.07354 22.3854 3.6146 21.9265 3.32698 21.362C3 20.7202 3 19.8802 3 18.2V5.8Z" fill="#169951"/>
+</g>
+<path opacity="0.5" d="M14 1L21 8H16C14.8954 8 14 7.10457 14 6V1Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M17 12C17.5523 12 18 12.4477 18 13V18C18 18.5523 17.5523 19 17 19H7C6.44772 19 6 18.5523 6 18V13C6 12.4477 6.44772 12 7 12H17ZM11.5 13H7L7 15H11.5V13ZM12.5 18H17V16H12.5V18ZM11.5 16V18H7L7 16H11.5ZM12.5 15H17V13H12.5V15Z" fill="white" fill-opacity="0.96"/>
+<defs>
+<filter id="filter0_d_5938_927" x="1" y="0" width="22" height="26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5938_927"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5938_927" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/app/components/datasets/create/assets/zap-fast.svg b/app/components/datasets/create/assets/zap-fast.svg
new file mode 100644
index 0000000..7c67cf9
--- /dev/null
+++ b/app/components/datasets/create/assets/zap-fast.svg
@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.66675 11.6666C1.66675 11.2985 1.96522 11 2.33341 11H6.00008C6.36827 11 6.66675 11.2985 6.66675 11.6666C6.66675 12.0348 6.36827 12.3333 6.00008 12.3333H2.33341C1.96522 12.3333 1.66675 12.0348 1.66675 11.6666Z" fill="#7839EE"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M0.666748 7.99997C0.666748 7.63178 0.965225 7.33331 1.33341 7.33331H4.33341C4.7016 7.33331 5.00008 7.63178 5.00008 7.99997C5.00008 8.36816 4.7016 8.66664 4.33341 8.66664H1.33341C0.965225 8.66664 0.666748 8.36816 0.666748 7.99997Z" fill="#7839EE"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M2.00008 4.33331C2.00008 3.96512 2.29856 3.66664 2.66675 3.66664H6.00008C6.36827 3.66664 6.66675 3.96512 6.66675 4.33331C6.66675 4.7015 6.36827 4.99997 6.00008 4.99997H2.66675C2.29856 4.99997 2.00008 4.7015 2.00008 4.33331Z" fill="#7839EE"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M11.5785 1.37998C11.8632 1.49253 12.0347 1.78458 11.9942 2.08808L11.4282 6.33331H13.9637C13.9714 6.33331 13.979 6.33331 13.9867 6.3333C14.1339 6.33327 14.2864 6.33324 14.4124 6.34476C14.5363 6.35609 14.7618 6.38612 14.9633 6.54167C15.1984 6.72308 15.3407 6.99955 15.3517 7.29625C15.3611 7.55067 15.2545 7.7516 15.1917 7.85904C15.1278 7.96825 15.0391 8.09234 14.9536 8.21207C14.9491 8.21833 14.9446 8.22457 14.9402 8.23079L10.5426 14.3875C10.3646 14.6366 10.0398 14.7325 9.75503 14.62C9.47027 14.5074 9.29879 14.2154 9.33926 13.9119L9.90529 9.66664H7.36978C7.36213 9.66664 7.35447 9.66664 7.34679 9.66664C7.19962 9.66668 7.0471 9.66671 6.92111 9.65519C6.79717 9.64386 6.5717 9.61383 6.37015 9.45828C6.13511 9.27687 5.99283 9.0004 5.98183 8.7037C5.9724 8.44928 6.07901 8.24835 6.14183 8.14091C6.20569 8.0317 6.29437 7.9076 6.37993 7.78787C6.3844 7.78162 6.38886 7.77538 6.3933 7.76915L10.7909 1.61248C10.9689 1.36332 11.2937 1.26743 11.5785 1.37998Z" fill="#7839EE"/>
+</svg>
diff --git a/app/components/datasets/create/embedding-process/index.module.css b/app/components/datasets/create/embedding-process/index.module.css
new file mode 100644
index 0000000..f2ab4d8
--- /dev/null
+++ b/app/components/datasets/create/embedding-process/index.module.css
@@ -0,0 +1,89 @@
+.progressContainer {
+ @apply relative pb-4 w-full;
+ border-bottom: 0.5px solid #EAECF0;
+}
+.sourceItem {
+ position: relative;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 4px;
+ padding: 0 4px;
+ height: 24px;
+ background: #EFF4FF;
+ border-radius: 6px;
+ overflow: hidden;
+}
+
+.sourceItem .info .name {
+ font-weight: 500;
+ font-size: 12px;
+ line-height: 18px;
+ color: #101828;
+}
+.sourceItem.success .info .name {
+ color: #05603A;
+}
+.sourceItem .percent {
+ font-weight: 500;
+ font-size: 12px;
+ line-height: 18px;
+ color: #344054;
+ z-index: 1;
+}
+.sourceItem .error {
+ color: #D92D20;
+}
+.sourceItem .success {
+ color: #05603A;
+}
+
+.commonIcon {
+ @apply w-3 h-3 mr-1 inline-block align-middle;
+}
+.highIcon {
+ mask-image: url(../assets/star.svg);
+ @apply bg-orange-500;
+}
+.economyIcon {
+ background-color: #444ce7;
+ mask-image: url(../assets/normal.svg);
+}
+.tokens {
+ @apply text-xs font-medium px-1;
+}
+.price {
+ color: #f79009;
+ @apply text-xs font-medium;
+}
+
+.unknownFileIcon {
+ background-image: url(../assets/unknown.svg);
+}
+.csv {
+ background-image: url(../assets/csv.svg);
+}
+.docx {
+ background-image: url(../assets/docx.svg);
+}
+.xlsx,
+.xls {
+ background-image: url(../assets/xlsx.svg);
+}
+.pdf {
+ background-image: url(../assets/pdf.svg);
+}
+.html,
+.htm {
+ background-image: url(../assets/html.svg);
+}
+.md,
+.markdown {
+ background-image: url(../assets/md.svg);
+}
+.txt {
+ background-image: url(../assets/txt.svg);
+}
+.json {
+ background-image: url(../assets/json.svg);
+}
diff --git a/app/components/datasets/create/embedding-process/index.tsx b/app/components/datasets/create/embedding-process/index.tsx
new file mode 100644
index 0000000..2890670
--- /dev/null
+++ b/app/components/datasets/create/embedding-process/index.tsx
@@ -0,0 +1,357 @@
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import useSWR from 'swr'
+import { useRouter } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import { omit } from 'lodash-es'
+import { ArrowRightIcon } from '@heroicons/react/24/solid'
+import {
+ RiCheckboxCircleFill,
+ RiErrorWarningFill,
+ RiLoader2Fill,
+ RiTerminalBoxLine,
+} from '@remixicon/react'
+import Image from 'next/image'
+import { indexMethodIcon, retrievalIcon } from '../icons'
+import { IndexingType } from '../step-two'
+import DocumentFileIcon from '../../common/document-file-icon'
+import cn from '@/utils/classnames'
+import { FieldInfo } from '@/app/components/datasets/documents/detail/metadata'
+import Button from '@/app/components/base/button'
+import type { FullDocumentDetail, IndexingStatusResponse, ProcessRuleResponse } from '@/models/datasets'
+import { fetchIndexingStatusBatch as doFetchIndexingStatus, fetchProcessRule } from '@/service/datasets'
+import { DataSourceType, ProcessMode } from '@/models/datasets'
+import NotionIcon from '@/app/components/base/notion-icon'
+import PriorityLabel from '@/app/components/billing/priority-label'
+import { Plan } from '@/app/components/billing/type'
+import { ZapFast } from '@/app/components/base/icons/src/vender/solid/general'
+import UpgradeBtn from '@/app/components/billing/upgrade-btn'
+import { useProviderContext } from '@/context/provider-context'
+import { sleep } from '@/utils'
+import { RETRIEVE_METHOD } from '@/types/app'
+import Tooltip from '@/app/components/base/tooltip'
+import { useInvalidDocumentList } from '@/service/knowledge/use-document'
+
+type Props = {
+ datasetId: string
+ batchId: string
+ documents?: FullDocumentDetail[]
+ indexingType?: string
+ retrievalMethod?: string
+}
+
+const RuleDetail: FC<{
+ sourceData?: ProcessRuleResponse
+ indexingType?: string
+ retrievalMethod?: string
+}> = ({ sourceData, indexingType, retrievalMethod }) => {
+ const { t } = useTranslation()
+
+ const segmentationRuleMap = {
+ mode: t('datasetDocuments.embedding.mode'),
+ segmentLength: t('datasetDocuments.embedding.segmentLength'),
+ textCleaning: t('datasetDocuments.embedding.textCleaning'),
+ }
+
+ const getRuleName = (key: string) => {
+ if (key === 'remove_extra_spaces')
+ return t('datasetCreation.stepTwo.removeExtraSpaces')
+
+ if (key === 'remove_urls_emails')
+ return t('datasetCreation.stepTwo.removeUrlEmails')
+
+ if (key === 'remove_stopwords')
+ return t('datasetCreation.stepTwo.removeStopwords')
+ }
+
+ const isNumber = (value: unknown) => {
+ return typeof value === 'number'
+ }
+
+ const getValue = useCallback((field: string) => {
+ let value: string | number | undefined = '-'
+ const maxTokens = isNumber(sourceData?.rules?.segmentation?.max_tokens)
+ ? sourceData.rules.segmentation.max_tokens
+ : value
+ const childMaxTokens = isNumber(sourceData?.rules?.subchunk_segmentation?.max_tokens)
+ ? sourceData.rules.subchunk_segmentation.max_tokens
+ : value
+ switch (field) {
+ case 'mode':
+ value = !sourceData?.mode
+ ? value
+ : sourceData.mode === ProcessMode.general
+ ? (t('datasetDocuments.embedding.custom') as string)
+ : `${t('datasetDocuments.embedding.hierarchical')} 路 ${sourceData?.rules?.parent_mode === 'paragraph'
+ ? t('dataset.parentMode.paragraph')
+ : t('dataset.parentMode.fullDoc')}`
+ break
+ case 'segmentLength':
+ value = !sourceData?.mode
+ ? value
+ : sourceData.mode === ProcessMode.general
+ ? maxTokens
+ : `${t('datasetDocuments.embedding.parentMaxTokens')} ${maxTokens}; ${t('datasetDocuments.embedding.childMaxTokens')} ${childMaxTokens}`
+ break
+ default:
+ value = !sourceData?.mode
+ ? value
+ : sourceData?.rules?.pre_processing_rules?.filter(rule =>
+ rule.enabled).map(rule => getRuleName(rule.id)).join(',')
+ break
+ }
+ return value
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [sourceData])
+
+ return <div className='flex flex-col gap-1'>
+ {Object.keys(segmentationRuleMap).map((field) => {
+ return <FieldInfo
+ key={field}
+ label={segmentationRuleMap[field as keyof typeof segmentationRuleMap]}
+ displayedValue={String(getValue(field))}
+ />
+ })}
+ <FieldInfo
+ label={t('datasetCreation.stepTwo.indexMode')}
+ displayedValue={t(`datasetCreation.stepTwo.${indexingType === IndexingType.ECONOMICAL ? 'economical' : 'qualified'}`) as string}
+ valueIcon={
+ <Image
+ className='size-4'
+ src={
+ indexingType === IndexingType.ECONOMICAL
+ ? indexMethodIcon.economical
+ : indexMethodIcon.high_quality
+ }
+ alt=''
+ />
+ }
+ />
+ <FieldInfo
+ label={t('datasetSettings.form.retrievalSetting.title')}
+ // displayedValue={t(`datasetSettings.form.retrievalSetting.${retrievalMethod}`) as string}
+ displayedValue={t(`dataset.retrieval.${indexingType === IndexingType.ECONOMICAL ? 'invertedIndex' : retrievalMethod}.title`) as string}
+ valueIcon={
+ <Image
+ className='size-4'
+ src={
+ retrievalMethod === RETRIEVE_METHOD.fullText
+ ? retrievalIcon.fullText
+ : retrievalMethod === RETRIEVE_METHOD.hybrid
+ ? retrievalIcon.hybrid
+ : retrievalIcon.vector
+ }
+ alt=''
+ />
+ }
+ />
+ </div>
+}
+
+const EmbeddingProcess: FC<Props> = ({ datasetId, batchId, documents = [], indexingType, retrievalMethod }) => {
+ const { t } = useTranslation()
+ const { enableBilling, plan } = useProviderContext()
+
+ const getFirstDocument = documents[0]
+
+ const [indexingStatusBatchDetail, setIndexingStatusDetail] = useState<IndexingStatusResponse[]>([])
+ const fetchIndexingStatus = async () => {
+ const status = await doFetchIndexingStatus({ datasetId, batchId })
+ setIndexingStatusDetail(status.data)
+ return status.data
+ }
+
+ const [isStopQuery, setIsStopQuery] = useState(false)
+ const isStopQueryRef = useRef(isStopQuery)
+ useEffect(() => {
+ isStopQueryRef.current = isStopQuery
+ }, [isStopQuery])
+ const stopQueryStatus = () => {
+ setIsStopQuery(true)
+ }
+
+ const startQueryStatus = async () => {
+ if (isStopQueryRef.current)
+ return
+
+ try {
+ const indexingStatusBatchDetail = await fetchIndexingStatus()
+ const isCompleted = indexingStatusBatchDetail.every(indexingStatusDetail => ['completed', 'error', 'paused'].includes(indexingStatusDetail.indexing_status))
+ if (isCompleted) {
+ stopQueryStatus()
+ return
+ }
+ await sleep(2500)
+ await startQueryStatus()
+ }
+ catch {
+ await sleep(2500)
+ await startQueryStatus()
+ }
+ }
+
+ useEffect(() => {
+ setIsStopQuery(false)
+ startQueryStatus()
+ return () => {
+ stopQueryStatus()
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+
+ // get rule
+ const { data: ruleDetail } = useSWR({
+ action: 'fetchProcessRule',
+ params: { documentId: getFirstDocument.id },
+ }, apiParams => fetchProcessRule(omit(apiParams, 'action')), {
+ revalidateOnFocus: false,
+ })
+
+ const router = useRouter()
+ const invalidDocumentList = useInvalidDocumentList()
+ const navToDocumentList = () => {
+ invalidDocumentList()
+ router.push(`/datasets/${datasetId}/documents`)
+ }
+ const navToApiDocs = () => {
+ router.push('/datasets?category=api')
+ }
+
+ const isEmbedding = useMemo(() => {
+ return indexingStatusBatchDetail.some(indexingStatusDetail => ['indexing', 'splitting', 'parsing', 'cleaning'].includes(indexingStatusDetail?.indexing_status || ''))
+ }, [indexingStatusBatchDetail])
+ const isEmbeddingCompleted = useMemo(() => {
+ return indexingStatusBatchDetail.every(indexingStatusDetail => ['completed', 'error', 'paused'].includes(indexingStatusDetail?.indexing_status || ''))
+ }, [indexingStatusBatchDetail])
+
+ const getSourceName = (id: string) => {
+ const doc = documents.find(document => document.id === id)
+ return doc?.name
+ }
+ const getFileType = (name?: string) => name?.split('.').pop() || 'txt'
+ const getSourcePercent = (detail: IndexingStatusResponse) => {
+ const completedCount = detail.completed_segments || 0
+ const totalCount = detail.total_segments || 0
+ if (totalCount === 0)
+ return 0
+ const percent = Math.round(completedCount * 100 / totalCount)
+ return percent > 100 ? 100 : percent
+ }
+ const getSourceType = (id: string) => {
+ const doc = documents.find(document => document.id === id)
+ return doc?.data_source_type as DataSourceType
+ }
+
+ const getIcon = (id: string) => {
+ const doc = documents.find(document => document.id === id)
+
+ return doc?.data_source_info.notion_page_icon
+ }
+ const isSourceEmbedding = (detail: IndexingStatusResponse) =>
+ ['indexing', 'splitting', 'parsing', 'cleaning', 'waiting'].includes(detail.indexing_status || '')
+
+ return (
+ <>
+ <div className="mb-3 flex h-5 items-center">
+ <div className="mr-2 flex items-center justify-between text-sm font-medium text-text-secondary">
+ {isEmbedding && <div className='flex items-center'>
+ <RiLoader2Fill className='mr-1 size-4 animate-spin text-text-secondary' />
+ {t('datasetDocuments.embedding.processing')}
+ </div>}
+ {isEmbeddingCompleted && t('datasetDocuments.embedding.completed')}
+ </div>
+ </div>
+ {
+ enableBilling && plan.type !== Plan.team && (
+ <div className='mb-3 flex h-14 items-center rounded-xl border-[0.5px] border-black/5 bg-white p-3 shadow-md'>
+ <div className='flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-[#FFF6ED]'>
+ <ZapFast className='h-4 w-4 text-[#FB6514]' />
+ </div>
+ <div className='mx-3 grow text-[13px] font-medium text-gray-700'>
+ {t('billing.plansCommon.documentProcessingPriorityUpgrade')}
+ </div>
+ <UpgradeBtn loc='knowledge-speed-up' />
+ </div>
+ )
+ }
+ <div className="flex flex-col gap-0.5 pb-2">
+ {indexingStatusBatchDetail.map(indexingStatusDetail => (
+ <div key={indexingStatusDetail.id} className={cn(
+ 'relative h-[26px] overflow-hidden rounded-md bg-components-progress-bar-bg',
+ indexingStatusDetail.indexing_status === 'error' && 'bg-state-destructive-hover-alt',
+ // indexingStatusDetail.indexing_status === 'completed' && 's.success',
+ )}>
+ {isSourceEmbedding(indexingStatusDetail) && (
+ <div className="absolute left-0 top-0 h-full min-w-0.5 border-r-[2px] border-r-components-progress-bar-progress-highlight bg-components-progress-bar-progress" style={{ width: `${getSourcePercent(indexingStatusDetail)}%` }} />
+ )}
+ <div className="z-[1] flex h-full items-center gap-1 pl-[6px] pr-2">
+ {getSourceType(indexingStatusDetail.id) === DataSourceType.FILE && (
+ // <div className={cn(
+ // 'shrink-0 marker:size-4 bg-center bg-no-repeat bg-contain',
+ // s[getFileType(getSourceName(indexingStatusDetail.id))] || s.unknownFileIcon,
+ // )} />
+ <DocumentFileIcon
+ className="size-4 shrink-0"
+ name={getSourceName(indexingStatusDetail.id)}
+ extension={getFileType(getSourceName(indexingStatusDetail.id))}
+ />
+ )}
+ {getSourceType(indexingStatusDetail.id) === DataSourceType.NOTION && (
+ <NotionIcon
+ className='shrink-0'
+ type='page'
+ src={getIcon(indexingStatusDetail.id)}
+ />
+ )}
+ <div className="flex w-0 grow items-center gap-1" title={getSourceName(indexingStatusDetail.id)}>
+ <div className="system-xs-medium truncate text-text-secondary">
+ {getSourceName(indexingStatusDetail.id)}
+ </div>
+ {
+ enableBilling && (
+ <PriorityLabel className='ml-0' />
+ )
+ }
+ </div>
+ {isSourceEmbedding(indexingStatusDetail) && (
+ <div className="shrink-0 text-xs text-text-secondary">{`${getSourcePercent(indexingStatusDetail)}%`}</div>
+ )}
+ {indexingStatusDetail.indexing_status === 'error' && (
+ <Tooltip
+ popupClassName='px-4 py-[14px] max-w-60 text-sm leading-4 text-text-secondary border-[0.5px] border-components-panel-border rounded-xl'
+ offset={4}
+ popupContent={indexingStatusDetail.error}
+ >
+ <span>
+ <RiErrorWarningFill className='size-4 shrink-0 text-text-destructive' />
+ </span>
+ </Tooltip>
+ )}
+ {indexingStatusDetail.indexing_status === 'completed' && (
+ <RiCheckboxCircleFill className='size-4 shrink-0 text-text-success' />
+ )}
+ </div>
+ </div>
+ ))}
+ </div>
+ <hr className="my-3 h-[1px] border-0 bg-divider-subtle" />
+ <RuleDetail
+ sourceData={ruleDetail}
+ indexingType={indexingType}
+ retrievalMethod={retrievalMethod}
+ />
+ <div className='my-10 flex items-center gap-2'>
+ <Button className='w-fit' onClick={navToApiDocs}>
+ <RiTerminalBoxLine className='mr-2 size-4' />
+ <span>Access the API</span>
+ </Button>
+ <Button className='w-fit' variant='primary' onClick={navToDocumentList}>
+ <span>{t('datasetCreation.stepThree.navTo')}</span>
+ <ArrowRightIcon className='ml-2 size-4 stroke-current stroke-1' />
+ </Button>
+ </div>
+ </>
+ )
+}
+
+export default EmbeddingProcess
diff --git a/app/components/datasets/create/empty-dataset-creation-modal/index.module.css b/app/components/datasets/create/empty-dataset-creation-modal/index.module.css
new file mode 100644
index 0000000..3131c9e
--- /dev/null
+++ b/app/components/datasets/create/empty-dataset-creation-modal/index.module.css
@@ -0,0 +1,35 @@
+.modal {
+ position: relative;
+}
+
+.modalHeader {
+ @apply flex items-center place-content-between h-8;
+}
+.modalHeader .title {
+ @apply grow text-text-primary;
+ font-weight: 600;
+ font-size: 20px;
+ line-height: 32px;
+}
+.modalHeader .close {
+ @apply shrink-0 h-4 w-4 bg-center bg-no-repeat cursor-pointer;
+ background-image: url(../assets/close.svg);
+ background-size: 16px;
+}
+
+.modal .tip {
+ @apply mt-1 mb-8 text-text-tertiary;
+ font-weight: 400;
+ font-size: 13px;
+ line-height: 18px;
+}
+
+.form {
+ @apply mb-8;
+}
+.form .label {
+ @apply mb-2 text-text-primary;
+ font-weight: 500;
+ font-size: 14px;
+ line-height: 20px;
+}
diff --git a/app/components/datasets/create/empty-dataset-creation-modal/index.tsx b/app/components/datasets/create/empty-dataset-creation-modal/index.tsx
new file mode 100644
index 0000000..f9a3584
--- /dev/null
+++ b/app/components/datasets/create/empty-dataset-creation-modal/index.tsx
@@ -0,0 +1,71 @@
+'use client'
+import React, { useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import s from './index.module.css'
+import cn from '@/utils/classnames'
+import Modal from '@/app/components/base/modal'
+import Input from '@/app/components/base/input'
+import Button from '@/app/components/base/button'
+
+import { ToastContext } from '@/app/components/base/toast'
+import { createEmptyDataset } from '@/service/datasets'
+
+type IProps = {
+ show: boolean
+ onHide: () => void
+}
+
+const EmptyDatasetCreationModal = ({
+ show = false,
+ onHide,
+}: IProps) => {
+ const [inputValue, setInputValue] = useState('')
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const router = useRouter()
+
+ const submit = async () => {
+ if (!inputValue) {
+ notify({ type: 'error', message: t('datasetCreation.stepOne.modal.nameNotEmpty') })
+ return
+ }
+ if (inputValue.length > 40) {
+ notify({ type: 'error', message: t('datasetCreation.stepOne.modal.nameLengthInvalid') })
+ return
+ }
+ try {
+ const dataset = await createEmptyDataset({ name: inputValue })
+ onHide()
+ router.push(`/datasets/${dataset.id}/documents`)
+ }
+ catch {
+ notify({ type: 'error', message: t('datasetCreation.stepOne.modal.failed') })
+ }
+ }
+
+ return (
+ <Modal
+ isShow={show}
+ onClose={onHide}
+ className={cn(s.modal, '!max-w-[520px]', 'px-8')}
+ >
+ <div className={s.modalHeader}>
+ <div className={s.title}>{t('datasetCreation.stepOne.modal.title')}</div>
+ <span className={s.close} onClick={onHide} />
+ </div>
+ <div className={s.tip}>{t('datasetCreation.stepOne.modal.tip')}</div>
+ <div className={s.form}>
+ <div className={s.label}>{t('datasetCreation.stepOne.modal.input')}</div>
+ <Input value={inputValue} placeholder={t('datasetCreation.stepOne.modal.placeholder') || ''} onChange={e => setInputValue(e.target.value)} />
+ </div>
+ <div className='flex flex-row-reverse'>
+ <Button className='ml-2 w-24' variant='primary' onClick={submit}>{t('datasetCreation.stepOne.modal.confirmButton')}</Button>
+ <Button className='w-24' onClick={onHide}>{t('datasetCreation.stepOne.modal.cancelButton')}</Button>
+ </div>
+ </Modal>
+ )
+}
+
+export default EmptyDatasetCreationModal
diff --git a/app/components/datasets/create/file-preview/index.module.css b/app/components/datasets/create/file-preview/index.module.css
new file mode 100644
index 0000000..da139fa
--- /dev/null
+++ b/app/components/datasets/create/file-preview/index.module.css
@@ -0,0 +1,39 @@
+.filePreview {
+ @apply flex flex-col border-l border-components-panel-border shrink-0 bg-background-default-lighter;
+ width: 100%;
+ }
+
+ .previewHeader {
+ @apply border-b border-divider-subtle shrink-0;
+ margin: 42px 32px 0;
+ padding-bottom: 16px;
+ }
+
+ .previewHeader .title {
+ @apply flex justify-between items-center text-text-primary;
+ }
+
+ .previewHeader .fileName {
+ @apply text-text-tertiary;
+ }
+
+ .previewHeader .filetype {
+ @apply text-text-tertiary;
+ }
+
+ .previewContent {
+ @apply overflow-y-auto grow text-text-secondary;
+ padding: 20px 32px;
+ }
+
+ .previewContent .loading {
+ width: 100%;
+ height: 180px;
+ background: transparent center no-repeat url(../assets/Loading.svg);
+ background-size: contain;
+ }
+
+ .fileContent {
+ white-space: pre-line;
+ word-break: break-all;
+ }
diff --git a/app/components/datasets/create/file-preview/index.tsx b/app/components/datasets/create/file-preview/index.tsx
new file mode 100644
index 0000000..8a88834
--- /dev/null
+++ b/app/components/datasets/create/file-preview/index.tsx
@@ -0,0 +1,70 @@
+'use client'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { XMarkIcon } from '@heroicons/react/20/solid'
+import Loading from '@/app/components/base/loading'
+import s from './index.module.css'
+import cn from '@/utils/classnames'
+import type { CustomFile as File } from '@/models/datasets'
+import { fetchFilePreview } from '@/service/common'
+
+type IProps = {
+ file?: File
+ hidePreview: () => void
+}
+
+const FilePreview = ({
+ file,
+ hidePreview,
+}: IProps) => {
+ const { t } = useTranslation()
+ const [previewContent, setPreviewContent] = useState('')
+ const [loading, setLoading] = useState(true)
+
+ const getPreviewContent = async (fileID: string) => {
+ try {
+ const res = await fetchFilePreview({ fileID })
+ setPreviewContent(res.content)
+ setLoading(false)
+ }
+ catch { }
+ }
+
+ const getFileName = (currentFile?: File) => {
+ if (!currentFile)
+ return ''
+ const arr = currentFile.name.split('.')
+ return arr.slice(0, -1).join()
+ }
+
+ useEffect(() => {
+ if (file?.id) {
+ setLoading(true)
+ getPreviewContent(file.id)
+ }
+ }, [file])
+
+ return (
+ <div className={cn(s.filePreview, 'h-full')}>
+ <div className={cn(s.previewHeader)}>
+ <div className={cn(s.title, 'title-md-semi-bold')}>
+ <span>{t('datasetCreation.stepOne.filePreview')}</span>
+ <div className='flex h-6 w-6 cursor-pointer items-center justify-center' onClick={hidePreview}>
+ <XMarkIcon className='h-4 w-4'></XMarkIcon>
+ </div>
+ </div>
+ <div className={cn(s.fileName, 'system-xs-medium')}>
+ <span>{getFileName(file)}</span><span className={cn(s.filetype)}>.{file?.extension}</span>
+ </div>
+ </div>
+ <div className={cn(s.previewContent)}>
+ {loading && <Loading type='area' />}
+ {!loading && (
+ <div className={cn(s.fileContent, 'body-md-regular')}>{previewContent}</div>
+ )}
+ </div>
+ </div>
+ )
+}
+
+export default FilePreview
diff --git a/app/components/datasets/create/file-uploader/index.module.css b/app/components/datasets/create/file-uploader/index.module.css
new file mode 100644
index 0000000..7d29f2e
--- /dev/null
+++ b/app/components/datasets/create/file-uploader/index.module.css
@@ -0,0 +1,131 @@
+.file {
+ @apply box-border relative flex items-center justify-between;
+ padding: 8px 12px 8px 8px;
+ max-width: 640px;
+ height: 40px;
+ background: #ffffff;
+ border: 0.5px solid #EAECF0;
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+ border-radius: 8px;
+ overflow: hidden;
+ cursor: pointer;
+}
+
+.progressbar {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ background-color: #F2F4F7;
+}
+
+.file.uploading,
+.file.uploading:hover {
+ background: #FCFCFD;
+ border: 0.5px solid #EAECF0;
+}
+
+.file.active {
+ background: #F5F8FF;
+ border: 1px solid #D1E0FF;
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+}
+
+.file:hover {
+ background: #F5F8FF;
+ border: 1px solid #D1E0FF;
+ box-shadow: 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06);
+}
+
+.fileIcon {
+ @apply shrink-0 w-6 h-6 mr-2 bg-center bg-no-repeat;
+ background-image: url(../assets/unknown.svg);
+ background-size: 24px;
+}
+
+.fileIcon.csv {
+ background-image: url(../assets/csv.svg);
+}
+
+.fileIcon.doc {
+ background-image: url(../assets/doc.svg);
+}
+
+.fileIcon.docx {
+ background-image: url(../assets/docx.svg);
+}
+
+.fileIcon.xlsx,
+.fileIcon.xls {
+ background-image: url(../assets/xlsx.svg);
+}
+
+.fileIcon.pdf {
+ background-image: url(../assets/pdf.svg);
+}
+
+.fileIcon.html,
+.fileIcon.htm {
+ background-image: url(../assets/html.svg);
+}
+
+.fileIcon.md,
+.fileIcon.markdown {
+ background-image: url(../assets/md.svg);
+}
+
+.fileIcon.txt {
+ background-image: url(../assets/txt.svg);
+}
+
+.fileIcon.json {
+ background-image: url(../assets/json.svg);
+}
+
+.fileInfo {
+ @apply grow flex items-center;
+ z-index: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.filename {
+ font-weight: 500;
+ font-size: 13px;
+ line-height: 18px;
+ color: #1D2939;
+}
+
+.size {
+ @apply ml-3;
+ font-weight: 400;
+ font-size: 12px;
+ line-height: 18px;
+ color: #667085;
+}
+
+.actionWrapper {
+ @apply flex items-center shrink-0;
+ z-index: 1;
+}
+
+.actionWrapper .percent {
+ font-weight: 400;
+ font-size: 13px;
+ line-height: 18px;
+ color: #344054;
+}
+
+.actionWrapper .remove {
+ display: none;
+ width: 24px;
+ height: 24px;
+ background: center no-repeat url(../assets/trash.svg);
+ background-size: 16px;
+ cursor: pointer;
+}
+
+.file:hover .actionWrapper .remove {
+ display: block;
+}
diff --git a/app/components/datasets/create/file-uploader/index.tsx b/app/components/datasets/create/file-uploader/index.tsx
new file mode 100644
index 0000000..5ed4b7d
--- /dev/null
+++ b/app/components/datasets/create/file-uploader/index.tsx
@@ -0,0 +1,381 @@
+'use client'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import useSWR from 'swr'
+import { RiDeleteBinLine, RiUploadCloud2Line } from '@remixicon/react'
+import DocumentFileIcon from '../../common/document-file-icon'
+import cn from '@/utils/classnames'
+import type { CustomFile as File, FileItem } from '@/models/datasets'
+import { ToastContext } from '@/app/components/base/toast'
+import SimplePieChart from '@/app/components/base/simple-pie-chart'
+
+import { upload } from '@/service/base'
+import { fetchFileUploadConfig } from '@/service/common'
+import { fetchSupportFileTypes } from '@/service/datasets'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+import { IS_CE_EDITION } from '@/config'
+import { Theme } from '@/types/app'
+import useTheme from '@/hooks/use-theme'
+
+const FILES_NUMBER_LIMIT = 20
+
+type IFileUploaderProps = {
+ fileList: FileItem[]
+ titleClassName?: string
+ prepareFileList: (files: FileItem[]) => void
+ onFileUpdate: (fileItem: FileItem, progress: number, list: FileItem[]) => void
+ onFileListUpdate?: (files: FileItem[]) => void
+ onPreview: (file: File) => void
+ notSupportBatchUpload?: boolean
+}
+
+const FileUploader = ({
+ fileList,
+ titleClassName,
+ prepareFileList,
+ onFileUpdate,
+ onFileListUpdate,
+ onPreview,
+ notSupportBatchUpload,
+}: IFileUploaderProps) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const { locale } = useContext(I18n)
+ const [dragging, setDragging] = useState(false)
+ const dropRef = useRef<HTMLDivElement>(null)
+ const dragRef = useRef<HTMLDivElement>(null)
+ const fileUploader = useRef<HTMLInputElement>(null)
+ const hideUpload = notSupportBatchUpload && fileList.length > 0
+
+ const { data: fileUploadConfigResponse } = useSWR({ url: '/files/upload' }, fetchFileUploadConfig)
+ const { data: supportFileTypesResponse } = useSWR({ url: '/files/support-type' }, fetchSupportFileTypes)
+ const supportTypes = supportFileTypesResponse?.allowed_extensions || []
+ const supportTypesShowNames = (() => {
+ const extensionMap: { [key: string]: string } = {
+ md: 'markdown',
+ pptx: 'pptx',
+ htm: 'html',
+ xlsx: 'xlsx',
+ docx: 'docx',
+ }
+
+ return [...supportTypes]
+ .map(item => extensionMap[item] || item) // map to standardized extension
+ .map(item => item.toLowerCase()) // convert to lower case
+ .filter((item, index, self) => self.indexOf(item) === index) // remove duplicates
+ .map(item => item.toUpperCase()) // convert to upper case
+ .join(locale !== LanguagesSupported[1] ? ', ' : '銆� ')
+ })()
+ const ACCEPTS = supportTypes.map((ext: string) => `.${ext}`)
+ const fileUploadConfig = useMemo(() => fileUploadConfigResponse ?? {
+ file_size_limit: 15,
+ batch_count_limit: 5,
+ }, [fileUploadConfigResponse])
+
+ const fileListRef = useRef<FileItem[]>([])
+
+ // utils
+ const getFileType = (currentFile: File) => {
+ if (!currentFile)
+ return ''
+
+ const arr = currentFile.name.split('.')
+ return arr[arr.length - 1]
+ }
+
+ const getFileSize = (size: number) => {
+ if (size / 1024 < 10)
+ return `${(size / 1024).toFixed(2)}KB`
+
+ return `${(size / 1024 / 1024).toFixed(2)}MB`
+ }
+
+ const isValid = useCallback((file: File) => {
+ const { size } = file
+ const ext = `.${getFileType(file)}`
+ const isValidType = ACCEPTS.includes(ext.toLowerCase())
+ if (!isValidType)
+ notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.typeError') })
+
+ const isValidSize = size <= fileUploadConfig.file_size_limit * 1024 * 1024
+ if (!isValidSize)
+ notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.size', { size: fileUploadConfig.file_size_limit }) })
+
+ return isValidType && isValidSize
+ }, [fileUploadConfig, notify, t, ACCEPTS])
+
+ const fileUpload = useCallback(async (fileItem: FileItem): Promise<FileItem> => {
+ const formData = new FormData()
+ formData.append('file', fileItem.file)
+ const onProgress = (e: ProgressEvent) => {
+ if (e.lengthComputable) {
+ const percent = Math.floor(e.loaded / e.total * 100)
+ onFileUpdate(fileItem, percent, fileListRef.current)
+ }
+ }
+
+ return upload({
+ xhr: new XMLHttpRequest(),
+ data: formData,
+ onprogress: onProgress,
+ }, false, undefined, '?source=datasets')
+ .then((res: File) => {
+ const completeFile = {
+ fileID: fileItem.fileID,
+ file: res,
+ progress: -1,
+ }
+ const index = fileListRef.current.findIndex(item => item.fileID === fileItem.fileID)
+ fileListRef.current[index] = completeFile
+ onFileUpdate(completeFile, 100, fileListRef.current)
+ return Promise.resolve({ ...completeFile })
+ })
+ .catch((e) => {
+ notify({ type: 'error', message: e?.response?.code === 'forbidden' ? e?.response?.message : t('datasetCreation.stepOne.uploader.failed') })
+ onFileUpdate(fileItem, -2, fileListRef.current)
+ return Promise.resolve({ ...fileItem })
+ })
+ .finally()
+ }, [fileListRef, notify, onFileUpdate, t])
+
+ const uploadBatchFiles = useCallback((bFiles: FileItem[]) => {
+ bFiles.forEach(bf => (bf.progress = 0))
+ return Promise.all(bFiles.map(fileUpload))
+ }, [fileUpload])
+
+ const uploadMultipleFiles = useCallback(async (files: FileItem[]) => {
+ const batchCountLimit = fileUploadConfig.batch_count_limit
+ const length = files.length
+ let start = 0
+ let end = 0
+
+ while (start < length) {
+ if (start + batchCountLimit > length)
+ end = length
+ else
+ end = start + batchCountLimit
+ const bFiles = files.slice(start, end)
+ await uploadBatchFiles(bFiles)
+ start = end
+ }
+ }, [fileUploadConfig, uploadBatchFiles])
+
+ const initialUpload = useCallback((files: File[]) => {
+ if (!files.length)
+ return false
+
+ if (files.length + fileList.length > FILES_NUMBER_LIMIT && !IS_CE_EDITION) {
+ notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.filesNumber', { filesNumber: FILES_NUMBER_LIMIT }) })
+ return false
+ }
+
+ const preparedFiles = files.map((file, index) => ({
+ fileID: `file${index}-${Date.now()}`,
+ file,
+ progress: -1,
+ }))
+ const newFiles = [...fileListRef.current, ...preparedFiles]
+ prepareFileList(newFiles)
+ fileListRef.current = newFiles
+ uploadMultipleFiles(preparedFiles)
+ }, [prepareFileList, uploadMultipleFiles, notify, t, fileList])
+
+ const handleDragEnter = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ e.target !== dragRef.current && setDragging(true)
+ }
+ const handleDragOver = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }
+ const handleDragLeave = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ e.target === dragRef.current && setDragging(false)
+ }
+ type FileWithPath = {
+ relativePath?: string
+ } & File
+ const traverseFileEntry = useCallback(
+ (entry: any, prefix = ''): Promise<FileWithPath[]> => {
+ return new Promise((resolve) => {
+ if (entry.isFile) {
+ entry.file((file: FileWithPath) => {
+ file.relativePath = `${prefix}${file.name}`
+ resolve([file])
+ })
+ }
+ else if (entry.isDirectory) {
+ const reader = entry.createReader()
+ const entries: any[] = []
+ const read = () => {
+ reader.readEntries(async (results: FileSystemEntry[]) => {
+ if (!results.length) {
+ const files = await Promise.all(
+ entries.map(ent =>
+ traverseFileEntry(ent, `${prefix}${entry.name}/`),
+ ),
+ )
+ resolve(files.flat())
+ }
+ else {
+ entries.push(...results)
+ read()
+ }
+ })
+ }
+ read()
+ }
+ else {
+ resolve([])
+ }
+ })
+ },
+ [],
+ )
+
+ const handleDrop = useCallback(
+ async (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setDragging(false)
+ if (!e.dataTransfer) return
+ const nested = await Promise.all(
+ Array.from(e.dataTransfer.items).map((it) => {
+ const entry = (it as any).webkitGetAsEntry?.()
+ if (entry) return traverseFileEntry(entry)
+ const f = it.getAsFile?.()
+ return f ? Promise.resolve([f]) : Promise.resolve([])
+ }),
+ )
+ let files = nested.flat()
+ if (notSupportBatchUpload) files = files.slice(0, 1)
+ const valid = files.filter(isValid)
+ initialUpload(valid)
+ },
+ [initialUpload, isValid, notSupportBatchUpload, traverseFileEntry],
+ )
+ const selectHandle = () => {
+ if (fileUploader.current)
+ fileUploader.current.click()
+ }
+
+ const removeFile = (fileID: string) => {
+ if (fileUploader.current)
+ fileUploader.current.value = ''
+
+ fileListRef.current = fileListRef.current.filter(item => item.fileID !== fileID)
+ onFileListUpdate?.([...fileListRef.current])
+ }
+ const fileChangeHandle = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
+ const files = [...(e.target.files ?? [])] as File[]
+ initialUpload(files.filter(isValid))
+ }, [isValid, initialUpload])
+
+ const { theme } = useTheme()
+ const chartColor = useMemo(() => theme === Theme.dark ? '#5289ff' : '#296dff', [theme])
+
+ useEffect(() => {
+ dropRef.current?.addEventListener('dragenter', handleDragEnter)
+ dropRef.current?.addEventListener('dragover', handleDragOver)
+ dropRef.current?.addEventListener('dragleave', handleDragLeave)
+ dropRef.current?.addEventListener('drop', handleDrop)
+ return () => {
+ dropRef.current?.removeEventListener('dragenter', handleDragEnter)
+ dropRef.current?.removeEventListener('dragover', handleDragOver)
+ dropRef.current?.removeEventListener('dragleave', handleDragLeave)
+ dropRef.current?.removeEventListener('drop', handleDrop)
+ }
+ }, [handleDrop])
+
+ return (
+ <div className="mb-5 w-[640px]">
+ {!hideUpload && (
+ <input
+ ref={fileUploader}
+ id="fileUploader"
+ className="hidden"
+ type="file"
+ multiple={!notSupportBatchUpload}
+ accept={ACCEPTS.join(',')}
+ onChange={fileChangeHandle}
+ />
+ )}
+
+ <div className={cn('mb-1 text-sm font-semibold leading-6 text-text-secondary', titleClassName)}>{t('datasetCreation.stepOne.uploader.title')}</div>
+
+ {!hideUpload && (
+ <div ref={dropRef} className={cn('relative mb-2 box-border flex min-h-20 max-w-[640px] flex-col items-center justify-center gap-1 rounded-xl border border-dashed border-components-dropzone-border bg-components-dropzone-bg px-4 py-3 text-xs leading-4 text-text-tertiary', dragging && 'border-components-dropzone-border-accent bg-components-dropzone-bg-accent')}>
+ <div className="flex min-h-5 items-center justify-center text-sm leading-4 text-text-secondary">
+ <RiUploadCloud2Line className='mr-2 size-5' />
+
+ <span>
+ {t('datasetCreation.stepOne.uploader.button')}
+ {supportTypes.length > 0 && (
+ <label className="ml-1 cursor-pointer text-text-accent" onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.browse')}</label>
+ )}
+ </span>
+ </div>
+ <div>{t('datasetCreation.stepOne.uploader.tip', {
+ size: fileUploadConfig.file_size_limit,
+ supportTypes: supportTypesShowNames,
+ })}</div>
+ {dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />}
+ </div>
+ )}
+ <div className='max-w-[640px] cursor-default space-y-1'>
+
+ {fileList.map((fileItem, index) => (
+ <div
+ key={`${fileItem.fileID}-${index}`}
+ onClick={() => fileItem.file?.id && onPreview(fileItem.file)}
+ className={cn(
+ 'flex h-12 max-w-[640px] items-center rounded-lg border border-components-panel-border bg-components-panel-on-panel-item-bg text-xs leading-3 text-text-tertiary shadow-xs',
+ // 'border-state-destructive-border bg-state-destructive-hover',
+ )}
+ >
+ <div className="flex w-12 shrink-0 items-center justify-center">
+ <DocumentFileIcon
+ className="size-6 shrink-0"
+ name={fileItem.file.name}
+ extension={getFileType(fileItem.file)}
+ />
+ </div>
+ <div className="flex shrink grow flex-col gap-0.5">
+ <div className='flex w-full'>
+ <div className="w-0 grow truncate text-sm leading-4 text-text-secondary">{fileItem.file.name}</div>
+ </div>
+ <div className="w-full truncate leading-3 text-text-tertiary">
+ <span className='uppercase'>{getFileType(fileItem.file)}</span>
+ <span className='px-1 text-text-quaternary'>路</span>
+ <span>{getFileSize(fileItem.file.size)}</span>
+ {/* <span className='px-1 text-text-quaternary'>路</span>
+ <span>10k characters</span> */}
+ </div>
+ </div>
+ <div className="flex w-16 shrink-0 items-center justify-end gap-1 pr-3">
+ {/* <span className="flex justify-center items-center w-6 h-6 cursor-pointer">
+ <RiErrorWarningFill className='size-4 text-text-warning' />
+ </span> */}
+ {(fileItem.progress < 100 && fileItem.progress >= 0) && (
+ // <div className={s.percent}>{`${fileItem.progress}%`}</div>
+ <SimplePieChart percentage={fileItem.progress} stroke={chartColor} fill={chartColor} animationDuration={0} />
+ )}
+ <span className="flex h-6 w-6 cursor-pointer items-center justify-center" onClick={(e) => {
+ e.stopPropagation()
+ removeFile(fileItem.fileID)
+ }}>
+ <RiDeleteBinLine className='size-4 text-text-tertiary' />
+ </span>
+ </div>
+ </div>
+ ))}
+ </div>
+ </div>
+ )
+}
+
+export default FileUploader
diff --git a/app/components/datasets/create/icons.ts b/app/components/datasets/create/icons.ts
new file mode 100644
index 0000000..80c4b6c
--- /dev/null
+++ b/app/components/datasets/create/icons.ts
@@ -0,0 +1,16 @@
+import GoldIcon from './assets/gold.svg'
+import Piggybank from './assets/piggy-bank-mod.svg'
+import Selection from './assets/selection-mod.svg'
+import Research from './assets/research-mod.svg'
+import PatternRecognition from './assets/pattern-recognition-mod.svg'
+
+export const indexMethodIcon = {
+ high_quality: GoldIcon,
+ economical: Piggybank,
+}
+
+export const retrievalIcon = {
+ vector: Selection,
+ fullText: Research,
+ hybrid: PatternRecognition,
+}
diff --git a/app/components/datasets/create/index.module.css b/app/components/datasets/create/index.module.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/components/datasets/create/index.module.css
diff --git a/app/components/datasets/create/index.tsx b/app/components/datasets/create/index.tsx
new file mode 100644
index 0000000..b1e4087
--- /dev/null
+++ b/app/components/datasets/create/index.tsx
@@ -0,0 +1,177 @@
+'use client'
+import React, { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import AppUnavailable from '../../base/app-unavailable'
+import { ModelTypeEnum } from '../../header/account-setting/model-provider-page/declarations'
+import StepOne from './step-one'
+import StepTwo from './step-two'
+import StepThree from './step-three'
+import { TopBar } from './top-bar'
+import { DataSourceType } from '@/models/datasets'
+import type { CrawlOptions, CrawlResultItem, DataSet, FileItem, createDocumentResponse } from '@/models/datasets'
+import { fetchDataSource } from '@/service/common'
+import { fetchDatasetDetail } from '@/service/datasets'
+import { DataSourceProvider, type NotionPage } from '@/models/common'
+import { useModalContext } from '@/context/modal-context'
+import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+
+type DatasetUpdateFormProps = {
+ datasetId?: string
+}
+
+const DEFAULT_CRAWL_OPTIONS: CrawlOptions = {
+ crawl_sub_pages: true,
+ only_main_content: true,
+ includes: '',
+ excludes: '',
+ limit: 10,
+ max_depth: '',
+ use_sitemap: true,
+}
+
+const DatasetUpdateForm = ({ datasetId }: DatasetUpdateFormProps) => {
+ const { t } = useTranslation()
+ const { setShowAccountSettingModal } = useModalContext()
+ const [hasConnection, setHasConnection] = useState(true)
+ const [dataSourceType, setDataSourceType] = useState<DataSourceType>(DataSourceType.FILE)
+ const [step, setStep] = useState(1)
+ const [indexingTypeCache, setIndexTypeCache] = useState('')
+ const [retrievalMethodCache, setRetrievalMethodCache] = useState('')
+ const [fileList, setFiles] = useState<FileItem[]>([])
+ const [result, setResult] = useState<createDocumentResponse | undefined>()
+ const [hasError, setHasError] = useState(false)
+ const { data: embeddingsDefaultModel } = useDefaultModel(ModelTypeEnum.textEmbedding)
+
+ const [notionPages, setNotionPages] = useState<NotionPage[]>([])
+ const updateNotionPages = (value: NotionPage[]) => {
+ setNotionPages(value)
+ }
+
+ const [websitePages, setWebsitePages] = useState<CrawlResultItem[]>([])
+ const [crawlOptions, setCrawlOptions] = useState<CrawlOptions>(DEFAULT_CRAWL_OPTIONS)
+
+ const updateFileList = (preparedFiles: FileItem[]) => {
+ setFiles(preparedFiles)
+ }
+ const [websiteCrawlProvider, setWebsiteCrawlProvider] = useState<DataSourceProvider>(DataSourceProvider.fireCrawl)
+ const [websiteCrawlJobId, setWebsiteCrawlJobId] = useState('')
+
+ const updateFile = (fileItem: FileItem, progress: number, list: FileItem[]) => {
+ const targetIndex = list.findIndex(file => file.fileID === fileItem.fileID)
+ list[targetIndex] = {
+ ...list[targetIndex],
+ progress,
+ }
+ setFiles([...list])
+ // use follow code would cause dirty list update problem
+ // const newList = list.map((file) => {
+ // if (file.fileID === fileItem.fileID) {
+ // return {
+ // ...fileItem,
+ // progress,
+ // }
+ // }
+ // return file
+ // })
+ // setFiles(newList)
+ }
+ const updateIndexingTypeCache = (type: string) => {
+ setIndexTypeCache(type)
+ }
+ const updateResultCache = (res?: createDocumentResponse) => {
+ setResult(res)
+ }
+ const updateRetrievalMethodCache = (method: string) => {
+ setRetrievalMethodCache(method)
+ }
+
+ const nextStep = useCallback(() => {
+ setStep(step + 1)
+ }, [step, setStep])
+
+ const changeStep = useCallback((delta: number) => {
+ setStep(step + delta)
+ }, [step, setStep])
+
+ const checkNotionConnection = async () => {
+ const { data } = await fetchDataSource({ url: '/data-source/integrates' })
+ const hasConnection = data.filter(item => item.provider === 'notion') || []
+ setHasConnection(hasConnection.length > 0)
+ }
+
+ useEffect(() => {
+ checkNotionConnection()
+ }, [])
+
+ const [detail, setDetail] = useState<DataSet | null>(null)
+ useEffect(() => {
+ (async () => {
+ if (datasetId) {
+ try {
+ const detail = await fetchDatasetDetail(datasetId)
+ setDetail(detail)
+ }
+ catch {
+ setHasError(true)
+ }
+ }
+ })()
+ }, [datasetId])
+
+ if (hasError)
+ return <AppUnavailable code={500} unknownReason={t('datasetCreation.error.unavailable') as string} />
+
+ return (
+ <div className='flex flex-col bg-components-panel-bg' style={{ height: 'calc(100vh - 56px)' }}>
+ <TopBar activeIndex={step - 1} datasetId={datasetId} />
+ <div style={{ height: 'calc(100% - 52px)' }}>
+ {step === 1 && <StepOne
+ hasConnection={hasConnection}
+ onSetting={() => setShowAccountSettingModal({ payload: 'data-source' })}
+ datasetId={datasetId}
+ dataSourceType={dataSourceType}
+ dataSourceTypeDisable={!!detail?.data_source_type}
+ changeType={setDataSourceType}
+ files={fileList}
+ updateFile={updateFile}
+ updateFileList={updateFileList}
+ notionPages={notionPages}
+ updateNotionPages={updateNotionPages}
+ onStepChange={nextStep}
+ websitePages={websitePages}
+ updateWebsitePages={setWebsitePages}
+ onWebsiteCrawlProviderChange={setWebsiteCrawlProvider}
+ onWebsiteCrawlJobIdChange={setWebsiteCrawlJobId}
+ crawlOptions={crawlOptions}
+ onCrawlOptionsChange={setCrawlOptions}
+ />}
+ {(step === 2 && (!datasetId || (datasetId && !!detail))) && <StepTwo
+ isAPIKeySet={!!embeddingsDefaultModel}
+ onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
+ indexingType={detail?.indexing_technique}
+ datasetId={datasetId}
+ dataSourceType={dataSourceType}
+ files={fileList.map(file => file.file)}
+ notionPages={notionPages}
+ websitePages={websitePages}
+ websiteCrawlProvider={websiteCrawlProvider}
+ websiteCrawlJobId={websiteCrawlJobId}
+ onStepChange={changeStep}
+ updateIndexingTypeCache={updateIndexingTypeCache}
+ updateRetrievalMethodCache={updateRetrievalMethodCache}
+ updateResultCache={updateResultCache}
+ crawlOptions={crawlOptions}
+ />}
+ {step === 3 && <StepThree
+ datasetId={datasetId}
+ datasetName={detail?.name}
+ indexingType={detail?.indexing_technique || indexingTypeCache}
+ retrievalMethod={detail?.retrieval_model_dict?.search_method || retrievalMethodCache}
+ creationCache={result}
+ />}
+ </div>
+ </div>
+ )
+}
+
+export default DatasetUpdateForm
diff --git a/app/components/datasets/create/notion-page-preview/index.module.css b/app/components/datasets/create/notion-page-preview/index.module.css
new file mode 100644
index 0000000..b3bc589
--- /dev/null
+++ b/app/components/datasets/create/notion-page-preview/index.module.css
@@ -0,0 +1,33 @@
+.filePreview {
+ @apply flex flex-col border-l border-components-panel-border shrink-0 bg-background-default-lighter;
+ width: 528px;
+}
+
+.previewHeader {
+ @apply border-b border-divider-subtle shrink-0;
+ margin: 42px 32px 0;
+ padding-bottom: 16px;
+}
+
+.previewHeader .title {
+ @apply flex justify-between items-center text-text-primary;
+}
+
+.previewHeader .fileName {
+ @apply flex items-center text-text-tertiary;
+}
+
+.previewContent {
+ @apply overflow-y-auto grow text-text-secondary;
+ padding: 20px 32px;
+}
+
+.previewContent .loading {
+ width: 100%;
+ height: 180px;
+ background: #f9fafb center no-repeat url(../assets/Loading.svg);
+ background-size: contain;
+}
+.fileContent {
+ white-space: pre-line;
+}
diff --git a/app/components/datasets/create/notion-page-preview/index.tsx b/app/components/datasets/create/notion-page-preview/index.tsx
new file mode 100644
index 0000000..5b56036
--- /dev/null
+++ b/app/components/datasets/create/notion-page-preview/index.tsx
@@ -0,0 +1,75 @@
+'use client'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { XMarkIcon } from '@heroicons/react/20/solid'
+import Loading from '@/app/components/base/loading'
+import s from './index.module.css'
+import cn from '@/utils/classnames'
+import type { NotionPage } from '@/models/common'
+import NotionIcon from '@/app/components/base/notion-icon'
+import { fetchNotionPagePreview } from '@/service/datasets'
+
+type IProps = {
+ currentPage?: NotionPage
+ hidePreview: () => void
+}
+
+const NotionPagePreview = ({
+ currentPage,
+ hidePreview,
+}: IProps) => {
+ const { t } = useTranslation()
+ const [previewContent, setPreviewContent] = useState('')
+ const [loading, setLoading] = useState(true)
+
+ const getPreviewContent = async () => {
+ if (!currentPage)
+ return
+ try {
+ const res = await fetchNotionPagePreview({
+ workspaceID: currentPage.workspace_id,
+ pageID: currentPage.page_id,
+ pageType: currentPage.type,
+ })
+ setPreviewContent(res.content)
+ setLoading(false)
+ }
+ catch { }
+ }
+
+ useEffect(() => {
+ if (currentPage) {
+ setLoading(true)
+ getPreviewContent()
+ }
+ }, [currentPage])
+
+ return (
+ <div className={cn(s.filePreview, 'h-full')}>
+ <div className={cn(s.previewHeader)}>
+ <div className={cn(s.title, 'title-md-semi-bold')}>
+ <span>{t('datasetCreation.stepOne.pagePreview')}</span>
+ <div className='flex h-6 w-6 cursor-pointer items-center justify-center' onClick={hidePreview}>
+ <XMarkIcon className='h-4 w-4'></XMarkIcon>
+ </div>
+ </div>
+ <div className={cn(s.fileName, 'system-xs-medium')}>
+ <NotionIcon
+ className='mr-1 shrink-0'
+ type='page'
+ src={currentPage?.page_icon}
+ />
+ {currentPage?.page_name}
+ </div>
+ </div>
+ <div className={cn(s.previewContent, 'body-md-regular')}>
+ {loading && <Loading type='area' />}
+ {!loading && (
+ <div className={cn(s.fileContent, 'body-md-regular')}>{previewContent}</div>
+ )}
+ </div>
+ </div>
+ )
+}
+
+export default NotionPagePreview
diff --git a/app/components/datasets/create/step-one/index.module.css b/app/components/datasets/create/step-one/index.module.css
new file mode 100644
index 0000000..581409b
--- /dev/null
+++ b/app/components/datasets/create/step-one/index.module.css
@@ -0,0 +1,66 @@
+.stepHeader {
+ padding: 42px 64px 12px 0;
+}
+
+.form {
+ position: relative;
+ padding: 12px 64px;
+}
+
+.dataSourceItem {
+ @apply w-full relative flex items-center p-3 h-14 bg-components-option-card-option-bg rounded-xl
+ cursor-pointer border border-components-option-card-option-border text-text-secondary;
+}
+
+.dataSourceItem:hover {
+ @apply bg-components-option-card-option-bg-hover border border-components-option-card-option-border-hover shadow-xs shadow-shadow-shadow-3;
+}
+
+.dataSourceItem.active {
+ @apply bg-components-option-card-option-selected-bg border border-components-option-card-option-selected-border
+ ring-[0.5px] ring-components-option-card-option-selected-border;
+}
+
+.dataSourceItem.disabled,
+.dataSourceItem.disabled:hover {
+ @apply bg-components-option-card-option-bg border-[0.5px] border-components-option-card-option-border cursor-not-allowed text-text-disabled shadow-none;
+}
+
+.comingTag {
+ @apply flex justify-center items-center bg-white;
+ position: absolute;
+ right: 8px;
+ top: -10px;
+ padding: 1px 6px;
+ height: 20px;
+ border: 1px solid #E0EAFF;
+ border-radius: 6px;
+ font-weight: 500;
+ font-size: 12px;
+ line-height: 18px;
+ color: #444CE7;
+}
+
+.datasetIcon {
+ @apply flex shrink-0 mr-2 w-8 h-8 rounded-lg bg-center bg-no-repeat bg-text-primary-on-surface border-[0.5px] border-divider-regular backdrop-blur-sm;
+ background-image: url(../assets/file.svg);
+ background-size: 16px;
+}
+
+.datasetIcon.notion {
+ background-image: url(../assets/notion.svg);
+ background-size: 20px;
+}
+
+.datasetIcon.web {
+ background-image: url(../assets/web.svg);
+}
+
+.submitButton {
+ width: 120px;
+}
+
+.notionIcon {
+ background: var(--color-components-card-bg) center no-repeat url(../assets/notion.svg);
+ background-size: 24px;
+}
diff --git a/app/components/datasets/create/step-one/index.tsx b/app/components/datasets/create/step-one/index.tsx
new file mode 100644
index 0000000..38c885e
--- /dev/null
+++ b/app/components/datasets/create/step-one/index.tsx
@@ -0,0 +1,325 @@
+'use client'
+import React, { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowRightLine, RiFolder6Line } from '@remixicon/react'
+import FilePreview from '../file-preview'
+import FileUploader from '../file-uploader'
+import NotionPagePreview from '../notion-page-preview'
+import EmptyDatasetCreationModal from '../empty-dataset-creation-modal'
+import Website from '../website'
+import WebsitePreview from '../website/preview'
+import s from './index.module.css'
+import cn from '@/utils/classnames'
+import type { CrawlOptions, CrawlResultItem, FileItem } from '@/models/datasets'
+import type { DataSourceProvider, NotionPage } from '@/models/common'
+import { DataSourceType } from '@/models/datasets'
+import Button from '@/app/components/base/button'
+import { NotionPageSelector } from '@/app/components/base/notion-page-selector'
+import { useDatasetDetailContext } from '@/context/dataset-detail'
+import { useProviderContext } from '@/context/provider-context'
+import VectorSpaceFull from '@/app/components/billing/vector-space-full'
+import classNames from '@/utils/classnames'
+import { Icon3Dots } from '@/app/components/base/icons/src/vender/line/others'
+import { ENABLE_WEBSITE_FIRECRAWL, ENABLE_WEBSITE_JINAREADER, ENABLE_WEBSITE_WATERCRAWL } from '@/config'
+type IStepOneProps = {
+ datasetId?: string
+ dataSourceType?: DataSourceType
+ dataSourceTypeDisable: boolean
+ hasConnection: boolean
+ onSetting: () => void
+ files: FileItem[]
+ updateFileList: (files: FileItem[]) => void
+ updateFile: (fileItem: FileItem, progress: number, list: FileItem[]) => void
+ notionPages?: NotionPage[]
+ updateNotionPages: (value: NotionPage[]) => void
+ onStepChange: () => void
+ changeType: (type: DataSourceType) => void
+ websitePages?: CrawlResultItem[]
+ updateWebsitePages: (value: CrawlResultItem[]) => void
+ onWebsiteCrawlProviderChange: (provider: DataSourceProvider) => void
+ onWebsiteCrawlJobIdChange: (jobId: string) => void
+ crawlOptions: CrawlOptions
+ onCrawlOptionsChange: (payload: CrawlOptions) => void
+}
+
+type NotionConnectorProps = {
+ onSetting: () => void
+}
+export const NotionConnector = ({ onSetting }: NotionConnectorProps) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex w-[640px] flex-col items-start rounded-2xl bg-workflow-process-bg p-6'>
+ <span className={cn(s.notionIcon, 'mb-2 h-12 w-12 rounded-[10px] border-[0.5px] border-components-card-border p-3 shadow-lg shadow-shadow-shadow-5')} />
+ <div className='mb-1 flex flex-col gap-y-1 pb-3 pt-1'>
+ <span className='system-md-semibold text-text-secondary'>
+ {t('datasetCreation.stepOne.notionSyncTitle')}
+ <Icon3Dots className='relative -left-1.5 -top-2.5 inline h-4 w-4 text-text-secondary' />
+ </span>
+ <div className='system-sm-regular text-text-tertiary'>{t('datasetCreation.stepOne.notionSyncTip')}</div>
+ </div>
+ <Button className='h-8' variant='primary' onClick={onSetting}>{t('datasetCreation.stepOne.connect')}</Button>
+ </div>
+ )
+}
+
+const StepOne = ({
+ datasetId,
+ dataSourceType: inCreatePageDataSourceType,
+ dataSourceTypeDisable,
+ changeType,
+ hasConnection,
+ onSetting,
+ onStepChange,
+ files,
+ updateFileList,
+ updateFile,
+ notionPages = [],
+ updateNotionPages,
+ websitePages = [],
+ updateWebsitePages,
+ onWebsiteCrawlProviderChange,
+ onWebsiteCrawlJobIdChange,
+ crawlOptions,
+ onCrawlOptionsChange,
+}: IStepOneProps) => {
+ const { dataset } = useDatasetDetailContext()
+ const [showModal, setShowModal] = useState(false)
+ const [currentFile, setCurrentFile] = useState<File | undefined>()
+ const [currentNotionPage, setCurrentNotionPage] = useState<NotionPage | undefined>()
+ const [currentWebsite, setCurrentWebsite] = useState<CrawlResultItem | undefined>()
+ const { t } = useTranslation()
+
+ const modalShowHandle = () => setShowModal(true)
+ const modalCloseHandle = () => setShowModal(false)
+
+ const updateCurrentFile = (file: File) => {
+ setCurrentFile(file)
+ }
+ const hideFilePreview = () => {
+ setCurrentFile(undefined)
+ }
+
+ const updateCurrentPage = (page: NotionPage) => {
+ setCurrentNotionPage(page)
+ }
+
+ const hideNotionPagePreview = () => {
+ setCurrentNotionPage(undefined)
+ }
+
+ const hideWebsitePreview = () => {
+ setCurrentWebsite(undefined)
+ }
+
+ const shouldShowDataSourceTypeList = !datasetId || (datasetId && !dataset?.data_source_type)
+ const isInCreatePage = shouldShowDataSourceTypeList
+ const dataSourceType = isInCreatePage ? inCreatePageDataSourceType : dataset?.data_source_type
+ const { plan, enableBilling } = useProviderContext()
+ const allFileLoaded = (files.length > 0 && files.every(file => file.file.id))
+ const hasNotin = notionPages.length > 0
+ const isVectorSpaceFull = plan.usage.vectorSpace >= plan.total.vectorSpace
+ const isShowVectorSpaceFull = (allFileLoaded || hasNotin) && isVectorSpaceFull && enableBilling
+ const notSupportBatchUpload = enableBilling && plan.type === 'sandbox'
+ const nextDisabled = useMemo(() => {
+ if (!files.length)
+ return true
+ if (files.some(file => !file.file.id))
+ return true
+ return isShowVectorSpaceFull
+ }, [files, isShowVectorSpaceFull])
+
+ return (
+ <div className='h-full w-full overflow-x-auto'>
+ <div className='flex h-full w-full min-w-[1440px]'>
+ <div className='relative h-full w-1/2 overflow-y-auto'>
+ <div className='flex justify-end'>
+ <div className={classNames(s.form)}>
+ {
+ shouldShowDataSourceTypeList && (
+ <div className={classNames(s.stepHeader, 'text-text-secondary system-md-semibold')}>
+ {t('datasetCreation.steps.one')}
+ </div>
+ )
+ }
+ {
+ shouldShowDataSourceTypeList && (
+ <div className='mb-8 grid grid-cols-3 gap-4'>
+ <div
+ className={cn(
+ s.dataSourceItem,
+ 'system-sm-medium',
+ dataSourceType === DataSourceType.FILE && s.active,
+ dataSourceTypeDisable && dataSourceType !== DataSourceType.FILE && s.disabled,
+ )}
+ onClick={() => {
+ if (dataSourceTypeDisable)
+ return
+ changeType(DataSourceType.FILE)
+ hideFilePreview()
+ hideNotionPagePreview()
+ }}
+ >
+ <span className={cn(s.datasetIcon)} />
+ <span
+ title={t('datasetCreation.stepOne.dataSourceType.file')}
+ className='truncate'
+ >
+ {t('datasetCreation.stepOne.dataSourceType.file')}
+ </span>
+ </div>
+ <div
+ className={cn(
+ s.dataSourceItem,
+ 'system-sm-medium',
+ dataSourceType === DataSourceType.NOTION && s.active,
+ dataSourceTypeDisable && dataSourceType !== DataSourceType.NOTION && s.disabled,
+ )}
+ onClick={() => {
+ if (dataSourceTypeDisable)
+ return
+ changeType(DataSourceType.NOTION)
+ hideFilePreview()
+ hideNotionPagePreview()
+ }}
+ >
+ <span className={cn(s.datasetIcon, s.notion)} />
+ <span
+ title={t('datasetCreation.stepOne.dataSourceType.notion')}
+ className='truncate'
+ >
+ {t('datasetCreation.stepOne.dataSourceType.notion')}
+ </span>
+ </div>
+ {(ENABLE_WEBSITE_FIRECRAWL || ENABLE_WEBSITE_JINAREADER || ENABLE_WEBSITE_WATERCRAWL) && (
+ <div
+ className={cn(
+ s.dataSourceItem,
+ 'system-sm-medium',
+ dataSourceType === DataSourceType.WEB && s.active,
+ dataSourceTypeDisable && dataSourceType !== DataSourceType.WEB && s.disabled,
+ )}
+ onClick={() => changeType(DataSourceType.WEB)}
+ >
+ <span className={cn(s.datasetIcon, s.web)} />
+ <span
+ title={t('datasetCreation.stepOne.dataSourceType.web')}
+ className='truncate'
+ >
+ {t('datasetCreation.stepOne.dataSourceType.web')}
+ </span>
+ </div>
+ )}
+ </div>
+ )
+ }
+ {dataSourceType === DataSourceType.FILE && (
+ <>
+ <FileUploader
+ fileList={files}
+ titleClassName={!shouldShowDataSourceTypeList ? 'mt-[30px] !mb-[44px] !text-lg' : undefined}
+ prepareFileList={updateFileList}
+ onFileListUpdate={updateFileList}
+ onFileUpdate={updateFile}
+ onPreview={updateCurrentFile}
+ notSupportBatchUpload={notSupportBatchUpload}
+ />
+ {isShowVectorSpaceFull && (
+ <div className='mb-4 max-w-[640px]'>
+ <VectorSpaceFull />
+ </div>
+ )}
+ <div className="flex max-w-[640px] justify-end gap-2">
+ {/* <Button>{t('datasetCreation.stepOne.cancel')}</Button> */}
+ <Button disabled={nextDisabled} variant='primary' onClick={onStepChange}>
+ <span className="flex gap-0.5 px-[10px]">
+ <span className="px-0.5">{t('datasetCreation.stepOne.button')}</span>
+ <RiArrowRightLine className="size-4" />
+ </span>
+ </Button>
+ </div>
+ </>
+ )}
+ {dataSourceType === DataSourceType.NOTION && (
+ <>
+ {!hasConnection && <NotionConnector onSetting={onSetting} />}
+ {hasConnection && (
+ <>
+ <div className='mb-8 w-[640px]'>
+ <NotionPageSelector
+ value={notionPages.map(page => page.page_id)}
+ onSelect={updateNotionPages}
+ onPreview={updateCurrentPage}
+ />
+ </div>
+ {isShowVectorSpaceFull && (
+ <div className='mb-4 max-w-[640px]'>
+ <VectorSpaceFull />
+ </div>
+ )}
+ <div className="flex max-w-[640px] justify-end gap-2">
+ {/* <Button>{t('datasetCreation.stepOne.cancel')}</Button> */}
+ <Button disabled={isShowVectorSpaceFull || !notionPages.length} variant='primary' onClick={onStepChange}>
+ <span className="flex gap-0.5 px-[10px]">
+ <span className="px-0.5">{t('datasetCreation.stepOne.button')}</span>
+ <RiArrowRightLine className="size-4" />
+ </span>
+ </Button>
+ </div>
+ </>
+ )}
+ </>
+ )}
+ {dataSourceType === DataSourceType.WEB && (
+ <>
+ <div className={cn('mb-8 w-[640px]', !shouldShowDataSourceTypeList && 'mt-12')}>
+ <Website
+ onPreview={setCurrentWebsite}
+ checkedCrawlResult={websitePages}
+ onCheckedCrawlResultChange={updateWebsitePages}
+ onCrawlProviderChange={onWebsiteCrawlProviderChange}
+ onJobIdChange={onWebsiteCrawlJobIdChange}
+ crawlOptions={crawlOptions}
+ onCrawlOptionsChange={onCrawlOptionsChange}
+ />
+ </div>
+ {isShowVectorSpaceFull && (
+ <div className='mb-4 max-w-[640px]'>
+ <VectorSpaceFull />
+ </div>
+ )}
+ <div className="flex max-w-[640px] justify-end gap-2">
+ {/* <Button>{t('datasetCreation.stepOne.cancel')}</Button> */}
+ <Button disabled={isShowVectorSpaceFull || !websitePages.length} variant='primary' onClick={onStepChange}>
+ <span className="flex gap-0.5 px-[10px]">
+ <span className="px-0.5">{t('datasetCreation.stepOne.button')}</span>
+ <RiArrowRightLine className="size-4" />
+ </span>
+ </Button>
+ </div>
+ </>
+ )}
+ {!datasetId && (
+ <>
+ <div className='my-8 h-px max-w-[640px] bg-divider-regular' />
+ <span className="inline-flex cursor-pointer items-center text-[13px] leading-4 text-text-accent" onClick={modalShowHandle}>
+ <RiFolder6Line className="mr-1 size-4" />
+ {t('datasetCreation.stepOne.emptyDatasetCreation')}
+ </span>
+ </>
+ )}
+ </div>
+ <EmptyDatasetCreationModal show={showModal} onHide={modalCloseHandle} />
+ </div>
+ </div>
+ <div className='h-full w-1/2 overflow-y-auto'>
+ {currentFile && <FilePreview file={currentFile} hidePreview={hideFilePreview} />}
+ {currentNotionPage && <NotionPagePreview currentPage={currentNotionPage} hidePreview={hideNotionPagePreview} />}
+ {currentWebsite && <WebsitePreview payload={currentWebsite} hidePreview={hideWebsitePreview} />}
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default StepOne
diff --git a/app/components/datasets/create/step-three/index.module.css b/app/components/datasets/create/step-three/index.module.css
new file mode 100644
index 0000000..57fe705
--- /dev/null
+++ b/app/components/datasets/create/step-three/index.module.css
@@ -0,0 +1,75 @@
+.creationInfo {
+ padding-top: 42px;
+}
+.creationInfo .title {
+ @apply mb-2;
+ font-weight: 500;
+ font-size: 20px;
+ line-height: 30px;
+ color: #101828;
+}
+.creationInfo .content {
+ margin-bottom: 44px;
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 20px;
+ color: #667085;
+}
+.creationInfo .label {
+ @apply mb-2;
+ font-weight: 500;
+ font-size: 14px;
+ line-height: 20px;
+ color: #101828;
+}
+.datasetName {
+ padding: 8px 12px;
+ background: #F9FAFB;
+ border-radius: 8px;
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 20px;
+ color: #101828;
+ word-break: break-all;
+}
+
+.dividerLine {
+ margin: 24px 0;
+ height: 1px;
+ background-color: #eaecf0;
+}
+
+.sideTip {
+ @apply flex flex-col items-center shrink-0 ;
+ padding-top: 108px;
+ width: 524px;
+ border-left: 0.5px solid #F2F4F7;
+}
+.tipCard {
+ @apply flex flex-col items-start p-6;
+ width: 320px;
+ background-color: #F9FAFB;
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+ border-radius: 12px;
+}
+.tipCard .icon {
+ width: 32px;
+ height: 32px;
+ border: 1px solid #EAECF0;
+ border-radius: 6px;
+ background: center no-repeat url(../assets/book-open-01.svg);
+ background-size: 16px;
+}
+.tipCard .title {
+ margin: 12px 0;
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 24px;
+ color: #344054;
+}
+.tipCard .content {
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 20px;
+ color: #344054;
+}
diff --git a/app/components/datasets/create/step-three/index.tsx b/app/components/datasets/create/step-three/index.tsx
new file mode 100644
index 0000000..cdaa003
--- /dev/null
+++ b/app/components/datasets/create/step-three/index.tsx
@@ -0,0 +1,75 @@
+'use client'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiBookOpenLine } from '@remixicon/react'
+import EmbeddingProcess from '../embedding-process'
+
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import type { FullDocumentDetail, createDocumentResponse } from '@/models/datasets'
+import AppIcon from '@/app/components/base/app-icon'
+
+type StepThreeProps = {
+ datasetId?: string
+ datasetName?: string
+ indexingType?: string
+ retrievalMethod?: string
+ creationCache?: createDocumentResponse
+}
+
+const StepThree = ({ datasetId, datasetName, indexingType, creationCache, retrievalMethod }: StepThreeProps) => {
+ const { t } = useTranslation()
+
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ return (
+ <div className="flex h-full max-h-full w-full justify-center overflow-y-auto">
+ <div className="h-full max-w-[960px] shrink-0 grow overflow-y-auto px-14 sm:px-16">
+ <div className="mx-auto max-w-[640px]">
+ {!datasetId && (
+ <>
+ <div className="pt-10">
+ <div className="mb-1 text-xl font-semibold leading-[22px] text-text-primary">{t('datasetCreation.stepThree.creationTitle')}</div>
+ <div className="mb-7 text-[13px] leading-4 text-text-tertiary">{t('datasetCreation.stepThree.creationContent')}</div>
+ <div className="flex gap-4">
+ <AppIcon {...creationCache?.dataset} className="size-14 self-center text-2xl" />
+ <div className="flex grow flex-col gap-1">
+ <div className="text-[13px] font-semibold leading-6 text-text-secondary">{t('datasetCreation.stepThree.label')}</div>
+ <div className="w-full truncate rounded-lg bg-components-input-bg-normal px-3 py-2 text-[13px] leading-4 text-components-input-text-filled">{datasetName || creationCache?.dataset?.name}</div>
+ </div>
+ </div>
+ </div>
+ <hr className="my-6 h-[1px] border-0 bg-divider-subtle" />
+ </>
+ )}
+ {datasetId && (
+ <div className="pt-10">
+ <div className="mb-1 text-xl font-semibold leading-[22px] text-text-primary">{t('datasetCreation.stepThree.additionTitle')}</div>
+ <div className="mb-7 text-[13px] leading-4 text-text-tertiary">{`${t('datasetCreation.stepThree.additionP1')} ${datasetName || creationCache?.dataset?.name} ${t('datasetCreation.stepThree.additionP2')}`}</div>
+ </div>
+ )}
+ <EmbeddingProcess
+ datasetId={datasetId || creationCache?.dataset?.id || ''}
+ batchId={creationCache?.batch || ''}
+ documents={creationCache?.documents as FullDocumentDetail[]}
+ indexingType={indexingType || creationCache?.dataset?.indexing_technique}
+ retrievalMethod={retrievalMethod || creationCache?.dataset?.retrieval_model?.search_method}
+ />
+ </div>
+ </div>
+ {!isMobile && (
+ <div className="shrink-0 pr-8 pt-[88px] text-xs">
+ <div className="flex w-[328px] flex-col gap-3 rounded-xl bg-background-section p-6 text-text-tertiary">
+ <div className="flex size-10 items-center justify-center rounded-[10px] bg-components-card-bg shadow-lg">
+ <RiBookOpenLine className="size-5 text-text-accent" />
+ </div>
+ <div className="text-base font-semibold text-text-secondary">{t('datasetCreation.stepThree.sideTipTitle')}</div>
+ <div className="text-text-tertiary">{t('datasetCreation.stepThree.sideTipContent')}</div>
+ </div>
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default StepThree
diff --git a/app/components/datasets/create/step-two/escape.ts b/app/components/datasets/create/step-two/escape.ts
new file mode 100644
index 0000000..2e1c3a9
--- /dev/null
+++ b/app/components/datasets/create/step-two/escape.ts
@@ -0,0 +1,18 @@
+function escape(input: string): string {
+ if (!input || typeof input !== 'string')
+ return ''
+
+ const res = input
+ // .replaceAll('\\', '\\\\') // This would add too many backslashes
+ .replaceAll('\0', '\\0')
+ .replaceAll('\b', '\\b')
+ .replaceAll('\f', '\\f')
+ .replaceAll('\n', '\\n')
+ .replaceAll('\r', '\\r')
+ .replaceAll('\t', '\\t')
+ .replaceAll('\v', '\\v')
+ .replaceAll('\'', '\\\'')
+ return res
+}
+
+export default escape
diff --git a/app/components/datasets/create/step-two/index.module.css b/app/components/datasets/create/step-two/index.module.css
new file mode 100644
index 0000000..e79ab2d
--- /dev/null
+++ b/app/components/datasets/create/step-two/index.module.css
@@ -0,0 +1,413 @@
+.pageHeader {
+ @apply px-16 flex justify-between items-center;
+ position: sticky;
+ top: 0;
+ left: 0;
+ padding-top: 42px;
+ padding-bottom: 12px;
+ background-color: #fff;
+ font-weight: 600;
+ font-size: 18px;
+ line-height: 28px;
+ color: #101828;
+ z-index: 10;
+}
+
+.segmentationItem {
+ min-height: 68px;
+}
+
+.indexItem {
+ min-height: 126px;
+}
+
+.indexItem .disableMask {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(255, 255, 255, 0.5);
+ border-radius: 12px;
+ z-index: 2;
+}
+
+.indexItem .warningTip {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ padding: 8px 20px 8px 40px;
+ background: #FFFAEB;
+ border-top: 0.5px solid #FEF0C7;
+ border-radius: 12px;
+ font-size: 12px;
+ line-height: 18px;
+ color: #344054;
+ z-index: 3;
+}
+
+.indexItem .warningTip::before {
+ content: '';
+ position: absolute;
+ top: 11px;
+ left: 20px;
+ width: 12px;
+ height: 12px;
+ background: center no-repeat url(../assets/alert-triangle.svg);
+ background-size: 12px;
+}
+
+.indexItem .warningTip .click {
+ color: #155EEF;
+ cursor: pointer;
+}
+
+.disabled {
+ cursor: not-allowed !important;
+}
+
+.indexItem.disabled:hover {
+ background-color: #fcfcfd;
+ border-color: #f2f4f7;
+ box-shadow: none;
+ cursor: default;
+}
+
+.indexItem.disabled:hover .radio {
+ @apply w-4 h-4 border-[2px] border-gray-200 rounded-full;
+}
+
+.radioItem {
+ @apply relative mb-2 rounded-xl border border-components-option-card-option-border cursor-pointer bg-components-option-card-option-bg;
+}
+
+.radioItem.segmentationItem.custom {
+ height: auto;
+}
+
+.radioItem.segmentationItem.custom .typeHeader {
+ /* height: 65px; */
+}
+
+.radioItem.indexItem .typeHeader {
+ @apply py-4 pr-5;
+}
+
+.radioItem.indexItem.active .typeHeader {
+ padding: 15.5px 19.5px 15.5px 63.5px;
+}
+
+.radioItem.indexItem .radio {
+ top: 16px;
+ right: 20px;
+}
+
+.radioItem.indexItem.active .radio {
+ top: 16px;
+ right: 19.5px;
+}
+
+.radioItem.indexItem .typeHeader .title {
+ @apply pb-1;
+}
+
+.radioItem .typeIcon {
+ position: absolute;
+ top: 18px;
+ left: 20px;
+ width: 32px;
+ height: 32px;
+ background: #EEF4FF center no-repeat;
+ border-radius: 8px;
+}
+
+.typeIcon.auto {
+ background-color: #F5F3FF;
+ background-image: url(../assets/zap-fast.svg);
+}
+
+.typeIcon.customize {
+ background-image: url(../assets/sliders-02.svg);
+}
+
+.typeIcon.qualified {
+ background-color: #FFF6ED;
+ background-image: url(../assets/star-07.svg);
+}
+
+.typeIcon.economical {
+ background-image: url(../assets/piggy-bank-mod.svg);
+}
+
+.radioItem .radio {
+ @apply w-4 h-4 border-[2px] border-gray-200 rounded-full;
+ position: absolute;
+ top: 26px;
+ right: 20px;
+}
+
+.radioItem:hover {
+ background-color: #ffffff;
+ border-color: #B2CCFF;
+ box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);
+}
+
+.radioItem:hover .radio {
+ border-color: #155eef;
+}
+
+.radioItem.active {
+ border-width: 1.5px;
+ border-color: #528BFF;
+ box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1), 0px 1px 2px rgba(16, 24, 40, 0.06);
+}
+
+.radioItem.active .radio {
+ top: 25.5px;
+ right: 19.5px;
+ border-width: 5px;
+ border-color: #155EEF;
+}
+
+.radioItem.active:hover {
+ border-width: 1.5px;
+ border-color: #528BFF;
+ box-shadow: 0px 1px 3px rgba(16, 24, 40, 0.1), 0px 1px 2px rgba(16, 24, 40, 0.06);
+}
+
+.radioItem.active .typeIcon {
+ top: 17.5px;
+ left: 19.5px;
+}
+
+.radioItem.active .typeHeader {
+ padding: 11.5px 63.5px;
+}
+
+.typeHeader {
+ @apply flex flex-col px-16 py-3 justify-center;
+}
+
+.typeHeader .title {
+ display: flex;
+ align-items: center;
+ padding-bottom: 2px;
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 24px;
+ color: #101828;
+}
+
+.typeHeader .tip {
+ font-weight: 400;
+ font-size: 13px;
+ line-height: 18px;
+ color: #667085;
+}
+
+.recommendTag {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ padding: 0 6px;
+ margin-left: 4px;
+ border: 1px solid #E0EAFF;
+ border-radius: 6px;
+ font-weight: 500;
+ font-size: 12px;
+ line-height: 20px;
+ color: #444CE7;
+}
+
+.typeFormBody {
+ @apply px-16;
+ border-top: 1px solid #F2F4F7;
+}
+
+.formRow {
+ @apply flex justify-between mt-6;
+}
+
+.formRow .label {
+ @apply mb-2 p-0;
+ font-weight: 500;
+ font-size: 14px;
+ line-height: 20px;
+ color: #101828;
+}
+
+.ruleItem {
+ @apply flex items-center py-1.5;
+}
+
+.formFooter {
+ padding: 16px 0 28px;
+}
+
+.formFooter .button {
+ font-size: 13px;
+ line-height: 18px;
+}
+
+.input {
+ @apply inline-flex h-9 w-full py-1 px-2 pr-14 rounded-lg text-xs leading-normal;
+ @apply bg-gray-100 caret-primary-600 hover:bg-gray-100 focus:ring-1 focus:ring-inset focus:ring-gray-200 focus-visible:outline-none focus:bg-white placeholder:text-gray-400;
+}
+
+.source {
+ @apply flex justify-between items-center mt-8 px-6 py-4 rounded-xl bg-gray-50 border border-gray-100;
+}
+
+.source .divider {
+ @apply shrink-0 mx-4 w-px bg-gray-200;
+ height: 42px;
+}
+
+.fileIcon {
+ @apply inline-flex mr-1 w-6 h-6 bg-center bg-no-repeat;
+ background-image: url(../assets/pdf.svg);
+ background-size: 24px;
+}
+
+.fileIcon.pdf {
+ background-image: url(../assets/pdf.svg);
+}
+
+.fileIcon.csv {
+ background-image: url(../assets/csv.svg);
+}
+
+.fileIcon.doc {
+ background-image: url(../assets/doc.svg);
+}
+
+.fileIcon.docx {
+ background-image: url(../assets/docx.svg);
+}
+
+.fileIcon.xlsx,
+.fileIcon.xls {
+ background-image: url(../assets/xlsx.svg);
+}
+
+.fileIcon.html,
+.fileIcon.htm {
+ background-image: url(../assets/html.svg);
+}
+
+.fileIcon.md,
+.fileIcon.markdown {
+ background-image: url(../assets/md.svg);
+}
+
+.fileIcon.txt {
+ background-image: url(../assets/txt.svg);
+}
+
+.fileIcon.json {
+ background-image: url(../assets/json.svg);
+}
+
+.sourceContent {
+ width: 0;
+ flex: 1 1 auto;
+}
+
+.sourceCount {
+ @apply shrink-0 ml-1;
+ font-weight: 500;
+ font-size: 13px;
+ line-height: 18px;
+ color: #667085;
+}
+
+.segmentCount {
+ flex: 1 1 30%;
+ max-width: 120px;
+}
+
+.divider {
+ @apply mx-3 w-px h-4 bg-gray-200;
+}
+
+.calculating {
+ color: #98A2B3;
+ font-size: 12px;
+ line-height: 18px;
+}
+
+.sideTip {
+ @apply flex flex-col items-center shrink-0;
+ padding-top: 108px;
+ width: 524px;
+ border-left: 0.5px solid #F2F4F7;
+}
+
+.tipCard {
+ @apply flex flex-col items-start p-6;
+ width: 320px;
+ background-color: #F9FAFB;
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+ border-radius: 12px;
+}
+
+.tipCard .icon {
+ width: 32px;
+ height: 32px;
+ border: 1px solid #EAECF0;
+ border-radius: 6px;
+ background: center no-repeat url(../assets/book-open-01.svg);
+ background-size: 16px;
+}
+
+.tipCard .title {
+ margin: 12px 0;
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 24px;
+ color: #344054;
+}
+
+.tipCard .content {
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 20px;
+ color: #344054;
+}
+
+.previewWrap {
+ flex-shrink: 0;
+ width: 524px;
+}
+
+.previewWrap.isMobile {
+ max-width: 524px;
+}
+
+/*
+ * `fixed` must under `previewHeader` because of style override would not work
+ */
+.fixed {
+ padding-top: 12px;
+ font-size: 12px;
+ line-height: 18px;
+ background: rgba(255, 255, 255, 0.9);
+ border-bottom: 0.5px solid #EAECF0;
+ backdrop-filter: blur(4px);
+ animation: fix 0.5s;
+}
+
+@keyframes fix {
+ from {
+ padding-top: 42px;
+ font-size: 18px;
+ line-height: 28px;
+ }
+
+ to {
+ padding-top: 12px;
+ font-size: 12px;
+ line-height: 18px;
+ }
+}
diff --git a/app/components/datasets/create/step-two/index.tsx b/app/components/datasets/create/step-two/index.tsx
new file mode 100644
index 0000000..6b6580a
--- /dev/null
+++ b/app/components/datasets/create/step-two/index.tsx
@@ -0,0 +1,1175 @@
+'use client'
+import type { FC, PropsWithChildren } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import {
+ RiAlertFill,
+ RiArrowLeftLine,
+ RiSearchEyeLine,
+} from '@remixicon/react'
+import Link from 'next/link'
+import Image from 'next/image'
+import { useHover } from 'ahooks'
+import SettingCog from '../assets/setting-gear-mod.svg'
+import OrangeEffect from '../assets/option-card-effect-orange.svg'
+import FamilyMod from '../assets/family-mod.svg'
+import Note from '../assets/note-mod.svg'
+import FileList from '../assets/file-list-3-fill.svg'
+import { indexMethodIcon } from '../icons'
+import { PreviewContainer } from '../../preview/container'
+import { ChunkContainer, QAPreview } from '../../chunk'
+import { PreviewHeader } from '../../preview/header'
+import { FormattedText } from '../../formatted-text/formatted'
+import { PreviewSlice } from '../../formatted-text/flavours/preview-slice'
+import PreviewDocumentPicker from '../../common/document-picker/preview-document-picker'
+import s from './index.module.css'
+import unescape from './unescape'
+import escape from './escape'
+import { OptionCard } from './option-card'
+import LanguageSelect from './language-select'
+import { DelimiterInput, MaxLengthInput, OverlapInput } from './inputs'
+import cn from '@/utils/classnames'
+import type { CrawlOptions, CrawlResultItem, CreateDocumentReq, CustomFile, DocumentItem, FullDocumentDetail, ParentMode, PreProcessingRule, ProcessRule, Rules, createDocumentResponse } from '@/models/datasets'
+import { ChunkingMode, DataSourceType, ProcessMode } from '@/models/datasets'
+
+import Button from '@/app/components/base/button'
+import FloatRightContainer from '@/app/components/base/float-right-container'
+import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
+import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
+import type { RetrievalConfig } from '@/types/app'
+import { isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
+import Toast from '@/app/components/base/toast'
+import type { NotionPage } from '@/models/common'
+import { DataSourceProvider } from '@/models/common'
+import { useDatasetDetailContext } from '@/context/dataset-detail'
+import I18n from '@/context/i18n'
+import { RETRIEVE_METHOD } from '@/types/app'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import { useDefaultModel, useModelList, useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { LanguagesSupported } from '@/i18n/language'
+import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
+import type { DefaultModel } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import Checkbox from '@/app/components/base/checkbox'
+import RadioCard from '@/app/components/base/radio-card'
+import { FULL_DOC_PREVIEW_LENGTH, IS_CE_EDITION } from '@/config'
+import Divider from '@/app/components/base/divider'
+import { getNotionInfo, getWebsiteInfo, useCreateDocument, useCreateFirstDocument, useFetchDefaultProcessRule, useFetchFileIndexingEstimateForFile, useFetchFileIndexingEstimateForNotion, useFetchFileIndexingEstimateForWeb } from '@/service/knowledge/use-create-dataset'
+import Badge from '@/app/components/base/badge'
+import { SkeletonContainer, SkeletonPoint, SkeletonRectangle, SkeletonRow } from '@/app/components/base/skeleton'
+import Tooltip from '@/app/components/base/tooltip'
+import CustomDialog from '@/app/components/base/dialog'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
+import { noop } from 'lodash-es'
+
+const TextLabel: FC<PropsWithChildren> = (props) => {
+ return <label className='system-sm-semibold text-text-secondary'>{props.children}</label>
+}
+
+type StepTwoProps = {
+ isSetting?: boolean
+ documentDetail?: FullDocumentDetail
+ isAPIKeySet: boolean
+ onSetting: () => void
+ datasetId?: string
+ indexingType?: IndexingType
+ retrievalMethod?: string
+ dataSourceType: DataSourceType
+ files: CustomFile[]
+ notionPages?: NotionPage[]
+ websitePages?: CrawlResultItem[]
+ crawlOptions?: CrawlOptions
+ websiteCrawlProvider?: DataSourceProvider
+ websiteCrawlJobId?: string
+ onStepChange?: (delta: number) => void
+ updateIndexingTypeCache?: (type: string) => void
+ updateRetrievalMethodCache?: (method: string) => void
+ updateResultCache?: (res: createDocumentResponse) => void
+ onSave?: () => void
+ onCancel?: () => void
+}
+
+export enum IndexingType {
+ QUALIFIED = 'high_quality',
+ ECONOMICAL = 'economy',
+}
+
+const DEFAULT_SEGMENT_IDENTIFIER = '\\n\\n'
+const DEFAULT_MAXIMUM_CHUNK_LENGTH = 1024
+const DEFAULT_OVERLAP = 50
+const MAXIMUM_CHUNK_TOKEN_LENGTH = Number.parseInt(globalThis.document?.body?.getAttribute('data-public-indexing-max-segmentation-tokens-length') || '4000', 10)
+
+type ParentChildConfig = {
+ chunkForContext: ParentMode
+ parent: {
+ delimiter: string
+ maxLength: number
+ }
+ child: {
+ delimiter: string
+ maxLength: number
+ }
+}
+
+const defaultParentChildConfig: ParentChildConfig = {
+ chunkForContext: 'paragraph',
+ parent: {
+ delimiter: '\\n\\n',
+ maxLength: 1024,
+ },
+ child: {
+ delimiter: '\\n',
+ maxLength: 512,
+ },
+}
+
+const StepTwo = ({
+ isSetting,
+ documentDetail,
+ isAPIKeySet,
+ datasetId,
+ indexingType,
+ dataSourceType: inCreatePageDataSourceType,
+ files,
+ notionPages = [],
+ websitePages = [],
+ crawlOptions,
+ websiteCrawlProvider = DataSourceProvider.fireCrawl,
+ websiteCrawlJobId = '',
+ onStepChange,
+ updateIndexingTypeCache,
+ updateResultCache,
+ onSave,
+ onCancel,
+ updateRetrievalMethodCache,
+}: StepTwoProps) => {
+ const { t } = useTranslation()
+ const { locale } = useContext(I18n)
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ const { dataset: currentDataset, mutateDatasetRes } = useDatasetDetailContext()
+
+ const isInUpload = Boolean(currentDataset)
+ const isUploadInEmptyDataset = isInUpload && !currentDataset?.doc_form
+ const isNotUploadInEmptyDataset = !isUploadInEmptyDataset
+ const isInInit = !isInUpload && !isSetting
+
+ const isInCreatePage = !datasetId || (datasetId && !currentDataset?.data_source_type)
+ const dataSourceType = isInCreatePage ? inCreatePageDataSourceType : currentDataset?.data_source_type
+ const [segmentationType, setSegmentationType] = useState<ProcessMode>(ProcessMode.general)
+ const [segmentIdentifier, doSetSegmentIdentifier] = useState(DEFAULT_SEGMENT_IDENTIFIER)
+ const setSegmentIdentifier = useCallback((value: string, canEmpty?: boolean) => {
+ doSetSegmentIdentifier(value ? escape(value) : (canEmpty ? '' : DEFAULT_SEGMENT_IDENTIFIER))
+ }, [])
+ const [maxChunkLength, setMaxChunkLength] = useState(DEFAULT_MAXIMUM_CHUNK_LENGTH) // default chunk length
+ const [limitMaxChunkLength, setLimitMaxChunkLength] = useState(MAXIMUM_CHUNK_TOKEN_LENGTH)
+ const [overlap, setOverlap] = useState(DEFAULT_OVERLAP)
+ const [rules, setRules] = useState<PreProcessingRule[]>([])
+ const [defaultConfig, setDefaultConfig] = useState<Rules>()
+ const hasSetIndexType = !!indexingType
+ const [indexType, setIndexType] = useState<IndexingType>(() => {
+ if (hasSetIndexType)
+ return indexingType
+ return isAPIKeySet ? IndexingType.QUALIFIED : IndexingType.ECONOMICAL
+ })
+
+ const [previewFile, setPreviewFile] = useState<DocumentItem>(
+ (datasetId && documentDetail)
+ ? documentDetail.file
+ : files[0],
+ )
+ const [previewNotionPage, setPreviewNotionPage] = useState<NotionPage>(
+ (datasetId && documentDetail)
+ ? documentDetail.notion_page
+ : notionPages[0],
+ )
+
+ const [previewWebsitePage, setPreviewWebsitePage] = useState<CrawlResultItem>(
+ (datasetId && documentDetail)
+ ? documentDetail.website_page
+ : websitePages[0],
+ )
+
+ // QA Related
+ const [isQAConfirmDialogOpen, setIsQAConfirmDialogOpen] = useState(false)
+ const [docForm, setDocForm] = useState<ChunkingMode>(
+ (datasetId && documentDetail) ? documentDetail.doc_form as ChunkingMode : ChunkingMode.text,
+ )
+ const handleChangeDocform = (value: ChunkingMode) => {
+ if (value === ChunkingMode.qa && indexType === IndexingType.ECONOMICAL) {
+ setIsQAConfirmDialogOpen(true)
+ return
+ }
+ if (value === ChunkingMode.parentChild && indexType === IndexingType.ECONOMICAL)
+ setIndexType(IndexingType.QUALIFIED)
+ setDocForm(value)
+ // eslint-disable-next-line ts/no-use-before-define
+ currentEstimateMutation.reset()
+ }
+
+ const [docLanguage, setDocLanguage] = useState<string>(
+ (datasetId && documentDetail) ? documentDetail.doc_language : (locale !== LanguagesSupported[1] ? 'English' : 'Chinese Simplified'),
+ )
+
+ const [parentChildConfig, setParentChildConfig] = useState<ParentChildConfig>(defaultParentChildConfig)
+
+ const getIndexing_technique = () => indexingType || indexType
+ const currentDocForm = currentDataset?.doc_form || docForm
+
+ const getProcessRule = (): ProcessRule => {
+ if (currentDocForm === ChunkingMode.parentChild) {
+ return {
+ rules: {
+ pre_processing_rules: rules,
+ segmentation: {
+ separator: unescape(
+ parentChildConfig.parent.delimiter,
+ ),
+ max_tokens: parentChildConfig.parent.maxLength,
+ },
+ parent_mode: parentChildConfig.chunkForContext,
+ subchunk_segmentation: {
+ separator: unescape(parentChildConfig.child.delimiter),
+ max_tokens: parentChildConfig.child.maxLength,
+ },
+ },
+ mode: 'hierarchical',
+ } as ProcessRule
+ }
+ return {
+ rules: {
+ pre_processing_rules: rules,
+ segmentation: {
+ separator: unescape(segmentIdentifier),
+ max_tokens: maxChunkLength,
+ chunk_overlap: overlap,
+ },
+ }, // api will check this. It will be removed after api refactored.
+ mode: segmentationType,
+ } as ProcessRule
+ }
+
+ const fileIndexingEstimateQuery = useFetchFileIndexingEstimateForFile({
+ docForm: currentDocForm,
+ docLanguage,
+ dataSourceType: DataSourceType.FILE,
+ files: previewFile
+ ? [files.find(file => file.name === previewFile.name)!]
+ : files,
+ indexingTechnique: getIndexing_technique() as any,
+ processRule: getProcessRule(),
+ dataset_id: datasetId!,
+ })
+ const notionIndexingEstimateQuery = useFetchFileIndexingEstimateForNotion({
+ docForm: currentDocForm,
+ docLanguage,
+ dataSourceType: DataSourceType.NOTION,
+ notionPages: [previewNotionPage],
+ indexingTechnique: getIndexing_technique() as any,
+ processRule: getProcessRule(),
+ dataset_id: datasetId || '',
+ })
+
+ const websiteIndexingEstimateQuery = useFetchFileIndexingEstimateForWeb({
+ docForm: currentDocForm,
+ docLanguage,
+ dataSourceType: DataSourceType.WEB,
+ websitePages: [previewWebsitePage],
+ crawlOptions,
+ websiteCrawlProvider,
+ websiteCrawlJobId,
+ indexingTechnique: getIndexing_technique() as any,
+ processRule: getProcessRule(),
+ dataset_id: datasetId || '',
+ })
+
+ const currentEstimateMutation = dataSourceType === DataSourceType.FILE
+ ? fileIndexingEstimateQuery
+ : dataSourceType === DataSourceType.NOTION
+ ? notionIndexingEstimateQuery
+ : websiteIndexingEstimateQuery
+
+ const fetchEstimate = useCallback(() => {
+ if (dataSourceType === DataSourceType.FILE)
+ fileIndexingEstimateQuery.mutate()
+
+ if (dataSourceType === DataSourceType.NOTION)
+ notionIndexingEstimateQuery.mutate()
+
+ if (dataSourceType === DataSourceType.WEB)
+ websiteIndexingEstimateQuery.mutate()
+ }, [dataSourceType, fileIndexingEstimateQuery, notionIndexingEstimateQuery, websiteIndexingEstimateQuery])
+
+ const estimate
+ = dataSourceType === DataSourceType.FILE
+ ? fileIndexingEstimateQuery.data
+ : dataSourceType === DataSourceType.NOTION
+ ? notionIndexingEstimateQuery.data
+ : websiteIndexingEstimateQuery.data
+
+ const getRuleName = (key: string) => {
+ if (key === 'remove_extra_spaces')
+ return t('datasetCreation.stepTwo.removeExtraSpaces')
+
+ if (key === 'remove_urls_emails')
+ return t('datasetCreation.stepTwo.removeUrlEmails')
+
+ if (key === 'remove_stopwords')
+ return t('datasetCreation.stepTwo.removeStopwords')
+ }
+ const ruleChangeHandle = (id: string) => {
+ const newRules = rules.map((rule) => {
+ if (rule.id === id) {
+ return {
+ id: rule.id,
+ enabled: !rule.enabled,
+ }
+ }
+ return rule
+ })
+ setRules(newRules)
+ }
+ const resetRules = () => {
+ if (defaultConfig) {
+ setSegmentIdentifier(defaultConfig.segmentation.separator)
+ setMaxChunkLength(defaultConfig.segmentation.max_tokens)
+ setOverlap(defaultConfig.segmentation.chunk_overlap!)
+ setRules(defaultConfig.pre_processing_rules)
+ }
+ setParentChildConfig(defaultParentChildConfig)
+ }
+
+ const updatePreview = () => {
+ if (segmentationType === ProcessMode.general && maxChunkLength > MAXIMUM_CHUNK_TOKEN_LENGTH) {
+ Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.maxLengthCheck', { limit: MAXIMUM_CHUNK_TOKEN_LENGTH }) })
+ return
+ }
+ fetchEstimate()
+ }
+
+ const {
+ modelList: rerankModelList,
+ defaultModel: rerankDefaultModel,
+ currentModel: isRerankDefaultModelValid,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
+ const { data: embeddingModelList } = useModelList(ModelTypeEnum.textEmbedding)
+ const { data: defaultEmbeddingModel } = useDefaultModel(ModelTypeEnum.textEmbedding)
+ const [embeddingModel, setEmbeddingModel] = useState<DefaultModel>(
+ currentDataset?.embedding_model
+ ? {
+ provider: currentDataset.embedding_model_provider,
+ model: currentDataset.embedding_model,
+ }
+ : {
+ provider: defaultEmbeddingModel?.provider.provider || '',
+ model: defaultEmbeddingModel?.model || '',
+ },
+ )
+ const [retrievalConfig, setRetrievalConfig] = useState(currentDataset?.retrieval_model_dict || {
+ search_method: RETRIEVE_METHOD.semantic,
+ reranking_enable: false,
+ reranking_model: {
+ reranking_provider_name: '',
+ reranking_model_name: '',
+ },
+ top_k: 3,
+ score_threshold_enabled: false,
+ score_threshold: 0.5,
+ } as RetrievalConfig)
+
+ useEffect(() => {
+ if (currentDataset?.retrieval_model_dict)
+ return
+ setRetrievalConfig({
+ search_method: RETRIEVE_METHOD.semantic,
+ reranking_enable: !!isRerankDefaultModelValid,
+ reranking_model: {
+ reranking_provider_name: isRerankDefaultModelValid ? rerankDefaultModel?.provider.provider ?? '' : '',
+ reranking_model_name: isRerankDefaultModelValid ? rerankDefaultModel?.model ?? '' : '',
+ },
+ top_k: 3,
+ score_threshold_enabled: false,
+ score_threshold: 0.5,
+ })
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [rerankDefaultModel, isRerankDefaultModelValid])
+
+ const getCreationParams = () => {
+ let params
+ if (segmentationType === ProcessMode.general && overlap > maxChunkLength) {
+ Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.overlapCheck') })
+ return
+ }
+ if (segmentationType === ProcessMode.general && maxChunkLength > limitMaxChunkLength) {
+ Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.maxLengthCheck', { limit: limitMaxChunkLength }) })
+ return
+ }
+ if (isSetting) {
+ params = {
+ original_document_id: documentDetail?.id,
+ doc_form: currentDocForm,
+ doc_language: docLanguage,
+ process_rule: getProcessRule(),
+ retrieval_model: retrievalConfig, // Readonly. If want to changed, just go to settings page.
+ embedding_model: embeddingModel.model, // Readonly
+ embedding_model_provider: embeddingModel.provider, // Readonly
+ indexing_technique: getIndexing_technique(),
+ } as CreateDocumentReq
+ }
+ else { // create
+ const indexMethod = getIndexing_technique()
+ if (indexMethod === IndexingType.QUALIFIED && (!embeddingModel.model || !embeddingModel.provider)) {
+ Toast.notify({
+ type: 'error',
+ message: t('appDebug.datasetConfig.embeddingModelRequired'),
+ })
+ return
+ }
+ if (
+ !isReRankModelSelected({
+ rerankModelList,
+ retrievalConfig,
+ indexMethod: indexMethod as string,
+ })
+ ) {
+ Toast.notify({ type: 'error', message: t('appDebug.datasetConfig.rerankModelRequired') })
+ return
+ }
+ params = {
+ data_source: {
+ type: dataSourceType,
+ info_list: {
+ data_source_type: dataSourceType,
+ },
+ },
+ indexing_technique: getIndexing_technique(),
+ process_rule: getProcessRule(),
+ doc_form: currentDocForm,
+ doc_language: docLanguage,
+ retrieval_model: retrievalConfig,
+ embedding_model: embeddingModel.model,
+ embedding_model_provider: embeddingModel.provider,
+ } as CreateDocumentReq
+ if (dataSourceType === DataSourceType.FILE) {
+ params.data_source.info_list.file_info_list = {
+ file_ids: files.map(file => file.id || '').filter(Boolean),
+ }
+ }
+ if (dataSourceType === DataSourceType.NOTION)
+ params.data_source.info_list.notion_info_list = getNotionInfo(notionPages)
+
+ if (dataSourceType === DataSourceType.WEB) {
+ params.data_source.info_list.website_info_list = getWebsiteInfo({
+ websiteCrawlProvider,
+ websiteCrawlJobId,
+ websitePages,
+ })
+ }
+ }
+ return params
+ }
+
+ const fetchDefaultProcessRuleMutation = useFetchDefaultProcessRule({
+ onSuccess(data) {
+ const separator = data.rules.segmentation.separator
+ setSegmentIdentifier(separator)
+ setMaxChunkLength(data.rules.segmentation.max_tokens)
+ setOverlap(data.rules.segmentation.chunk_overlap!)
+ setRules(data.rules.pre_processing_rules)
+ setDefaultConfig(data.rules)
+ setLimitMaxChunkLength(data.limits.indexing_max_segmentation_tokens_length)
+ },
+ onError(error) {
+ Toast.notify({
+ type: 'error',
+ message: `${error}`,
+ })
+ },
+ })
+
+ const getRulesFromDetail = () => {
+ if (documentDetail) {
+ const rules = documentDetail.dataset_process_rule.rules
+ const separator = rules.segmentation.separator
+ const max = rules.segmentation.max_tokens
+ const overlap = rules.segmentation.chunk_overlap
+ setSegmentIdentifier(separator)
+ setMaxChunkLength(max)
+ setOverlap(overlap!)
+ setRules(rules.pre_processing_rules)
+ setDefaultConfig(rules)
+ }
+ }
+
+ const getDefaultMode = () => {
+ if (documentDetail)
+ setSegmentationType(documentDetail.dataset_process_rule.mode)
+ }
+
+ const createFirstDocumentMutation = useCreateFirstDocument({
+ onError(error) {
+ Toast.notify({
+ type: 'error',
+ message: `${error}`,
+ })
+ },
+ })
+ const createDocumentMutation = useCreateDocument(datasetId!, {
+ onError(error) {
+ Toast.notify({
+ type: 'error',
+ message: `${error}`,
+ })
+ },
+ })
+
+ const isCreating = createFirstDocumentMutation.isPending || createDocumentMutation.isPending
+
+ const createHandle = async () => {
+ const params = getCreationParams()
+ if (!params)
+ return false
+
+ if (!datasetId) {
+ await createFirstDocumentMutation.mutateAsync(
+ params,
+ {
+ onSuccess(data) {
+ updateIndexingTypeCache && updateIndexingTypeCache(indexType as string)
+ updateResultCache && updateResultCache(data)
+ updateRetrievalMethodCache && updateRetrievalMethodCache(retrievalConfig.search_method as string)
+ },
+ },
+ )
+ }
+ else {
+ await createDocumentMutation.mutateAsync(params, {
+ onSuccess(data) {
+ updateIndexingTypeCache && updateIndexingTypeCache(indexType as string)
+ updateResultCache && updateResultCache(data)
+ },
+ })
+ }
+ if (mutateDatasetRes)
+ mutateDatasetRes()
+ onStepChange && onStepChange(+1)
+ isSetting && onSave && onSave()
+ }
+
+ useEffect(() => {
+ // fetch rules
+ if (!isSetting) {
+ fetchDefaultProcessRuleMutation.mutate('/datasets/process-rule')
+ }
+ else {
+ getRulesFromDetail()
+ getDefaultMode()
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+
+ useEffect(() => {
+ // get indexing type by props
+ if (indexingType)
+ setIndexType(indexingType as IndexingType)
+ else
+ setIndexType(isAPIKeySet ? IndexingType.QUALIFIED : IndexingType.ECONOMICAL)
+ }, [isAPIKeySet, indexingType, datasetId])
+
+ const economyDomRef = useRef<HTMLDivElement>(null)
+ const isHoveringEconomy = useHover(economyDomRef)
+
+ const isModelAndRetrievalConfigDisabled = !!datasetId && !!currentDataset?.data_source_type
+
+ return (
+ <div className='flex h-full w-full'>
+ <div className={cn('relative h-full w-1/2 overflow-y-auto py-6', isMobile ? 'px-4' : 'px-12')}>
+ <div className={'system-md-semibold mb-1 text-text-secondary'}>{t('datasetCreation.stepTwo.segmentation')}</div>
+ {((isInUpload && [ChunkingMode.text, ChunkingMode.qa].includes(currentDataset!.doc_form))
+ || isUploadInEmptyDataset
+ || isInInit)
+ && <OptionCard
+ className='mb-2 bg-background-section'
+ title={t('datasetCreation.stepTwo.general')}
+ icon={<Image width={20} height={20} src={SettingCog} alt={t('datasetCreation.stepTwo.general')} />}
+ activeHeaderClassName='bg-dataset-option-card-blue-gradient'
+ description={t('datasetCreation.stepTwo.generalTip')}
+ isActive={
+ [ChunkingMode.text, ChunkingMode.qa].includes(currentDocForm)
+ }
+ onSwitched={() =>
+ handleChangeDocform(ChunkingMode.text)
+ }
+ actions={
+ <>
+ <Button variant={'secondary-accent'} onClick={() => updatePreview()}>
+ <RiSearchEyeLine className='mr-0.5 h-4 w-4' />
+ {t('datasetCreation.stepTwo.previewChunk')}
+ </Button>
+ <Button variant={'ghost'} onClick={resetRules}>
+ {t('datasetCreation.stepTwo.reset')}
+ </Button>
+ </>
+ }
+ noHighlight={isInUpload && isNotUploadInEmptyDataset}
+ >
+ <div className='flex flex-col gap-y-4'>
+ <div className='flex gap-3'>
+ <DelimiterInput
+ value={segmentIdentifier}
+ onChange={e => setSegmentIdentifier(e.target.value, true)}
+ />
+ <MaxLengthInput
+ unit='characters'
+ value={maxChunkLength}
+ onChange={setMaxChunkLength}
+ />
+ <OverlapInput
+ unit='characters'
+ value={overlap}
+ min={1}
+ onChange={setOverlap}
+ />
+ </div>
+ <div className='flex w-full flex-col'>
+ <div className='flex items-center gap-x-2'>
+ <div className='inline-flex shrink-0'>
+ <TextLabel>{t('datasetCreation.stepTwo.rules')}</TextLabel>
+ </div>
+ <Divider className='grow' bgStyle='gradient' />
+ </div>
+ <div className='mt-1'>
+ {rules.map(rule => (
+ <div key={rule.id} className={s.ruleItem} onClick={() => {
+ ruleChangeHandle(rule.id)
+ }}>
+ <Checkbox
+ checked={rule.enabled}
+ />
+ <label className="system-sm-regular ml-2 cursor-pointer text-text-secondary">{getRuleName(rule.id)}</label>
+ </div>
+ ))}
+ {IS_CE_EDITION && <>
+ <Divider type='horizontal' className='my-4 bg-divider-subtle' />
+ <div className='flex items-center py-0.5'>
+ <div className='flex items-center' onClick={() => {
+ if (currentDataset?.doc_form)
+ return
+ if (docForm === ChunkingMode.qa)
+ handleChangeDocform(ChunkingMode.text)
+ else
+ handleChangeDocform(ChunkingMode.qa)
+ }}>
+ <Checkbox
+ checked={currentDocForm === ChunkingMode.qa}
+ disabled={!!currentDataset?.doc_form}
+ />
+ <label className="system-sm-regular ml-2 cursor-pointer text-text-secondary">
+ {t('datasetCreation.stepTwo.useQALanguage')}
+ </label>
+ </div>
+ <LanguageSelect
+ currentLanguage={docLanguage || locale}
+ onSelect={setDocLanguage}
+ disabled={currentDocForm !== ChunkingMode.qa}
+ />
+ <Tooltip popupContent={t('datasetCreation.stepTwo.QATip')} />
+ </div>
+ {currentDocForm === ChunkingMode.qa && (
+ <div
+ style={{
+ background: 'linear-gradient(92deg, rgba(247, 144, 9, 0.1) 0%, rgba(255, 255, 255, 0.00) 100%)',
+ }}
+ className='mt-2 flex h-10 items-center gap-2 rounded-xl border border-components-panel-border px-3 text-xs shadow-xs backdrop-blur-[5px]'
+ >
+ <RiAlertFill className='size-4 text-text-warning-secondary' />
+ <span className='system-xs-medium text-text-primary'>
+ {t('datasetCreation.stepTwo.QATip')}
+ </span>
+ </div>
+ )}
+ </>}
+ </div>
+ </div>
+ </div>
+ </OptionCard>}
+ {
+ (
+ (isInUpload && currentDataset!.doc_form === ChunkingMode.parentChild)
+ || isUploadInEmptyDataset
+ || isInInit
+ )
+ && <OptionCard
+ title={t('datasetCreation.stepTwo.parentChild')}
+ icon={<Image width={20} height={20} src={FamilyMod} alt={t('datasetCreation.stepTwo.parentChild')} />}
+ effectImg={OrangeEffect.src}
+ activeHeaderClassName='bg-dataset-option-card-orange-gradient'
+ description={t('datasetCreation.stepTwo.parentChildTip')}
+ isActive={currentDocForm === ChunkingMode.parentChild}
+ onSwitched={() => handleChangeDocform(ChunkingMode.parentChild)}
+ actions={
+ <>
+ <Button variant={'secondary-accent'} onClick={() => updatePreview()}>
+ <RiSearchEyeLine className='mr-0.5 h-4 w-4' />
+ {t('datasetCreation.stepTwo.previewChunk')}
+ </Button>
+ <Button variant={'ghost'} onClick={resetRules}>
+ {t('datasetCreation.stepTwo.reset')}
+ </Button>
+ </>
+ }
+ noHighlight={isInUpload && isNotUploadInEmptyDataset}
+ >
+ <div className='flex flex-col gap-4'>
+ <div>
+ <div className='flex items-center gap-x-2'>
+ <div className='inline-flex shrink-0'>
+ <TextLabel>{t('datasetCreation.stepTwo.parentChunkForContext')}</TextLabel>
+ </div>
+ <Divider className='grow' bgStyle='gradient' />
+ </div>
+ <RadioCard className='mt-1'
+ icon={<Image src={Note} alt='' />}
+ title={t('datasetCreation.stepTwo.paragraph')}
+ description={t('datasetCreation.stepTwo.paragraphTip')}
+ isChosen={parentChildConfig.chunkForContext === 'paragraph'}
+ onChosen={() => setParentChildConfig(
+ {
+ ...parentChildConfig,
+ chunkForContext: 'paragraph',
+ },
+ )}
+ chosenConfig={
+ <div className='flex gap-3'>
+ <DelimiterInput
+ value={parentChildConfig.parent.delimiter}
+ tooltip={t('datasetCreation.stepTwo.parentChildDelimiterTip')!}
+ onChange={e => setParentChildConfig({
+ ...parentChildConfig,
+ parent: {
+ ...parentChildConfig.parent,
+ delimiter: e.target.value ? escape(e.target.value) : '',
+ },
+ })}
+ />
+ <MaxLengthInput
+ unit='characters'
+ value={parentChildConfig.parent.maxLength}
+ onChange={value => setParentChildConfig({
+ ...parentChildConfig,
+ parent: {
+ ...parentChildConfig.parent,
+ maxLength: value,
+ },
+ })}
+ />
+ </div>
+ }
+ />
+ <RadioCard className='mt-2'
+ icon={<Image src={FileList} alt='' />}
+ title={t('datasetCreation.stepTwo.fullDoc')}
+ description={t('datasetCreation.stepTwo.fullDocTip')}
+ onChosen={() => setParentChildConfig(
+ {
+ ...parentChildConfig,
+ chunkForContext: 'full-doc',
+ },
+ )}
+ isChosen={parentChildConfig.chunkForContext === 'full-doc'}
+ />
+ </div>
+
+ <div>
+ <div className='flex items-center gap-x-2'>
+ <div className='inline-flex shrink-0'>
+ <TextLabel>{t('datasetCreation.stepTwo.childChunkForRetrieval')}</TextLabel>
+ </div>
+ <Divider className='grow' bgStyle='gradient' />
+ </div>
+ <div className='mt-1 flex gap-3'>
+ <DelimiterInput
+ value={parentChildConfig.child.delimiter}
+ tooltip={t('datasetCreation.stepTwo.parentChildChunkDelimiterTip')!}
+ onChange={e => setParentChildConfig({
+ ...parentChildConfig,
+ child: {
+ ...parentChildConfig.child,
+ delimiter: e.target.value ? escape(e.target.value) : '',
+ },
+ })}
+ />
+ <MaxLengthInput
+ unit='characters'
+ value={parentChildConfig.child.maxLength}
+ onChange={value => setParentChildConfig({
+ ...parentChildConfig,
+ child: {
+ ...parentChildConfig.child,
+ maxLength: value,
+ },
+ })}
+ />
+ </div>
+ </div>
+ <div>
+ <div className='flex items-center gap-x-2'>
+ <div className='inline-flex shrink-0'>
+ <TextLabel>{t('datasetCreation.stepTwo.rules')}</TextLabel>
+ </div>
+ <Divider className='grow' bgStyle='gradient' />
+ </div>
+ <div className='mt-1'>
+ {rules.map(rule => (
+ <div key={rule.id} className={s.ruleItem} onClick={() => {
+ ruleChangeHandle(rule.id)
+ }}>
+ <Checkbox
+ checked={rule.enabled}
+ />
+ <label className="system-sm-regular ml-2 cursor-pointer text-text-secondary">{getRuleName(rule.id)}</label>
+ </div>
+ ))}
+ </div>
+ </div>
+ </div>
+ </OptionCard>}
+ <Divider className='my-5' />
+ <div className={'system-md-semibold mb-1 text-text-secondary'}>{t('datasetCreation.stepTwo.indexMode')}</div>
+ <div className='flex items-center gap-2'>
+ {(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.QUALIFIED)) && (
+ <OptionCard className='flex-1 self-stretch'
+ title={<div className='flex items-center'>
+ {t('datasetCreation.stepTwo.qualified')}
+ <Badge className={cn('ml-1 h-[18px]', (!hasSetIndexType && indexType === IndexingType.QUALIFIED) ? 'border-text-accent-secondary text-text-accent-secondary' : '')} uppercase>
+ {t('datasetCreation.stepTwo.recommend')}
+ </Badge>
+ <span className='ml-auto'>
+ {!hasSetIndexType && <span className={cn(s.radio)} />}
+ </span>
+ </div>}
+ description={t('datasetCreation.stepTwo.qualifiedTip')}
+ icon={<Image src={indexMethodIcon.high_quality} alt='' />}
+ isActive={!hasSetIndexType && indexType === IndexingType.QUALIFIED}
+ disabled={hasSetIndexType}
+ onSwitched={() => {
+ setIndexType(IndexingType.QUALIFIED)
+ }}
+ />
+ )}
+
+ {(!hasSetIndexType || (hasSetIndexType && indexingType === IndexingType.ECONOMICAL)) && (
+ <>
+ <CustomDialog show={isQAConfirmDialogOpen} onClose={() => setIsQAConfirmDialogOpen(false)} className='w-[432px]'>
+ <header className='mb-4 pt-6'>
+ <h2 className='text-lg font-semibold'>
+ {t('datasetCreation.stepTwo.qaSwitchHighQualityTipTitle')}
+ </h2>
+ <p className='mt-2 text-sm font-normal'>
+ {t('datasetCreation.stepTwo.qaSwitchHighQualityTipContent')}
+ </p>
+ </header>
+ <div className='flex gap-2 pb-6'>
+ <Button className='ml-auto' onClick={() => {
+ setIsQAConfirmDialogOpen(false)
+ }}>
+ {t('datasetCreation.stepTwo.cancel')}
+ </Button>
+ <Button variant={'primary'} onClick={() => {
+ setIsQAConfirmDialogOpen(false)
+ setIndexType(IndexingType.QUALIFIED)
+ setDocForm(ChunkingMode.qa)
+ }}>
+ {t('datasetCreation.stepTwo.switch')}
+ </Button>
+ </div>
+ </CustomDialog>
+ <PortalToFollowElem
+ open={
+ isHoveringEconomy && docForm !== ChunkingMode.text
+ }
+ placement={'top'}
+ >
+ <PortalToFollowElemTrigger asChild>
+ <OptionCard className='flex-1 self-stretch'
+ title={t('datasetCreation.stepTwo.economical')}
+ description={t('datasetCreation.stepTwo.economicalTip')}
+ icon={<Image src={indexMethodIcon.economical} alt='' />}
+ isActive={!hasSetIndexType && indexType === IndexingType.ECONOMICAL}
+ disabled={hasSetIndexType || docForm !== ChunkingMode.text}
+ ref={economyDomRef}
+ onSwitched={() => {
+ setIndexType(IndexingType.ECONOMICAL)
+ }}
+ />
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent>
+ <div className='rounded-lg border-components-panel-border bg-components-tooltip-bg p-3 text-xs font-medium text-text-secondary shadow-lg'>
+ {
+ docForm === ChunkingMode.qa
+ ? t('datasetCreation.stepTwo.notAvailableForQA')
+ : t('datasetCreation.stepTwo.notAvailableForParentChild')
+ }
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ </>)}
+ </div>
+ {!hasSetIndexType && indexType === IndexingType.QUALIFIED && (
+ <div className='mt-2 flex h-10 items-center gap-x-0.5 overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-2 shadow-xs backdrop-blur-[5px]'>
+ <div className='absolute bottom-0 left-0 right-0 top-0 bg-dataset-warning-message-bg opacity-40'></div>
+ <div className='p-1'>
+ <AlertTriangle className='size-4 text-text-warning-secondary' />
+ </div>
+ <span className='system-xs-medium text-text-primary'>{t('datasetCreation.stepTwo.highQualityTip')}</span>
+ </div>
+ )}
+ {hasSetIndexType && indexType === IndexingType.ECONOMICAL && (
+ <div className='system-xs-medium mt-2'>
+ {t('datasetCreation.stepTwo.indexSettingTip')}
+ <Link className='text-text-accent' href={`/datasets/${datasetId}/settings`}>{t('datasetCreation.stepTwo.datasetSettingLink')}</Link>
+ </div>
+ )}
+ {/* Embedding model */}
+ {indexType === IndexingType.QUALIFIED && (
+ <div className='mt-5'>
+ <div className={cn('system-md-semibold mb-1 text-text-secondary', datasetId && 'flex items-center justify-between')}>{t('datasetSettings.form.embeddingModel')}</div>
+ <ModelSelector
+ readonly={isModelAndRetrievalConfigDisabled}
+ triggerClassName={isModelAndRetrievalConfigDisabled ? 'opacity-50' : ''}
+ defaultModel={embeddingModel}
+ modelList={embeddingModelList}
+ onSelect={(model: DefaultModel) => {
+ setEmbeddingModel(model)
+ }}
+ />
+ {isModelAndRetrievalConfigDisabled && (
+ <div className='system-xs-medium mt-2 text-text-tertiary'>
+ {t('datasetCreation.stepTwo.indexSettingTip')}
+ <Link className='text-text-accent' href={`/datasets/${datasetId}/settings`}>{t('datasetCreation.stepTwo.datasetSettingLink')}</Link>
+ </div>
+ )}
+ </div>
+ )}
+ <Divider className='my-5' />
+ {/* Retrieval Method Config */}
+ <div>
+ {!isModelAndRetrievalConfigDisabled
+ ? (
+ <div className={'mb-1'}>
+ <div className='system-md-semibold mb-0.5 text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
+ <div className='body-xs-regular text-text-tertiary'>
+ <a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
+ {t('datasetSettings.form.retrievalSetting.longDescription')}
+ </div>
+ </div>
+ )
+ : (
+ <div className={cn('system-md-semibold mb-0.5 text-text-secondary', 'flex items-center justify-between')}>
+ <div>{t('datasetSettings.form.retrievalSetting.title')}</div>
+ </div>
+ )}
+
+ <div className=''>
+ {
+ getIndexing_technique() === IndexingType.QUALIFIED
+ ? (
+ <RetrievalMethodConfig
+ disabled={isModelAndRetrievalConfigDisabled}
+ value={retrievalConfig}
+ onChange={setRetrievalConfig}
+ />
+ )
+ : (
+ <EconomicalRetrievalMethodConfig
+ disabled={isModelAndRetrievalConfigDisabled}
+ value={retrievalConfig}
+ onChange={setRetrievalConfig}
+ />
+ )
+ }
+ </div>
+ </div>
+
+ {!isSetting
+ ? (
+ <div className='mt-8 flex items-center py-2'>
+ <Button onClick={() => onStepChange && onStepChange(-1)}>
+ <RiArrowLeftLine className='mr-1 h-4 w-4' />
+ {t('datasetCreation.stepTwo.previousStep')}
+ </Button>
+ <Button className='ml-auto' loading={isCreating} variant='primary' onClick={createHandle}>{t('datasetCreation.stepTwo.nextStep')}</Button>
+ </div>
+ )
+ : (
+ <div className='mt-8 flex items-center py-2'>
+ <Button loading={isCreating} variant='primary' onClick={createHandle}>{t('datasetCreation.stepTwo.save')}</Button>
+ <Button className='ml-2' onClick={onCancel}>{t('datasetCreation.stepTwo.cancel')}</Button>
+ </div>
+ )}
+ </div>
+ <FloatRightContainer isMobile={isMobile} isOpen={true} onClose={noop} footer={null}>
+ <PreviewContainer
+ header={<PreviewHeader
+ title={t('datasetCreation.stepTwo.preview')}
+ >
+ <div className='flex items-center gap-1'>
+ {dataSourceType === DataSourceType.FILE
+ && <PreviewDocumentPicker
+ files={files as Array<Required<CustomFile>>}
+ onChange={(selected) => {
+ currentEstimateMutation.reset()
+ setPreviewFile(selected)
+ currentEstimateMutation.mutate()
+ }}
+ // when it is from setting, it just has one file
+ value={isSetting ? (files[0]! as Required<CustomFile>) : previewFile}
+ />
+ }
+ {dataSourceType === DataSourceType.NOTION
+ && <PreviewDocumentPicker
+ files={
+ notionPages.map(page => ({
+ id: page.page_id,
+ name: page.page_name,
+ extension: 'md',
+ }))
+ }
+ onChange={(selected) => {
+ currentEstimateMutation.reset()
+ const selectedPage = notionPages.find(page => page.page_id === selected.id)
+ setPreviewNotionPage(selectedPage!)
+ currentEstimateMutation.mutate()
+ }}
+ value={{
+ id: previewNotionPage?.page_id || '',
+ name: previewNotionPage?.page_name || '',
+ extension: 'md',
+ }}
+ />
+ }
+ {dataSourceType === DataSourceType.WEB
+ && <PreviewDocumentPicker
+ files={
+ websitePages.map(page => ({
+ id: page.source_url,
+ name: page.title,
+ extension: 'md',
+ }))
+ }
+ onChange={(selected) => {
+ currentEstimateMutation.reset()
+ const selectedPage = websitePages.find(page => page.source_url === selected.id)
+ setPreviewWebsitePage(selectedPage!)
+ currentEstimateMutation.mutate()
+ }}
+ value={
+ {
+ id: previewWebsitePage?.source_url || '',
+ name: previewWebsitePage?.title || '',
+ extension: 'md',
+ }
+ }
+ />
+ }
+ {
+ currentDocForm !== ChunkingMode.qa
+ && <Badge text={t('datasetCreation.stepTwo.previewChunkCount', {
+ count: estimate?.total_segments || 0,
+ }) as string}
+ />
+ }
+ </div>
+ </PreviewHeader>}
+ className={cn('relative flex h-full w-1/2 shrink-0 p-4 pr-0', isMobile && 'w-full max-w-[524px]')}
+ mainClassName='space-y-6'
+ >
+ {currentDocForm === ChunkingMode.qa && estimate?.qa_preview && (
+ estimate?.qa_preview.map((item, index) => (
+ <ChunkContainer
+ key={item.question}
+ label={`Chunk-${index + 1}`}
+ characterCount={item.question.length + item.answer.length}
+ >
+ <QAPreview qa={item} />
+ </ChunkContainer>
+ ))
+ )}
+ {currentDocForm === ChunkingMode.text && estimate?.preview && (
+ estimate?.preview.map((item, index) => (
+ <ChunkContainer
+ key={item.content}
+ label={`Chunk-${index + 1}`}
+ characterCount={item.content.length}
+ >
+ {item.content}
+ </ChunkContainer>
+ ))
+ )}
+ {currentDocForm === ChunkingMode.parentChild && currentEstimateMutation.data?.preview && (
+ estimate?.preview?.map((item, index) => {
+ const indexForLabel = index + 1
+ const childChunks = parentChildConfig.chunkForContext === 'full-doc'
+ ? item.child_chunks.slice(0, FULL_DOC_PREVIEW_LENGTH)
+ : item.child_chunks
+ return (
+ <ChunkContainer
+ key={item.content}
+ label={`Chunk-${indexForLabel}`}
+ characterCount={item.content.length}
+ >
+ <FormattedText>
+ {childChunks.map((child, index) => {
+ const indexForLabel = index + 1
+ return (
+ <PreviewSlice
+ key={child}
+ label={`C-${indexForLabel}`}
+ text={child}
+ tooltip={`Child-chunk-${indexForLabel} 路 ${child.length} Characters`}
+ labelInnerClassName='text-[10px] font-semibold align-bottom leading-7'
+ dividerClassName='leading-7'
+ />
+ )
+ })}
+ </FormattedText>
+ </ChunkContainer>
+ )
+ })
+ )}
+ {currentEstimateMutation.isIdle && (
+ <div className='flex h-full w-full items-center justify-center'>
+ <div className='flex flex-col items-center justify-center gap-3'>
+ <RiSearchEyeLine className='size-10 text-text-empty-state-icon' />
+ <p className='text-sm text-text-tertiary'>
+ {t('datasetCreation.stepTwo.previewChunkTip')}
+ </p>
+ </div>
+ </div>
+ )}
+ {currentEstimateMutation.isPending && (
+ <div className='space-y-6'>
+ {Array.from({ length: 10 }, (_, i) => (
+ <SkeletonContainer key={i}>
+ <SkeletonRow>
+ <SkeletonRectangle className="w-20" />
+ <SkeletonPoint />
+ <SkeletonRectangle className="w-24" />
+ </SkeletonRow>
+ <SkeletonRectangle className="w-full" />
+ <SkeletonRectangle className="w-full" />
+ <SkeletonRectangle className="w-[422px]" />
+ </SkeletonContainer>
+ ))}
+ </div>
+ )}
+ </PreviewContainer>
+ </FloatRightContainer>
+ </div>
+ )
+}
+
+export default StepTwo
diff --git a/app/components/datasets/create/step-two/inputs.tsx b/app/components/datasets/create/step-two/inputs.tsx
new file mode 100644
index 0000000..d6dc6e9
--- /dev/null
+++ b/app/components/datasets/create/step-two/inputs.tsx
@@ -0,0 +1,79 @@
+import type { FC, PropsWithChildren, ReactNode } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { InputProps } from '@/app/components/base/input'
+import Input from '@/app/components/base/input'
+import Tooltip from '@/app/components/base/tooltip'
+import type { InputNumberProps } from '@/app/components/base/input-number'
+import { InputNumber } from '@/app/components/base/input-number'
+
+const TextLabel: FC<PropsWithChildren> = (props) => {
+ return <label className='text-xs font-semibold leading-none text-text-secondary'>{props.children}</label>
+}
+
+const FormField: FC<PropsWithChildren<{ label: ReactNode }>> = (props) => {
+ return <div className='flex-1 space-y-2'>
+ <TextLabel>{props.label}</TextLabel>
+ {props.children}
+ </div>
+}
+
+export const DelimiterInput: FC<InputProps & { tooltip?: string }> = (props) => {
+ const { t } = useTranslation()
+ return <FormField label={<div className='mb-1 flex items-center'>
+ <span className='system-sm-semibold mr-0.5'>{t('datasetCreation.stepTwo.separator')}</span>
+ <Tooltip
+ popupContent={
+ <div className='max-w-[200px]'>
+ {props.tooltip || t('datasetCreation.stepTwo.separatorTip')}
+ </div>
+ }
+ />
+ </div>}>
+ <Input
+ type="text"
+ className='h-9'
+ placeholder={t('datasetCreation.stepTwo.separatorPlaceholder')!}
+ {...props}
+ />
+ </FormField>
+}
+
+export const MaxLengthInput: FC<InputNumberProps> = (props) => {
+ const maxValue = Number.parseInt(globalThis.document?.body?.getAttribute('data-public-indexing-max-segmentation-tokens-length') || '4000', 10)
+
+ const { t } = useTranslation()
+ return <FormField label={<div className='system-sm-semibold mb-1'>
+ {t('datasetCreation.stepTwo.maxLength')}
+ </div>}>
+ <InputNumber
+ type="number"
+ size='large'
+ placeholder={`鈮� ${maxValue}`}
+ max={maxValue}
+ min={1}
+ {...props}
+ />
+ </FormField>
+}
+
+export const OverlapInput: FC<InputNumberProps> = (props) => {
+ const { t } = useTranslation()
+ return <FormField label={<div className='mb-1 flex items-center'>
+ <span className='system-sm-semibold'>{t('datasetCreation.stepTwo.overlap')}</span>
+ <Tooltip
+ popupContent={
+ <div className='max-w-[200px]'>
+ {t('datasetCreation.stepTwo.overlapTip')}
+ </div>
+ }
+ />
+ </div>}>
+ <InputNumber
+ type="number"
+ size='large'
+ placeholder={t('datasetCreation.stepTwo.overlap') || ''}
+ min={1}
+ {...props}
+ />
+ </FormField>
+}
diff --git a/app/components/datasets/create/step-two/language-select/index.tsx b/app/components/datasets/create/step-two/language-select/index.tsx
new file mode 100644
index 0000000..0e6bae9
--- /dev/null
+++ b/app/components/datasets/create/step-two/language-select/index.tsx
@@ -0,0 +1,62 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { RiArrowDownSLine, RiCheckLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import Popover from '@/app/components/base/popover'
+import { languages } from '@/i18n/language'
+
+export type ILanguageSelectProps = {
+ currentLanguage: string
+ onSelect: (language: string) => void
+ disabled?: boolean
+}
+
+const LanguageSelect: FC<ILanguageSelectProps> = ({
+ currentLanguage,
+ onSelect,
+ disabled,
+}) => {
+ return (
+ <Popover
+ manualClose
+ trigger='click'
+ disabled={disabled}
+ popupClassName='z-20'
+ htmlContent={
+ <div className='w-full p-1'>
+ {languages.filter(language => language.supported).map(({ prompt_name }) => (
+ <div
+ key={prompt_name}
+ className='inline-flex w-full cursor-pointer items-center justify-between rounded-lg px-3 py-2 hover:bg-state-base-hover'
+ onClick={() => onSelect(prompt_name)}
+ >
+ <span className='system-sm-medium text-text-secondary'>{prompt_name}</span>
+ {(currentLanguage === prompt_name) && <RiCheckLine className='size-4 text-text-accent' />}
+ </div>
+ ))}
+ </div>
+ }
+ btnElement={
+ <div className={cn('inline-flex items-center gap-x-[1px]', disabled && 'cursor-not-allowed')}>
+ <span className={cn(
+ 'system-xs-semibold px-[3px] text-components-button-tertiary-text',
+ disabled ? 'text-components-button-tertiary-text-disabled' : '',
+ )}>
+ {currentLanguage}
+ </span>
+ <RiArrowDownSLine className={cn(
+ 'size-3.5 text-components-button-tertiary-text',
+ disabled ? 'text-components-button-tertiary-text-disabled' : '',
+ )} />
+ </div>
+ }
+ btnClassName={() => cn(
+ '!hover:bg-components-button-tertiary-bg !mx-1 rounded-md !border-0 !bg-components-button-tertiary-bg !px-1.5 !py-1',
+ disabled ? 'bg-components-button-tertiary-bg-disabled' : '',
+ )}
+ className='!left-1 !z-20 h-fit !w-[140px] !translate-x-0'
+ />
+ )
+}
+export default React.memo(LanguageSelect)
diff --git a/app/components/datasets/create/step-two/option-card.tsx b/app/components/datasets/create/step-two/option-card.tsx
new file mode 100644
index 0000000..6bfe538
--- /dev/null
+++ b/app/components/datasets/create/step-two/option-card.tsx
@@ -0,0 +1,106 @@
+import type { ComponentProps, FC, ReactNode } from 'react'
+import Image from 'next/image'
+import classNames from '@/utils/classnames'
+
+const TriangleArrow: FC<ComponentProps<'svg'>> = props => (
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="11" viewBox="0 0 24 11" fill="none" {...props}>
+ <path d="M9.87868 1.12132C11.0503 -0.0502525 12.9497 -0.0502525 14.1213 1.12132L23.3137 10.3137H0.686292L9.87868 1.12132Z" fill="currentColor" />
+ </svg>
+)
+
+type OptionCardHeaderProps = {
+ icon: ReactNode
+ title: ReactNode
+ description: string
+ isActive?: boolean
+ activeClassName?: string
+ effectImg?: string
+ disabled?: boolean
+}
+
+export const OptionCardHeader: FC<OptionCardHeaderProps> = (props) => {
+ const { icon, title, description, isActive, activeClassName, effectImg, disabled } = props
+ return <div className={classNames(
+ 'flex h-full overflow-hidden rounded-t-xl relative',
+ isActive && activeClassName,
+ !disabled && 'cursor-pointer',
+ )}>
+ <div className='relative flex size-14 items-center justify-center overflow-hidden'>
+ {isActive && effectImg && <Image src={effectImg} className='absolute left-0 top-0 h-full w-full' alt='' width={56} height={56} />}
+ <div className='p-1'>
+ <div className='flex size-8 justify-center rounded-lg border border-components-panel-border-subtle bg-background-default-dodge p-1.5 shadow-md'>
+ {icon}
+ </div>
+ </div>
+ </div>
+ <TriangleArrow
+ className={classNames('absolute left-4 -bottom-1.5 text-transparent', isActive && 'text-components-panel-bg')}
+ />
+ <div className='flex-1 space-y-0.5 py-3 pr-4'>
+ <div className='system-md-semibold text-text-secondary'>{title}</div>
+ <div className='system-xs-regular text-text-tertiary'>{description}</div>
+ </div>
+ </div>
+}
+
+type OptionCardProps = {
+ icon: ReactNode
+ className?: string
+ activeHeaderClassName?: string
+ title: ReactNode
+ description: string
+ isActive?: boolean
+ actions?: ReactNode
+ effectImg?: string
+ onSwitched?: () => void
+ noHighlight?: boolean
+ disabled?: boolean
+} & Omit<ComponentProps<'div'>, 'title' | 'onClick'>
+
+export const OptionCard: FC<OptionCardProps> = (
+ {
+ ref,
+ ...props
+ },
+) => {
+ const { icon, className, title, description, isActive, children, actions, activeHeaderClassName, style, effectImg, onSwitched, noHighlight, disabled, ...rest } = props
+ return <div
+ className={classNames(
+ 'rounded-xl bg-components-option-card-option-bg shadow-xs',
+ (isActive && !noHighlight)
+ ? 'border-[1.5px] border-components-option-card-option-selected-border'
+ : 'border border-components-option-card-option-border',
+ disabled && 'opacity-50 pointer-events-none',
+ className,
+ )}
+ style={{
+ ...style,
+ }}
+ onClick={() => {
+ if (!isActive && !disabled)
+ onSwitched?.()
+ }}
+ {...rest}
+ ref={ref}
+ >
+ <OptionCardHeader
+ icon={icon}
+ title={title}
+ description={description}
+ isActive={isActive && !noHighlight}
+ activeClassName={activeHeaderClassName}
+ effectImg={effectImg}
+ disabled={disabled}
+ />
+ {/** Body */}
+ {isActive && (children || actions) && <div className='rounded-b-xl bg-components-panel-bg px-4 py-3'>
+ {children}
+ {actions && <div className='mt-4 flex gap-2'>
+ {actions}
+ </div>
+ }
+ </div>}
+ </div>
+}
+
+OptionCard.displayName = 'OptionCard'
diff --git a/app/components/datasets/create/step-two/preview-item/index.tsx b/app/components/datasets/create/step-two/preview-item/index.tsx
new file mode 100644
index 0000000..7c6c920
--- /dev/null
+++ b/app/components/datasets/create/step-two/preview-item/index.tsx
@@ -0,0 +1,78 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+
+export type IPreviewItemProps = {
+ type: string
+ index: number
+ content?: string
+ qa?: {
+ answer: string
+ question: string
+ }
+}
+
+export enum PreviewType {
+ TEXT = 'text',
+ QA = 'QA',
+}
+
+const sharpIcon = (
+ <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M4.74999 1.5L3.24999 10.5M8.74998 1.5L7.24998 10.5M10.25 4H1.75M9.75 8H1.25" stroke="#98A2B3" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+)
+
+const textIcon = (
+ <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M4 3.5H8M6 3.5V8.5M3.9 10.5H8.1C8.94008 10.5 9.36012 10.5 9.68099 10.3365C9.96323 10.1927 10.1927 9.96323 10.3365 9.68099C10.5 9.36012 10.5 8.94008 10.5 8.1V3.9C10.5 3.05992 10.5 2.63988 10.3365 2.31901C10.1927 2.03677 9.96323 1.8073 9.68099 1.66349C9.36012 1.5 8.94008 1.5 8.1 1.5H3.9C3.05992 1.5 2.63988 1.5 2.31901 1.66349C2.03677 1.8073 1.8073 2.03677 1.66349 2.31901C1.5 2.63988 1.5 3.05992 1.5 3.9V8.1C1.5 8.94008 1.5 9.36012 1.66349 9.68099C1.8073 9.96323 2.03677 10.1927 2.31901 10.3365C2.63988 10.5 3.05992 10.5 3.9 10.5Z" stroke="#667085" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+
+)
+
+const PreviewItem: FC<IPreviewItemProps> = ({
+ type = PreviewType.TEXT,
+ index,
+ content,
+ qa,
+}) => {
+ const { t } = useTranslation()
+ const charNums = type === PreviewType.TEXT
+ ? (content || '').length
+ : (qa?.answer || '').length + (qa?.question || '').length
+ const formattedIndex = (() => String(index).padStart(3, '0'))()
+
+ return (
+ <div className='rounded-xl bg-gray-50 p-4'>
+ <div className='flex h-5 items-center justify-between text-xs text-gray-500'>
+ <div className='box-border flex h-[18px] items-center space-x-1 rounded-md border border-gray-200 pl-1 pr-1.5 font-medium italic'>
+ {sharpIcon}
+ <span>{formattedIndex}</span>
+ </div>
+ <div className='flex items-center space-x-1'>
+ {textIcon}
+ <span>{charNums} {t('datasetCreation.stepTwo.characters')}</span>
+ </div>
+ </div>
+ <div className='mt-2 line-clamp-6 max-h-[120px] overflow-hidden text-sm text-gray-800'>
+ {type === PreviewType.TEXT && (
+ <div style={{ whiteSpace: 'pre-line' }}>{content}</div>
+ )}
+ {type === PreviewType.QA && (
+ <div style={{ whiteSpace: 'pre-line' }}>
+ <div className='flex'>
+ <div className='text-medium mr-2 shrink-0 text-gray-400'>Q</div>
+ <div style={{ whiteSpace: 'pre-line' }}>{qa?.question}</div>
+ </div>
+ <div className='flex'>
+ <div className='text-medium mr-2 shrink-0 text-gray-400'>A</div>
+ <div style={{ whiteSpace: 'pre-line' }}>{qa?.answer}</div>
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+export default React.memo(PreviewItem)
diff --git a/app/components/datasets/create/step-two/unescape.ts b/app/components/datasets/create/step-two/unescape.ts
new file mode 100644
index 0000000..fae3e96
--- /dev/null
+++ b/app/components/datasets/create/step-two/unescape.ts
@@ -0,0 +1,54 @@
+// https://github.com/iamakulov/unescape-js/blob/master/src/index.js
+
+/**
+ * \\ - matches the backslash which indicates the beginning of an escape sequence
+ * (
+ * u\{([0-9A-Fa-f]+)\} - first alternative; matches the variable-length hexadecimal escape sequence (\u{ABCD0})
+ * |
+ * u([0-9A-Fa-f]{4}) - second alternative; matches the 4-digit hexadecimal escape sequence (\uABCD)
+ * |
+ * x([0-9A-Fa-f]{2}) - third alternative; matches the 2-digit hexadecimal escape sequence (\xA5)
+ * |
+ * ([1-7][0-7]{0,2}|[0-7]{2,3}) - fourth alternative; matches the up-to-3-digit octal escape sequence (\5 or \512)
+ * |
+ * (['"tbrnfv0\\]) - fifth alternative; matches the special escape characters (\t, \n and so on)
+ * |
+ * \U([0-9A-Fa-f]+) - sixth alternative; matches the 8-digit hexadecimal escape sequence used by python (\U0001F3B5)
+ * )
+ */
+const jsEscapeRegex = /\\(u\{([0-9A-Fa-f]+)\}|u([0-9A-Fa-f]{4})|x([0-9A-Fa-f]{2})|([1-7][0-7]{0,2}|[0-7]{2,3})|(['"tbrnfv0\\]))|\\U([0-9A-Fa-f]{8})/g
+
+const usualEscapeSequences: Record<string, string> = {
+ '0': '\0',
+ 'b': '\b',
+ 'f': '\f',
+ 'n': '\n',
+ 'r': '\r',
+ 't': '\t',
+ 'v': '\v',
+ '\'': '\'',
+ '"': '"',
+ '\\': '\\',
+}
+
+const fromHex = (str: string) => String.fromCodePoint(Number.parseInt(str, 16))
+const fromOct = (str: string) => String.fromCodePoint(Number.parseInt(str, 8))
+
+const unescape = (str: string) => {
+ return str.replace(jsEscapeRegex, (_, __, varHex, longHex, shortHex, octal, specialCharacter, python) => {
+ if (varHex !== undefined)
+ return fromHex(varHex)
+ else if (longHex !== undefined)
+ return fromHex(longHex)
+ else if (shortHex !== undefined)
+ return fromHex(shortHex)
+ else if (octal !== undefined)
+ return fromOct(octal)
+ else if (python !== undefined)
+ return fromHex(python)
+ else
+ return usualEscapeSequences[specialCharacter]
+ })
+}
+
+export default unescape
diff --git a/app/components/datasets/create/stepper/index.tsx b/app/components/datasets/create/stepper/index.tsx
new file mode 100644
index 0000000..8882ec6
--- /dev/null
+++ b/app/components/datasets/create/stepper/index.tsx
@@ -0,0 +1,27 @@
+import { type FC, Fragment } from 'react'
+import type { Step } from './step'
+import { StepperStep } from './step'
+
+export type StepperProps = {
+ steps: Step[]
+ activeIndex: number
+}
+
+export const Stepper: FC<StepperProps> = (props) => {
+ const { steps, activeIndex } = props
+ return <div className='flex items-center gap-3'>
+ {steps.map((step, index) => {
+ const isLast = index === steps.length - 1
+ return (
+ <Fragment key={index}>
+ <StepperStep
+ {...step}
+ activeIndex={activeIndex}
+ index={index}
+ />
+ {!isLast && <div className='h-px w-4 bg-divider-deep' />}
+ </Fragment>
+ )
+ })}
+ </div>
+}
diff --git a/app/components/datasets/create/stepper/step.tsx b/app/components/datasets/create/stepper/step.tsx
new file mode 100644
index 0000000..91e9c71
--- /dev/null
+++ b/app/components/datasets/create/stepper/step.tsx
@@ -0,0 +1,46 @@
+import type { FC } from 'react'
+import classNames from '@/utils/classnames'
+
+export type Step = {
+ name: string
+}
+
+export type StepperStepProps = Step & {
+ index: number
+ activeIndex: number
+}
+
+export const StepperStep: FC<StepperStepProps> = (props) => {
+ const { name, activeIndex, index } = props
+ const isActive = index === activeIndex
+ const isDisabled = activeIndex < index
+ const label = isActive ? `STEP ${index + 1}` : `${index + 1}`
+ return <div className='flex items-center gap-2'>
+ <div className={classNames(
+ 'h-5 py-1 rounded-3xl flex-col justify-center items-center gap-2 inline-flex',
+ isActive
+ ? 'px-2 bg-state-accent-solid'
+ : !isDisabled
+ ? 'w-5 border border-text-quaternary'
+ : 'w-5 border border-divider-deep',
+ )}>
+ <div className={classNames(
+ 'text-center system-2xs-semibold-uppercase',
+ isActive
+ ? 'text-text-primary-on-surface'
+ : !isDisabled
+ ? 'text-text-tertiary'
+ : 'text-text-quaternary',
+ )}>
+ {label}
+ </div>
+ </div>
+ <div className={classNames('system-xs-medium-uppercase',
+ isActive
+ ? 'text-text-accent system-xs-semibold-uppercase'
+ : !isDisabled
+ ? 'text-text-tertiary'
+ : 'text-text-quaternary',
+ )}>{name}</div>
+ </div>
+}
diff --git a/app/components/datasets/create/stop-embedding-modal/index.module.css b/app/components/datasets/create/stop-embedding-modal/index.module.css
new file mode 100644
index 0000000..95f999d
--- /dev/null
+++ b/app/components/datasets/create/stop-embedding-modal/index.module.css
@@ -0,0 +1,37 @@
+.modal {
+ position: relative;
+}
+.modal .icon {
+ width: 48px;
+ height: 48px;
+ background: rgba(255, 255, 255, 0.9) center no-repeat url(../assets/annotation-info.svg);
+ background-size: 24px;
+ border: 0.5px solid #F2F4F7;
+ box-shadow: 0px 20px 24px -4px rgba(16, 24, 40, 0.08), 0px 8px 8px -4px rgba(16, 24, 40, 0.03);
+ border-radius: 12px;
+}
+.modal .close {
+ position: absolute;
+ right: 16px;
+ top: 16px;
+ width: 32px;
+ height: 32px;
+ border-radius: 8px;
+ background: center no-repeat url(../assets/close.svg);
+ background-size: 16px;
+ cursor: pointer;
+}
+.modal .title {
+ @apply mt-3 mb-1;
+ font-weight: 600;
+ font-size: 20px;
+ line-height: 30px;
+ color: #101828;
+}
+.modal .content {
+ @apply mb-10;
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 20px;
+ color: #667085;
+}
diff --git a/app/components/datasets/create/stop-embedding-modal/index.tsx b/app/components/datasets/create/stop-embedding-modal/index.tsx
new file mode 100644
index 0000000..9d29187
--- /dev/null
+++ b/app/components/datasets/create/stop-embedding-modal/index.tsx
@@ -0,0 +1,45 @@
+'use client'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import s from './index.module.css'
+import cn from '@/utils/classnames'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+
+type IProps = {
+ show: boolean
+ onConfirm: () => void
+ onHide: () => void
+}
+
+const StopEmbeddingModal = ({
+ show = false,
+ onConfirm,
+ onHide,
+}: IProps) => {
+ const { t } = useTranslation()
+
+ const submit = () => {
+ onConfirm()
+ onHide()
+ }
+
+ return (
+ <Modal
+ isShow={show}
+ onClose={onHide}
+ className={cn(s.modal, '!max-w-[480px]', 'px-8')}
+ >
+ <div className={s.icon} />
+ <span className={s.close} onClick={onHide} />
+ <div className={s.title}>{t('datasetCreation.stepThree.modelTitle')}</div>
+ <div className={s.content}>{t('datasetCreation.stepThree.modelContent')}</div>
+ <div className='flex flex-row-reverse'>
+ <Button className='ml-2 w-24' variant='primary' onClick={submit}>{t('datasetCreation.stepThree.modelButtonConfirm')}</Button>
+ <Button className='w-24' onClick={onHide}>{t('datasetCreation.stepThree.modelButtonCancel')}</Button>
+ </div>
+ </Modal>
+ )
+}
+
+export default StopEmbeddingModal
diff --git a/app/components/datasets/create/top-bar/index.tsx b/app/components/datasets/create/top-bar/index.tsx
new file mode 100644
index 0000000..c5d8921
--- /dev/null
+++ b/app/components/datasets/create/top-bar/index.tsx
@@ -0,0 +1,47 @@
+import { type FC, useMemo } from 'react'
+import { RiArrowLeftLine } from '@remixicon/react'
+import Link from 'next/link'
+import { useTranslation } from 'react-i18next'
+import { Stepper, type StepperProps } from '../stepper'
+import classNames from '@/utils/classnames'
+
+export type TopBarProps = Pick<StepperProps, 'activeIndex'> & {
+ className?: string
+ datasetId?: string
+}
+
+const STEP_T_MAP: Record<number, string> = {
+ 1: 'datasetCreation.steps.one',
+ 2: 'datasetCreation.steps.two',
+ 3: 'datasetCreation.steps.three',
+}
+
+export const TopBar: FC<TopBarProps> = (props) => {
+ const { className, datasetId, ...rest } = props
+ const { t } = useTranslation()
+
+ const fallbackRoute = useMemo(() => {
+ return datasetId ? `/datasets/${datasetId}/documents` : '/datasets'
+ }, [datasetId])
+
+ return <div className={classNames('flex shrink-0 h-[52px] items-center justify-between relative border-b border-b-divider-subtle', className)}>
+ <Link href={fallbackRoute} replace className="inline-flex h-12 items-center justify-start gap-1 py-2 pl-2 pr-6">
+ <div className='p-2'>
+ <RiArrowLeftLine className='size-4 text-text-primary' />
+ </div>
+ <p className="system-sm-semibold-uppercase text-text-primary">
+ {t('datasetCreation.steps.header.fallbackRoute')}
+ </p>
+ </Link>
+ <div className={
+ 'absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2'
+ }>
+ <Stepper
+ steps={Array.from({ length: 3 }, (_, i) => ({
+ name: t(STEP_T_MAP[i + 1]),
+ }))}
+ {...rest}
+ />
+ </div>
+ </div>
+}
diff --git a/app/components/datasets/create/website/base/checkbox-with-label.tsx b/app/components/datasets/create/website/base/checkbox-with-label.tsx
new file mode 100644
index 0000000..f5451af
--- /dev/null
+++ b/app/components/datasets/create/website/base/checkbox-with-label.tsx
@@ -0,0 +1,40 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import Checkbox from '@/app/components/base/checkbox'
+import Tooltip from '@/app/components/base/tooltip'
+
+type Props = {
+ className?: string
+ isChecked: boolean
+ onChange: (isChecked: boolean) => void
+ label: string
+ labelClassName?: string
+ tooltip?: string
+}
+
+const CheckboxWithLabel: FC<Props> = ({
+ className = '',
+ isChecked,
+ onChange,
+ label,
+ labelClassName,
+ tooltip,
+}) => {
+ return (
+ <label className={cn(className, 'flex h-7 items-center space-x-2')}>
+ <Checkbox checked={isChecked} onCheck={() => onChange(!isChecked)} />
+ <div className={cn('text-sm font-normal text-text-secondary', labelClassName)}>{label}</div>
+ {tooltip && (
+ <Tooltip
+ popupContent={
+ <div className='w-[200px]'>{tooltip}</div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4'
+ />
+ )}
+ </label>
+ )
+}
+export default React.memo(CheckboxWithLabel)
diff --git a/app/components/datasets/create/website/base/crawled-result-item.tsx b/app/components/datasets/create/website/base/crawled-result-item.tsx
new file mode 100644
index 0000000..8ea316f
--- /dev/null
+++ b/app/components/datasets/create/website/base/crawled-result-item.tsx
@@ -0,0 +1,60 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+import type { CrawlResultItem as CrawlResultItemType } from '@/models/datasets'
+import Checkbox from '@/app/components/base/checkbox'
+import Button from '@/app/components/base/button'
+
+type Props = {
+ payload: CrawlResultItemType
+ isChecked: boolean
+ isPreview: boolean
+ onCheckChange: (checked: boolean) => void
+ onPreview: () => void
+}
+
+const CrawledResultItem: FC<Props> = ({
+ isPreview,
+ payload,
+ isChecked,
+ onCheckChange,
+ onPreview,
+}) => {
+ const { t } = useTranslation()
+
+ const handleCheckChange = useCallback(() => {
+ onCheckChange(!isChecked)
+ }, [isChecked, onCheckChange])
+ return (
+ <div className={cn(isPreview ? 'bg-state-base-active' : 'group hover:bg-state-base-hover', 'cursor-pointer rounded-lg p-2')}>
+ <div className='relative flex'>
+ <div className='flex h-5 items-center'>
+ <Checkbox className='mr-2 shrink-0' checked={isChecked} onCheck={handleCheckChange} />
+ </div>
+ <div className='flex min-w-0 grow flex-col'>
+ <div
+ className='truncate text-sm font-medium text-text-secondary'
+ title={payload.title}
+ >
+ {payload.title}
+ </div>
+ <div
+ className='mt-0.5 truncate text-xs text-text-tertiary'
+ title={payload.source_url}
+ >
+ {payload.source_url}
+ </div>
+ </div>
+ <Button
+ onClick={onPreview}
+ className='right-0 top-0 hidden h-6 px-1.5 text-xs font-medium uppercase group-hover:absolute group-hover:block'
+ >
+ {t('datasetCreation.stepOne.website.preview')}
+ </Button>
+ </div>
+ </div>
+ )
+}
+export default React.memo(CrawledResultItem)
diff --git a/app/components/datasets/create/website/base/crawled-result.tsx b/app/components/datasets/create/website/base/crawled-result.tsx
new file mode 100644
index 0000000..c168405
--- /dev/null
+++ b/app/components/datasets/create/website/base/crawled-result.tsx
@@ -0,0 +1,89 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import CheckboxWithLabel from './checkbox-with-label'
+import CrawledResultItem from './crawled-result-item'
+import cn from '@/utils/classnames'
+import type { CrawlResultItem } from '@/models/datasets'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ className?: string
+ list: CrawlResultItem[]
+ checkedList: CrawlResultItem[]
+ onSelectedChange: (selected: CrawlResultItem[]) => void
+ onPreview: (payload: CrawlResultItem) => void
+ usedTime: number
+}
+
+const CrawledResult: FC<Props> = ({
+ className = '',
+ list,
+ checkedList,
+ onSelectedChange,
+ onPreview,
+ usedTime,
+}) => {
+ const { t } = useTranslation()
+
+ const isCheckAll = checkedList.length === list.length
+
+ const handleCheckedAll = useCallback(() => {
+ if (!isCheckAll)
+ onSelectedChange(list)
+
+ else
+ onSelectedChange([])
+ }, [isCheckAll, list, onSelectedChange])
+
+ const handleItemCheckChange = useCallback((item: CrawlResultItem) => {
+ return (checked: boolean) => {
+ if (checked)
+ onSelectedChange([...checkedList, item])
+
+ else
+ onSelectedChange(checkedList.filter(checkedItem => checkedItem.source_url !== item.source_url))
+ }
+ }, [checkedList, onSelectedChange])
+
+ const [previewIndex, setPreviewIndex] = React.useState<number>(-1)
+ const handlePreview = useCallback((index: number) => {
+ return () => {
+ setPreviewIndex(index)
+ onPreview(list[index])
+ }
+ }, [list, onPreview])
+
+ return (
+ <div className={cn(className, 'border-t-[0.5px] border-divider-regular shadow-xs shadow-shadow-shadow-3')}>
+ <div className='flex h-[34px] items-center justify-between px-4'>
+ <CheckboxWithLabel
+ isChecked={isCheckAll}
+ onChange={handleCheckedAll} label={isCheckAll ? t(`${I18N_PREFIX}.resetAll`) : t(`${I18N_PREFIX}.selectAll`)}
+ labelClassName='system-[13px] leading-[16px] font-medium text-text-secondary'
+ />
+ <div className='text-xs text-text-tertiary'>
+ {t(`${I18N_PREFIX}.scrapTimeInfo`, {
+ total: list.length,
+ time: usedTime.toFixed(1),
+ })}
+ </div>
+ </div>
+ <div className='p-2'>
+ {list.map((item, index) => (
+ <CrawledResultItem
+ key={item.source_url}
+ isPreview={index === previewIndex}
+ onPreview={handlePreview(index)}
+ payload={item}
+ isChecked={checkedList.some(checkedItem => checkedItem.source_url === item.source_url)}
+ onCheckChange={handleItemCheckChange(item)}
+ />
+ ))}
+ </div>
+ </div>
+ )
+}
+export default React.memo(CrawledResult)
diff --git a/app/components/datasets/create/website/base/crawling.tsx b/app/components/datasets/create/website/base/crawling.tsx
new file mode 100644
index 0000000..915f17d
--- /dev/null
+++ b/app/components/datasets/create/website/base/crawling.tsx
@@ -0,0 +1,37 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RowStruct } from '@/app/components/base/icons/src/public/other'
+
+type Props = {
+ className?: string
+ crawledNum: number
+ totalNum: number
+}
+
+const Crawling: FC<Props> = ({
+ className = '',
+ crawledNum,
+ totalNum,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={className}>
+ <div className='flex h-[34px] items-center border-y-[0.5px] border-divider-regular px-4
+ text-xs text-text-tertiary shadow-xs shadow-shadow-shadow-3'>
+ {t('datasetCreation.stepOne.website.totalPageScraped')} {crawledNum}/{totalNum}
+ </div>
+
+ <div className='p-2'>
+ {['', '', '', ''].map((item, index) => (
+ <div className='py-[5px]' key={index}>
+ <RowStruct className='text-text-quaternary' />
+ </div>
+ ))}
+ </div>
+ </div>
+ )
+}
+export default React.memo(Crawling)
diff --git a/app/components/datasets/create/website/base/error-message.tsx b/app/components/datasets/create/website/base/error-message.tsx
new file mode 100644
index 0000000..2788eb9
--- /dev/null
+++ b/app/components/datasets/create/website/base/error-message.tsx
@@ -0,0 +1,30 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
+
+type Props = {
+ className?: string
+ title: string
+ errorMsg?: string
+}
+
+const ErrorMessage: FC<Props> = ({
+ className,
+ title,
+ errorMsg,
+}) => {
+ return (
+ <div className={cn(className, 'border-t border-divider-subtle bg-dataset-warning-message-bg px-4 py-2 opacity-40')}>
+ <div className='flex h-5 items-center'>
+ <AlertTriangle className='mr-2 h-4 w-4 text-text-warning-secondary' />
+ <div className='system-md-medium text-text-warning'>{title}</div>
+ </div>
+ {errorMsg && (
+ <div className='system-xs-regular mt-1 pl-6 text-text-secondary'>{errorMsg}</div>
+ )}
+ </div>
+ )
+}
+export default React.memo(ErrorMessage)
diff --git a/app/components/datasets/create/website/base/field.tsx b/app/components/datasets/create/website/base/field.tsx
new file mode 100644
index 0000000..43d7646
--- /dev/null
+++ b/app/components/datasets/create/website/base/field.tsx
@@ -0,0 +1,54 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import Input from './input'
+import cn from '@/utils/classnames'
+import Tooltip from '@/app/components/base/tooltip'
+
+type Props = {
+ className?: string
+ label: string
+ labelClassName?: string
+ value: string | number
+ onChange: (value: string | number) => void
+ isRequired?: boolean
+ placeholder?: string
+ isNumber?: boolean
+ tooltip?: string
+}
+
+const Field: FC<Props> = ({
+ className,
+ label,
+ labelClassName,
+ value,
+ onChange,
+ isRequired = false,
+ placeholder = '',
+ isNumber = false,
+ tooltip,
+}) => {
+ return (
+ <div className={cn(className)}>
+ <div className='flex py-[7px]'>
+ <div className={cn(labelClassName, 'flex h-[16px] items-center text-[13px] font-semibold text-text-secondary')}>{label} </div>
+ {isRequired && <span className='ml-0.5 text-xs font-semibold text-text-destructive'>*</span>}
+ {tooltip && (
+ <Tooltip
+ popupContent={
+ <div className='w-[200px]'>{tooltip}</div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4'
+ />
+ )}
+ </div>
+ <Input
+ value={value}
+ onChange={onChange}
+ placeholder={placeholder}
+ isNumber={isNumber}
+ />
+ </div>
+ )
+}
+export default React.memo(Field)
diff --git a/app/components/datasets/create/website/base/input.tsx b/app/components/datasets/create/website/base/input.tsx
new file mode 100644
index 0000000..ae47111
--- /dev/null
+++ b/app/components/datasets/create/website/base/input.tsx
@@ -0,0 +1,63 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+
+type Props = {
+ value: string | number
+ onChange: (value: string | number) => void
+ placeholder?: string
+ isNumber?: boolean
+}
+
+const MIN_VALUE = 0
+
+const Input: FC<Props> = ({
+ value,
+ onChange,
+ placeholder = '',
+ isNumber = false,
+}) => {
+ const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
+ const value = e.target.value
+ if (isNumber) {
+ let numberValue = Number.parseInt(value, 10) // integer only
+ if (isNaN(numberValue)) {
+ onChange('')
+ return
+ }
+ if (numberValue < MIN_VALUE)
+ numberValue = MIN_VALUE
+
+ onChange(numberValue)
+ return
+ }
+ onChange(value)
+ }, [isNumber, onChange])
+
+ const otherOption = (() => {
+ if (isNumber) {
+ return {
+ min: MIN_VALUE,
+ }
+ }
+ return {
+
+ }
+ })()
+ return (
+ <input
+ type={isNumber ? 'number' : 'text'}
+ {...otherOption}
+ value={value}
+ onChange={handleChange}
+ className='system-xs-regular focus:bg-components-inout-border-active flex h-8 w-full rounded-lg border border-transparent
+ bg-components-input-bg-normal p-2 text-components-input-text-filled
+ caret-[#295eff] placeholder:text-components-input-text-placeholder hover:border
+ hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border focus:border-components-input-border-active
+ focus:shadow-xs focus:shadow-shadow-shadow-3
+ focus-visible:outline-none'
+ placeholder={placeholder}
+ />
+ )
+}
+export default React.memo(Input)
diff --git a/app/components/datasets/create/website/base/mock-crawl-result.ts b/app/components/datasets/create/website/base/mock-crawl-result.ts
new file mode 100644
index 0000000..8fd5e66
--- /dev/null
+++ b/app/components/datasets/create/website/base/mock-crawl-result.ts
@@ -0,0 +1,24 @@
+import type { CrawlResultItem } from '@/models/datasets'
+
+const result: CrawlResultItem[] = [
+ {
+ title: 'Start the frontend Docker container separately',
+ markdown: 'Markdown 1',
+ description: 'Description 1',
+ source_url: 'https://example.com/1',
+ },
+ {
+ title: 'Advanced Tool Integration',
+ markdown: 'Markdown 2',
+ description: 'Description 2',
+ source_url: 'https://example.com/2',
+ },
+ {
+ title: 'Local Source Code Start | English | Dify',
+ markdown: 'Markdown 3',
+ description: 'Description 3',
+ source_url: 'https://example.com/3',
+ },
+]
+
+export default result
diff --git a/app/components/datasets/create/website/base/options-wrap.tsx b/app/components/datasets/create/website/base/options-wrap.tsx
new file mode 100644
index 0000000..8e9181b
--- /dev/null
+++ b/app/components/datasets/create/website/base/options-wrap.tsx
@@ -0,0 +1,55 @@
+'use client'
+import { useBoolean } from 'ahooks'
+import type { FC } from 'react'
+import React, { useEffect } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiEqualizer2Line } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows'
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ className?: string
+ children: React.ReactNode
+ controlFoldOptions?: number
+}
+
+const OptionsWrap: FC<Props> = ({
+ className = '',
+ children,
+ controlFoldOptions,
+}) => {
+ const { t } = useTranslation()
+
+ const [fold, {
+ toggle: foldToggle,
+ setTrue: foldHide,
+ }] = useBoolean(false)
+
+ useEffect(() => {
+ if (controlFoldOptions)
+ foldHide()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [controlFoldOptions])
+ return (
+ <div className={cn(className, !fold ? 'mb-0' : 'mb-3')}>
+ <div
+ className='flex h-[26px] cursor-pointer select-none items-center gap-x-1 py-1'
+ onClick={foldToggle}
+ >
+ <div className='flex grow items-center'>
+ <RiEqualizer2Line className='mr-1 h-4 w-4 text-text-secondary' />
+ <span className='text-[13px] font-semibold uppercase leading-[16px] text-text-secondary'>{t(`${I18N_PREFIX}.options`)}</span>
+ </div>
+ <ChevronRight className={cn(!fold && 'rotate-90', 'h-4 w-4 shrink-0 text-text-tertiary')} />
+ </div>
+ {!fold && (
+ <div className='mb-4'>
+ {children}
+ </div>
+ )}
+
+ </div>
+ )
+}
+export default React.memo(OptionsWrap)
diff --git a/app/components/datasets/create/website/base/url-input.tsx b/app/components/datasets/create/website/base/url-input.tsx
new file mode 100644
index 0000000..b7dc9bf
--- /dev/null
+++ b/app/components/datasets/create/website/base/url-input.tsx
@@ -0,0 +1,48 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import Input from './input'
+import Button from '@/app/components/base/button'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ isRunning: boolean
+ onRun: (url: string) => void
+}
+
+const UrlInput: FC<Props> = ({
+ isRunning,
+ onRun,
+}) => {
+ const { t } = useTranslation()
+ const [url, setUrl] = useState('')
+ const handleUrlChange = useCallback((url: string | number) => {
+ setUrl(url as string)
+ }, [])
+ const handleOnRun = useCallback(() => {
+ if (isRunning)
+ return
+ onRun(url)
+ }, [isRunning, onRun, url])
+
+ return (
+ <div className='flex items-center justify-between gap-x-2'>
+ <Input
+ value={url}
+ onChange={handleUrlChange}
+ placeholder='https://docs.dify.ai'
+ />
+ <Button
+ variant='primary'
+ onClick={handleOnRun}
+ loading={isRunning}
+ spinnerClassName='!ml-0'
+ >
+ {!isRunning ? t(`${I18N_PREFIX}.run`) : ''}
+ </Button>
+ </div>
+ )
+}
+export default React.memo(UrlInput)
diff --git a/app/components/datasets/create/website/firecrawl/header.tsx b/app/components/datasets/create/website/firecrawl/header.tsx
new file mode 100644
index 0000000..d23c57f
--- /dev/null
+++ b/app/components/datasets/create/website/firecrawl/header.tsx
@@ -0,0 +1,43 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiBookOpenLine, RiEqualizer2Line } from '@remixicon/react'
+import Button from '@/app/components/base/button'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ onSetting: () => void
+}
+
+const Header: FC<Props> = ({
+ onSetting,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex h-6 items-center justify-between'>
+ <div className='flex items-center'>
+ <div className='text-base font-medium text-text-secondary'>{t(`${I18N_PREFIX}.firecrawlTitle`)}</div>
+ <div className='ml-2 mr-2 h-3.5 w-px bg-divider-regular' />
+ <Button className='flex h-6 items-center gap-x-[1px] px-1.5' onClick={onSetting}>
+ <RiEqualizer2Line className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <span className='px-[3px] text-xs font-medium text-components-button-secondary-text'>
+ {t(`${I18N_PREFIX}.configureFirecrawl`)}
+ </span>
+ </Button>
+ </div>
+ <a
+ href='https://docs.firecrawl.dev/introduction'
+ target='_blank'
+ rel='noopener noreferrer'
+ className='inline-flex items-center gap-x-1 text-xs font-medium text-text-accent'
+ >
+ <RiBookOpenLine className='h-3.5 w-3.5 text-text-accent' />
+ <span>{t(`${I18N_PREFIX}.firecrawlDoc`)}</span>
+ </a>
+ </div>
+ )
+}
+export default React.memo(Header)
diff --git a/app/components/datasets/create/website/firecrawl/index.tsx b/app/components/datasets/create/website/firecrawl/index.tsx
new file mode 100644
index 0000000..77f9666
--- /dev/null
+++ b/app/components/datasets/create/website/firecrawl/index.tsx
@@ -0,0 +1,217 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import UrlInput from '../base/url-input'
+import OptionsWrap from '../base/options-wrap'
+import CrawledResult from '../base/crawled-result'
+import Crawling from '../base/crawling'
+import ErrorMessage from '../base/error-message'
+import Header from './header'
+import Options from './options'
+import { useModalContext } from '@/context/modal-context'
+import type { CrawlOptions, CrawlResultItem } from '@/models/datasets'
+import Toast from '@/app/components/base/toast'
+import { checkFirecrawlTaskStatus, createFirecrawlTask } from '@/service/datasets'
+import { sleep } from '@/utils'
+
+const ERROR_I18N_PREFIX = 'common.errorMsg'
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ onPreview: (payload: CrawlResultItem) => void
+ checkedCrawlResult: CrawlResultItem[]
+ onCheckedCrawlResultChange: (payload: CrawlResultItem[]) => void
+ onJobIdChange: (jobId: string) => void
+ crawlOptions: CrawlOptions
+ onCrawlOptionsChange: (payload: CrawlOptions) => void
+}
+
+enum Step {
+ init = 'init',
+ running = 'running',
+ finished = 'finished',
+}
+
+const FireCrawl: FC<Props> = ({
+ onPreview,
+ checkedCrawlResult,
+ onCheckedCrawlResultChange,
+ onJobIdChange,
+ crawlOptions,
+ onCrawlOptionsChange,
+}) => {
+ const { t } = useTranslation()
+ const [step, setStep] = useState<Step>(Step.init)
+ const [controlFoldOptions, setControlFoldOptions] = useState<number>(0)
+ useEffect(() => {
+ if (step !== Step.init)
+ setControlFoldOptions(Date.now())
+ }, [step])
+ const { setShowAccountSettingModal } = useModalContext()
+ const handleSetting = useCallback(() => {
+ setShowAccountSettingModal({
+ payload: 'data-source',
+ })
+ }, [setShowAccountSettingModal])
+
+ const checkValid = useCallback((url: string) => {
+ let errorMsg = ''
+ if (!url) {
+ errorMsg = t(`${ERROR_I18N_PREFIX}.fieldRequired`, {
+ field: 'url',
+ })
+ }
+
+ if (!errorMsg && !((url.startsWith('http://') || url.startsWith('https://'))))
+ errorMsg = t(`${ERROR_I18N_PREFIX}.urlError`)
+
+ if (!errorMsg && (crawlOptions.limit === null || crawlOptions.limit === undefined || crawlOptions.limit === '')) {
+ errorMsg = t(`${ERROR_I18N_PREFIX}.fieldRequired`, {
+ field: t(`${I18N_PREFIX}.limit`),
+ })
+ }
+
+ return {
+ isValid: !errorMsg,
+ errorMsg,
+ }
+ }, [crawlOptions, t])
+
+ const isInit = step === Step.init
+ const isCrawlFinished = step === Step.finished
+ const isRunning = step === Step.running
+ const [crawlResult, setCrawlResult] = useState<{
+ current: number
+ total: number
+ data: CrawlResultItem[]
+ time_consuming: number | string
+ } | undefined>(undefined)
+ const [crawlErrorMessage, setCrawlErrorMessage] = useState('')
+ const showError = isCrawlFinished && crawlErrorMessage
+
+ const waitForCrawlFinished = useCallback(async (jobId: string) => {
+ try {
+ const res = await checkFirecrawlTaskStatus(jobId) as any
+ if (res.status === 'completed') {
+ return {
+ isError: false,
+ data: {
+ ...res,
+ total: Math.min(res.total, Number.parseFloat(crawlOptions.limit as string)),
+ },
+ }
+ }
+ if (res.status === 'error' || !res.status) {
+ // can't get the error message from the firecrawl api
+ return {
+ isError: true,
+ errorMessage: res.message,
+ data: {
+ data: [],
+ },
+ }
+ }
+ // update the progress
+ setCrawlResult({
+ ...res,
+ total: Math.min(res.total, Number.parseFloat(crawlOptions.limit as string)),
+ })
+ onCheckedCrawlResultChange(res.data || []) // default select the crawl result
+ await sleep(2500)
+ return await waitForCrawlFinished(jobId)
+ }
+ catch (e: any) {
+ const errorBody = await e.json()
+ return {
+ isError: true,
+ errorMessage: errorBody.message,
+ data: {
+ data: [],
+ },
+ }
+ }
+ }, [crawlOptions.limit])
+
+ const handleRun = useCallback(async (url: string) => {
+ const { isValid, errorMsg } = checkValid(url)
+ if (!isValid) {
+ Toast.notify({
+ message: errorMsg!,
+ type: 'error',
+ })
+ return
+ }
+ setStep(Step.running)
+ try {
+ const passToServerCrawlOptions: any = {
+ ...crawlOptions,
+ }
+ if (crawlOptions.max_depth === '')
+ delete passToServerCrawlOptions.max_depth
+
+ const res = await createFirecrawlTask({
+ url,
+ options: passToServerCrawlOptions,
+ }) as any
+ const jobId = res.job_id
+ onJobIdChange(jobId)
+ const { isError, data, errorMessage } = await waitForCrawlFinished(jobId)
+ if (isError) {
+ setCrawlErrorMessage(errorMessage || t(`${I18N_PREFIX}.unknownError`))
+ }
+ else {
+ setCrawlResult(data)
+ onCheckedCrawlResultChange(data.data || []) // default select the crawl result
+ setCrawlErrorMessage('')
+ }
+ }
+ catch (e) {
+ setCrawlErrorMessage(t(`${I18N_PREFIX}.unknownError`)!)
+ console.log(e)
+ }
+ finally {
+ setStep(Step.finished)
+ }
+ }, [checkValid, crawlOptions, onJobIdChange, t, waitForCrawlFinished])
+
+ return (
+ <div>
+ <Header onSetting={handleSetting} />
+ <div className='mt-2 rounded-xl border border-components-panel-border bg-background-default-subtle p-4 pb-0'>
+ <UrlInput onRun={handleRun} isRunning={isRunning} />
+ <OptionsWrap
+ className='mt-4'
+ controlFoldOptions={controlFoldOptions}
+ >
+ <Options className='mt-2' payload={crawlOptions} onChange={onCrawlOptionsChange} />
+ </OptionsWrap>
+
+ {!isInit && (
+ <div className='relative left-[-16px] mt-3 w-[calc(100%_+_32px)] rounded-b-xl'>
+ {isRunning
+ && <Crawling
+ className='mt-2'
+ crawledNum={crawlResult?.current || 0}
+ totalNum={crawlResult?.total || Number.parseFloat(crawlOptions.limit as string) || 0}
+ />}
+ {showError && (
+ <ErrorMessage className='rounded-b-xl' title={t(`${I18N_PREFIX}.exceptionErrorTitle`)} errorMsg={crawlErrorMessage} />
+ )}
+ {isCrawlFinished && !showError
+ && <CrawledResult
+ className='mb-2'
+ list={crawlResult?.data || []}
+ checkedList={checkedCrawlResult}
+ onSelectedChange={onCheckedCrawlResultChange}
+ onPreview={onPreview}
+ usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0}
+ />
+ }
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+export default React.memo(FireCrawl)
diff --git a/app/components/datasets/create/website/firecrawl/options.tsx b/app/components/datasets/create/website/firecrawl/options.tsx
new file mode 100644
index 0000000..dea6c0e
--- /dev/null
+++ b/app/components/datasets/create/website/firecrawl/options.tsx
@@ -0,0 +1,85 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import CheckboxWithLabel from '../base/checkbox-with-label'
+import Field from '../base/field'
+import cn from '@/utils/classnames'
+import type { CrawlOptions } from '@/models/datasets'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ className?: string
+ payload: CrawlOptions
+ onChange: (payload: CrawlOptions) => void
+}
+
+const Options: FC<Props> = ({
+ className = '',
+ payload,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+
+ const handleChange = useCallback((key: keyof CrawlOptions) => {
+ return (value: any) => {
+ onChange({
+ ...payload,
+ [key]: value,
+ })
+ }
+ }, [payload, onChange])
+ return (
+ <div className={cn(className, ' space-y-2')}>
+ <CheckboxWithLabel
+ label={t(`${I18N_PREFIX}.crawlSubPage`)}
+ isChecked={payload.crawl_sub_pages}
+ onChange={handleChange('crawl_sub_pages')}
+ labelClassName='text-[13px] leading-[16px] font-medium text-text-secondary'
+ />
+ <div className='flex justify-between space-x-4'>
+ <Field
+ className='shrink-0 grow'
+ label={t(`${I18N_PREFIX}.limit`)}
+ value={payload.limit}
+ onChange={handleChange('limit')}
+ isNumber
+ isRequired
+ />
+ <Field
+ className='shrink-0 grow'
+ label={t(`${I18N_PREFIX}.maxDepth`)}
+ value={payload.max_depth}
+ onChange={handleChange('max_depth')}
+ isNumber
+ tooltip={t(`${I18N_PREFIX}.maxDepthTooltip`)!}
+ />
+ </div>
+
+ <div className='flex justify-between space-x-4'>
+ <Field
+ className='shrink-0 grow'
+ label={t(`${I18N_PREFIX}.excludePaths`)}
+ value={payload.excludes}
+ onChange={handleChange('excludes')}
+ placeholder='blog/*, /about/*'
+ />
+ <Field
+ className='shrink-0 grow'
+ label={t(`${I18N_PREFIX}.includeOnlyPaths`)}
+ value={payload.includes}
+ onChange={handleChange('includes')}
+ placeholder='articles/*'
+ />
+ </div>
+ <CheckboxWithLabel
+ label={t(`${I18N_PREFIX}.extractOnlyMainContent`)}
+ isChecked={payload.only_main_content}
+ onChange={handleChange('only_main_content')}
+ labelClassName='text-[13px] leading-[16px] font-medium text-text-secondary'
+ />
+ </div>
+ )
+}
+export default React.memo(Options)
diff --git a/app/components/datasets/create/website/index.module.css b/app/components/datasets/create/website/index.module.css
new file mode 100644
index 0000000..cf6c364
--- /dev/null
+++ b/app/components/datasets/create/website/index.module.css
@@ -0,0 +1,13 @@
+.jinaLogo {
+ @apply w-4 h-4 bg-center bg-no-repeat inline-block;
+ background-color: #F5FAFF;
+ background-image: url(../assets/jina.png);
+ background-size: 16px;
+}
+
+.watercrawlLogo {
+ @apply w-5 h-5 bg-center bg-no-repeat inline-block;
+ /*background-color: #F5FAFF;*/
+ background-image: url(../assets/watercrawl.svg);
+ background-size: 16px;
+}
diff --git a/app/components/datasets/create/website/index.tsx b/app/components/datasets/create/website/index.tsx
new file mode 100644
index 0000000..e2d0e2d
--- /dev/null
+++ b/app/components/datasets/create/website/index.tsx
@@ -0,0 +1,161 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import s from './index.module.css'
+import NoData from './no-data'
+import Firecrawl from './firecrawl'
+import Watercrawl from './watercrawl'
+import JinaReader from './jina-reader'
+import cn from '@/utils/classnames'
+import { useModalContext } from '@/context/modal-context'
+import type { CrawlOptions, CrawlResultItem } from '@/models/datasets'
+import { fetchDataSources } from '@/service/datasets'
+import { type DataSourceItem, DataSourceProvider } from '@/models/common'
+import { ENABLE_WEBSITE_FIRECRAWL, ENABLE_WEBSITE_JINAREADER, ENABLE_WEBSITE_WATERCRAWL } from '@/config'
+
+type Props = {
+ onPreview: (payload: CrawlResultItem) => void
+ checkedCrawlResult: CrawlResultItem[]
+ onCheckedCrawlResultChange: (payload: CrawlResultItem[]) => void
+ onCrawlProviderChange: (provider: DataSourceProvider) => void
+ onJobIdChange: (jobId: string) => void
+ crawlOptions: CrawlOptions
+ onCrawlOptionsChange: (payload: CrawlOptions) => void
+}
+
+const Website: FC<Props> = ({
+ onPreview,
+ checkedCrawlResult,
+ onCheckedCrawlResultChange,
+ onCrawlProviderChange,
+ onJobIdChange,
+ crawlOptions,
+ onCrawlOptionsChange,
+}) => {
+ const { t } = useTranslation()
+ const { setShowAccountSettingModal } = useModalContext()
+ const [isLoaded, setIsLoaded] = useState(false)
+ const [selectedProvider, setSelectedProvider] = useState<DataSourceProvider>(DataSourceProvider.jinaReader)
+ const [sources, setSources] = useState<DataSourceItem[]>([])
+
+ useEffect(() => {
+ onCrawlProviderChange(selectedProvider)
+ }, [selectedProvider, onCrawlProviderChange])
+
+ const checkSetApiKey = useCallback(async () => {
+ const res = await fetchDataSources() as any
+ setSources(res.sources)
+
+ // If users have configured one of the providers, select it.
+ const availableProviders = res.sources.filter((item: DataSourceItem) =>
+ [
+ DataSourceProvider.jinaReader,
+ DataSourceProvider.fireCrawl,
+ DataSourceProvider.waterCrawl,
+ ].includes(item.provider),
+ )
+
+ if (availableProviders.length > 0)
+ setSelectedProvider(availableProviders[0].provider)
+ }, [])
+
+ useEffect(() => {
+ checkSetApiKey().then(() => {
+ setIsLoaded(true)
+ })
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+ const handleOnConfig = useCallback(() => {
+ setShowAccountSettingModal({
+ payload: 'data-source',
+ onCancelCallback: checkSetApiKey,
+ })
+ }, [checkSetApiKey, setShowAccountSettingModal])
+
+ if (!isLoaded)
+ return null
+
+ const source = sources.find(source => source.provider === selectedProvider)
+
+ return (
+ <div>
+ <div className="mb-4">
+ <div className="system-md-medium mb-2 text-text-secondary">
+ {t('datasetCreation.stepOne.website.chooseProvider')}
+ </div>
+ <div className="flex space-x-2">
+ {ENABLE_WEBSITE_JINAREADER && <button
+ className={cn('flex items-center justify-center rounded-lg px-4 py-2',
+ selectedProvider === DataSourceProvider.jinaReader
+ ? 'system-sm-medium border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary'
+ : `system-sm-regular border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary
+ hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover hover:shadow-xs hover:shadow-shadow-shadow-3`,
+ )}
+ onClick={() => setSelectedProvider(DataSourceProvider.jinaReader)}
+ >
+ <span className={cn(s.jinaLogo, 'mr-2')}/>
+ <span>Jina Reader</span>
+ </button>}
+ {ENABLE_WEBSITE_FIRECRAWL && <button
+ className={cn('rounded-lg px-4 py-2',
+ selectedProvider === DataSourceProvider.fireCrawl
+ ? 'system-sm-medium border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary'
+ : `system-sm-regular border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary
+ hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover hover:shadow-xs hover:shadow-shadow-shadow-3`,
+ )}
+ onClick={() => setSelectedProvider(DataSourceProvider.fireCrawl)}
+ >
+ 馃敟 Firecrawl
+ </button>}
+ {ENABLE_WEBSITE_WATERCRAWL && <button
+ className={cn('flex items-center justify-center rounded-lg px-4 py-2',
+ selectedProvider === DataSourceProvider.waterCrawl
+ ? 'system-sm-medium border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary'
+ : `system-sm-regular border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary
+ hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover hover:shadow-xs hover:shadow-shadow-shadow-3`,
+ )}
+ onClick={() => setSelectedProvider(DataSourceProvider.waterCrawl)}
+ >
+ <span className={cn(s.watercrawlLogo, 'mr-2')}/>
+ <span>WaterCrawl</span>
+ </button>}
+ </div>
+ </div>
+ {source && selectedProvider === DataSourceProvider.fireCrawl && (
+ <Firecrawl
+ onPreview={onPreview}
+ checkedCrawlResult={checkedCrawlResult}
+ onCheckedCrawlResultChange={onCheckedCrawlResultChange}
+ onJobIdChange={onJobIdChange}
+ crawlOptions={crawlOptions}
+ onCrawlOptionsChange={onCrawlOptionsChange}
+ />
+ )}
+ {source && selectedProvider === DataSourceProvider.waterCrawl && (
+ <Watercrawl
+ onPreview={onPreview}
+ checkedCrawlResult={checkedCrawlResult}
+ onCheckedCrawlResultChange={onCheckedCrawlResultChange}
+ onJobIdChange={onJobIdChange}
+ crawlOptions={crawlOptions}
+ onCrawlOptionsChange={onCrawlOptionsChange}
+ />
+ )}
+ {source && selectedProvider === DataSourceProvider.jinaReader && (
+ <JinaReader
+ onPreview={onPreview}
+ checkedCrawlResult={checkedCrawlResult}
+ onCheckedCrawlResultChange={onCheckedCrawlResultChange}
+ onJobIdChange={onJobIdChange}
+ crawlOptions={crawlOptions}
+ onCrawlOptionsChange={onCrawlOptionsChange}
+ />
+ )}
+ {!source && (
+ <NoData onConfig={handleOnConfig} provider={selectedProvider}/>
+ )}
+ </div>
+ )
+}
+export default React.memo(Website)
diff --git a/app/components/datasets/create/website/jina-reader/base/checkbox-with-label.tsx b/app/components/datasets/create/website/jina-reader/base/checkbox-with-label.tsx
new file mode 100644
index 0000000..3ec1375
--- /dev/null
+++ b/app/components/datasets/create/website/jina-reader/base/checkbox-with-label.tsx
@@ -0,0 +1,40 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import Checkbox from '@/app/components/base/checkbox'
+import Tooltip from '@/app/components/base/tooltip'
+
+type Props = {
+ className?: string
+ isChecked: boolean
+ onChange: (isChecked: boolean) => void
+ label: string
+ labelClassName?: string
+ tooltip?: string
+}
+
+const CheckboxWithLabel: FC<Props> = ({
+ className = '',
+ isChecked,
+ onChange,
+ label,
+ labelClassName,
+ tooltip,
+}) => {
+ return (
+ <label className={cn(className, 'flex h-7 items-center space-x-2')}>
+ <Checkbox checked={isChecked} onCheck={() => onChange(!isChecked)} />
+ <div className={cn('text-sm font-normal text-gray-800', labelClassName)}>{label}</div>
+ {tooltip && (
+ <Tooltip
+ popupContent={
+ <div className='w-[200px]'>{tooltip}</div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4'
+ />
+ )}
+ </label>
+ )
+}
+export default React.memo(CheckboxWithLabel)
diff --git a/app/components/datasets/create/website/jina-reader/base/error-message.tsx b/app/components/datasets/create/website/jina-reader/base/error-message.tsx
new file mode 100644
index 0000000..5a61638
--- /dev/null
+++ b/app/components/datasets/create/website/jina-reader/base/error-message.tsx
@@ -0,0 +1,30 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
+
+type Props = {
+ className?: string
+ title: string
+ errorMsg?: string
+}
+
+const ErrorMessage: FC<Props> = ({
+ className,
+ title,
+ errorMsg,
+}) => {
+ return (
+ <div className={cn(className, 'border-t border-gray-200 bg-[#FFFAEB] px-4 py-2')}>
+ <div className='flex h-5 items-center'>
+ <AlertTriangle className='mr-2 h-4 w-4 text-[#F79009]' />
+ <div className='text-sm font-medium text-[#DC6803]'>{title}</div>
+ </div>
+ {errorMsg && (
+ <div className='mt-1 pl-6 text-xs font-normal leading-[18px] text-gray-700'>{errorMsg}</div>
+ )}
+ </div>
+ )
+}
+export default React.memo(ErrorMessage)
diff --git a/app/components/datasets/create/website/jina-reader/base/field.tsx b/app/components/datasets/create/website/jina-reader/base/field.tsx
new file mode 100644
index 0000000..13477ff
--- /dev/null
+++ b/app/components/datasets/create/website/jina-reader/base/field.tsx
@@ -0,0 +1,54 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import Input from './input'
+import cn from '@/utils/classnames'
+import Tooltip from '@/app/components/base/tooltip'
+
+type Props = {
+ className?: string
+ label: string
+ labelClassName?: string
+ value: string | number
+ onChange: (value: string | number) => void
+ isRequired?: boolean
+ placeholder?: string
+ isNumber?: boolean
+ tooltip?: string
+}
+
+const Field: FC<Props> = ({
+ className,
+ label,
+ labelClassName,
+ value,
+ onChange,
+ isRequired = false,
+ placeholder = '',
+ isNumber = false,
+ tooltip,
+}) => {
+ return (
+ <div className={cn(className)}>
+ <div className='flex py-[7px]'>
+ <div className={cn(labelClassName, 'flex h-[18px] items-center text-[13px] font-medium text-gray-900')}>{label} </div>
+ {isRequired && <span className='ml-0.5 text-xs font-semibold text-[#D92D20]'>*</span>}
+ {tooltip && (
+ <Tooltip
+ popupContent={
+ <div className='w-[200px]'>{tooltip}</div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4'
+ />
+ )}
+ </div>
+ <Input
+ value={value}
+ onChange={onChange}
+ placeholder={placeholder}
+ isNumber={isNumber}
+ />
+ </div>
+ )
+}
+export default React.memo(Field)
diff --git a/app/components/datasets/create/website/jina-reader/base/input.tsx b/app/components/datasets/create/website/jina-reader/base/input.tsx
new file mode 100644
index 0000000..bc7a15a
--- /dev/null
+++ b/app/components/datasets/create/website/jina-reader/base/input.tsx
@@ -0,0 +1,58 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+
+type Props = {
+ value: string | number
+ onChange: (value: string | number) => void
+ placeholder?: string
+ isNumber?: boolean
+}
+
+const MIN_VALUE = 0
+
+const Input: FC<Props> = ({
+ value,
+ onChange,
+ placeholder = '',
+ isNumber = false,
+}) => {
+ const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
+ const value = e.target.value
+ if (isNumber) {
+ let numberValue = Number.parseInt(value, 10) // integer only
+ if (isNaN(numberValue)) {
+ onChange('')
+ return
+ }
+ if (numberValue < MIN_VALUE)
+ numberValue = MIN_VALUE
+
+ onChange(numberValue)
+ return
+ }
+ onChange(value)
+ }, [isNumber, onChange])
+
+ const otherOption = (() => {
+ if (isNumber) {
+ return {
+ min: MIN_VALUE,
+ }
+ }
+ return {
+
+ }
+ })()
+ return (
+ <input
+ type={isNumber ? 'number' : 'text'}
+ {...otherOption}
+ value={value}
+ onChange={handleChange}
+ className='flex h-9 w-full rounded-lg bg-gray-100 px-2 py-1 text-xs leading-normal caret-primary-600 placeholder:text-gray-400 hover:bg-gray-100 focus:bg-gray-50 focus:ring-1 focus:ring-inset focus:ring-gray-200 focus-visible:outline-none'
+ placeholder={placeholder}
+ />
+ )
+}
+export default React.memo(Input)
diff --git a/app/components/datasets/create/website/jina-reader/base/options-wrap.tsx b/app/components/datasets/create/website/jina-reader/base/options-wrap.tsx
new file mode 100644
index 0000000..a5fa687
--- /dev/null
+++ b/app/components/datasets/create/website/jina-reader/base/options-wrap.tsx
@@ -0,0 +1,55 @@
+'use client'
+import { useBoolean } from 'ahooks'
+import type { FC } from 'react'
+import React, { useEffect } from 'react'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
+import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows'
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ className?: string
+ children: React.ReactNode
+ controlFoldOptions?: number
+}
+
+const OptionsWrap: FC<Props> = ({
+ className = '',
+ children,
+ controlFoldOptions,
+}) => {
+ const { t } = useTranslation()
+
+ const [fold, {
+ toggle: foldToggle,
+ setTrue: foldHide,
+ }] = useBoolean(false)
+
+ useEffect(() => {
+ if (controlFoldOptions)
+ foldHide()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [controlFoldOptions])
+ return (
+ <div className={cn(className, !fold ? 'mb-0' : 'mb-3')}>
+ <div
+ className='flex h-[26px] cursor-pointer select-none items-center justify-between py-1'
+ onClick={foldToggle}
+ >
+ <div className='flex items-center text-gray-700'>
+ <Settings04 className='mr-1 h-4 w-4' />
+ <div className='text-[13px] font-semibold uppercase text-gray-800'>{t(`${I18N_PREFIX}.options`)}</div>
+ </div>
+ <ChevronRight className={cn(!fold && 'rotate-90', 'h-4 w-4 text-gray-500')} />
+ </div>
+ {!fold && (
+ <div className='mb-4'>
+ {children}
+ </div>
+ )}
+
+ </div>
+ )
+}
+export default React.memo(OptionsWrap)
diff --git a/app/components/datasets/create/website/jina-reader/base/url-input.tsx b/app/components/datasets/create/website/jina-reader/base/url-input.tsx
new file mode 100644
index 0000000..e6b0475
--- /dev/null
+++ b/app/components/datasets/create/website/jina-reader/base/url-input.tsx
@@ -0,0 +1,48 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import Input from './input'
+import Button from '@/app/components/base/button'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ isRunning: boolean
+ onRun: (url: string) => void
+}
+
+const UrlInput: FC<Props> = ({
+ isRunning,
+ onRun,
+}) => {
+ const { t } = useTranslation()
+ const [url, setUrl] = useState('')
+ const handleUrlChange = useCallback((url: string | number) => {
+ setUrl(url as string)
+ }, [])
+ const handleOnRun = useCallback(() => {
+ if (isRunning)
+ return
+ onRun(url)
+ }, [isRunning, onRun, url])
+
+ return (
+ <div className='flex items-center justify-between'>
+ <Input
+ value={url}
+ onChange={handleUrlChange}
+ placeholder='https://docs.dify.ai'
+ />
+ <Button
+ variant='primary'
+ onClick={handleOnRun}
+ className='ml-2'
+ loading={isRunning}
+ >
+ {!isRunning ? t(`${I18N_PREFIX}.run`) : ''}
+ </Button>
+ </div>
+ )
+}
+export default React.memo(UrlInput)
diff --git a/app/components/datasets/create/website/jina-reader/header.tsx b/app/components/datasets/create/website/jina-reader/header.tsx
new file mode 100644
index 0000000..13b8a9e
--- /dev/null
+++ b/app/components/datasets/create/website/jina-reader/header.tsx
@@ -0,0 +1,43 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiBookOpenLine, RiEqualizer2Line } from '@remixicon/react'
+import Button from '@/app/components/base/button'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ onSetting: () => void
+}
+
+const Header: FC<Props> = ({
+ onSetting,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex h-6 items-center justify-between'>
+ <div className='flex items-center'>
+ <div className='text-sm font-semibold text-text-secondary'>{t(`${I18N_PREFIX}.jinaReaderTitle`)}</div>
+ <div className='ml-2 mr-2 h-3.5 w-px bg-divider-regular' />
+ <Button className='flex h-6 items-center gap-x-[1px] px-1.5' onClick={onSetting}>
+ <RiEqualizer2Line className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <span className='px-[3px] text-xs font-medium text-components-button-secondary-text'>
+ {t(`${I18N_PREFIX}.configureJinaReader`)}
+ </span>
+ </Button>
+ </div>
+ <a
+ href='https://jina.ai/reader'
+ target='_blank'
+ rel='noopener noreferrer'
+ className='inline-flex items-center gap-x-1 text-xs font-medium text-text-accent'
+ >
+ <RiBookOpenLine className='h-3.5 w-3.5 text-text-accent' />
+ <span>{t(`${I18N_PREFIX}.jinaReaderDoc`)}</span>
+ </a>
+ </div>
+ )
+}
+export default React.memo(Header)
diff --git a/app/components/datasets/create/website/jina-reader/index.tsx b/app/components/datasets/create/website/jina-reader/index.tsx
new file mode 100644
index 0000000..2ab0444
--- /dev/null
+++ b/app/components/datasets/create/website/jina-reader/index.tsx
@@ -0,0 +1,230 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import UrlInput from '../base/url-input'
+import OptionsWrap from '../base/options-wrap'
+import CrawledResult from '../base/crawled-result'
+import Crawling from '../base/crawling'
+import ErrorMessage from '../base/error-message'
+import Header from './header'
+import Options from './options'
+import { useModalContext } from '@/context/modal-context'
+import Toast from '@/app/components/base/toast'
+import { checkJinaReaderTaskStatus, createJinaReaderTask } from '@/service/datasets'
+import { sleep } from '@/utils'
+import type { CrawlOptions, CrawlResultItem } from '@/models/datasets'
+
+const ERROR_I18N_PREFIX = 'common.errorMsg'
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ onPreview: (payload: CrawlResultItem) => void
+ checkedCrawlResult: CrawlResultItem[]
+ onCheckedCrawlResultChange: (payload: CrawlResultItem[]) => void
+ onJobIdChange: (jobId: string) => void
+ crawlOptions: CrawlOptions
+ onCrawlOptionsChange: (payload: CrawlOptions) => void
+}
+
+enum Step {
+ init = 'init',
+ running = 'running',
+ finished = 'finished',
+}
+
+const JinaReader: FC<Props> = ({
+ onPreview,
+ checkedCrawlResult,
+ onCheckedCrawlResultChange,
+ onJobIdChange,
+ crawlOptions,
+ onCrawlOptionsChange,
+}) => {
+ const { t } = useTranslation()
+ const [step, setStep] = useState<Step>(Step.init)
+ const [controlFoldOptions, setControlFoldOptions] = useState<number>(0)
+ useEffect(() => {
+ if (step !== Step.init)
+ setControlFoldOptions(Date.now())
+ }, [step])
+ const { setShowAccountSettingModal } = useModalContext()
+ const handleSetting = useCallback(() => {
+ setShowAccountSettingModal({
+ payload: 'data-source',
+ })
+ }, [setShowAccountSettingModal])
+
+ const checkValid = useCallback((url: string) => {
+ let errorMsg = ''
+ if (!url) {
+ errorMsg = t(`${ERROR_I18N_PREFIX}.fieldRequired`, {
+ field: 'url',
+ })
+ }
+
+ if (!errorMsg && !((url.startsWith('http://') || url.startsWith('https://'))))
+ errorMsg = t(`${ERROR_I18N_PREFIX}.urlError`)
+
+ if (!errorMsg && (crawlOptions.limit === null || crawlOptions.limit === undefined || crawlOptions.limit === '')) {
+ errorMsg = t(`${ERROR_I18N_PREFIX}.fieldRequired`, {
+ field: t(`${I18N_PREFIX}.limit`),
+ })
+ }
+
+ return {
+ isValid: !errorMsg,
+ errorMsg,
+ }
+ }, [crawlOptions, t])
+
+ const isInit = step === Step.init
+ const isCrawlFinished = step === Step.finished
+ const isRunning = step === Step.running
+ const [crawlResult, setCrawlResult] = useState<{
+ current: number
+ total: number
+ data: CrawlResultItem[]
+ time_consuming: number | string
+ } | undefined>(undefined)
+ const [crawlErrorMessage, setCrawlErrorMessage] = useState('')
+ const showError = isCrawlFinished && crawlErrorMessage
+
+ const waitForCrawlFinished = useCallback(async (jobId: string) => {
+ try {
+ const res = await checkJinaReaderTaskStatus(jobId) as any
+ if (res.status === 'completed') {
+ return {
+ isError: false,
+ data: {
+ ...res,
+ total: Math.min(res.total, Number.parseFloat(crawlOptions.limit as string)),
+ },
+ }
+ }
+ if (res.status === 'failed' || !res.status) {
+ return {
+ isError: true,
+ errorMessage: res.message,
+ data: {
+ data: [],
+ },
+ }
+ }
+ // update the progress
+ setCrawlResult({
+ ...res,
+ total: Math.min(res.total, Number.parseFloat(crawlOptions.limit as string)),
+ })
+ onCheckedCrawlResultChange(res.data || []) // default select the crawl result
+ await sleep(2500)
+ return await waitForCrawlFinished(jobId)
+ }
+ catch (e: any) {
+ const errorBody = await e.json()
+ return {
+ isError: true,
+ errorMessage: errorBody.message,
+ data: {
+ data: [],
+ },
+ }
+ }
+ }, [crawlOptions.limit, onCheckedCrawlResultChange])
+
+ const handleRun = useCallback(async (url: string) => {
+ const { isValid, errorMsg } = checkValid(url)
+ if (!isValid) {
+ Toast.notify({
+ message: errorMsg!,
+ type: 'error',
+ })
+ return
+ }
+ setStep(Step.running)
+ try {
+ const startTime = Date.now()
+ const res = await createJinaReaderTask({
+ url,
+ options: crawlOptions,
+ }) as any
+
+ if (res.data) {
+ const data = {
+ current: 1,
+ total: 1,
+ data: [{
+ title: res.data.title,
+ markdown: res.data.content,
+ description: res.data.description,
+ source_url: res.data.url,
+ }],
+ time_consuming: (Date.now() - startTime) / 1000,
+ }
+ setCrawlResult(data)
+ onCheckedCrawlResultChange(data.data || [])
+ setCrawlErrorMessage('')
+ }
+ else if (res.job_id) {
+ const jobId = res.job_id
+ onJobIdChange(jobId)
+ const { isError, data, errorMessage } = await waitForCrawlFinished(jobId)
+ if (isError) {
+ setCrawlErrorMessage(errorMessage || t(`${I18N_PREFIX}.unknownError`))
+ }
+ else {
+ setCrawlResult(data)
+ onCheckedCrawlResultChange(data.data || []) // default select the crawl result
+ setCrawlErrorMessage('')
+ }
+ }
+ }
+ catch (e) {
+ setCrawlErrorMessage(t(`${I18N_PREFIX}.unknownError`)!)
+ console.log(e)
+ }
+ finally {
+ setStep(Step.finished)
+ }
+ }, [checkValid, crawlOptions, onCheckedCrawlResultChange, onJobIdChange, t, waitForCrawlFinished])
+
+ return (
+ <div>
+ <Header onSetting={handleSetting} />
+ <div className='mt-2 rounded-xl border border-components-panel-border bg-background-default-subtle p-4 pb-0'>
+ <UrlInput onRun={handleRun} isRunning={isRunning} />
+ <OptionsWrap
+ className='mt-4'
+ controlFoldOptions={controlFoldOptions}
+ >
+ <Options className='mt-2' payload={crawlOptions} onChange={onCrawlOptionsChange} />
+ </OptionsWrap>
+
+ {!isInit && (
+ <div className='relative left-[-16px] mt-3 w-[calc(100%_+_32px)] rounded-b-xl'>
+ {isRunning
+ && <Crawling
+ className='mt-2'
+ crawledNum={crawlResult?.current || 0}
+ totalNum={crawlResult?.total || Number.parseFloat(crawlOptions.limit as string) || 0}
+ />}
+ {showError && (
+ <ErrorMessage className='rounded-b-xl' title={t(`${I18N_PREFIX}.exceptionErrorTitle`)} errorMsg={crawlErrorMessage} />
+ )}
+ {isCrawlFinished && !showError
+ && <CrawledResult
+ className='mb-2'
+ list={crawlResult?.data || []}
+ checkedList={checkedCrawlResult}
+ onSelectedChange={onCheckedCrawlResultChange}
+ onPreview={onPreview}
+ usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0}
+ />
+ }
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+export default React.memo(JinaReader)
diff --git a/app/components/datasets/create/website/jina-reader/options.tsx b/app/components/datasets/create/website/jina-reader/options.tsx
new file mode 100644
index 0000000..e18cff8
--- /dev/null
+++ b/app/components/datasets/create/website/jina-reader/options.tsx
@@ -0,0 +1,61 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import CheckboxWithLabel from '../base/checkbox-with-label'
+import Field from '../base/field'
+import cn from '@/utils/classnames'
+import type { CrawlOptions } from '@/models/datasets'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ className?: string
+ payload: CrawlOptions
+ onChange: (payload: CrawlOptions) => void
+}
+
+const Options: FC<Props> = ({
+ className = '',
+ payload,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+
+ const handleChange = useCallback((key: keyof CrawlOptions) => {
+ return (value: any) => {
+ onChange({
+ ...payload,
+ [key]: value,
+ })
+ }
+ }, [payload, onChange])
+ return (
+ <div className={cn(className, ' space-y-2')}>
+ <CheckboxWithLabel
+ label={t(`${I18N_PREFIX}.crawlSubPage`)}
+ isChecked={payload.crawl_sub_pages}
+ onChange={handleChange('crawl_sub_pages')}
+ labelClassName='text-[13px] leading-[16px] font-medium text-text-secondary'
+ />
+ <CheckboxWithLabel
+ label={t(`${I18N_PREFIX}.useSitemap`)}
+ isChecked={payload.use_sitemap}
+ onChange={handleChange('use_sitemap')}
+ tooltip={t(`${I18N_PREFIX}.useSitemapTooltip`) as string}
+ labelClassName='text-[13px] leading-[16px] font-medium text-text-secondary'
+ />
+ <div className='flex justify-between space-x-4'>
+ <Field
+ className='shrink-0 grow'
+ label={t(`${I18N_PREFIX}.limit`)}
+ value={payload.limit}
+ onChange={handleChange('limit')}
+ isNumber
+ isRequired
+ />
+ </div>
+ </div>
+ )
+}
+export default React.memo(Options)
diff --git a/app/components/datasets/create/website/no-data.tsx b/app/components/datasets/create/website/no-data.tsx
new file mode 100644
index 0000000..1db83a7
--- /dev/null
+++ b/app/components/datasets/create/website/no-data.tsx
@@ -0,0 +1,69 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import s from './index.module.css'
+import { Icon3Dots } from '@/app/components/base/icons/src/vender/line/others'
+import Button from '@/app/components/base/button'
+import { DataSourceProvider } from '@/models/common'
+import { ENABLE_WEBSITE_FIRECRAWL, ENABLE_WEBSITE_JINAREADER, ENABLE_WEBSITE_WATERCRAWL } from '@/config'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ onConfig: () => void
+ provider: DataSourceProvider
+}
+
+const NoData: FC<Props> = ({
+ onConfig,
+ provider,
+}) => {
+ const { t } = useTranslation()
+
+ const providerConfig = {
+ [DataSourceProvider.jinaReader]: ENABLE_WEBSITE_JINAREADER ? {
+ emoji: <span className={s.jinaLogo} />,
+ title: t(`${I18N_PREFIX}.jinaReaderNotConfigured`),
+ description: t(`${I18N_PREFIX}.jinaReaderNotConfiguredDescription`),
+ } : null,
+ [DataSourceProvider.fireCrawl]: ENABLE_WEBSITE_FIRECRAWL ? {
+ emoji: '馃敟',
+ title: t(`${I18N_PREFIX}.fireCrawlNotConfigured`),
+ description: t(`${I18N_PREFIX}.fireCrawlNotConfiguredDescription`),
+ } : null,
+ [DataSourceProvider.waterCrawl]: ENABLE_WEBSITE_WATERCRAWL ? {
+ emoji: '馃挧',
+ title: t(`${I18N_PREFIX}.waterCrawlNotConfigured`),
+ description: t(`${I18N_PREFIX}.waterCrawlNotConfiguredDescription`),
+ } : null,
+ }
+
+ const currentProvider = providerConfig[provider] || providerConfig[DataSourceProvider.jinaReader]
+
+ if (!currentProvider) return null
+
+ return (
+ <>
+ <div className='mt-4 max-w-[640px] rounded-2xl bg-workflow-process-bg p-6'>
+ <div className='flex h-12 w-12 items-center justify-center rounded-[10px] border-[0.5px]
+ border-components-card-border bg-components-card-bg shadow-lg shadow-shadow-shadow-5 backdrop-blur-[5px]'>
+ {currentProvider.emoji}
+ </div>
+ <div className='mb-1 mt-2 flex flex-col gap-y-1 pb-3 pt-1'>
+ <span className='system-md-semibold text-text-secondary'>
+ {currentProvider.title}
+ <Icon3Dots className='relative -left-1.5 -top-2.5 inline' />
+ </span>
+ <div className='system-sm-regular text-text-tertiary'>
+ {currentProvider.description}
+ </div>
+ </div>
+ <Button variant='primary' onClick={onConfig}>
+ {t(`${I18N_PREFIX}.configure`)}
+ </Button>
+ </div>
+ </>
+ )
+}
+export default React.memo(NoData)
diff --git a/app/components/datasets/create/website/preview.tsx b/app/components/datasets/create/website/preview.tsx
new file mode 100644
index 0000000..f43dc83
--- /dev/null
+++ b/app/components/datasets/create/website/preview.tsx
@@ -0,0 +1,41 @@
+'use client'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { XMarkIcon } from '@heroicons/react/20/solid'
+import s from '../file-preview/index.module.css'
+import cn from '@/utils/classnames'
+import type { CrawlResultItem } from '@/models/datasets'
+
+type IProps = {
+ payload: CrawlResultItem
+ hidePreview: () => void
+}
+
+const WebsitePreview = ({
+ payload,
+ hidePreview,
+}: IProps) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={cn(s.filePreview, 'h-full')}>
+ <div className={cn(s.previewHeader)}>
+ <div className={cn(s.title, 'title-md-semi-bold')}>
+ <span>{t('datasetCreation.stepOne.pagePreview')}</span>
+ <div className='flex h-6 w-6 cursor-pointer items-center justify-center' onClick={hidePreview}>
+ <XMarkIcon className='h-4 w-4'></XMarkIcon>
+ </div>
+ </div>
+ <div className='title-sm-semi-bold break-words text-text-primary'>
+ {payload.title}
+ </div>
+ <div className='system-xs-medium truncate text-text-tertiary' title={payload.source_url}>{payload.source_url}</div>
+ </div>
+ <div className={cn(s.previewContent, 'body-md-regular')}>
+ <div className={cn(s.fileContent)}>{payload.markdown}</div>
+ </div>
+ </div>
+ )
+}
+
+export default WebsitePreview
diff --git a/app/components/datasets/create/website/watercrawl/header.tsx b/app/components/datasets/create/website/watercrawl/header.tsx
new file mode 100644
index 0000000..38b2813
--- /dev/null
+++ b/app/components/datasets/create/website/watercrawl/header.tsx
@@ -0,0 +1,43 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiBookOpenLine, RiEqualizer2Line } from '@remixicon/react'
+import Button from '@/app/components/base/button'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ onSetting: () => void
+}
+
+const Header: FC<Props> = ({
+ onSetting,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex h-6 items-center justify-between'>
+ <div className='flex items-center'>
+ <div className='text-base font-medium text-text-secondary'>{t(`${I18N_PREFIX}.watercrawlTitle`)}</div>
+ <div className='ml-2 mr-2 h-3.5 w-px bg-divider-regular' />
+ <Button className='flex h-6 items-center gap-x-[1px] px-1.5' onClick={onSetting}>
+ <RiEqualizer2Line className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <span className='px-[3px] text-xs font-medium text-components-button-secondary-text'>
+ {t(`${I18N_PREFIX}.configureWatercrawl`)}
+ </span>
+ </Button>
+ </div>
+ <a
+ href='https://docs.watercrawl.dev/'
+ target='_blank'
+ rel='noopener noreferrer'
+ className='inline-flex items-center gap-x-1 text-xs font-medium text-text-accent'
+ >
+ <RiBookOpenLine className='h-3.5 w-3.5 text-text-accent' />
+ <span>{t(`${I18N_PREFIX}.watercrawlDoc`)}</span>
+ </a>
+ </div>
+ )
+}
+export default React.memo(Header)
diff --git a/app/components/datasets/create/website/watercrawl/index.tsx b/app/components/datasets/create/website/watercrawl/index.tsx
new file mode 100644
index 0000000..bd4faa1
--- /dev/null
+++ b/app/components/datasets/create/website/watercrawl/index.tsx
@@ -0,0 +1,217 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import UrlInput from '../base/url-input'
+import OptionsWrap from '../base/options-wrap'
+import CrawledResult from '../base/crawled-result'
+import Crawling from '../base/crawling'
+import ErrorMessage from '../base/error-message'
+import Header from './header'
+import Options from './options'
+import { useModalContext } from '@/context/modal-context'
+import type { CrawlOptions, CrawlResultItem } from '@/models/datasets'
+import Toast from '@/app/components/base/toast'
+import { checkWatercrawlTaskStatus, createWatercrawlTask } from '@/service/datasets'
+import { sleep } from '@/utils'
+
+const ERROR_I18N_PREFIX = 'common.errorMsg'
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ onPreview: (payload: CrawlResultItem) => void
+ checkedCrawlResult: CrawlResultItem[]
+ onCheckedCrawlResultChange: (payload: CrawlResultItem[]) => void
+ onJobIdChange: (jobId: string) => void
+ crawlOptions: CrawlOptions
+ onCrawlOptionsChange: (payload: CrawlOptions) => void
+}
+
+enum Step {
+ init = 'init',
+ running = 'running',
+ finished = 'finished',
+}
+
+const WaterCrawl: FC<Props> = ({
+ onPreview,
+ checkedCrawlResult,
+ onCheckedCrawlResultChange,
+ onJobIdChange,
+ crawlOptions,
+ onCrawlOptionsChange,
+}) => {
+ const { t } = useTranslation()
+ const [step, setStep] = useState<Step>(Step.init)
+ const [controlFoldOptions, setControlFoldOptions] = useState<number>(0)
+ useEffect(() => {
+ if (step !== Step.init)
+ setControlFoldOptions(Date.now())
+ }, [step])
+ const { setShowAccountSettingModal } = useModalContext()
+ const handleSetting = useCallback(() => {
+ setShowAccountSettingModal({
+ payload: 'data-source',
+ })
+ }, [setShowAccountSettingModal])
+
+ const checkValid = useCallback((url: string) => {
+ let errorMsg = ''
+ if (!url) {
+ errorMsg = t(`${ERROR_I18N_PREFIX}.fieldRequired`, {
+ field: 'url',
+ })
+ }
+
+ if (!errorMsg && !((url.startsWith('http://') || url.startsWith('https://'))))
+ errorMsg = t(`${ERROR_I18N_PREFIX}.urlError`)
+
+ if (!errorMsg && (crawlOptions.limit === null || crawlOptions.limit === undefined || crawlOptions.limit === '')) {
+ errorMsg = t(`${ERROR_I18N_PREFIX}.fieldRequired`, {
+ field: t(`${I18N_PREFIX}.limit`),
+ })
+ }
+
+ return {
+ isValid: !errorMsg,
+ errorMsg,
+ }
+ }, [crawlOptions, t])
+
+ const isInit = step === Step.init
+ const isCrawlFinished = step === Step.finished
+ const isRunning = step === Step.running
+ const [crawlResult, setCrawlResult] = useState<{
+ current: number
+ total: number
+ data: CrawlResultItem[]
+ time_consuming: number | string
+ } | undefined>(undefined)
+ const [crawlErrorMessage, setCrawlErrorMessage] = useState('')
+ const showError = isCrawlFinished && crawlErrorMessage
+
+ const waitForCrawlFinished = useCallback(async (jobId: string): Promise<any> => {
+ try {
+ const res = await checkWatercrawlTaskStatus(jobId) as any
+ if (res.status === 'completed') {
+ return {
+ isError: false,
+ data: {
+ ...res,
+ total: Math.min(res.total, Number.parseFloat(crawlOptions.limit as string)),
+ },
+ }
+ }
+ if (res.status === 'error' || !res.status) {
+ // can't get the error message from the watercrawl api
+ return {
+ isError: true,
+ errorMessage: res.message,
+ data: {
+ data: [],
+ },
+ }
+ }
+ // update the progress
+ setCrawlResult({
+ ...res,
+ total: Math.min(res.total, Number.parseFloat(crawlOptions.limit as string)),
+ })
+ onCheckedCrawlResultChange(res.data || []) // default select the crawl result
+ await sleep(2500)
+ return await waitForCrawlFinished(jobId)
+ }
+ catch (e: any) {
+ const errorBody = await e.json()
+ return {
+ isError: true,
+ errorMessage: errorBody.message,
+ data: {
+ data: [],
+ },
+ }
+ }
+ }, [crawlOptions.limit])
+
+ const handleRun = useCallback(async (url: string) => {
+ const { isValid, errorMsg } = checkValid(url)
+ if (!isValid) {
+ Toast.notify({
+ message: errorMsg!,
+ type: 'error',
+ })
+ return
+ }
+ setStep(Step.running)
+ try {
+ const passToServerCrawlOptions: any = {
+ ...crawlOptions,
+ }
+ if (crawlOptions.max_depth === '')
+ delete passToServerCrawlOptions.max_depth
+
+ const res = await createWatercrawlTask({
+ url,
+ options: passToServerCrawlOptions,
+ }) as any
+ const jobId = res.job_id
+ onJobIdChange(jobId)
+ const { isError, data, errorMessage } = await waitForCrawlFinished(jobId)
+ if (isError) {
+ setCrawlErrorMessage(errorMessage || t(`${I18N_PREFIX}.unknownError`))
+ }
+ else {
+ setCrawlResult(data)
+ onCheckedCrawlResultChange(data.data || []) // default select the crawl result
+ setCrawlErrorMessage('')
+ }
+ }
+ catch (e) {
+ setCrawlErrorMessage(t(`${I18N_PREFIX}.unknownError`)!)
+ console.log(e)
+ }
+ finally {
+ setStep(Step.finished)
+ }
+ }, [checkValid, crawlOptions, onJobIdChange, t, waitForCrawlFinished])
+
+ return (
+ <div>
+ <Header onSetting={handleSetting} />
+ <div className='mt-2 rounded-xl border border-components-panel-border bg-background-default-subtle p-4 pb-0'>
+ <UrlInput onRun={handleRun} isRunning={isRunning} />
+ <OptionsWrap
+ className='mt-4'
+ controlFoldOptions={controlFoldOptions}
+ >
+ <Options className='mt-2' payload={crawlOptions} onChange={onCrawlOptionsChange} />
+ </OptionsWrap>
+
+ {!isInit && (
+ <div className='relative left-[-16px] mt-3 w-[calc(100%_+_32px)] rounded-b-xl'>
+ {isRunning
+ && <Crawling
+ className='mt-2'
+ crawledNum={crawlResult?.current || 0}
+ totalNum={crawlResult?.total || Number.parseFloat(crawlOptions.limit as string) || 0}
+ />}
+ {showError && (
+ <ErrorMessage className='rounded-b-xl' title={t(`${I18N_PREFIX}.exceptionErrorTitle`)} errorMsg={crawlErrorMessage} />
+ )}
+ {isCrawlFinished && !showError
+ && <CrawledResult
+ className='mb-2'
+ list={crawlResult?.data || []}
+ checkedList={checkedCrawlResult}
+ onSelectedChange={onCheckedCrawlResultChange}
+ onPreview={onPreview}
+ usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0}
+ />
+ }
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+export default React.memo(WaterCrawl)
diff --git a/app/components/datasets/create/website/watercrawl/options.tsx b/app/components/datasets/create/website/watercrawl/options.tsx
new file mode 100644
index 0000000..dea6c0e
--- /dev/null
+++ b/app/components/datasets/create/website/watercrawl/options.tsx
@@ -0,0 +1,85 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import CheckboxWithLabel from '../base/checkbox-with-label'
+import Field from '../base/field'
+import cn from '@/utils/classnames'
+import type { CrawlOptions } from '@/models/datasets'
+
+const I18N_PREFIX = 'datasetCreation.stepOne.website'
+
+type Props = {
+ className?: string
+ payload: CrawlOptions
+ onChange: (payload: CrawlOptions) => void
+}
+
+const Options: FC<Props> = ({
+ className = '',
+ payload,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+
+ const handleChange = useCallback((key: keyof CrawlOptions) => {
+ return (value: any) => {
+ onChange({
+ ...payload,
+ [key]: value,
+ })
+ }
+ }, [payload, onChange])
+ return (
+ <div className={cn(className, ' space-y-2')}>
+ <CheckboxWithLabel
+ label={t(`${I18N_PREFIX}.crawlSubPage`)}
+ isChecked={payload.crawl_sub_pages}
+ onChange={handleChange('crawl_sub_pages')}
+ labelClassName='text-[13px] leading-[16px] font-medium text-text-secondary'
+ />
+ <div className='flex justify-between space-x-4'>
+ <Field
+ className='shrink-0 grow'
+ label={t(`${I18N_PREFIX}.limit`)}
+ value={payload.limit}
+ onChange={handleChange('limit')}
+ isNumber
+ isRequired
+ />
+ <Field
+ className='shrink-0 grow'
+ label={t(`${I18N_PREFIX}.maxDepth`)}
+ value={payload.max_depth}
+ onChange={handleChange('max_depth')}
+ isNumber
+ tooltip={t(`${I18N_PREFIX}.maxDepthTooltip`)!}
+ />
+ </div>
+
+ <div className='flex justify-between space-x-4'>
+ <Field
+ className='shrink-0 grow'
+ label={t(`${I18N_PREFIX}.excludePaths`)}
+ value={payload.excludes}
+ onChange={handleChange('excludes')}
+ placeholder='blog/*, /about/*'
+ />
+ <Field
+ className='shrink-0 grow'
+ label={t(`${I18N_PREFIX}.includeOnlyPaths`)}
+ value={payload.includes}
+ onChange={handleChange('includes')}
+ placeholder='articles/*'
+ />
+ </div>
+ <CheckboxWithLabel
+ label={t(`${I18N_PREFIX}.extractOnlyMainContent`)}
+ isChecked={payload.only_main_content}
+ onChange={handleChange('only_main_content')}
+ labelClassName='text-[13px] leading-[16px] font-medium text-text-secondary'
+ />
+ </div>
+ )
+}
+export default React.memo(Options)
diff --git a/app/components/datasets/documents/assets/atSign.svg b/app/components/datasets/documents/assets/atSign.svg
new file mode 100644
index 0000000..49bf606
--- /dev/null
+++ b/app/components/datasets/documents/assets/atSign.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_2427_26665)">
+<path d="M10.6668 5.33333V8.66666C10.6668 9.19709 10.8776 9.7058 11.2526 10.0809C11.6277 10.4559 12.1364 10.6667 12.6668 10.6667C13.1973 10.6667 13.706 10.4559 14.0811 10.0809C14.4561 9.7058 14.6668 9.19709 14.6668 8.66666V7.99999C14.6667 6.49535 14.1577 5.03498 13.2224 3.85635C12.287 2.67772 10.9805 1.85014 9.51526 1.50819C8.04999 1.16624 6.51213 1.33002 5.15173 1.9729C3.79134 2.61579 2.68843 3.69996 2.02234 5.04914C1.35625 6.39832 1.16615 7.93315 1.48295 9.40407C1.79975 10.875 2.60482 12.1955 3.76726 13.1508C4.92969 14.1062 6.38112 14.6402 7.88555 14.6661C9.38997 14.692 10.8589 14.2082 12.0535 13.2933M10.6668 7.99999C10.6668 9.47275 9.47293 10.6667 8.00017 10.6667C6.52741 10.6667 5.3335 9.47275 5.3335 7.99999C5.3335 6.52723 6.52741 5.33333 8.00017 5.33333C9.47293 5.33333 10.6668 6.52723 10.6668 7.99999Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_2427_26665">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/datasets/documents/assets/bezierCurve.svg b/app/components/datasets/documents/assets/bezierCurve.svg
new file mode 100644
index 0000000..f2d1a3b
--- /dev/null
+++ b/app/components/datasets/documents/assets/bezierCurve.svg
@@ -0,0 +1,3 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M5.42857 3.5L2.57143 8.5M3 9.5H8.9999M9.42857 8.5L6.57143 3.5M1.8 10.5H2.2C2.48003 10.5 2.62004 10.5 2.727 10.4455C2.82108 10.3976 2.89757 10.3211 2.9455 10.227C3 10.12 3 9.98003 3 9.7V9.3C3 9.01997 3 8.87996 2.9455 8.773C2.89757 8.67892 2.82108 8.60243 2.727 8.5545C2.62004 8.5 2.48003 8.5 2.2 8.5H1.8C1.51997 8.5 1.37996 8.5 1.273 8.5545C1.17892 8.60243 1.10243 8.67892 1.0545 8.773C1 8.87996 1 9.01997 1 9.3V9.7C1 9.98003 1 10.12 1.0545 10.227C1.10243 10.3211 1.17892 10.3976 1.273 10.4455C1.37996 10.5 1.51997 10.5 1.8 10.5ZM9.8 10.5H10.2C10.48 10.5 10.62 10.5 10.727 10.4455C10.8211 10.3976 10.8976 10.3211 10.9455 10.227C11 10.12 11 9.98003 11 9.7V9.3C11 9.01997 11 8.87996 10.9455 8.773C10.8976 8.67892 10.8211 8.60243 10.727 8.5545C10.62 8.5 10.48 8.5 10.2 8.5H9.8C9.51997 8.5 9.37996 8.5 9.273 8.5545C9.17892 8.60243 9.10243 8.67892 9.0545 8.773C9 8.87996 9 9.01997 9 9.3V9.7C9 9.98003 9 10.12 9.0545 10.227C9.10243 10.3211 9.17892 10.3976 9.273 10.4455C9.37996 10.5 9.51997 10.5 9.8 10.5ZM5.8 3.5H6.2C6.48003 3.5 6.62004 3.5 6.727 3.4455C6.82108 3.39757 6.89757 3.32108 6.9455 3.227C7 3.12004 7 2.98003 7 2.7V2.3C7 2.01997 7 1.87996 6.9455 1.773C6.89757 1.67892 6.82108 1.60243 6.727 1.5545C6.62004 1.5 6.48003 1.5 6.2 1.5H5.8C5.51997 1.5 5.37996 1.5 5.273 1.5545C5.17892 1.60243 5.10243 1.67892 5.0545 1.773C5 1.87996 5 2.01997 5 2.3V2.7C5 2.98003 5 3.12004 5.0545 3.227C5.10243 3.32108 5.17892 3.39757 5.273 3.4455C5.37996 3.5 5.51997 3.5 5.8 3.5Z" stroke="#667085" stroke-linecap="round" stroke-linejoin="round" />
+ </svg>
diff --git a/app/components/datasets/documents/assets/bookOpen.svg b/app/components/datasets/documents/assets/bookOpen.svg
new file mode 100644
index 0000000..04a38fb
--- /dev/null
+++ b/app/components/datasets/documents/assets/bookOpen.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.00016 14L7.93346 13.8999C7.47037 13.2053 7.23882 12.858 6.9329 12.6065C6.66207 12.3839 6.35001 12.2169 6.01457 12.1151C5.63566 12 5.21823 12 4.38338 12H3.46683C2.72009 12 2.34672 12 2.06151 11.8547C1.81063 11.7268 1.60665 11.5229 1.47882 11.272C1.3335 10.9868 1.3335 10.6134 1.3335 9.86667V4.13333C1.3335 3.3866 1.3335 3.01323 1.47882 2.72801C1.60665 2.47713 1.81063 2.27316 2.06151 2.14532C2.34672 2 2.72009 2 3.46683 2H3.7335C5.22697 2 5.97371 2 6.54414 2.29065C7.0459 2.54631 7.45385 2.95426 7.70951 3.45603C8.00016 4.02646 8.00016 4.77319 8.00016 6.26667M8.00016 14V6.26667M8.00016 14L8.06687 13.8999C8.52996 13.2053 8.76151 12.858 9.06743 12.6065C9.33826 12.3839 9.65032 12.2169 9.98576 12.1151C10.3647 12 10.7821 12 11.6169 12H12.5335C13.2802 12 13.6536 12 13.9388 11.8547C14.1897 11.7268 14.3937 11.5229 14.5215 11.272C14.6668 10.9868 14.6668 10.6134 14.6668 9.86667V4.13333C14.6668 3.3866 14.6668 3.01323 14.5215 2.72801C14.3937 2.47713 14.1897 2.27316 13.9388 2.14532C13.6536 2 13.2802 2 12.5335 2H12.2668C10.7734 2 10.0266 2 9.45619 2.29065C8.95442 2.54631 8.54647 2.95426 8.29081 3.45603C8.00016 4.02646 8.00016 4.77319 8.00016 6.26667" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/documents/assets/briefcase.svg b/app/components/datasets/documents/assets/briefcase.svg
new file mode 100644
index 0000000..7ec1aa4
--- /dev/null
+++ b/app/components/datasets/documents/assets/briefcase.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.3335 14V4.66667C5.3335 4.04669 5.3335 3.7367 5.40164 3.48236C5.58658 2.79218 6.12567 2.25308 6.81586 2.06815C7.07019 2 7.38018 2 8.00016 2C8.62014 2 8.93013 2 9.18447 2.06815C9.87465 2.25308 10.4137 2.79218 10.5987 3.48236C10.6668 3.7367 10.6668 4.04669 10.6668 4.66667V14M3.46683 14H12.5335C13.2802 14 13.6536 14 13.9388 13.8547C14.1897 13.7268 14.3937 13.5229 14.5215 13.272C14.6668 12.9868 14.6668 12.6134 14.6668 11.8667V6.8C14.6668 6.05326 14.6668 5.6799 14.5215 5.39468C14.3937 5.1438 14.1897 4.93982 13.9388 4.81199C13.6536 4.66667 13.2802 4.66667 12.5335 4.66667H3.46683C2.72009 4.66667 2.34672 4.66667 2.06151 4.81199C1.81063 4.93982 1.60665 5.1438 1.47882 5.39468C1.3335 5.6799 1.3335 6.05326 1.3335 6.8V11.8667C1.3335 12.6134 1.3335 12.9868 1.47882 13.272C1.60665 13.5229 1.81063 13.7268 2.06151 13.8547C2.34672 14 2.72009 14 3.46683 14Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/documents/assets/cardLoading.svg b/app/components/datasets/documents/assets/cardLoading.svg
new file mode 100644
index 0000000..76ba4d7
--- /dev/null
+++ b/app/components/datasets/documents/assets/cardLoading.svg
@@ -0,0 +1,15 @@
+<svg width="232" height="120" viewBox="0 0 232 120" preserveAspectRatio="none" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect y="6" width="232" height="8" rx="3" fill="#EAECF0"/>
+<rect y="26" width="232" height="8" rx="3" fill="#EAECF0"/>
+<rect y="46" width="232" height="8" rx="3" fill="#EAECF0"/>
+<rect y="66" width="232" height="8" rx="3" fill="#EAECF0"/>
+<rect y="86" width="232" height="8" rx="3" fill="#EAECF0"/>
+<g clip-path="url(#clip0_2368_22256)">
+<rect y="106" width="256" height="8" rx="3" fill="#EAECF0"/>
+</g>
+<defs>
+<clipPath id="clip0_2368_22256">
+<rect width="232" height="20" fill="white" transform="translate(0 100)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/datasets/documents/assets/file.svg b/app/components/datasets/documents/assets/file.svg
new file mode 100644
index 0000000..32fb805
--- /dev/null
+++ b/app/components/datasets/documents/assets/file.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.33317 1.51306V4.26676C9.33317 4.64012 9.33317 4.82681 9.40583 4.96942C9.46975 5.09486 9.57173 5.19684 9.69718 5.26076C9.83978 5.33342 10.0265 5.33342 10.3998 5.33342H13.1535M10.6665 8.66671H5.33317M10.6665 11.3334H5.33317M6.6665 6.00004H5.33317M9.33317 1.33337H5.8665C4.7464 1.33337 4.18635 1.33337 3.75852 1.55136C3.3822 1.74311 3.07624 2.04907 2.88449 2.42539C2.6665 2.85322 2.6665 3.41327 2.6665 4.53337V11.4667C2.6665 12.5868 2.6665 13.1469 2.88449 13.5747C3.07624 13.951 3.3822 14.257 3.75852 14.4487C4.18635 14.6667 4.7464 14.6667 5.8665 14.6667H10.1332C11.2533 14.6667 11.8133 14.6667 12.2412 14.4487C12.6175 14.257 12.9234 13.951 13.1152 13.5747C13.3332 13.1469 13.3332 12.5868 13.3332 11.4667V5.33337L9.33317 1.33337Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/documents/assets/globe.svg b/app/components/datasets/documents/assets/globe.svg
new file mode 100644
index 0000000..457c924
--- /dev/null
+++ b/app/components/datasets/documents/assets/globe.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_2427_26661)">
+<path d="M1.79133 10.4301L3.06346 9.69574C3.13237 9.65596 3.21323 9.64214 3.29143 9.65678L5.79443 10.1252C6.00013 10.1637 6.19001 10.0054 6.18908 9.7961L6.17934 7.60301C6.17907 7.54342 6.19478 7.48486 6.22484 7.43341L7.48799 5.27085C7.55373 5.1583 7.54784 5.01776 7.47291 4.91111L5.34611 1.88383M12.667 3.23941C9.0003 5.00007 11.0002 7.3334 11.667 7.66674C12.9184 8.29232 14.6586 8.33337 14.6586 8.33337C14.664 8.22294 14.6668 8.11182 14.6668 8.00004C14.6668 4.31814 11.6821 1.33337 8.00016 1.33337C4.31826 1.33337 1.3335 4.31814 1.3335 8.00004C1.3335 11.6819 4.31826 14.6667 8.00016 14.6667C8.11194 14.6667 8.22307 14.664 8.3335 14.6585M11.172 14.6266L9.06083 9.06071L14.6267 11.1719L12.1586 12.1585L11.172 14.6266Z" stroke="#155EEF" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_2427_26661">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/datasets/documents/assets/graduationHat.svg b/app/components/datasets/documents/assets/graduationHat.svg
new file mode 100644
index 0000000..405a377
--- /dev/null
+++ b/app/components/datasets/documents/assets/graduationHat.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.3335 9.66667V7.66295C11.3335 7.5433 11.3335 7.48348 11.3153 7.43066C11.2992 7.38395 11.2729 7.34141 11.2383 7.30611C11.1992 7.26619 11.1457 7.23944 11.0387 7.18593L8.00016 5.66667M2.66683 6.33334V10.8711C2.66683 11.119 2.66683 11.243 2.70551 11.3515C2.7397 11.4475 2.79543 11.5343 2.86842 11.6054C2.95097 11.6858 3.06368 11.7374 3.28906 11.8408L7.55573 13.7963C7.71922 13.8712 7.80097 13.9087 7.88612 13.9235C7.96159 13.9366 8.03874 13.9366 8.1142 13.9235C8.19936 13.9087 8.28111 13.8712 8.44459 13.7963L12.7113 11.8408C12.9367 11.7374 13.0494 11.6858 13.1319 11.6054C13.2049 11.5343 13.2606 11.4475 13.2948 11.3515C13.3335 11.243 13.3335 11.119 13.3335 10.8711V6.33334M1.3335 5.66667L7.76165 2.45259C7.8491 2.40887 7.89283 2.387 7.9387 2.3784C7.97932 2.37078 8.02101 2.37078 8.06163 2.3784C8.1075 2.387 8.15122 2.40887 8.23868 2.45259L14.6668 5.66667L8.23868 8.88075C8.15122 8.92447 8.1075 8.94634 8.06163 8.95494C8.02101 8.96256 7.97932 8.96256 7.9387 8.95494C7.89283 8.94634 7.8491 8.92447 7.76165 8.88075L1.3335 5.66667Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/documents/assets/hitLoading.svg b/app/components/datasets/documents/assets/hitLoading.svg
new file mode 100644
index 0000000..713b6a2
--- /dev/null
+++ b/app/components/datasets/documents/assets/hitLoading.svg
@@ -0,0 +1,15 @@
+<svg width="252" height="120" viewBox="0 0 252 120" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect y="6" width="252" height="8" rx="3" fill="#EAECF0"/>
+<rect y="26" width="252" height="8" rx="3" fill="#EAECF0"/>
+<rect y="46" width="252" height="8" rx="3" fill="#EAECF0"/>
+<rect y="66" width="252" height="8" rx="3" fill="#EAECF0"/>
+<rect y="86" width="252" height="8" rx="3" fill="#EAECF0"/>
+<g clip-path="url(#clip0_1562_6752)">
+<rect y="106" width="256" height="8" rx="3" fill="#EAECF0"/>
+</g>
+<defs>
+<clipPath id="clip0_1562_6752">
+<rect width="252" height="20" fill="white" transform="translate(0 100)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/datasets/documents/assets/layoutRightClose.svg b/app/components/datasets/documents/assets/layoutRightClose.svg
new file mode 100644
index 0000000..b247d10
--- /dev/null
+++ b/app/components/datasets/documents/assets/layoutRightClose.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.12" d="M10 2H10.8C11.9201 2 12.4802 2 12.908 2.21799C13.2843 2.40973 13.5903 2.71569 13.782 3.09202C14 3.51984 14 4.0799 14 5.2V10.8C14 11.9201 14 12.4802 13.782 12.908C13.5903 13.2843 13.2843 13.5903 12.908 13.782C12.4802 14 11.9201 14 10.8 14H10V2Z" fill="#344054"/>
+<path d="M10 2V14M5.2 2H10.8C11.9201 2 12.4802 2 12.908 2.21799C13.2843 2.40973 13.5903 2.71569 13.782 3.09202C14 3.51984 14 4.0799 14 5.2V10.8C14 11.9201 14 12.4802 13.782 12.908C13.5903 13.2843 13.2843 13.5903 12.908 13.782C12.4802 14 11.9201 14 10.8 14H5.2C4.07989 14 3.51984 14 3.09202 13.782C2.71569 13.5903 2.40973 13.2843 2.21799 12.908C2 12.4802 2 11.9201 2 10.8V5.2C2 4.07989 2 3.51984 2.21799 3.09202C2.40973 2.71569 2.71569 2.40973 3.09202 2.21799C3.51984 2 4.0799 2 5.2 2Z" stroke="#344054" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/documents/assets/layoutRightShow.svg b/app/components/datasets/documents/assets/layoutRightShow.svg
new file mode 100644
index 0000000..889e469
--- /dev/null
+++ b/app/components/datasets/documents/assets/layoutRightShow.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.12" d="M10 2H10.8C11.9201 2 12.4802 2 12.908 2.21799C13.2843 2.40973 13.5903 2.71569 13.782 3.09202C14 3.51984 14 4.0799 14 5.2V10.8C14 11.9201 14 12.4802 13.782 12.908C13.5903 13.2843 13.2843 13.5903 12.908 13.782C12.4802 14 11.9201 14 10.8 14H10V2Z" fill="#004EEB"/>
+<path d="M10 2V14M5.2 2H10.8C11.9201 2 12.4802 2 12.908 2.21799C13.2843 2.40973 13.5903 2.71569 13.782 3.09202C14 3.51984 14 4.0799 14 5.2V10.8C14 11.9201 14 12.4802 13.782 12.908C13.5903 13.2843 13.2843 13.5903 12.908 13.782C12.4802 14 11.9201 14 10.8 14H5.2C4.07989 14 3.51984 14 3.09202 13.782C2.71569 13.5903 2.40973 13.2843 2.21799 12.908C2 12.4802 2 11.9201 2 10.8V5.2C2 4.07989 2 3.51984 2.21799 3.09202C2.40973 2.71569 2.71569 2.40973 3.09202 2.21799C3.51984 2 4.0799 2 5.2 2Z" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/documents/assets/messageTextCircle.svg b/app/components/datasets/documents/assets/messageTextCircle.svg
new file mode 100644
index 0000000..e2c508c
--- /dev/null
+++ b/app/components/datasets/documents/assets/messageTextCircle.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.33333 6.33333H8M5.33333 8.66667H10M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 8.7981 2.15582 9.5598 2.43871 10.2563C2.49285 10.3897 2.51992 10.4563 2.532 10.5102C2.54381 10.5629 2.54813 10.6019 2.54814 10.6559C2.54814 10.7111 2.53812 10.7713 2.51807 10.8916L2.12275 13.2635C2.08135 13.5119 2.06065 13.6361 2.09917 13.7259C2.13289 13.8045 2.19552 13.8671 2.27412 13.9008C2.36393 13.9393 2.48812 13.9186 2.73651 13.8772L5.10843 13.4819C5.22872 13.4619 5.28887 13.4519 5.34409 13.4519C5.3981 13.4519 5.43711 13.4562 5.48981 13.468C5.54369 13.4801 5.61035 13.5072 5.74366 13.5613C6.4402 13.8442 7.2019 14 8 14Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/documents/assets/normal.svg b/app/components/datasets/documents/assets/normal.svg
new file mode 100644
index 0000000..1d94adf
--- /dev/null
+++ b/app/components/datasets/documents/assets/normal.svg
@@ -0,0 +1,4 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.75 4.5C6.7165 4.5 7.5 3.7165 7.5 2.75C7.5 1.7835 6.7165 1 5.75 1C4.7835 1 4 1.7835 4 2.75C4 3.7165 4.7835 4.5 5.75 4.5Z" fill="#444CE7"/>
+<path d="M3.48775 4.314C3.36842 4.14172 3.30875 4.05558 3.24448 4.02712C3.18679 4.00157 3.12605 3.99844 3.06603 4.01794C2.99918 4.03965 2.94661 4.10099 2.84146 4.22367C2.41951 4.71598 2.13172 5.32705 2.03543 6.00009H2C1.72386 6.00009 1.5 5.77623 1.5 5.50009C1.5 5.31565 1.59961 5.15388 1.75036 5.06668C1.98939 4.9284 2.07107 4.62254 1.9328 4.38351C1.79453 4.14448 1.48867 4.0628 1.24964 4.20107C0.802591 4.45967 0.5 4.94425 0.5 5.50009C0.5 6.32852 1.17157 7.00009 2 7.00009H2.03545C2.14342 7.75422 2.49192 8.43113 2.99997 8.94961L2.99997 10.1117C2.99994 10.1712 2.99992 10.2424 3.00504 10.305C3.01097 10.3776 3.02619 10.4816 3.08171 10.5906C3.15362 10.7317 3.26835 10.8465 3.40948 10.9184C3.51845 10.9739 3.62245 10.9891 3.69505 10.9951C3.7577 11.0002 3.82881 11.0001 3.88836 11.0001H4.86154C4.92109 11.0001 4.99224 11.0002 5.05488 10.9951C5.12749 10.9891 5.23149 10.9739 5.34046 10.9184C5.48158 10.8465 5.59632 10.7317 5.66822 10.5906C5.72375 10.4816 5.73897 10.3776 5.7449 10.305C5.75002 10.2424 5.75 10.1712 5.74997 10.1117L5.74997 10.0001H6.24998L6.24997 10.1115C6.24995 10.1711 6.24992 10.2422 6.25504 10.3048C6.26097 10.3775 6.2762 10.4815 6.33172 10.5904C6.40363 10.7315 6.51836 10.8463 6.65948 10.9182C6.76846 10.9737 6.87245 10.9889 6.94506 10.9949C7.0077 11 7.0788 11 7.13835 10.9999H8.11159C8.17113 11 8.24229 11 8.30493 10.9949C8.37753 10.9889 8.48153 10.9737 8.5905 10.9182C8.73162 10.8463 8.84636 10.7315 8.91827 10.5904C8.97379 10.4815 8.98901 10.3775 8.99494 10.3048C9.00006 10.2422 9.00004 10.1711 9.00001 10.1115L9.00001 9.66299C9.55312 9.40029 10.0258 8.99721 10.3726 8.49993L10.6116 8.49994C10.6711 8.49996 10.7423 8.49999 10.8049 8.49487C10.8775 8.48893 10.9815 8.47371 11.0905 8.41819C11.2316 8.34628 11.3464 8.23155 11.4183 8.09043C11.4738 7.98145 11.489 7.87746 11.4949 7.80485C11.5001 7.74221 11.5 7.67109 11.5 7.61154V5.88181C11.5 5.82509 11.5001 5.75735 11.4954 5.69761C11.49 5.62851 11.4763 5.5294 11.4257 5.42448C11.352 5.27143 11.2285 5.14794 11.0755 5.07422C10.9705 5.02369 10.8714 5.00992 10.8023 5.00454C10.7577 5.00106 10.7087 5.0002 10.6631 4.99999C10.4953 4.64662 10.2702 4.32616 10 4.05044L10 3.51615C10 3.43874 10.0001 3.35111 9.99335 3.27574C9.98593 3.19252 9.96656 3.06385 9.88754 2.93633C9.78902 2.77733 9.63465 2.66089 9.4547 2.60984C9.31038 2.56889 9.18134 2.58561 9.09929 2.60134C9.02497 2.61559 8.94073 2.63969 8.8663 2.66098L8.78839 2.68324C8.6859 2.71252 8.63465 2.72716 8.59861 2.75356C8.5638 2.77904 8.54252 2.80415 8.52309 2.84266C8.50297 2.88255 8.49603 2.94339 8.48215 3.06506C8.32585 4.43546 7.16224 5.5 5.75 5.5C4.81225 5.5 3.98413 5.03063 3.48775 4.314Z" fill="#444CE7"/>
+</svg>
diff --git a/app/components/datasets/documents/assets/star.svg b/app/components/datasets/documents/assets/star.svg
new file mode 100644
index 0000000..3ffda57
--- /dev/null
+++ b/app/components/datasets/documents/assets/star.svg
@@ -0,0 +1,11 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6 0.5C6.27614 0.5 6.5 0.723858 6.5 1V2C6.5 2.27614 6.27614 2.5 6 2.5C5.72386 2.5 5.5 2.27614 5.5 2V1C5.5 0.723858 5.72386 0.5 6 0.5Z" fill="#FB6514"/>
+<path d="M2.81791 2.11092C2.62265 1.91566 2.30606 1.91566 2.1108 2.11092C1.91554 2.30619 1.91554 2.62277 2.1108 2.81803L2.81791 3.52514C3.01317 3.7204 3.32975 3.7204 3.52502 3.52514C3.72028 3.32988 3.72028 3.01329 3.52502 2.81803L2.81791 2.11092Z" fill="#FB6514"/>
+<path d="M0.5 6C0.5 5.72386 0.723858 5.5 1 5.5H2C2.27614 5.5 2.5 5.72386 2.5 6C2.5 6.27614 2.27614 6.5 2 6.5H1C0.723858 6.5 0.5 6.27614 0.5 6Z" fill="#FB6514"/>
+<path d="M10 5.5C9.72386 5.5 9.5 5.72386 9.5 6C9.5 6.27614 9.72386 6.5 10 6.5H11C11.2761 6.5 11.5 6.27614 11.5 6C11.5 5.72386 11.2761 5.5 11 5.5H10Z" fill="#FB6514"/>
+<path d="M9.18192 8.47482C8.98666 8.27955 8.67008 8.27955 8.47482 8.47482C8.27955 8.67008 8.27955 8.98666 8.47482 9.18192L9.18192 9.88903C9.37718 10.0843 9.69377 10.0843 9.88903 9.88903C10.0843 9.69377 10.0843 9.37718 9.88903 9.18192L9.18192 8.47482Z" fill="#FB6514"/>
+<path d="M9.88903 2.81803C10.0843 2.62277 10.0843 2.30619 9.88903 2.11092C9.69377 1.91566 9.37718 1.91566 9.18192 2.11092L8.47482 2.81803C8.27955 3.01329 8.27955 3.32988 8.47482 3.52514C8.67008 3.7204 8.98666 3.7204 9.18192 3.52514L9.88903 2.81803Z" fill="#FB6514"/>
+<path d="M6 9.5C6.27614 9.5 6.5 9.72386 6.5 10V11C6.5 11.2761 6.27614 11.5 6 11.5C5.72386 11.5 5.5 11.2761 5.5 11V10C5.5 9.72386 5.72386 9.5 6 9.5Z" fill="#FB6514"/>
+<path d="M3.52502 9.18192C3.72028 8.98666 3.72028 8.67008 3.52502 8.47482C3.32975 8.27955 3.01317 8.27955 2.81791 8.47482L2.1108 9.18192C1.91554 9.37718 1.91554 9.69377 2.1108 9.88903C2.30606 10.0843 2.62265 10.0843 2.81791 9.88903L3.52502 9.18192Z" fill="#FB6514"/>
+<path d="M6.44837 3.27869C6.36413 3.10804 6.19032 3 6.00001 3C5.8097 3 5.6359 3.10804 5.55166 3.27869L4.89538 4.60823L3.4277 4.82276C3.23942 4.85028 3.08308 4.98228 3.02439 5.16328C2.9657 5.34429 3.01484 5.54291 3.15115 5.67568L4.21275 6.70968L3.96221 8.17048C3.93004 8.35807 4.00716 8.54766 4.16115 8.65953C4.31514 8.77139 4.51928 8.78613 4.68774 8.69754L6.00001 8.00742L7.31229 8.69754C7.48075 8.78613 7.68489 8.77139 7.83888 8.65953C7.99287 8.54766 8.06999 8.35807 8.03782 8.17048L7.78728 6.70968L8.84888 5.67568C8.98519 5.54291 9.03433 5.34429 8.97564 5.16328C8.91695 4.98228 8.76061 4.85028 8.57233 4.82276L7.10465 4.60823L6.44837 3.27869Z" fill="#FB6514"/>
+</svg>
diff --git a/app/components/datasets/documents/assets/target.svg b/app/components/datasets/documents/assets/target.svg
new file mode 100644
index 0000000..cb74c9e
--- /dev/null
+++ b/app/components/datasets/documents/assets/target.svg
@@ -0,0 +1,10 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <g clip-path="url(#clip0_1745_6117)">
+ <path d="M7.99998 4V2.5L9.49998 1L9.99998 2L11 2.5L9.49998 4H7.99998ZM7.99998 4L5.99999 5.99997M11 6C11 8.76142 8.76142 11 6 11C3.23858 11 1 8.76142 1 6C1 3.23858 3.23858 1 6 1M8.5 6C8.5 7.38071 7.38071 8.5 6 8.5C4.61929 8.5 3.5 7.38071 3.5 6C3.5 4.61929 4.61929 3.5 6 3.5" stroke="#667085" stroke-linecap="round" stroke-linejoin="round" />
+ </g>
+ <defs>
+ <clipPath id="clip0_1745_6117">
+ <rect width="12" height="12" fill="white" />
+ </clipPath>
+ </defs>
+ </svg>
diff --git a/app/components/datasets/documents/assets/typeSquare.svg b/app/components/datasets/documents/assets/typeSquare.svg
new file mode 100644
index 0000000..d1588e8
--- /dev/null
+++ b/app/components/datasets/documents/assets/typeSquare.svg
@@ -0,0 +1,3 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M4 3.5H8M6 3.5V8.5M3.9 10.5H8.1C8.94008 10.5 9.36012 10.5 9.68099 10.3365C9.96323 10.1927 10.1927 9.96323 10.3365 9.68099C10.5 9.36012 10.5 8.94008 10.5 8.1V3.9C10.5 3.05992 10.5 2.63988 10.3365 2.31901C10.1927 2.03677 9.96323 1.8073 9.68099 1.66349C9.36012 1.5 8.94008 1.5 8.1 1.5H3.9C3.05992 1.5 2.63988 1.5 2.31901 1.66349C2.03677 1.8073 1.8073 2.03677 1.66349 2.31901C1.5 2.63988 1.5 3.05992 1.5 3.9V8.1C1.5 8.94008 1.5 9.36012 1.66349 9.68099C1.8073 9.96323 2.03677 10.1927 2.31901 10.3365C2.63988 10.5 3.05992 10.5 3.9 10.5Z" stroke="#667085" stroke-linecap="round" stroke-linejoin="round" />
+ </svg>
diff --git a/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx b/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx
new file mode 100644
index 0000000..90bdb70
--- /dev/null
+++ b/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx
@@ -0,0 +1,109 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import {
+ useCSVDownloader,
+} from 'react-papaparse'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { Download02 as DownloadIcon } from '@/app/components/base/icons/src/vender/solid/general'
+import { ChunkingMode } from '@/models/datasets'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+
+const CSV_TEMPLATE_QA_EN = [
+ ['question', 'answer'],
+ ['question1', 'answer1'],
+ ['question2', 'answer2'],
+]
+const CSV_TEMPLATE_QA_CN = [
+ ['闂', '绛旀'],
+ ['闂 1', '绛旀 1'],
+ ['闂 2', '绛旀 2'],
+]
+const CSV_TEMPLATE_EN = [
+ ['segment content'],
+ ['content1'],
+ ['content2'],
+]
+const CSV_TEMPLATE_CN = [
+ ['鍒嗘鍐呭'],
+ ['鍐呭 1'],
+ ['鍐呭 2'],
+]
+
+const CSVDownload: FC<{ docForm: ChunkingMode }> = ({ docForm }) => {
+ const { t } = useTranslation()
+ const { locale } = useContext(I18n)
+ const { CSVDownloader, Type } = useCSVDownloader()
+
+ const getTemplate = () => {
+ if (locale === LanguagesSupported[1]) {
+ if (docForm === ChunkingMode.qa)
+ return CSV_TEMPLATE_QA_CN
+ return CSV_TEMPLATE_CN
+ }
+ if (docForm === ChunkingMode.qa)
+ return CSV_TEMPLATE_QA_EN
+ return CSV_TEMPLATE_EN
+ }
+
+ return (
+ <div className='mt-6'>
+ <div className='text-sm font-medium text-gray-900'>{t('share.generation.csvStructureTitle')}</div>
+ <div className='mt-2 max-h-[500px] overflow-auto'>
+ {docForm === ChunkingMode.qa && (
+ <table className='w-full table-fixed border-separate border-spacing-0 rounded-lg border border-gray-200 text-xs'>
+ <thead className='text-gray-500'>
+ <tr>
+ <td className='h-9 border-b border-gray-200 pl-3 pr-2'>{t('datasetDocuments.list.batchModal.question')}</td>
+ <td className='h-9 border-b border-gray-200 pl-3 pr-2'>{t('datasetDocuments.list.batchModal.answer')}</td>
+ </tr>
+ </thead>
+ <tbody className='text-gray-700'>
+ <tr>
+ <td className='h-9 border-b border-gray-100 pl-3 pr-2 text-[13px]'>{t('datasetDocuments.list.batchModal.question')} 1</td>
+ <td className='h-9 border-b border-gray-100 pl-3 pr-2 text-[13px]'>{t('datasetDocuments.list.batchModal.answer')} 1</td>
+ </tr>
+ <tr>
+ <td className='h-9 pl-3 pr-2 text-[13px]'>{t('datasetDocuments.list.batchModal.question')} 2</td>
+ <td className='h-9 pl-3 pr-2 text-[13px]'>{t('datasetDocuments.list.batchModal.answer')} 2</td>
+ </tr>
+ </tbody>
+ </table>
+ )}
+ {docForm === ChunkingMode.text && (
+ <table className='w-full table-fixed border-separate border-spacing-0 rounded-lg border border-gray-200 text-xs'>
+ <thead className='text-gray-500'>
+ <tr>
+ <td className='h-9 border-b border-gray-200 pl-3 pr-2'>{t('datasetDocuments.list.batchModal.contentTitle')}</td>
+ </tr>
+ </thead>
+ <tbody className='text-gray-700'>
+ <tr>
+ <td className='h-9 border-b border-gray-100 pl-3 pr-2 text-[13px]'>{t('datasetDocuments.list.batchModal.content')} 1</td>
+ </tr>
+ <tr>
+ <td className='h-9 pl-3 pr-2 text-[13px]'>{t('datasetDocuments.list.batchModal.content')} 2</td>
+ </tr>
+ </tbody>
+ </table>
+ )}
+ </div>
+ <CSVDownloader
+ className="mt-2 block cursor-pointer"
+ type={Type.Link}
+ filename={'template'}
+ bom={true}
+ data={getTemplate()}
+ >
+ <div className='flex h-[18px] items-center space-x-1 text-xs font-medium text-text-accent'>
+ <DownloadIcon className='mr-1 h-3 w-3' />
+ {t('datasetDocuments.list.batchModal.template')}
+ </div>
+ </CSVDownloader>
+ </div>
+
+ )
+}
+export default React.memo(CSVDownload)
diff --git a/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx b/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx
new file mode 100644
index 0000000..471bf7b
--- /dev/null
+++ b/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx
@@ -0,0 +1,128 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
+import {
+ RiDeleteBinLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import cn from '@/utils/classnames'
+import { Csv as CSVIcon } from '@/app/components/base/icons/src/public/files'
+import { ToastContext } from '@/app/components/base/toast'
+import Button from '@/app/components/base/button'
+
+export type Props = {
+ file: File | undefined
+ updateFile: (file?: File) => void
+}
+
+const CSVUploader: FC<Props> = ({
+ file,
+ updateFile,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const [dragging, setDragging] = useState(false)
+ const dropRef = useRef<HTMLDivElement>(null)
+ const dragRef = useRef<HTMLDivElement>(null)
+ const fileUploader = useRef<HTMLInputElement>(null)
+
+ const handleDragEnter = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ e.target !== dragRef.current && setDragging(true)
+ }
+ const handleDragOver = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }
+ const handleDragLeave = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ e.target === dragRef.current && setDragging(false)
+ }
+ const handleDrop = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+ setDragging(false)
+ if (!e.dataTransfer)
+ return
+ const files = [...e.dataTransfer.files]
+ if (files.length > 1) {
+ notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.count') })
+ return
+ }
+ updateFile(files[0])
+ }
+ const selectHandle = () => {
+ if (fileUploader.current)
+ fileUploader.current.click()
+ }
+ const removeFile = () => {
+ if (fileUploader.current)
+ fileUploader.current.value = ''
+ updateFile()
+ }
+ const fileChangeHandle = (e: React.ChangeEvent<HTMLInputElement>) => {
+ const currentFile = e.target.files?.[0]
+ updateFile(currentFile)
+ }
+
+ useEffect(() => {
+ dropRef.current?.addEventListener('dragenter', handleDragEnter)
+ dropRef.current?.addEventListener('dragover', handleDragOver)
+ dropRef.current?.addEventListener('dragleave', handleDragLeave)
+ dropRef.current?.addEventListener('drop', handleDrop)
+ return () => {
+ dropRef.current?.removeEventListener('dragenter', handleDragEnter)
+ dropRef.current?.removeEventListener('dragover', handleDragOver)
+ dropRef.current?.removeEventListener('dragleave', handleDragLeave)
+ dropRef.current?.removeEventListener('drop', handleDrop)
+ }
+ }, [])
+
+ return (
+ <div className='mt-6'>
+ <input
+ ref={fileUploader}
+ style={{ display: 'none' }}
+ type="file"
+ id="fileUploader"
+ accept='.csv'
+ onChange={fileChangeHandle}
+ />
+ <div ref={dropRef}>
+ {!file && (
+ <div className={cn('flex h-20 items-center rounded-xl border border-dashed border-gray-200 bg-gray-50 text-sm font-normal', dragging && 'border border-[#B2CCFF] bg-[#F5F8FF]')}>
+ <div className='flex w-full items-center justify-center space-x-2'>
+ <CSVIcon className="shrink-0" />
+ <div className='text-gray-500'>
+ {t('datasetDocuments.list.batchModal.csvUploadTitle')}
+ <span className='cursor-pointer text-primary-400' onClick={selectHandle}>{t('datasetDocuments.list.batchModal.browse')}</span>
+ </div>
+ </div>
+ {dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />}
+ </div>
+ )}
+ {file && (
+ <div className={cn('group flex h-20 items-center rounded-xl border border-gray-200 bg-gray-50 px-6 text-sm font-normal', 'hover:border-[#B2CCFF] hover:bg-[#F5F8FF]')}>
+ <CSVIcon className="shrink-0" />
+ <div className='ml-2 flex w-0 grow'>
+ <span className='max-w-[calc(100%_-_30px)] overflow-hidden text-ellipsis whitespace-nowrap text-gray-800'>{file.name.replace(/.csv$/, '')}</span>
+ <span className='shrink-0 text-gray-500'>.csv</span>
+ </div>
+ <div className='hidden items-center group-hover:flex'>
+ <Button onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.change')}</Button>
+ <div className='mx-2 h-4 w-px bg-gray-200' />
+ <div className='cursor-pointer p-2' onClick={removeFile}>
+ <RiDeleteBinLine className='h-4 w-4 text-gray-500' />
+ </div>
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(CSVUploader)
diff --git a/app/components/datasets/documents/detail/batch-modal/index.tsx b/app/components/datasets/documents/detail/batch-modal/index.tsx
new file mode 100644
index 0000000..775d755
--- /dev/null
+++ b/app/components/datasets/documents/detail/batch-modal/index.tsx
@@ -0,0 +1,66 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import CSVUploader from './csv-uploader'
+import CSVDownloader from './csv-downloader'
+import Button from '@/app/components/base/button'
+import Modal from '@/app/components/base/modal'
+import type { ChunkingMode } from '@/models/datasets'
+import { noop } from 'lodash-es'
+
+export type IBatchModalProps = {
+ isShow: boolean
+ docForm: ChunkingMode
+ onCancel: () => void
+ onConfirm: (file: File) => void
+}
+
+const BatchModal: FC<IBatchModalProps> = ({
+ isShow,
+ docForm,
+ onCancel,
+ onConfirm,
+}) => {
+ const { t } = useTranslation()
+ const [currentCSV, setCurrentCSV] = useState<File>()
+ const handleFile = (file?: File) => setCurrentCSV(file)
+
+ const handleSend = () => {
+ if (!currentCSV)
+ return
+ onCancel()
+ onConfirm(currentCSV)
+ }
+
+ useEffect(() => {
+ if (!isShow)
+ setCurrentCSV(undefined)
+ }, [isShow])
+
+ return (
+ <Modal isShow={isShow} onClose={noop} className='!max-w-[520px] !rounded-xl px-8 py-6'>
+ <div className='relative pb-1 text-xl font-medium leading-[30px] text-gray-900'>{t('datasetDocuments.list.batchModal.title')}</div>
+ <div className='absolute right-4 top-4 cursor-pointer p-2' onClick={onCancel}>
+ <RiCloseLine className='h-4 w-4 text-gray-500' />
+ </div>
+ <CSVUploader
+ file={currentCSV}
+ updateFile={handleFile}
+ />
+ <CSVDownloader
+ docForm={docForm}
+ />
+ <div className='mt-[28px] flex justify-end pt-6'>
+ <Button className='mr-2' onClick={onCancel}>
+ {t('datasetDocuments.list.batchModal.cancel')}
+ </Button>
+ <Button variant="primary" onClick={handleSend} disabled={!currentCSV}>
+ {t('datasetDocuments.list.batchModal.run')}
+ </Button>
+ </div>
+ </Modal>
+ )
+}
+export default React.memo(BatchModal)
diff --git a/app/components/datasets/documents/detail/completed/child-segment-detail.tsx b/app/components/datasets/documents/detail/completed/child-segment-detail.tsx
new file mode 100644
index 0000000..81afed9
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/child-segment-detail.tsx
@@ -0,0 +1,134 @@
+import React, { type FC, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiCloseLine,
+ RiCollapseDiagonalLine,
+ RiExpandDiagonalLine,
+} from '@remixicon/react'
+import ActionButtons from './common/action-buttons'
+import ChunkContent from './common/chunk-content'
+import Dot from './common/dot'
+import { SegmentIndexTag } from './common/segment-index-tag'
+import { useSegmentListContext } from './index'
+import type { ChildChunkDetail, ChunkingMode } from '@/models/datasets'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { formatNumber } from '@/utils/format'
+import classNames from '@/utils/classnames'
+import Divider from '@/app/components/base/divider'
+import { formatTime } from '@/utils/time'
+
+type IChildSegmentDetailProps = {
+ chunkId: string
+ childChunkInfo?: Partial<ChildChunkDetail> & { id: string }
+ onUpdate: (segmentId: string, childChunkId: string, content: string) => void
+ onCancel: () => void
+ docForm: ChunkingMode
+}
+
+/**
+ * Show all the contents of the segment
+ */
+const ChildSegmentDetail: FC<IChildSegmentDetailProps> = ({
+ chunkId,
+ childChunkInfo,
+ onUpdate,
+ onCancel,
+ docForm,
+}) => {
+ const { t } = useTranslation()
+ const [content, setContent] = useState(childChunkInfo?.content || '')
+ const { eventEmitter } = useEventEmitterContextContext()
+ const [loading, setLoading] = useState(false)
+ const fullScreen = useSegmentListContext(s => s.fullScreen)
+ const toggleFullScreen = useSegmentListContext(s => s.toggleFullScreen)
+
+ eventEmitter?.useSubscription((v) => {
+ if (v === 'update-child-segment')
+ setLoading(true)
+ if (v === 'update-child-segment-done')
+ setLoading(false)
+ })
+
+ const handleCancel = () => {
+ onCancel()
+ }
+
+ const handleSave = () => {
+ onUpdate(chunkId, childChunkInfo?.id || '', content)
+ }
+
+ const wordCountText = useMemo(() => {
+ const count = content.length
+ return `${formatNumber(count)} ${t('datasetDocuments.segment.characters', { count })}`
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [content.length])
+
+ const EditTimeText = useMemo(() => {
+ const timeText = formatTime({
+ date: (childChunkInfo?.updated_at ?? 0) * 1000,
+ dateFormat: 'MM/DD/YYYY h:mm:ss',
+ })
+ return `${t('datasetDocuments.segment.editedAt')} ${timeText}`
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [childChunkInfo?.updated_at])
+
+ return (
+ <div className={'flex h-full flex-col'}>
+ <div className={classNames('flex items-center justify-between', fullScreen ? 'py-3 pr-4 pl-6 border border-divider-subtle' : 'pt-3 pr-3 pl-4')}>
+ <div className='flex flex-col'>
+ <div className='system-xl-semibold text-text-primary'>{t('datasetDocuments.segment.editChildChunk')}</div>
+ <div className='flex items-center gap-x-2'>
+ <SegmentIndexTag positionId={childChunkInfo?.position || ''} labelPrefix={t('datasetDocuments.segment.childChunk') as string} />
+ <Dot />
+ <span className='system-xs-medium text-text-tertiary'>{wordCountText}</span>
+ <Dot />
+ <span className='system-xs-medium text-text-tertiary'>
+ {EditTimeText}
+ </span>
+ </div>
+ </div>
+ <div className='flex items-center'>
+ {fullScreen && (
+ <>
+ <ActionButtons
+ handleCancel={handleCancel}
+ handleSave={handleSave}
+ loading={loading}
+ isChildChunk={true}
+ />
+ <Divider type='vertical' className='ml-4 mr-2 h-3.5 bg-divider-regular' />
+ </>
+ )}
+ <div className='mr-1 flex h-8 w-8 cursor-pointer items-center justify-center p-1.5' onClick={toggleFullScreen}>
+ {fullScreen ? <RiCollapseDiagonalLine className='h-4 w-4 text-text-tertiary' /> : <RiExpandDiagonalLine className='h-4 w-4 text-text-tertiary' />}
+ </div>
+ <div className='flex h-8 w-8 cursor-pointer items-center justify-center p-1.5' onClick={onCancel}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ <div className={classNames('flex grow w-full', fullScreen ? 'flex-row justify-center px-6 pt-6' : 'py-3 px-4')}>
+ <div className={classNames('break-all overflow-hidden whitespace-pre-line h-full', fullScreen ? 'w-1/2' : 'w-full')}>
+ <ChunkContent
+ docForm={docForm}
+ question={content}
+ onQuestionChange={content => setContent(content)}
+ isEditMode={true}
+ />
+ </div>
+ </div>
+ {!fullScreen && (
+ <div className='flex items-center justify-end border-t-[1px] border-t-divider-subtle p-4 pt-3'>
+ <ActionButtons
+ handleCancel={handleCancel}
+ handleSave={handleSave}
+ loading={loading}
+ isChildChunk={true}
+ />
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default React.memo(ChildSegmentDetail)
diff --git a/app/components/datasets/documents/detail/completed/child-segment-list.tsx b/app/components/datasets/documents/detail/completed/child-segment-list.tsx
new file mode 100644
index 0000000..be5fc8b
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/child-segment-list.tsx
@@ -0,0 +1,195 @@
+import { type FC, useMemo, useState } from 'react'
+import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { EditSlice } from '../../../formatted-text/flavours/edit-slice'
+import { useDocumentContext } from '../index'
+import { FormattedText } from '../../../formatted-text/formatted'
+import Empty from './common/empty'
+import FullDocListSkeleton from './skeleton/full-doc-list-skeleton'
+import { useSegmentListContext } from './index'
+import type { ChildChunkDetail } from '@/models/datasets'
+import Input from '@/app/components/base/input'
+import classNames from '@/utils/classnames'
+import Divider from '@/app/components/base/divider'
+import { formatNumber } from '@/utils/format'
+
+type IChildSegmentCardProps = {
+ childChunks: ChildChunkDetail[]
+ parentChunkId: string
+ handleInputChange?: (value: string) => void
+ handleAddNewChildChunk?: (parentChunkId: string) => void
+ enabled: boolean
+ onDelete?: (segId: string, childChunkId: string) => Promise<void>
+ onClickSlice?: (childChunk: ChildChunkDetail) => void
+ total?: number
+ inputValue?: string
+ onClearFilter?: () => void
+ isLoading?: boolean
+ focused?: boolean
+}
+
+const ChildSegmentList: FC<IChildSegmentCardProps> = ({
+ childChunks,
+ parentChunkId,
+ handleInputChange,
+ handleAddNewChildChunk,
+ enabled,
+ onDelete,
+ onClickSlice,
+ total,
+ inputValue,
+ onClearFilter,
+ isLoading,
+ focused = false,
+}) => {
+ const { t } = useTranslation()
+ const parentMode = useDocumentContext(s => s.parentMode)
+ const currChildChunk = useSegmentListContext(s => s.currChildChunk)
+
+ const [collapsed, setCollapsed] = useState(true)
+
+ const toggleCollapse = () => {
+ setCollapsed(!collapsed)
+ }
+
+ const isParagraphMode = useMemo(() => {
+ return parentMode === 'paragraph'
+ }, [parentMode])
+
+ const isFullDocMode = useMemo(() => {
+ return parentMode === 'full-doc'
+ }, [parentMode])
+
+ const contentOpacity = useMemo(() => {
+ return (enabled || focused) ? '' : 'opacity-50 group-hover/card:opacity-100'
+ }, [enabled, focused])
+
+ const totalText = useMemo(() => {
+ const isSearch = inputValue !== '' && isFullDocMode
+ if (!isSearch) {
+ const text = isFullDocMode
+ ? !total
+ ? '--'
+ : formatNumber(total)
+ : formatNumber(childChunks.length)
+ const count = isFullDocMode
+ ? text === '--'
+ ? 0
+ : total
+ : childChunks.length
+ return `${text} ${t('datasetDocuments.segment.childChunks', { count })}`
+ }
+ else {
+ const text = !total ? '--' : formatNumber(total)
+ const count = text === '--' ? 0 : total
+ return `${count} ${t('datasetDocuments.segment.searchResults', { count })}`
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isFullDocMode, total, childChunks.length, inputValue])
+
+ return (
+ <div className={classNames(
+ 'flex flex-col',
+ contentOpacity,
+ isParagraphMode ? 'pt-1 pb-2' : 'px-3 grow',
+ (isFullDocMode && isLoading) && 'overflow-y-hidden',
+ )}>
+ {isFullDocMode ? <Divider type='horizontal' className='my-1 h-[1px] bg-divider-subtle' /> : null}
+ <div className={classNames('flex items-center justify-between', isFullDocMode ? 'pt-2 pb-3 sticky -top-2 left-0 bg-background-default' : '')}>
+ <div className={classNames(
+ 'h-7 flex items-center pl-1 pr-3 rounded-lg',
+ isParagraphMode && 'cursor-pointer',
+ (isParagraphMode && collapsed) && 'bg-dataset-child-chunk-expand-btn-bg',
+ isFullDocMode && 'pl-0',
+ )}
+ onClick={(event) => {
+ event.stopPropagation()
+ toggleCollapse()
+ }}
+ >
+ {
+ isParagraphMode
+ ? collapsed
+ ? (
+ <RiArrowRightSLine className='mr-0.5 h-4 w-4 text-text-secondary opacity-50' />
+ )
+ : (<RiArrowDownSLine className='mr-0.5 h-4 w-4 text-text-secondary' />)
+ : null
+ }
+ <span className='system-sm-semibold-uppercase text-text-secondary'>{totalText}</span>
+ <span className={classNames('text-text-quaternary text-xs font-medium pl-1.5', isParagraphMode ? 'hidden group-hover/card:inline-block' : '')}>路</span>
+ <button
+ type='button'
+ className={classNames(
+ 'px-1.5 py-1 text-components-button-secondary-accent-text system-xs-semibold-uppercase',
+ isParagraphMode ? 'hidden group-hover/card:inline-block' : '',
+ (isFullDocMode && isLoading) ? 'text-components-button-secondary-accent-text-disabled' : '',
+ )}
+ onClick={(event) => {
+ event.stopPropagation()
+ handleAddNewChildChunk?.(parentChunkId)
+ }}
+ disabled={isLoading}
+ >
+ {t('common.operation.add')}
+ </button>
+ </div>
+ {isFullDocMode
+ ? <Input
+ showLeftIcon
+ showClearIcon
+ wrapperClassName='!w-52'
+ value={inputValue}
+ onChange={e => handleInputChange?.(e.target.value)}
+ onClear={() => handleInputChange?.('')}
+ />
+ : null}
+ </div>
+ {isLoading ? <FullDocListSkeleton /> : null}
+ {((isFullDocMode && !isLoading) || !collapsed)
+ ? <div className={classNames('flex gap-x-0.5', isFullDocMode ? 'grow mb-6' : 'items-center')}>
+ {isParagraphMode && (
+ <div className='self-stretch'>
+ <Divider type='vertical' className='mx-[7px] w-[2px] bg-text-accent-secondary' />
+ </div>
+ )}
+ {childChunks.length > 0
+ ? <FormattedText className={classNames('w-full !leading-6 flex flex-col', isParagraphMode ? 'gap-y-2' : 'gap-y-3')}>
+ {childChunks.map((childChunk) => {
+ const edited = childChunk.updated_at !== childChunk.created_at
+ const focused = currChildChunk?.childChunkInfo?.id === childChunk.id
+ return <EditSlice
+ key={childChunk.id}
+ label={`C-${childChunk.position}${edited ? ` 路 ${t('datasetDocuments.segment.edited')}` : ''}`}
+ text={childChunk.content}
+ onDelete={() => onDelete?.(childChunk.segment_id, childChunk.id)}
+ labelClassName={focused ? 'bg-state-accent-solid text-text-primary-on-surface' : ''}
+ labelInnerClassName={'text-[10px] font-semibold align-bottom leading-6'}
+ contentClassName={classNames('!leading-6', focused ? 'bg-state-accent-hover-alt text-text-primary' : 'text-text-secondary')}
+ showDivider={false}
+ onClick={(e) => {
+ e.stopPropagation()
+ onClickSlice?.(childChunk)
+ }}
+ offsetOptions={({ rects }) => {
+ return {
+ mainAxis: isFullDocMode ? -rects.floating.width : 12 - rects.floating.width,
+ crossAxis: (20 - rects.floating.height) / 2,
+ }
+ }}
+ />
+ })}
+ </FormattedText>
+ : inputValue !== ''
+ ? <div className='h-full w-full'>
+ <Empty onClearFilter={onClearFilter!} />
+ </div>
+ : null
+ }
+ </div>
+ : null}
+ </div>
+ )
+}
+
+export default ChildSegmentList
diff --git a/app/components/datasets/documents/detail/completed/common/action-buttons.tsx b/app/components/datasets/documents/detail/completed/common/action-buttons.tsx
new file mode 100644
index 0000000..fd0a072
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/action-buttons.tsx
@@ -0,0 +1,86 @@
+import React, { type FC, useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useKeyPress } from 'ahooks'
+import { useDocumentContext } from '../../index'
+import Button from '@/app/components/base/button'
+import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '@/app/components/workflow/utils'
+
+type IActionButtonsProps = {
+ handleCancel: () => void
+ handleSave: () => void
+ loading: boolean
+ actionType?: 'edit' | 'add'
+ handleRegeneration?: () => void
+ isChildChunk?: boolean
+}
+
+const ActionButtons: FC<IActionButtonsProps> = ({
+ handleCancel,
+ handleSave,
+ loading,
+ actionType = 'edit',
+ handleRegeneration,
+ isChildChunk = false,
+}) => {
+ const { t } = useTranslation()
+ const mode = useDocumentContext(s => s.mode)
+ const parentMode = useDocumentContext(s => s.parentMode)
+
+ useKeyPress(['esc'], (e) => {
+ e.preventDefault()
+ handleCancel()
+ })
+
+ useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.s`, (e) => {
+ e.preventDefault()
+ if (loading)
+ return
+ handleSave()
+ },
+ { exactMatch: true, useCapture: true })
+
+ const isParentChildParagraphMode = useMemo(() => {
+ return mode === 'hierarchical' && parentMode === 'paragraph'
+ }, [mode, parentMode])
+
+ return (
+ <div className='flex items-center gap-x-2'>
+ <Button
+ onClick={handleCancel}
+ >
+ <div className='flex items-center gap-x-1'>
+ <span className='system-sm-medium text-components-button-secondary-text'>{t('common.operation.cancel')}</span>
+ <span className='system-kbd rounded-[4px] bg-components-kbd-bg-gray px-[1px] text-text-tertiary'>ESC</span>
+ </div>
+ </Button>
+ {(isParentChildParagraphMode && actionType === 'edit' && !isChildChunk)
+ ? <Button
+ onClick={handleRegeneration}
+ disabled={loading}
+ >
+ <span className='system-sm-medium text-components-button-secondary-text'>
+ {t('common.operation.saveAndRegenerate')}
+ </span>
+ </Button>
+ : null
+ }
+ <Button
+ variant='primary'
+ onClick={handleSave}
+ disabled={loading}
+ >
+ <div className='flex items-center gap-x-1'>
+ <span className='text-components-button-primary-text'>{t('common.operation.save')}</span>
+ <div className='flex items-center gap-x-0.5'>
+ <span className='system-kbd h-4 w-4 rounded-[4px] bg-components-kbd-bg-white capitalize text-text-primary-on-surface'>{getKeyboardKeyNameBySystem('ctrl')}</span>
+ <span className='system-kbd h-4 w-4 rounded-[4px] bg-components-kbd-bg-white text-text-primary-on-surface'>S</span>
+ </div>
+ </div>
+ </Button>
+ </div>
+ )
+}
+
+ActionButtons.displayName = 'ActionButtons'
+
+export default React.memo(ActionButtons)
diff --git a/app/components/datasets/documents/detail/completed/common/add-another.tsx b/app/components/datasets/documents/detail/completed/common/add-another.tsx
new file mode 100644
index 0000000..c504faa
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/add-another.tsx
@@ -0,0 +1,32 @@
+import React, { type FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import classNames from '@/utils/classnames'
+import Checkbox from '@/app/components/base/checkbox'
+
+type AddAnotherProps = {
+ className?: string
+ isChecked: boolean
+ onCheck: () => void
+}
+
+const AddAnother: FC<AddAnotherProps> = ({
+ className,
+ isChecked,
+ onCheck,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={classNames('flex items-center gap-x-1 pl-1', className)}>
+ <Checkbox
+ key='add-another-checkbox'
+ className='shrink-0'
+ checked={isChecked}
+ onCheck={onCheck}
+ />
+ <span className='system-xs-medium text-text-tertiary'>{t('datasetDocuments.segment.addAnother')}</span>
+ </div>
+ )
+}
+
+export default React.memo(AddAnother)
diff --git a/app/components/datasets/documents/detail/completed/common/batch-action.tsx b/app/components/datasets/documents/detail/completed/common/batch-action.tsx
new file mode 100644
index 0000000..78dda7b
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/batch-action.tsx
@@ -0,0 +1,114 @@
+import React, { type FC } from 'react'
+import { RiArchive2Line, RiCheckboxCircleLine, RiCloseCircleLine, RiDeleteBinLine, RiDraftLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import Divider from '@/app/components/base/divider'
+import classNames from '@/utils/classnames'
+import Confirm from '@/app/components/base/confirm'
+
+const i18nPrefix = 'dataset.batchAction'
+type IBatchActionProps = {
+ className?: string
+ selectedIds: string[]
+ onBatchEnable: () => void
+ onBatchDisable: () => void
+ onBatchDelete: () => Promise<void>
+ onArchive?: () => void
+ onEditMetadata?: () => void
+ onCancel: () => void
+}
+
+const BatchAction: FC<IBatchActionProps> = ({
+ className,
+ selectedIds,
+ onBatchEnable,
+ onBatchDisable,
+ onArchive,
+ onBatchDelete,
+ onEditMetadata,
+ onCancel,
+}) => {
+ const { t } = useTranslation()
+ const [isShowDeleteConfirm, {
+ setTrue: showDeleteConfirm,
+ setFalse: hideDeleteConfirm,
+ }] = useBoolean(false)
+ const [isDeleting, {
+ setTrue: setIsDeleting,
+ }] = useBoolean(false)
+
+ const handleBatchDelete = async () => {
+ setIsDeleting()
+ await onBatchDelete()
+ hideDeleteConfirm()
+ }
+ return (
+ <div className={classNames('w-full flex justify-center gap-x-2', className)}>
+ <div className='flex items-center gap-x-1 rounded-[10px] border border-components-actionbar-border-accent bg-components-actionbar-bg-accent p-1 shadow-xl shadow-shadow-shadow-5 backdrop-blur-[5px]'>
+ <div className='inline-flex items-center gap-x-2 py-1 pl-2 pr-3'>
+ <span className='flex h-5 w-5 items-center justify-center rounded-md bg-text-accent px-1 py-0.5 text-xs font-medium text-text-primary-on-surface'>
+ {selectedIds.length}
+ </span>
+ <span className='text-[13px] font-semibold leading-[16px] text-text-accent'>{t(`${i18nPrefix}.selected`)}</span>
+ </div>
+ <Divider type='vertical' className='mx-0.5 h-3.5 bg-divider-regular' />
+ <div className='flex items-center gap-x-0.5 px-3 py-2'>
+ <RiCheckboxCircleLine className='h-4 w-4 text-components-button-ghost-text' />
+ <button type='button' className='px-0.5 text-[13px] font-medium leading-[16px] text-components-button-ghost-text' onClick={onBatchEnable}>
+ {t(`${i18nPrefix}.enable`)}
+ </button>
+ </div>
+ <div className='flex items-center gap-x-0.5 px-3 py-2'>
+ <RiCloseCircleLine className='h-4 w-4 text-components-button-ghost-text' />
+ <button type='button' className='px-0.5 text-[13px] font-medium leading-[16px] text-components-button-ghost-text' onClick={onBatchDisable}>
+ {t(`${i18nPrefix}.disable`)}
+ </button>
+ </div>
+ {onEditMetadata && (
+ <div className='flex items-center gap-x-0.5 px-3 py-2'>
+ <RiDraftLine className='h-4 w-4 text-components-button-ghost-text' />
+ <button type='button' className='px-0.5 text-[13px] font-medium leading-[16px] text-components-button-ghost-text' onClick={onEditMetadata}>
+ {t('dataset.metadata.metadata')}
+ </button>
+ </div>
+ )}
+
+ {onArchive && (
+ <div className='flex items-center gap-x-0.5 px-3 py-2'>
+ <RiArchive2Line className='h-4 w-4 text-components-button-ghost-text' />
+ <button type='button' className='px-0.5 text-[13px] font-medium leading-[16px] text-components-button-ghost-text' onClick={onArchive}>
+ {t(`${i18nPrefix}.archive`)}
+ </button>
+ </div>
+ )}
+ <div className='flex items-center gap-x-0.5 px-3 py-2'>
+ <RiDeleteBinLine className='h-4 w-4 text-components-button-destructive-ghost-text' />
+ <button type='button' className='px-0.5 text-[13px] font-medium leading-[16px] text-components-button-destructive-ghost-text' onClick={showDeleteConfirm}>
+ {t(`${i18nPrefix}.delete`)}
+ </button>
+ </div>
+
+ <Divider type='vertical' className='mx-0.5 h-3.5 bg-divider-regular' />
+ <button type='button' className='px-3.5 py-2 text-[13px] font-medium leading-[16px] text-components-button-ghost-text' onClick={onCancel}>
+ {t(`${i18nPrefix}.cancel`)}
+ </button>
+ </div>
+ {
+ isShowDeleteConfirm && (
+ <Confirm
+ isShow
+ title={t('datasetDocuments.list.delete.title')}
+ content={t('datasetDocuments.list.delete.content')}
+ confirmText={t('common.operation.sure')}
+ onConfirm={handleBatchDelete}
+ onCancel={hideDeleteConfirm}
+ isLoading={isDeleting}
+ isDisabled={isDeleting}
+ />
+ )
+ }
+ </div>
+ )
+}
+
+export default React.memo(BatchAction)
diff --git a/app/components/datasets/documents/detail/completed/common/chunk-content.tsx b/app/components/datasets/documents/detail/completed/common/chunk-content.tsx
new file mode 100644
index 0000000..2f20549
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/chunk-content.tsx
@@ -0,0 +1,203 @@
+import React, { useEffect, useRef, useState } from 'react'
+import type { ComponentProps, FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { ChunkingMode } from '@/models/datasets'
+import classNames from '@/utils/classnames'
+import { Markdown } from '@/app/components/base/markdown'
+
+type IContentProps = ComponentProps<'textarea'>
+
+const Textarea: FC<IContentProps> = React.memo(({
+ value,
+ placeholder,
+ className,
+ disabled,
+ ...rest
+}) => {
+ return (
+ <textarea
+ className={classNames(
+ 'bg-transparent inset-0 outline-none border-none appearance-none resize-none w-full overflow-y-auto',
+ className,
+ )}
+ placeholder={placeholder}
+ value={value}
+ disabled={disabled}
+ {...rest}
+ />
+ )
+})
+
+Textarea.displayName = 'Textarea'
+
+type IAutoResizeTextAreaProps = ComponentProps<'textarea'> & {
+ containerRef: React.RefObject<HTMLDivElement>
+ labelRef: React.RefObject<HTMLDivElement>
+}
+
+const AutoResizeTextArea: FC<IAutoResizeTextAreaProps> = React.memo(({
+ className,
+ placeholder,
+ value,
+ disabled,
+ containerRef,
+ labelRef,
+ ...rest
+}) => {
+ const textareaRef = useRef<HTMLTextAreaElement>(null)
+ const observerRef = useRef<ResizeObserver>()
+ const [maxHeight, setMaxHeight] = useState(0)
+
+ useEffect(() => {
+ const textarea = textareaRef.current
+ if (!textarea)
+ return
+ textarea.style.height = 'auto'
+ const lineHeight = Number.parseInt(getComputedStyle(textarea).lineHeight)
+ const textareaHeight = Math.max(textarea.scrollHeight, lineHeight)
+ textarea.style.height = `${textareaHeight}px`
+ }, [value])
+
+ useEffect(() => {
+ const container = containerRef.current
+ const label = labelRef.current
+ if (!container || !label)
+ return
+ const updateMaxHeight = () => {
+ const containerHeight = container.clientHeight
+ const labelHeight = label.clientHeight
+ const padding = 32
+ const space = 12
+ const maxHeight = Math.floor((containerHeight - 2 * labelHeight - padding - space) / 2)
+ setMaxHeight(maxHeight)
+ }
+ updateMaxHeight()
+ observerRef.current = new ResizeObserver(updateMaxHeight)
+ observerRef.current.observe(container)
+ return () => {
+ observerRef.current?.disconnect()
+ }
+ }, [])
+
+ return (
+ <textarea
+ ref={textareaRef}
+ className={classNames(
+ 'bg-transparent inset-0 outline-none border-none appearance-none resize-none w-full',
+ className,
+ )}
+ style={{
+ maxHeight,
+ }}
+ placeholder={placeholder}
+ value={value}
+ disabled={disabled}
+ {...rest}
+ />
+ )
+})
+
+AutoResizeTextArea.displayName = 'AutoResizeTextArea'
+
+type IQATextAreaProps = {
+ question: string
+ answer?: string
+ onQuestionChange: (question: string) => void
+ onAnswerChange?: (answer: string) => void
+ isEditMode?: boolean
+}
+
+const QATextArea: FC<IQATextAreaProps> = React.memo(({
+ question,
+ answer,
+ onQuestionChange,
+ onAnswerChange,
+ isEditMode = true,
+}) => {
+ const { t } = useTranslation()
+ const containerRef = useRef<HTMLDivElement>(null)
+ const labelRef = useRef<HTMLDivElement>(null)
+
+ return (
+ <div ref={containerRef} className='h-full overflow-hidden'>
+ <div ref={labelRef} className='mb-1 text-xs font-medium text-text-tertiary'>QUESTION</div>
+ <AutoResizeTextArea
+ className='text-sm tracking-[-0.07px] text-text-secondary caret-[#295EFF]'
+ value={question}
+ placeholder={t('datasetDocuments.segment.questionPlaceholder') || ''}
+ onChange={e => onQuestionChange(e.target.value)}
+ disabled={!isEditMode}
+ containerRef={containerRef}
+ labelRef={labelRef}
+ />
+ <div className='mb-1 mt-6 text-xs font-medium text-text-tertiary'>ANSWER</div>
+ <AutoResizeTextArea
+ className='text-sm tracking-[-0.07px] text-text-secondary caret-[#295EFF]'
+ value={answer}
+ placeholder={t('datasetDocuments.segment.answerPlaceholder') || ''}
+ onChange={e => onAnswerChange?.(e.target.value)}
+ disabled={!isEditMode}
+ autoFocus
+ containerRef={containerRef}
+ labelRef={labelRef}
+ />
+ </div>
+ )
+})
+
+QATextArea.displayName = 'QATextArea'
+
+type IChunkContentProps = {
+ question: string
+ answer?: string
+ onQuestionChange: (question: string) => void
+ onAnswerChange?: (answer: string) => void
+ isEditMode?: boolean
+ docForm: ChunkingMode
+}
+
+const ChunkContent: FC<IChunkContentProps> = ({
+ question,
+ answer,
+ onQuestionChange,
+ onAnswerChange,
+ isEditMode,
+ docForm,
+}) => {
+ const { t } = useTranslation()
+
+ if (docForm === ChunkingMode.qa) {
+ return <QATextArea
+ question={question}
+ answer={answer}
+ onQuestionChange={onQuestionChange}
+ onAnswerChange={onAnswerChange}
+ isEditMode={isEditMode}
+ />
+ }
+
+ if (!isEditMode) {
+ return (
+ <Markdown
+ className='h-full w-full !text-text-secondary'
+ content={question}
+ customDisallowedElements={['input']}
+ />
+ )
+ }
+
+ return (
+ <Textarea
+ className='body-md-regular h-full w-full pb-6 tracking-[-0.07px] text-text-secondary caret-[#295EFF]'
+ value={question}
+ placeholder={t('datasetDocuments.segment.contentPlaceholder') || ''}
+ onChange={e => onQuestionChange(e.target.value)}
+ disabled={!isEditMode}
+ autoFocus
+ />
+ )
+}
+
+ChunkContent.displayName = 'ChunkContent'
+
+export default React.memo(ChunkContent)
diff --git a/app/components/datasets/documents/detail/completed/common/dot.tsx b/app/components/datasets/documents/detail/completed/common/dot.tsx
new file mode 100644
index 0000000..2c70f6f
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/dot.tsx
@@ -0,0 +1,11 @@
+import React from 'react'
+
+const Dot = () => {
+ return (
+ <div className='system-xs-medium text-text-quaternary'>路</div>
+ )
+}
+
+Dot.displayName = 'Dot'
+
+export default React.memo(Dot)
diff --git a/app/components/datasets/documents/detail/completed/common/empty.tsx b/app/components/datasets/documents/detail/completed/common/empty.tsx
new file mode 100644
index 0000000..eef2aa9
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/empty.tsx
@@ -0,0 +1,78 @@
+import React, { type FC } from 'react'
+import { RiFileList2Line } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+
+type IEmptyProps = {
+ onClearFilter: () => void
+}
+
+const EmptyCard = React.memo(() => {
+ return (
+ <div className='h-32 w-full shrink-0 rounded-xl bg-background-section-burn opacity-30' />
+ )
+})
+
+EmptyCard.displayName = 'EmptyCard'
+
+type LineProps = {
+ className?: string
+}
+
+const Line = React.memo(({
+ className,
+}: LineProps) => {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" width="2" height="241" viewBox="0 0 2 241" fill="none" className={className}>
+ <path d="M1 0.5L1 240.5" stroke="url(#paint0_linear_1989_74474)"/>
+ <defs>
+ <linearGradient id="paint0_linear_1989_74474" x1="-7.99584" y1="240.5" x2="-7.88094" y2="0.50004" gradientUnits="userSpaceOnUse">
+ <stop stopColor="white" stopOpacity="0.01"/>
+ <stop offset="0.503965" stopColor="#101828" stopOpacity="0.08"/>
+ <stop offset="1" stopColor="white" stopOpacity="0.01"/>
+ </linearGradient>
+ </defs>
+ </svg>
+ )
+})
+
+Line.displayName = 'Line'
+
+const Empty: FC<IEmptyProps> = ({
+ onClearFilter,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={'relative z-0 flex h-full items-center justify-center'}>
+ <div className='flex flex-col items-center'>
+ <div className='relative z-10 flex h-14 w-14 items-center justify-center rounded-xl border border-divider-subtle bg-components-card-bg shadow-lg shadow-shadow-shadow-5'>
+ <RiFileList2Line className='h-6 w-6 text-text-secondary' />
+ <Line className='absolute -right-[1px] top-1/2 -translate-y-1/2' />
+ <Line className='absolute -left-[1px] top-1/2 -translate-y-1/2' />
+ <Line className='absolute left-1/2 top-0 -translate-x-1/2 -translate-y-1/2 rotate-90' />
+ <Line className='absolute left-1/2 top-full -translate-x-1/2 -translate-y-1/2 rotate-90' />
+ </div>
+ <div className='system-md-regular mt-3 text-text-tertiary'>
+ {t('datasetDocuments.segment.empty')}
+ </div>
+ <button
+ type='button'
+ className='system-sm-medium mt-1 text-text-accent'
+ onClick={onClearFilter}
+ >
+ {t('datasetDocuments.segment.clearFilter')}
+ </button>
+ </div>
+ <div className='absolute left-0 top-0 -z-20 flex h-full w-full flex-col gap-y-3 overflow-hidden'>
+ {
+ Array.from({ length: 10 }).map((_, i) => (
+ <EmptyCard key={i} />
+ ))
+ }
+ </div>
+ <div className='absolute left-0 top-0 -z-10 h-full w-full bg-dataset-chunk-list-mask-bg' />
+ </div>
+ )
+}
+
+export default React.memo(Empty)
diff --git a/app/components/datasets/documents/detail/completed/common/full-screen-drawer.tsx b/app/components/datasets/documents/detail/completed/common/full-screen-drawer.tsx
new file mode 100644
index 0000000..277c429
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/full-screen-drawer.tsx
@@ -0,0 +1,36 @@
+import React, { type FC } from 'react'
+import Drawer from '@/app/components/base/drawer'
+import classNames from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+type IFullScreenDrawerProps = {
+ isOpen: boolean
+ onClose?: () => void
+ fullScreen: boolean
+ children: React.ReactNode
+}
+
+const FullScreenDrawer: FC<IFullScreenDrawerProps> = ({
+ isOpen,
+ onClose = noop,
+ fullScreen,
+ children,
+}) => {
+ return (
+ <Drawer
+ isOpen={isOpen}
+ onClose={onClose}
+ panelClassName={classNames('!p-0 bg-components-panel-bg',
+ fullScreen
+ ? '!max-w-full !w-full'
+ : 'mt-16 mr-2 mb-2 !max-w-[560px] !w-[560px] border-[0.5px] border-components-panel-border rounded-xl',
+ )}
+ mask={false}
+ unmount
+ footer={null}
+ >
+ {children}
+ </Drawer>)
+}
+
+export default FullScreenDrawer
diff --git a/app/components/datasets/documents/detail/completed/common/keywords.tsx b/app/components/datasets/documents/detail/completed/common/keywords.tsx
new file mode 100644
index 0000000..ee90ee2
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/keywords.tsx
@@ -0,0 +1,47 @@
+import React, { type FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import classNames from '@/utils/classnames'
+import type { SegmentDetailModel } from '@/models/datasets'
+import TagInput from '@/app/components/base/tag-input'
+
+type IKeywordsProps = {
+ segInfo?: Partial<SegmentDetailModel> & { id: string }
+ className?: string
+ keywords: string[]
+ onKeywordsChange: (keywords: string[]) => void
+ isEditMode?: boolean
+ actionType?: 'edit' | 'add' | 'view'
+}
+
+const Keywords: FC<IKeywordsProps> = ({
+ segInfo,
+ className,
+ keywords,
+ onKeywordsChange,
+ isEditMode,
+ actionType = 'view',
+}) => {
+ const { t } = useTranslation()
+ return (
+ <div className={classNames('flex flex-col', className)}>
+ <div className='system-xs-medium-uppercase text-text-tertiary'>{t('datasetDocuments.segment.keywords')}</div>
+ <div className='flex max-h-[200px] w-full flex-wrap gap-1 overflow-auto text-text-tertiary'>
+ {(!segInfo?.keywords?.length && actionType === 'view')
+ ? '-'
+ : (
+ <TagInput
+ items={keywords}
+ onChange={newKeywords => onKeywordsChange(newKeywords)}
+ disableAdd={!isEditMode}
+ disableRemove={!isEditMode || (keywords.length === 1)}
+ />
+ )
+ }
+ </div>
+ </div>
+ )
+}
+
+Keywords.displayName = 'Keywords'
+
+export default React.memo(Keywords)
diff --git a/app/components/datasets/documents/detail/completed/common/regeneration-modal.tsx b/app/components/datasets/documents/detail/completed/common/regeneration-modal.tsx
new file mode 100644
index 0000000..95bb339
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/regeneration-modal.tsx
@@ -0,0 +1,132 @@
+import React, { type FC, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiLoader2Line } from '@remixicon/react'
+import { useCountDown } from 'ahooks'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { noop } from 'lodash-es'
+
+type IDefaultContentProps = {
+ onCancel: () => void
+ onConfirm: () => void
+}
+
+const DefaultContent: FC<IDefaultContentProps> = React.memo(({
+ onCancel,
+ onConfirm,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <>
+ <div className='pb-4'>
+ <span className='title-2xl-semi-bold text-text-primary'>{t('datasetDocuments.segment.regenerationConfirmTitle')}</span>
+ <p className='system-md-regular text-text-secondary'>{t('datasetDocuments.segment.regenerationConfirmMessage')}</p>
+ </div>
+ <div className='flex justify-end gap-x-2 pt-6'>
+ <Button onClick={onCancel}>
+ {t('common.operation.cancel')}
+ </Button>
+ <Button variant='warning' destructive onClick={onConfirm}>
+ {t('common.operation.regenerate')}
+ </Button>
+ </div>
+ </>
+ )
+})
+
+DefaultContent.displayName = 'DefaultContent'
+
+const RegeneratingContent: FC = React.memo(() => {
+ const { t } = useTranslation()
+
+ return (
+ <>
+ <div className='pb-4'>
+ <span className='title-2xl-semi-bold text-text-primary'>{t('datasetDocuments.segment.regeneratingTitle')}</span>
+ <p className='system-md-regular text-text-secondary'>{t('datasetDocuments.segment.regeneratingMessage')}</p>
+ </div>
+ <div className='flex justify-end pt-6'>
+ <Button variant='warning' destructive disabled className='inline-flex items-center gap-x-0.5'>
+ <RiLoader2Line className='h-4 w-4 animate-spin text-components-button-destructive-primary-text-disabled' />
+ <span>{t('common.operation.regenerate')}</span>
+ </Button>
+ </div>
+ </>
+ )
+})
+
+RegeneratingContent.displayName = 'RegeneratingContent'
+
+type IRegenerationCompletedContentProps = {
+ onClose: () => void
+}
+
+const RegenerationCompletedContent: FC<IRegenerationCompletedContentProps> = React.memo(({
+ onClose,
+}) => {
+ const { t } = useTranslation()
+ const targetTime = useRef(Date.now() + 5000)
+ const [countdown] = useCountDown({
+ targetDate: targetTime.current,
+ onEnd: () => {
+ onClose()
+ },
+ })
+
+ return (
+ <>
+ <div className='pb-4'>
+ <span className='title-2xl-semi-bold text-text-primary'>{t('datasetDocuments.segment.regenerationSuccessTitle')}</span>
+ <p className='system-md-regular text-text-secondary'>{t('datasetDocuments.segment.regenerationSuccessMessage')}</p>
+ </div>
+ <div className='flex justify-end pt-6'>
+ <Button variant='primary' onClick={onClose}>
+ {`${t('common.operation.close')}${countdown === 0 ? '' : `(${Math.round(countdown / 1000)})`}`}
+ </Button>
+ </div>
+ </>
+ )
+})
+
+RegenerationCompletedContent.displayName = 'RegenerationCompletedContent'
+
+type IRegenerationModalProps = {
+ isShow: boolean
+ onConfirm: () => void
+ onCancel: () => void
+ onClose: () => void
+}
+
+const RegenerationModal: FC<IRegenerationModalProps> = ({
+ isShow,
+ onConfirm,
+ onCancel,
+ onClose,
+}) => {
+ const [loading, setLoading] = useState(false)
+ const [updateSucceeded, setUpdateSucceeded] = useState(false)
+ const { eventEmitter } = useEventEmitterContextContext()
+
+ eventEmitter?.useSubscription((v) => {
+ if (v === 'update-segment') {
+ setLoading(true)
+ setUpdateSucceeded(false)
+ }
+ if (v === 'update-segment-success')
+ setUpdateSucceeded(true)
+ if (v === 'update-segment-done')
+ setLoading(false)
+ })
+
+ return (
+ <Modal isShow={isShow} onClose={noop} className='!max-w-[480px] !rounded-2xl'>
+ {!loading && !updateSucceeded && <DefaultContent onCancel={onCancel} onConfirm={onConfirm} />}
+ {loading && !updateSucceeded && <RegeneratingContent />}
+ {!loading && updateSucceeded && <RegenerationCompletedContent onClose={onClose} />}
+ </Modal>
+ )
+}
+
+export default RegenerationModal
diff --git a/app/components/datasets/documents/detail/completed/common/segment-index-tag.tsx b/app/components/datasets/documents/detail/completed/common/segment-index-tag.tsx
new file mode 100644
index 0000000..8f30a55
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/segment-index-tag.tsx
@@ -0,0 +1,40 @@
+import React, { type FC, useMemo } from 'react'
+import { Chunk } from '@/app/components/base/icons/src/public/knowledge'
+import cn from '@/utils/classnames'
+
+type ISegmentIndexTagProps = {
+ positionId?: string | number
+ label?: string
+ className?: string
+ labelPrefix?: string
+ iconClassName?: string
+ labelClassName?: string
+}
+
+export const SegmentIndexTag: FC<ISegmentIndexTagProps> = ({
+ positionId,
+ label,
+ className,
+ labelPrefix = 'Chunk',
+ iconClassName,
+ labelClassName,
+}) => {
+ const localPositionId = useMemo(() => {
+ const positionIdStr = String(positionId)
+ if (positionIdStr.length >= 2)
+ return `${labelPrefix}-${positionId}`
+ return `${labelPrefix}-${positionIdStr.padStart(2, '0')}`
+ }, [positionId, labelPrefix])
+ return (
+ <div className={cn('flex items-center', className)}>
+ <Chunk className={cn('mr-0.5 h-3 w-3 p-[1px] text-text-tertiary', iconClassName)} />
+ <div className={cn('system-xs-medium text-text-tertiary', labelClassName)}>
+ {label || localPositionId}
+ </div>
+ </div>
+ )
+}
+
+SegmentIndexTag.displayName = 'SegmentIndexTag'
+
+export default React.memo(SegmentIndexTag)
diff --git a/app/components/datasets/documents/detail/completed/common/tag.tsx b/app/components/datasets/documents/detail/completed/common/tag.tsx
new file mode 100644
index 0000000..306087d
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/common/tag.tsx
@@ -0,0 +1,15 @@
+import React from 'react'
+import cn from '@/utils/classnames'
+
+const Tag = ({ text, className }: { text: string; className?: string }) => {
+ return (
+ <div className={cn('inline-flex items-center gap-x-0.5', className)}>
+ <span className='text-xs font-medium text-text-quaternary'>#</span>
+ <span className='line-clamp-1 max-w-12 shrink-0 text-xs text-text-tertiary'>{text}</span>
+ </div>
+ )
+}
+
+Tag.displayName = 'Tag'
+
+export default React.memo(Tag)
diff --git a/app/components/datasets/documents/detail/completed/display-toggle.tsx b/app/components/datasets/documents/detail/completed/display-toggle.tsx
new file mode 100644
index 0000000..24e0be1
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/display-toggle.tsx
@@ -0,0 +1,40 @@
+import React, { type FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiLineHeight } from '@remixicon/react'
+import Tooltip from '@/app/components/base/tooltip'
+import { Collapse } from '@/app/components/base/icons/src/vender/line/editor'
+
+type DisplayToggleProps = {
+ isCollapsed: boolean
+ toggleCollapsed: () => void
+}
+
+const DisplayToggle: FC<DisplayToggleProps> = ({
+ isCollapsed,
+ toggleCollapsed,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <Tooltip
+ popupContent={isCollapsed ? t('datasetDocuments.segment.expandChunks') : t('datasetDocuments.segment.collapseChunks')}
+ popupClassName='text-text-secondary system-xs-medium border-[0.5px] border-components-panel-border'
+ >
+ <button
+ type='button'
+ className='flex items-center justify-center rounded-lg border-[0.5px] border-components-button-secondary-border
+ bg-components-button-secondary-bg p-2 shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px]'
+ onClick={toggleCollapsed}
+ >
+ {
+ isCollapsed
+ ? <RiLineHeight className='h-4 w-4 text-components-button-secondary-text' />
+ : <Collapse className='h-4 w-4 text-components-button-secondary-text' />
+ }
+ </button>
+
+ </Tooltip>
+ )
+}
+
+export default React.memo(DisplayToggle)
diff --git a/app/components/datasets/documents/detail/completed/index.tsx b/app/components/datasets/documents/detail/completed/index.tsx
new file mode 100644
index 0000000..4fe0df2
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/index.tsx
@@ -0,0 +1,735 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { useDebounceFn } from 'ahooks'
+import { useTranslation } from 'react-i18next'
+import { createContext, useContext, useContextSelector } from 'use-context-selector'
+import { usePathname } from 'next/navigation'
+import { useDocumentContext } from '../index'
+import { ProcessStatus } from '../segment-add'
+import s from './style.module.css'
+import SegmentList from './segment-list'
+import DisplayToggle from './display-toggle'
+import BatchAction from './common/batch-action'
+import SegmentDetail from './segment-detail'
+import SegmentCard from './segment-card'
+import ChildSegmentList from './child-segment-list'
+import NewChildSegment from './new-child-segment'
+import FullScreenDrawer from './common/full-screen-drawer'
+import ChildSegmentDetail from './child-segment-detail'
+import StatusItem from './status-item'
+import Pagination from '@/app/components/base/pagination'
+import cn from '@/utils/classnames'
+import { formatNumber } from '@/utils/format'
+import Divider from '@/app/components/base/divider'
+import Input from '@/app/components/base/input'
+import { ToastContext } from '@/app/components/base/toast'
+import type { Item } from '@/app/components/base/select'
+import { SimpleSelect } from '@/app/components/base/select'
+import { type ChildChunkDetail, ChunkingMode, type SegmentDetailModel, type SegmentUpdater } from '@/models/datasets'
+import NewSegment from '@/app/components/datasets/documents/detail/new-segment'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import Checkbox from '@/app/components/base/checkbox'
+import {
+ useChildSegmentList,
+ useChildSegmentListKey,
+ useChunkListAllKey,
+ useChunkListDisabledKey,
+ useChunkListEnabledKey,
+ useDeleteChildSegment,
+ useDeleteSegment,
+ useDisableSegment,
+ useEnableSegment,
+ useSegmentList,
+ useSegmentListKey,
+ useUpdateChildSegment,
+ useUpdateSegment,
+} from '@/service/knowledge/use-segment'
+import { useInvalid } from '@/service/use-base'
+import { noop } from 'lodash-es'
+
+const DEFAULT_LIMIT = 10
+
+type CurrSegmentType = {
+ segInfo?: SegmentDetailModel
+ showModal: boolean
+ isEditMode?: boolean
+}
+
+type CurrChildChunkType = {
+ childChunkInfo?: ChildChunkDetail
+ showModal: boolean
+}
+
+type SegmentListContextValue = {
+ isCollapsed: boolean
+ fullScreen: boolean
+ toggleFullScreen: (fullscreen?: boolean) => void
+ currSegment: CurrSegmentType
+ currChildChunk: CurrChildChunkType
+}
+
+const SegmentListContext = createContext<SegmentListContextValue>({
+ isCollapsed: true,
+ fullScreen: false,
+ toggleFullScreen: noop,
+ currSegment: { showModal: false },
+ currChildChunk: { showModal: false },
+})
+
+export const useSegmentListContext = (selector: (value: SegmentListContextValue) => any) => {
+ return useContextSelector(SegmentListContext, selector)
+}
+
+type ICompletedProps = {
+ embeddingAvailable: boolean
+ showNewSegmentModal: boolean
+ onNewSegmentModalChange: (state: boolean) => void
+ importStatus: ProcessStatus | string | undefined
+ archived?: boolean
+}
+/**
+ * Embedding done, show list of all segments
+ * Support search and filter
+ */
+const Completed: FC<ICompletedProps> = ({
+ embeddingAvailable,
+ showNewSegmentModal,
+ onNewSegmentModalChange,
+ importStatus,
+ archived,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const pathname = usePathname()
+ const datasetId = useDocumentContext(s => s.datasetId) || ''
+ const documentId = useDocumentContext(s => s.documentId) || ''
+ const docForm = useDocumentContext(s => s.docForm)
+ const mode = useDocumentContext(s => s.mode)
+ const parentMode = useDocumentContext(s => s.parentMode)
+ // the current segment id and whether to show the modal
+ const [currSegment, setCurrSegment] = useState<CurrSegmentType>({ showModal: false })
+ const [currChildChunk, setCurrChildChunk] = useState<CurrChildChunkType>({ showModal: false })
+ const [currChunkId, setCurrChunkId] = useState('')
+
+ const [inputValue, setInputValue] = useState<string>('') // the input value
+ const [searchValue, setSearchValue] = useState<string>('') // the search value
+ const [selectedStatus, setSelectedStatus] = useState<boolean | 'all'>('all') // the selected status, enabled/disabled/undefined
+
+ const [segments, setSegments] = useState<SegmentDetailModel[]>([]) // all segments data
+ const [childSegments, setChildSegments] = useState<ChildChunkDetail[]>([]) // all child segments data
+ const [selectedSegmentIds, setSelectedSegmentIds] = useState<string[]>([])
+ const { eventEmitter } = useEventEmitterContextContext()
+ const [isCollapsed, setIsCollapsed] = useState(true)
+ const [currentPage, setCurrentPage] = useState(1) // start from 1
+ const [limit, setLimit] = useState(DEFAULT_LIMIT)
+ const [fullScreen, setFullScreen] = useState(false)
+ const [showNewChildSegmentModal, setShowNewChildSegmentModal] = useState(false)
+
+ const segmentListRef = useRef<HTMLDivElement>(null)
+ const childSegmentListRef = useRef<HTMLDivElement>(null)
+ const needScrollToBottom = useRef(false)
+ const statusList = useRef<Item[]>([
+ { value: 'all', name: t('datasetDocuments.list.index.all') },
+ { value: 0, name: t('datasetDocuments.list.status.disabled') },
+ { value: 1, name: t('datasetDocuments.list.status.enabled') },
+ ])
+
+ const { run: handleSearch } = useDebounceFn(() => {
+ setSearchValue(inputValue)
+ setCurrentPage(1)
+ }, { wait: 500 })
+
+ const handleInputChange = (value: string) => {
+ setInputValue(value)
+ handleSearch()
+ }
+
+ const onChangeStatus = ({ value }: Item) => {
+ setSelectedStatus(value === 'all' ? 'all' : !!value)
+ setCurrentPage(1)
+ }
+
+ const isFullDocMode = useMemo(() => {
+ return mode === 'hierarchical' && parentMode === 'full-doc'
+ }, [mode, parentMode])
+
+ const { isFetching: isLoadingSegmentList, data: segmentListData } = useSegmentList(
+ {
+ datasetId,
+ documentId,
+ params: {
+ page: isFullDocMode ? 1 : currentPage,
+ limit: isFullDocMode ? 10 : limit,
+ keyword: isFullDocMode ? '' : searchValue,
+ enabled: selectedStatus,
+ },
+ },
+ )
+ const invalidSegmentList = useInvalid(useSegmentListKey)
+
+ useEffect(() => {
+ if (segmentListData) {
+ setSegments(segmentListData.data || [])
+ const totalPages = segmentListData.total_pages
+ if (totalPages < currentPage)
+ setCurrentPage(totalPages === 0 ? 1 : totalPages)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [segmentListData])
+
+ useEffect(() => {
+ if (segmentListRef.current && needScrollToBottom.current) {
+ segmentListRef.current.scrollTo({ top: segmentListRef.current.scrollHeight, behavior: 'smooth' })
+ needScrollToBottom.current = false
+ }
+ }, [segments])
+
+ const { isFetching: isLoadingChildSegmentList, data: childChunkListData } = useChildSegmentList(
+ {
+ datasetId,
+ documentId,
+ segmentId: segments[0]?.id || '',
+ params: {
+ page: currentPage === 0 ? 1 : currentPage,
+ limit,
+ keyword: searchValue,
+ },
+ },
+ !isFullDocMode || segments.length === 0,
+ )
+ const invalidChildSegmentList = useInvalid(useChildSegmentListKey)
+
+ useEffect(() => {
+ if (childSegmentListRef.current && needScrollToBottom.current) {
+ childSegmentListRef.current.scrollTo({ top: childSegmentListRef.current.scrollHeight, behavior: 'smooth' })
+ needScrollToBottom.current = false
+ }
+ }, [childSegments])
+
+ useEffect(() => {
+ if (childChunkListData) {
+ setChildSegments(childChunkListData.data || [])
+ const totalPages = childChunkListData.total_pages
+ if (totalPages < currentPage)
+ setCurrentPage(totalPages === 0 ? 1 : totalPages)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [childChunkListData])
+
+ const resetList = useCallback(() => {
+ setSelectedSegmentIds([])
+ invalidSegmentList()
+ }, [invalidSegmentList])
+
+ const resetChildList = useCallback(() => {
+ invalidChildSegmentList()
+ }, [invalidChildSegmentList])
+
+ const onClickCard = (detail: SegmentDetailModel, isEditMode = false) => {
+ setCurrSegment({ segInfo: detail, showModal: true, isEditMode })
+ }
+
+ const onCloseSegmentDetail = useCallback(() => {
+ setCurrSegment({ showModal: false })
+ setFullScreen(false)
+ }, [])
+
+ const onCloseNewSegmentModal = useCallback(() => {
+ onNewSegmentModalChange(false)
+ setFullScreen(false)
+ }, [onNewSegmentModalChange])
+
+ const onCloseNewChildChunkModal = useCallback(() => {
+ setShowNewChildSegmentModal(false)
+ setFullScreen(false)
+ }, [])
+
+ const { mutateAsync: enableSegment } = useEnableSegment()
+ const { mutateAsync: disableSegment } = useDisableSegment()
+ const invalidChunkListAll = useInvalid(useChunkListAllKey)
+ const invalidChunkListEnabled = useInvalid(useChunkListEnabledKey)
+ const invalidChunkListDisabled = useInvalid(useChunkListDisabledKey)
+
+ const refreshChunkListWithStatusChanged = useCallback(() => {
+ switch (selectedStatus) {
+ case 'all':
+ invalidChunkListDisabled()
+ invalidChunkListEnabled()
+ break
+ default:
+ invalidSegmentList()
+ }
+ }, [selectedStatus, invalidChunkListDisabled, invalidChunkListEnabled, invalidSegmentList])
+
+ const onChangeSwitch = useCallback(async (enable: boolean, segId?: string) => {
+ const operationApi = enable ? enableSegment : disableSegment
+ await operationApi({ datasetId, documentId, segmentIds: segId ? [segId] : selectedSegmentIds }, {
+ onSuccess: () => {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ for (const seg of segments) {
+ if (segId ? seg.id === segId : selectedSegmentIds.includes(seg.id))
+ seg.enabled = enable
+ }
+ setSegments([...segments])
+ refreshChunkListWithStatusChanged()
+ },
+ onError: () => {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ },
+ })
+ }, [datasetId, documentId, selectedSegmentIds, segments, disableSegment, enableSegment, t, notify, refreshChunkListWithStatusChanged])
+
+ const { mutateAsync: deleteSegment } = useDeleteSegment()
+
+ const onDelete = useCallback(async (segId?: string) => {
+ await deleteSegment({ datasetId, documentId, segmentIds: segId ? [segId] : selectedSegmentIds }, {
+ onSuccess: () => {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ resetList()
+ !segId && setSelectedSegmentIds([])
+ },
+ onError: () => {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ },
+ })
+ }, [datasetId, documentId, selectedSegmentIds, deleteSegment, resetList, t, notify])
+
+ const { mutateAsync: updateSegment } = useUpdateSegment()
+
+ const refreshChunkListDataWithDetailChanged = useCallback(() => {
+ switch (selectedStatus) {
+ case 'all':
+ invalidChunkListDisabled()
+ invalidChunkListEnabled()
+ break
+ case true:
+ invalidChunkListAll()
+ invalidChunkListDisabled()
+ break
+ case false:
+ invalidChunkListAll()
+ invalidChunkListEnabled()
+ break
+ }
+ }, [selectedStatus, invalidChunkListDisabled, invalidChunkListEnabled, invalidChunkListAll])
+
+ const handleUpdateSegment = useCallback(async (
+ segmentId: string,
+ question: string,
+ answer: string,
+ keywords: string[],
+ needRegenerate = false,
+ ) => {
+ const params: SegmentUpdater = { content: '' }
+ if (docForm === ChunkingMode.qa) {
+ if (!question.trim())
+ return notify({ type: 'error', message: t('datasetDocuments.segment.questionEmpty') })
+ if (!answer.trim())
+ return notify({ type: 'error', message: t('datasetDocuments.segment.answerEmpty') })
+
+ params.content = question
+ params.answer = answer
+ }
+ else {
+ if (!question.trim())
+ return notify({ type: 'error', message: t('datasetDocuments.segment.contentEmpty') })
+
+ params.content = question
+ }
+
+ if (keywords.length)
+ params.keywords = keywords
+
+ if (needRegenerate)
+ params.regenerate_child_chunks = needRegenerate
+
+ eventEmitter?.emit('update-segment')
+ await updateSegment({ datasetId, documentId, segmentId, body: params }, {
+ onSuccess(res) {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ if (!needRegenerate)
+ onCloseSegmentDetail()
+ for (const seg of segments) {
+ if (seg.id === segmentId) {
+ seg.answer = res.data.answer
+ seg.content = res.data.content
+ seg.sign_content = res.data.sign_content
+ seg.keywords = res.data.keywords
+ seg.word_count = res.data.word_count
+ seg.hit_count = res.data.hit_count
+ seg.enabled = res.data.enabled
+ seg.updated_at = res.data.updated_at
+ seg.child_chunks = res.data.child_chunks
+ }
+ }
+ setSegments([...segments])
+ refreshChunkListDataWithDetailChanged()
+ eventEmitter?.emit('update-segment-success')
+ },
+ onSettled() {
+ eventEmitter?.emit('update-segment-done')
+ },
+ })
+ }, [segments, datasetId, documentId, updateSegment, docForm, notify, eventEmitter, onCloseSegmentDetail, refreshChunkListDataWithDetailChanged, t])
+
+ useEffect(() => {
+ resetList()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [pathname])
+
+ useEffect(() => {
+ if (importStatus === ProcessStatus.COMPLETED)
+ resetList()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [importStatus])
+
+ const onCancelBatchOperation = useCallback(() => {
+ setSelectedSegmentIds([])
+ }, [])
+
+ const onSelected = useCallback((segId: string) => {
+ setSelectedSegmentIds(prev =>
+ prev.includes(segId)
+ ? prev.filter(id => id !== segId)
+ : [...prev, segId],
+ )
+ }, [])
+
+ const isAllSelected = useMemo(() => {
+ return segments.length > 0 && segments.every(seg => selectedSegmentIds.includes(seg.id))
+ }, [segments, selectedSegmentIds])
+
+ const isSomeSelected = useMemo(() => {
+ return segments.some(seg => selectedSegmentIds.includes(seg.id))
+ }, [segments, selectedSegmentIds])
+
+ const onSelectedAll = useCallback(() => {
+ setSelectedSegmentIds((prev) => {
+ const currentAllSegIds = segments.map(seg => seg.id)
+ const prevSelectedIds = prev.filter(item => !currentAllSegIds.includes(item))
+ return [...prevSelectedIds, ...(isAllSelected ? [] : currentAllSegIds)]
+ })
+ }, [segments, isAllSelected])
+
+ const totalText = useMemo(() => {
+ const isSearch = searchValue !== '' || selectedStatus !== 'all'
+ if (!isSearch) {
+ const total = segmentListData?.total ? formatNumber(segmentListData.total) : '--'
+ const count = total === '--' ? 0 : segmentListData!.total
+ const translationKey = (mode === 'hierarchical' && parentMode === 'paragraph')
+ ? 'datasetDocuments.segment.parentChunks'
+ : 'datasetDocuments.segment.chunks'
+ return `${total} ${t(translationKey, { count })}`
+ }
+ else {
+ const total = typeof segmentListData?.total === 'number' ? formatNumber(segmentListData.total) : 0
+ const count = segmentListData?.total || 0
+ return `${total} ${t('datasetDocuments.segment.searchResults', { count })}`
+ }
+ }, [segmentListData, mode, parentMode, searchValue, selectedStatus, t])
+
+ const toggleFullScreen = useCallback(() => {
+ setFullScreen(!fullScreen)
+ }, [fullScreen])
+
+ const viewNewlyAddedChunk = useCallback(async () => {
+ const totalPages = segmentListData?.total_pages || 0
+ const total = segmentListData?.total || 0
+ const newPage = Math.ceil((total + 1) / limit)
+ needScrollToBottom.current = true
+ if (newPage > totalPages) {
+ setCurrentPage(totalPages + 1)
+ }
+ else {
+ resetList()
+ currentPage !== totalPages && setCurrentPage(totalPages)
+ }
+ }, [segmentListData, limit, currentPage, resetList])
+
+ const { mutateAsync: deleteChildSegment } = useDeleteChildSegment()
+
+ const onDeleteChildChunk = useCallback(async (segmentId: string, childChunkId: string) => {
+ await deleteChildSegment(
+ { datasetId, documentId, segmentId, childChunkId },
+ {
+ onSuccess: () => {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ if (parentMode === 'paragraph')
+ resetList()
+ else
+ resetChildList()
+ },
+ onError: () => {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ },
+ },
+ )
+ }, [datasetId, documentId, parentMode, deleteChildSegment, resetList, resetChildList, t, notify])
+
+ const handleAddNewChildChunk = useCallback((parentChunkId: string) => {
+ setShowNewChildSegmentModal(true)
+ setCurrChunkId(parentChunkId)
+ }, [])
+
+ const onSaveNewChildChunk = useCallback((newChildChunk?: ChildChunkDetail) => {
+ if (parentMode === 'paragraph') {
+ for (const seg of segments) {
+ if (seg.id === currChunkId)
+ seg.child_chunks?.push(newChildChunk!)
+ }
+ setSegments([...segments])
+ refreshChunkListDataWithDetailChanged()
+ }
+ else {
+ resetChildList()
+ }
+ }, [parentMode, currChunkId, segments, refreshChunkListDataWithDetailChanged, resetChildList])
+
+ const viewNewlyAddedChildChunk = useCallback(() => {
+ const totalPages = childChunkListData?.total_pages || 0
+ const total = childChunkListData?.total || 0
+ const newPage = Math.ceil((total + 1) / limit)
+ needScrollToBottom.current = true
+ if (newPage > totalPages) {
+ setCurrentPage(totalPages + 1)
+ }
+ else {
+ resetChildList()
+ currentPage !== totalPages && setCurrentPage(totalPages)
+ }
+ }, [childChunkListData, limit, currentPage, resetChildList])
+
+ const onClickSlice = useCallback((detail: ChildChunkDetail) => {
+ setCurrChildChunk({ childChunkInfo: detail, showModal: true })
+ setCurrChunkId(detail.segment_id)
+ }, [])
+
+ const onCloseChildSegmentDetail = useCallback(() => {
+ setCurrChildChunk({ showModal: false })
+ setFullScreen(false)
+ }, [])
+
+ const { mutateAsync: updateChildSegment } = useUpdateChildSegment()
+
+ const handleUpdateChildChunk = useCallback(async (
+ segmentId: string,
+ childChunkId: string,
+ content: string,
+ ) => {
+ const params: SegmentUpdater = { content: '' }
+ if (!content.trim())
+ return notify({ type: 'error', message: t('datasetDocuments.segment.contentEmpty') })
+
+ params.content = content
+
+ eventEmitter?.emit('update-child-segment')
+ await updateChildSegment({ datasetId, documentId, segmentId, childChunkId, body: params }, {
+ onSuccess: (res) => {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ onCloseChildSegmentDetail()
+ if (parentMode === 'paragraph') {
+ for (const seg of segments) {
+ if (seg.id === segmentId) {
+ for (const childSeg of seg.child_chunks!) {
+ if (childSeg.id === childChunkId) {
+ childSeg.content = res.data.content
+ childSeg.type = res.data.type
+ childSeg.word_count = res.data.word_count
+ childSeg.updated_at = res.data.updated_at
+ }
+ }
+ }
+ }
+ setSegments([...segments])
+ refreshChunkListDataWithDetailChanged()
+ }
+ else {
+ resetChildList()
+ }
+ },
+ onSettled: () => {
+ eventEmitter?.emit('update-child-segment-done')
+ },
+ })
+ }, [segments, datasetId, documentId, parentMode, updateChildSegment, notify, eventEmitter, onCloseChildSegmentDetail, refreshChunkListDataWithDetailChanged, resetChildList, t])
+
+ const onClearFilter = useCallback(() => {
+ setInputValue('')
+ setSearchValue('')
+ setSelectedStatus('all')
+ setCurrentPage(1)
+ }, [])
+
+ const selectDefaultValue = useMemo(() => {
+ if (selectedStatus === 'all')
+ return 'all'
+ return selectedStatus ? 1 : 0
+ }, [selectedStatus])
+
+ return (
+ <SegmentListContext.Provider value={{
+ isCollapsed,
+ fullScreen,
+ toggleFullScreen,
+ currSegment,
+ currChildChunk,
+ }}>
+ {/* Menu Bar */}
+ {!isFullDocMode && <div className={s.docSearchWrapper}>
+ <Checkbox
+ className='shrink-0'
+ checked={isAllSelected}
+ indeterminate={!isAllSelected && isSomeSelected}
+ onCheck={onSelectedAll}
+ disabled={isLoadingSegmentList}
+ />
+ <div className={'system-sm-semibold-uppercase flex-1 pl-5 text-text-secondary'}>{totalText}</div>
+ <SimpleSelect
+ onSelect={onChangeStatus}
+ items={statusList.current}
+ defaultValue={selectDefaultValue}
+ className={s.select}
+ wrapperClassName='h-fit mr-2'
+ optionWrapClassName='w-[160px]'
+ optionClassName='p-0'
+ renderOption={({ item, selected }) => <StatusItem item={item} selected={selected} />}
+ notClearable
+ />
+ <Input
+ showLeftIcon
+ showClearIcon
+ wrapperClassName='!w-52'
+ value={inputValue}
+ onChange={e => handleInputChange(e.target.value)}
+ onClear={() => handleInputChange('')}
+ />
+ <Divider type='vertical' className='mx-3 h-3.5' />
+ <DisplayToggle isCollapsed={isCollapsed} toggleCollapsed={() => setIsCollapsed(!isCollapsed)} />
+ </div>}
+ {/* Segment list */}
+ {
+ isFullDocMode
+ ? <div className={cn(
+ 'flex grow flex-col overflow-x-hidden',
+ (isLoadingSegmentList || isLoadingChildSegmentList) ? 'overflow-y-hidden' : 'overflow-y-auto',
+ )}>
+ <SegmentCard
+ detail={segments[0]}
+ onClick={() => onClickCard(segments[0])}
+ loading={isLoadingSegmentList}
+ focused={{
+ segmentIndex: currSegment?.segInfo?.id === segments[0]?.id,
+ segmentContent: currSegment?.segInfo?.id === segments[0]?.id,
+ }}
+ />
+ <ChildSegmentList
+ parentChunkId={segments[0]?.id}
+ onDelete={onDeleteChildChunk}
+ childChunks={childSegments}
+ handleInputChange={handleInputChange}
+ handleAddNewChildChunk={handleAddNewChildChunk}
+ onClickSlice={onClickSlice}
+ enabled={!archived}
+ total={childChunkListData?.total || 0}
+ inputValue={inputValue}
+ onClearFilter={onClearFilter}
+ isLoading={isLoadingSegmentList || isLoadingChildSegmentList}
+ />
+ </div>
+ : <SegmentList
+ ref={segmentListRef}
+ embeddingAvailable={embeddingAvailable}
+ isLoading={isLoadingSegmentList}
+ items={segments}
+ selectedSegmentIds={selectedSegmentIds}
+ onSelected={onSelected}
+ onChangeSwitch={onChangeSwitch}
+ onDelete={onDelete}
+ onClick={onClickCard}
+ archived={archived}
+ onDeleteChildChunk={onDeleteChildChunk}
+ handleAddNewChildChunk={handleAddNewChildChunk}
+ onClickSlice={onClickSlice}
+ onClearFilter={onClearFilter}
+ />
+ }
+ {/* Pagination */}
+ <Divider type='horizontal' className='mx-6 my-0 h-[1px] w-auto bg-divider-subtle' />
+ <Pagination
+ current={currentPage - 1}
+ onChange={cur => setCurrentPage(cur + 1)}
+ total={(isFullDocMode ? childChunkListData?.total : segmentListData?.total) || 0}
+ limit={limit}
+ onLimitChange={limit => setLimit(limit)}
+ className={isFullDocMode ? 'px-3' : ''}
+ />
+ {/* Edit or view segment detail */}
+ <FullScreenDrawer
+ isOpen={currSegment.showModal}
+ fullScreen={fullScreen}
+ onClose={onCloseSegmentDetail}
+ >
+ <SegmentDetail
+ segInfo={currSegment.segInfo ?? { id: '' }}
+ docForm={docForm}
+ isEditMode={currSegment.isEditMode}
+ onUpdate={handleUpdateSegment}
+ onCancel={onCloseSegmentDetail}
+ />
+ </FullScreenDrawer>
+ {/* Create New Segment */}
+ <FullScreenDrawer
+ isOpen={showNewSegmentModal}
+ fullScreen={fullScreen}
+ onClose={onCloseNewSegmentModal}
+ >
+ <NewSegment
+ docForm={docForm}
+ onCancel={onCloseNewSegmentModal}
+ onSave={resetList}
+ viewNewlyAddedChunk={viewNewlyAddedChunk}
+ />
+ </FullScreenDrawer>
+ {/* Edit or view child segment detail */}
+ <FullScreenDrawer
+ isOpen={currChildChunk.showModal}
+ fullScreen={fullScreen}
+ onClose={onCloseChildSegmentDetail}
+ >
+ <ChildSegmentDetail
+ chunkId={currChunkId}
+ childChunkInfo={currChildChunk.childChunkInfo ?? { id: '' }}
+ docForm={docForm}
+ onUpdate={handleUpdateChildChunk}
+ onCancel={onCloseChildSegmentDetail}
+ />
+ </FullScreenDrawer>
+ {/* Create New Child Segment */}
+ <FullScreenDrawer
+ isOpen={showNewChildSegmentModal}
+ fullScreen={fullScreen}
+ onClose={onCloseNewChildChunkModal}
+ >
+ <NewChildSegment
+ chunkId={currChunkId}
+ onCancel={onCloseNewChildChunkModal}
+ onSave={onSaveNewChildChunk}
+ viewNewlyAddedChildChunk={viewNewlyAddedChildChunk}
+ />
+ </FullScreenDrawer>
+ {/* Batch Action Buttons */}
+ {selectedSegmentIds.length > 0
+ && <BatchAction
+ className='absolute bottom-16 left-0 z-20'
+ selectedIds={selectedSegmentIds}
+ onBatchEnable={onChangeSwitch.bind(null, true, '')}
+ onBatchDisable={onChangeSwitch.bind(null, false, '')}
+ onBatchDelete={onDelete.bind(null, '')}
+ onCancel={onCancelBatchOperation}
+ />}
+ </SegmentListContext.Provider>
+ )
+}
+
+export default Completed
diff --git a/app/components/datasets/documents/detail/completed/new-child-segment.tsx b/app/components/datasets/documents/detail/completed/new-child-segment.tsx
new file mode 100644
index 0000000..e1d5701
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/new-child-segment.tsx
@@ -0,0 +1,174 @@
+import { memo, useMemo, useRef, useState } from 'react'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { useParams } from 'next/navigation'
+import { RiCloseLine, RiExpandDiagonalLine } from '@remixicon/react'
+import { useShallow } from 'zustand/react/shallow'
+import { useDocumentContext } from '../index'
+import { SegmentIndexTag } from './common/segment-index-tag'
+import ActionButtons from './common/action-buttons'
+import ChunkContent from './common/chunk-content'
+import AddAnother from './common/add-another'
+import Dot from './common/dot'
+import { useSegmentListContext } from './index'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import { ToastContext } from '@/app/components/base/toast'
+import { type ChildChunkDetail, ChunkingMode, type SegmentUpdater } from '@/models/datasets'
+import classNames from '@/utils/classnames'
+import { formatNumber } from '@/utils/format'
+import Divider from '@/app/components/base/divider'
+import { useAddChildSegment } from '@/service/knowledge/use-segment'
+
+type NewChildSegmentModalProps = {
+ chunkId: string
+ onCancel: () => void
+ onSave: (ChildChunk?: ChildChunkDetail) => void
+ viewNewlyAddedChildChunk?: () => void
+}
+
+const NewChildSegmentModal: FC<NewChildSegmentModalProps> = ({
+ chunkId,
+ onCancel,
+ onSave,
+ viewNewlyAddedChildChunk,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const [content, setContent] = useState('')
+ const { datasetId, documentId } = useParams<{ datasetId: string; documentId: string }>()
+ const [loading, setLoading] = useState(false)
+ const [addAnother, setAddAnother] = useState(true)
+ const fullScreen = useSegmentListContext(s => s.fullScreen)
+ const toggleFullScreen = useSegmentListContext(s => s.toggleFullScreen)
+ const { appSidebarExpand } = useAppStore(useShallow(state => ({
+ appSidebarExpand: state.appSidebarExpand,
+ })))
+ const parentMode = useDocumentContext(s => s.parentMode)
+
+ const refreshTimer = useRef<any>(null)
+
+ const isFullDocMode = useMemo(() => {
+ return parentMode === 'full-doc'
+ }, [parentMode])
+
+ const CustomButton = <>
+ <Divider type='vertical' className='mx-1 h-3 bg-divider-regular' />
+ <button
+ type='button'
+ className='system-xs-semibold text-text-accent'
+ onClick={() => {
+ clearTimeout(refreshTimer.current)
+ viewNewlyAddedChildChunk?.()
+ }}>
+ {t('common.operation.view')}
+ </button>
+ </>
+
+ const handleCancel = (actionType: 'esc' | 'add' = 'esc') => {
+ if (actionType === 'esc' || !addAnother)
+ onCancel()
+ }
+
+ const { mutateAsync: addChildSegment } = useAddChildSegment()
+
+ const handleSave = async () => {
+ const params: SegmentUpdater = { content: '' }
+
+ if (!content.trim())
+ return notify({ type: 'error', message: t('datasetDocuments.segment.contentEmpty') })
+
+ params.content = content
+
+ setLoading(true)
+ await addChildSegment({ datasetId, documentId, segmentId: chunkId, body: params }, {
+ onSuccess(res) {
+ notify({
+ type: 'success',
+ message: t('datasetDocuments.segment.childChunkAdded'),
+ className: `!w-[296px] !bottom-0 ${appSidebarExpand === 'expand' ? '!left-[216px]' : '!left-14'}
+ !top-auto !right-auto !mb-[52px] !ml-11`,
+ customComponent: isFullDocMode && CustomButton,
+ })
+ handleCancel('add')
+ if (isFullDocMode) {
+ refreshTimer.current = setTimeout(() => {
+ onSave()
+ }, 3000)
+ }
+ else {
+ onSave(res.data)
+ }
+ },
+ onSettled() {
+ setLoading(false)
+ },
+ })
+ }
+
+ const wordCountText = useMemo(() => {
+ const count = content.length
+ return `${formatNumber(count)} ${t('datasetDocuments.segment.characters', { count })}`
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [content.length])
+
+ return (
+ <div className={'flex h-full flex-col'}>
+ <div className={classNames('flex items-center justify-between', fullScreen ? 'py-3 pr-4 pl-6 border border-divider-subtle' : 'pt-3 pr-3 pl-4')}>
+ <div className='flex flex-col'>
+ <div className='system-xl-semibold text-text-primary'>{t('datasetDocuments.segment.addChildChunk')}</div>
+ <div className='flex items-center gap-x-2'>
+ <SegmentIndexTag label={t('datasetDocuments.segment.newChildChunk') as string} />
+ <Dot />
+ <span className='system-xs-medium text-text-tertiary'>{wordCountText}</span>
+ </div>
+ </div>
+ <div className='flex items-center'>
+ {fullScreen && (
+ <>
+ <AddAnother className='mr-3' isChecked={addAnother} onCheck={() => setAddAnother(!addAnother)} />
+ <ActionButtons
+ handleCancel={handleCancel.bind(null, 'esc')}
+ handleSave={handleSave}
+ loading={loading}
+ actionType='add'
+ isChildChunk={true}
+ />
+ <Divider type='vertical' className='ml-4 mr-2 h-3.5 bg-divider-regular' />
+ </>
+ )}
+ <div className='mr-1 flex h-8 w-8 cursor-pointer items-center justify-center p-1.5' onClick={toggleFullScreen}>
+ <RiExpandDiagonalLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div className='flex h-8 w-8 cursor-pointer items-center justify-center p-1.5' onClick={handleCancel.bind(null, 'esc')}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ <div className={classNames('flex grow w-full', fullScreen ? 'flex-row justify-center px-6 pt-6' : 'py-3 px-4')}>
+ <div className={classNames('break-all overflow-hidden whitespace-pre-line h-full', fullScreen ? 'w-1/2' : 'w-full')}>
+ <ChunkContent
+ docForm={ChunkingMode.parentChild}
+ question={content}
+ onQuestionChange={content => setContent(content)}
+ isEditMode={true}
+ />
+ </div>
+ </div>
+ {!fullScreen && (
+ <div className='flex items-center justify-between border-t-[1px] border-t-divider-subtle p-4 pt-3'>
+ <AddAnother isChecked={addAnother} onCheck={() => setAddAnother(!addAnother)} />
+ <ActionButtons
+ handleCancel={handleCancel.bind(null, 'esc')}
+ handleSave={handleSave}
+ loading={loading}
+ actionType='add'
+ isChildChunk={true}
+ />
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default memo(NewChildSegmentModal)
diff --git a/app/components/datasets/documents/detail/completed/segment-card/chunk-content.tsx b/app/components/datasets/documents/detail/completed/segment-card/chunk-content.tsx
new file mode 100644
index 0000000..d93eb94
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/segment-card/chunk-content.tsx
@@ -0,0 +1,57 @@
+import React, { type FC } from 'react'
+import cn from '@/utils/classnames'
+import { useSegmentListContext } from '..'
+import { Markdown } from '@/app/components/base/markdown'
+
+type ChunkContentProps = {
+ detail: {
+ answer?: string
+ content: string
+ sign_content: string
+ }
+ isFullDocMode: boolean
+ className?: string
+}
+
+const ChunkContent: FC<ChunkContentProps> = ({
+ detail,
+ isFullDocMode,
+ className,
+}) => {
+ const { answer, content, sign_content } = detail
+ const isCollapsed = useSegmentListContext(s => s.isCollapsed)
+
+ if (answer) {
+ return (
+ <div className={className}>
+ <div className='flex gap-x-1'>
+ <div className='w-4 shrink-0 text-[13px] font-medium leading-[20px] text-text-tertiary'>Q</div>
+ <div
+ className={cn('body-md-regular text-text-secondary',
+ isCollapsed ? 'line-clamp-2' : 'line-clamp-20',
+ )}>
+ {content}
+ </div>
+ </div>
+ <div className='flex gap-x-1'>
+ <div className='w-4 shrink-0 text-[13px] font-medium leading-[20px] text-text-tertiary'>A</div>
+ <div className={cn('body-md-regular text-text-secondary',
+ isCollapsed ? 'line-clamp-2' : 'line-clamp-20',
+ )}>
+ {answer}
+ </div>
+ </div>
+ </div>
+ )
+ }
+ return <Markdown
+ className={cn('!mt-0.5 !text-text-secondary',
+ isFullDocMode ? 'line-clamp-3' : isCollapsed ? 'line-clamp-2' : 'line-clamp-20',
+ className,
+ )}
+ content={sign_content || content || ''}
+ customDisallowedElements={['input']}
+ />
+}
+
+export default React.memo(ChunkContent)
diff --git a/app/components/datasets/documents/detail/completed/segment-card/index.tsx b/app/components/datasets/documents/detail/completed/segment-card/index.tsx
new file mode 100644
index 0000000..584a60b
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/segment-card/index.tsx
@@ -0,0 +1,254 @@
+import React, { type FC, useCallback, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiDeleteBinLine, RiEditLine } from '@remixicon/react'
+import { StatusItem } from '../../../list'
+import { useDocumentContext } from '../../index'
+import ChildSegmentList from '../child-segment-list'
+import Tag from '../common/tag'
+import Dot from '../common/dot'
+import { SegmentIndexTag } from '../common/segment-index-tag'
+import ParentChunkCardSkeleton from '../skeleton/parent-chunk-card-skeleton'
+import type { ChildChunkDetail, SegmentDetailModel } from '@/models/datasets'
+import Switch from '@/app/components/base/switch'
+import Divider from '@/app/components/base/divider'
+import { formatNumber } from '@/utils/format'
+import Confirm from '@/app/components/base/confirm'
+import cn from '@/utils/classnames'
+import Badge from '@/app/components/base/badge'
+import { isAfter } from '@/utils/time'
+import Tooltip from '@/app/components/base/tooltip'
+import ChunkContent from './chunk-content'
+
+type ISegmentCardProps = {
+ loading: boolean
+ detail?: SegmentDetailModel & { document?: { name: string } }
+ onClick?: () => void
+ onChangeSwitch?: (enabled: boolean, segId?: string) => Promise<void>
+ onDelete?: (segId: string) => Promise<void>
+ onDeleteChildChunk?: (segId: string, childChunkId: string) => Promise<void>
+ handleAddNewChildChunk?: (parentChunkId: string) => void
+ onClickSlice?: (childChunk: ChildChunkDetail) => void
+ onClickEdit?: () => void
+ className?: string
+ archived?: boolean
+ embeddingAvailable?: boolean
+ focused: {
+ segmentIndex: boolean
+ segmentContent: boolean
+ }
+}
+
+const SegmentCard: FC<ISegmentCardProps> = ({
+ detail = {},
+ onClick,
+ onChangeSwitch,
+ onDelete,
+ onDeleteChildChunk,
+ handleAddNewChildChunk,
+ onClickSlice,
+ onClickEdit,
+ loading = true,
+ className = '',
+ archived,
+ embeddingAvailable,
+ focused,
+}) => {
+ const { t } = useTranslation()
+ const {
+ id,
+ position,
+ enabled,
+ content,
+ sign_content,
+ word_count,
+ hit_count,
+ answer,
+ keywords,
+ child_chunks = [],
+ created_at,
+ updated_at,
+ } = detail as Required<ISegmentCardProps>['detail']
+ const [showModal, setShowModal] = useState(false)
+ const mode = useDocumentContext(s => s.mode)
+ const parentMode = useDocumentContext(s => s.parentMode)
+
+ const isGeneralMode = useMemo(() => {
+ return mode === 'custom'
+ }, [mode])
+
+ const isParentChildMode = useMemo(() => {
+ return mode === 'hierarchical'
+ }, [mode])
+
+ const isParagraphMode = useMemo(() => {
+ return mode === 'hierarchical' && parentMode === 'paragraph'
+ }, [mode, parentMode])
+
+ const isFullDocMode = useMemo(() => {
+ return mode === 'hierarchical' && parentMode === 'full-doc'
+ }, [mode, parentMode])
+
+ const chunkEdited = useMemo(() => {
+ if (mode === 'hierarchical' && parentMode === 'full-doc')
+ return false
+ return isAfter(updated_at * 1000, created_at * 1000)
+ }, [mode, parentMode, updated_at, created_at])
+
+ const contentOpacity = useMemo(() => {
+ return (enabled || focused.segmentContent) ? '' : 'opacity-50 group-hover/card:opacity-100'
+ }, [enabled, focused.segmentContent])
+
+ const handleClickCard = useCallback(() => {
+ if (mode !== 'hierarchical' || parentMode !== 'full-doc')
+ onClick?.()
+ }, [mode, parentMode, onClick])
+
+ const wordCountText = useMemo(() => {
+ const total = formatNumber(word_count)
+ return `${total} ${t('datasetDocuments.segment.characters', { count: word_count })}`
+ }, [word_count, t])
+
+ const labelPrefix = useMemo(() => {
+ return isParentChildMode ? t('datasetDocuments.segment.parentChunk') : t('datasetDocuments.segment.chunk')
+ }, [isParentChildMode, t])
+
+ if (loading)
+ return <ParentChunkCardSkeleton />
+
+ return (
+ <div
+ className={cn(
+ 'group/card w-full rounded-xl px-3',
+ isFullDocMode ? '' : 'pb-2 pt-2.5 hover:bg-dataset-chunk-detail-card-hover-bg',
+ focused.segmentContent ? 'bg-dataset-chunk-detail-card-hover-bg' : '',
+ className,
+ )}
+ onClick={handleClickCard}
+ >
+ <div className='relative flex h-5 items-center justify-between'>
+ <>
+ <div className='flex items-center gap-x-2'>
+ <SegmentIndexTag
+ className={cn(contentOpacity)}
+ iconClassName={focused.segmentIndex ? 'text-text-accent' : ''}
+ labelClassName={focused.segmentIndex ? 'text-text-accent' : ''}
+ positionId={position}
+ label={isFullDocMode ? labelPrefix : ''}
+ labelPrefix={labelPrefix}
+ />
+ <Dot />
+ <div className={cn('system-xs-medium text-text-tertiary', contentOpacity)}>{wordCountText}</div>
+ <Dot />
+ <div className={cn('system-xs-medium text-text-tertiary', contentOpacity)}>{`${formatNumber(hit_count)} ${t('datasetDocuments.segment.hitCount')}`}</div>
+ {chunkEdited && (
+ <>
+ <Dot />
+ <Badge text={t('datasetDocuments.segment.edited') as string} uppercase className={contentOpacity} />
+ </>
+ )}
+ </div>
+ {!isFullDocMode
+ ? <div className='flex items-center'>
+ <StatusItem status={enabled ? 'enabled' : 'disabled'} reverse textCls="text-text-tertiary system-xs-regular" />
+ {embeddingAvailable && (
+ <div className="absolute -right-2.5 -top-2 z-20 hidden items-center gap-x-0.5 rounded-[10px] border-[0.5px]
+ border-components-actionbar-border bg-components-actionbar-bg p-1 shadow-md backdrop-blur-[5px] group-hover/card:flex">
+ {!archived && (
+ <>
+ <Tooltip
+ popupContent='Edit'
+ popupClassName='text-text-secondary system-xs-medium'
+ >
+ <div
+ className='flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-lg hover:bg-state-base-hover'
+ onClick={(e) => {
+ e.stopPropagation()
+ onClickEdit?.()
+ }}>
+ <RiEditLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </Tooltip>
+ <Tooltip
+ popupContent='Delete'
+ popupClassName='text-text-secondary system-xs-medium'
+ >
+ <div className='group/delete flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-lg hover:bg-state-destructive-hover'
+ onClick={(e) => {
+ e.stopPropagation()
+ setShowModal(true)
+ }
+ }>
+ <RiDeleteBinLine className='h-4 w-4 text-text-tertiary group-hover/delete:text-text-destructive' />
+ </div>
+ </Tooltip>
+ <Divider type="vertical" className="h-3.5 bg-divider-regular" />
+ </>
+ )}
+ <div
+ onClick={(e: React.MouseEvent<HTMLDivElement, MouseEvent>) =>
+ e.stopPropagation()
+ }
+ className="flex items-center"
+ >
+ <Switch
+ size='md'
+ disabled={archived || detail?.status !== 'completed'}
+ defaultValue={enabled}
+ onChange={async (val) => {
+ await onChangeSwitch?.(val, id)
+ }}
+ />
+ </div>
+ </div>
+ )}
+ </div>
+ : null}
+ </>
+ </div>
+ <ChunkContent
+ detail={{
+ answer,
+ content,
+ sign_content,
+ }}
+ isFullDocMode={isFullDocMode}
+ className={contentOpacity}
+ />
+ {isGeneralMode && <div className={cn('flex flex-wrap items-center gap-2 py-1.5', contentOpacity)}>
+ {keywords?.map(keyword => <Tag key={keyword} text={keyword} />)}
+ </div>}
+ {
+ isFullDocMode
+ ? <button
+ type='button'
+ className='system-xs-semibold-uppercase mb-2 mt-0.5 text-text-accent'
+ onClick={() => onClick?.()}
+ >{t('common.operation.viewMore')}</button>
+ : null
+ }
+ {
+ isParagraphMode && child_chunks.length > 0
+ && <ChildSegmentList
+ parentChunkId={id}
+ childChunks={child_chunks}
+ enabled={enabled}
+ onDelete={onDeleteChildChunk!}
+ handleAddNewChildChunk={handleAddNewChildChunk}
+ onClickSlice={onClickSlice}
+ focused={focused.segmentContent}
+ />
+ }
+ {showModal
+ && <Confirm
+ isShow={showModal}
+ title={t('datasetDocuments.segment.delete')}
+ confirmText={t('common.operation.sure')}
+ onConfirm={async () => { await onDelete?.(id) }}
+ onCancel={() => setShowModal(false)}
+ />
+ }
+ </div>
+ )
+}
+
+export default React.memo(SegmentCard)
diff --git a/app/components/datasets/documents/detail/completed/segment-detail.tsx b/app/components/datasets/documents/detail/completed/segment-detail.tsx
new file mode 100644
index 0000000..d3575c1
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/segment-detail.tsx
@@ -0,0 +1,185 @@
+import React, { type FC, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiCloseLine,
+ RiCollapseDiagonalLine,
+ RiExpandDiagonalLine,
+} from '@remixicon/react'
+import { useDocumentContext } from '../index'
+import ActionButtons from './common/action-buttons'
+import ChunkContent from './common/chunk-content'
+import Keywords from './common/keywords'
+import RegenerationModal from './common/regeneration-modal'
+import { SegmentIndexTag } from './common/segment-index-tag'
+import Dot from './common/dot'
+import { useSegmentListContext } from './index'
+import { ChunkingMode, type SegmentDetailModel } from '@/models/datasets'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { formatNumber } from '@/utils/format'
+import classNames from '@/utils/classnames'
+import Divider from '@/app/components/base/divider'
+
+type ISegmentDetailProps = {
+ segInfo?: Partial<SegmentDetailModel> & { id: string }
+ onUpdate: (segmentId: string, q: string, a: string, k: string[], needRegenerate?: boolean) => void
+ onCancel: () => void
+ isEditMode?: boolean
+ docForm: ChunkingMode
+}
+
+/**
+ * Show all the contents of the segment
+ */
+const SegmentDetail: FC<ISegmentDetailProps> = ({
+ segInfo,
+ onUpdate,
+ onCancel,
+ isEditMode,
+ docForm,
+}) => {
+ const { t } = useTranslation()
+ const [question, setQuestion] = useState(isEditMode ? segInfo?.content || '' : segInfo?.sign_content || '')
+ const [answer, setAnswer] = useState(segInfo?.answer || '')
+ const [keywords, setKeywords] = useState<string[]>(segInfo?.keywords || [])
+ const { eventEmitter } = useEventEmitterContextContext()
+ const [loading, setLoading] = useState(false)
+ const [showRegenerationModal, setShowRegenerationModal] = useState(false)
+ const fullScreen = useSegmentListContext(s => s.fullScreen)
+ const toggleFullScreen = useSegmentListContext(s => s.toggleFullScreen)
+ const mode = useDocumentContext(s => s.mode)
+ const parentMode = useDocumentContext(s => s.parentMode)
+
+ eventEmitter?.useSubscription((v) => {
+ if (v === 'update-segment')
+ setLoading(true)
+ if (v === 'update-segment-done')
+ setLoading(false)
+ })
+
+ const handleCancel = () => {
+ onCancel()
+ }
+
+ const handleSave = () => {
+ onUpdate(segInfo?.id || '', question, answer, keywords)
+ }
+
+ const handleRegeneration = () => {
+ setShowRegenerationModal(true)
+ }
+
+ const onCancelRegeneration = () => {
+ setShowRegenerationModal(false)
+ }
+
+ const onConfirmRegeneration = () => {
+ onUpdate(segInfo?.id || '', question, answer, keywords, true)
+ }
+
+ const isParentChildMode = useMemo(() => {
+ return mode === 'hierarchical'
+ }, [mode])
+
+ const isFullDocMode = useMemo(() => {
+ return mode === 'hierarchical' && parentMode === 'full-doc'
+ }, [mode, parentMode])
+
+ const titleText = useMemo(() => {
+ return isEditMode ? t('datasetDocuments.segment.editChunk') : t('datasetDocuments.segment.chunkDetail')
+ }, [isEditMode, t])
+
+ const isQAModel = useMemo(() => {
+ return docForm === ChunkingMode.qa
+ }, [docForm])
+
+ const wordCountText = useMemo(() => {
+ const contentLength = isQAModel ? (question.length + answer.length) : question.length
+ const total = formatNumber(isEditMode ? contentLength : segInfo!.word_count as number)
+ const count = isEditMode ? contentLength : segInfo!.word_count as number
+ return `${total} ${t('datasetDocuments.segment.characters', { count })}`
+ }, [isEditMode, question.length, answer.length, isQAModel, segInfo, t])
+
+ const labelPrefix = useMemo(() => {
+ return isParentChildMode ? t('datasetDocuments.segment.parentChunk') : t('datasetDocuments.segment.chunk')
+ }, [isParentChildMode, t])
+
+ return (
+ <div className={'flex h-full flex-col'}>
+ <div className={classNames('flex items-center justify-between', fullScreen ? 'py-3 pr-4 pl-6 border border-divider-subtle' : 'pt-3 pr-3 pl-4')}>
+ <div className='flex flex-col'>
+ <div className='system-xl-semibold text-text-primary'>{titleText}</div>
+ <div className='flex items-center gap-x-2'>
+ <SegmentIndexTag positionId={segInfo?.position || ''} label={isFullDocMode ? labelPrefix : ''} labelPrefix={labelPrefix} />
+ <Dot />
+ <span className='system-xs-medium text-text-tertiary'>{wordCountText}</span>
+ </div>
+ </div>
+ <div className='flex items-center'>
+ {isEditMode && fullScreen && (
+ <>
+ <ActionButtons
+ handleCancel={handleCancel}
+ handleRegeneration={handleRegeneration}
+ handleSave={handleSave}
+ loading={loading}
+ />
+ <Divider type='vertical' className='ml-4 mr-2 h-3.5 bg-divider-regular' />
+ </>
+ )}
+ <div className='mr-1 flex h-8 w-8 cursor-pointer items-center justify-center p-1.5' onClick={toggleFullScreen}>
+ {fullScreen ? <RiCollapseDiagonalLine className='h-4 w-4 text-text-tertiary' /> : <RiExpandDiagonalLine className='h-4 w-4 text-text-tertiary' />}
+ </div>
+ <div className='flex h-8 w-8 cursor-pointer items-center justify-center p-1.5' onClick={onCancel}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ <div className={classNames(
+ 'flex grow',
+ fullScreen ? 'w-full flex-row justify-center px-6 pt-6 gap-x-8' : 'flex-col gap-y-1 py-3 px-4',
+ !isEditMode && 'pb-0 overflow-hidden',
+ )}>
+ <div className={classNames(isEditMode ? 'break-all whitespace-pre-line overflow-hidden' : 'overflow-y-auto', fullScreen ? 'w-1/2' : 'grow')}>
+ <ChunkContent
+ docForm={docForm}
+ question={question}
+ answer={answer}
+ onQuestionChange={question => setQuestion(question)}
+ onAnswerChange={answer => setAnswer(answer)}
+ isEditMode={isEditMode}
+ />
+ </div>
+ {mode === 'custom' && <Keywords
+ className={fullScreen ? 'w-1/5' : ''}
+ actionType={isEditMode ? 'edit' : 'view'}
+ segInfo={segInfo}
+ keywords={keywords}
+ isEditMode={isEditMode}
+ onKeywordsChange={keywords => setKeywords(keywords)}
+ />}
+ </div>
+ {isEditMode && !fullScreen && (
+ <div className='flex items-center justify-end border-t-[1px] border-t-divider-subtle p-4 pt-3'>
+ <ActionButtons
+ handleCancel={handleCancel}
+ handleRegeneration={handleRegeneration}
+ handleSave={handleSave}
+ loading={loading}
+ />
+ </div>
+ )}
+ {
+ showRegenerationModal && (
+ <RegenerationModal
+ isShow={showRegenerationModal}
+ onConfirm={onConfirmRegeneration}
+ onCancel={onCancelRegeneration}
+ onClose={onCancelRegeneration}
+ />
+ )
+ }
+ </div>
+ )
+}
+
+export default React.memo(SegmentDetail)
diff --git a/app/components/datasets/documents/detail/completed/segment-list.tsx b/app/components/datasets/documents/detail/completed/segment-list.tsx
new file mode 100644
index 0000000..f6076e5
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/segment-list.tsx
@@ -0,0 +1,119 @@
+import React, { useMemo } from 'react'
+import { useDocumentContext } from '../index'
+import SegmentCard from './segment-card'
+import Empty from './common/empty'
+import GeneralListSkeleton from './skeleton/general-list-skeleton'
+import ParagraphListSkeleton from './skeleton/paragraph-list-skeleton'
+import { useSegmentListContext } from './index'
+import type { ChildChunkDetail, SegmentDetailModel } from '@/models/datasets'
+import Checkbox from '@/app/components/base/checkbox'
+import Divider from '@/app/components/base/divider'
+
+type ISegmentListProps = {
+ isLoading: boolean
+ items: SegmentDetailModel[]
+ selectedSegmentIds: string[]
+ onSelected: (segId: string) => void
+ onClick: (detail: SegmentDetailModel, isEditMode?: boolean) => void
+ onChangeSwitch: (enabled: boolean, segId?: string,) => Promise<void>
+ onDelete: (segId: string) => Promise<void>
+ onDeleteChildChunk: (sgId: string, childChunkId: string) => Promise<void>
+ handleAddNewChildChunk: (parentChunkId: string) => void
+ onClickSlice: (childChunk: ChildChunkDetail) => void
+ archived?: boolean
+ embeddingAvailable: boolean
+ onClearFilter: () => void
+}
+
+const SegmentList = (
+ {
+ ref,
+ isLoading,
+ items,
+ selectedSegmentIds,
+ onSelected,
+ onClick: onClickCard,
+ onChangeSwitch,
+ onDelete,
+ onDeleteChildChunk,
+ handleAddNewChildChunk,
+ onClickSlice,
+ archived,
+ embeddingAvailable,
+ onClearFilter,
+ }: ISegmentListProps & {
+ ref: React.LegacyRef<HTMLDivElement>
+ },
+) => {
+ const mode = useDocumentContext(s => s.mode)
+ const parentMode = useDocumentContext(s => s.parentMode)
+ const currSegment = useSegmentListContext(s => s.currSegment)
+ const currChildChunk = useSegmentListContext(s => s.currChildChunk)
+
+ const Skeleton = useMemo(() => {
+ return (mode === 'hierarchical' && parentMode === 'paragraph') ? ParagraphListSkeleton : GeneralListSkeleton
+ }, [mode, parentMode])
+
+ // Loading skeleton
+ if (isLoading)
+ return <Skeleton />
+ // Search result is empty
+ if (items.length === 0) {
+ return (
+ <div className='h-full pl-6'>
+ <Empty onClearFilter={onClearFilter} />
+ </div>
+ )
+ }
+ return (
+ <div ref={ref} className={'flex grow flex-col overflow-y-auto'}>
+ {
+ items.map((segItem) => {
+ const isLast = items[items.length - 1].id === segItem.id
+ const segmentIndexFocused
+ = currSegment?.segInfo?.id === segItem.id
+ || (!currSegment && currChildChunk?.childChunkInfo?.segment_id === segItem.id)
+ const segmentContentFocused = currSegment?.segInfo?.id === segItem.id
+ || currChildChunk?.childChunkInfo?.segment_id === segItem.id
+ return (
+ <div key={segItem.id} className='flex items-start gap-x-2'>
+ <Checkbox
+ key={`${segItem.id}-checkbox`}
+ className='mt-3.5 shrink-0'
+ checked={selectedSegmentIds.includes(segItem.id)}
+ onCheck={() => onSelected(segItem.id)}
+ />
+ <div className='min-w-0 grow'>
+ <SegmentCard
+ key={`${segItem.id}-card`}
+ detail={segItem}
+ onClick={() => onClickCard(segItem, true)}
+ onChangeSwitch={onChangeSwitch}
+ onClickEdit={() => onClickCard(segItem, true)}
+ onDelete={onDelete}
+ onDeleteChildChunk={onDeleteChildChunk}
+ handleAddNewChildChunk={handleAddNewChildChunk}
+ onClickSlice={onClickSlice}
+ loading={false}
+ archived={archived}
+ embeddingAvailable={embeddingAvailable}
+ focused={{
+ segmentIndex: segmentIndexFocused,
+ segmentContent: segmentContentFocused,
+ }}
+ />
+ {!isLast && <div className='w-full px-3'>
+ <Divider type='horizontal' className='my-1 bg-divider-subtle' />
+ </div>}
+ </div>
+ </div>
+ )
+ })
+ }
+ </div>
+ )
+}
+
+SegmentList.displayName = 'SegmentList'
+
+export default SegmentList
diff --git a/app/components/datasets/documents/detail/completed/skeleton/full-doc-list-skeleton.tsx b/app/components/datasets/documents/detail/completed/skeleton/full-doc-list-skeleton.tsx
new file mode 100644
index 0000000..cc7daa5
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/skeleton/full-doc-list-skeleton.tsx
@@ -0,0 +1,25 @@
+import React from 'react'
+
+const Slice = React.memo(() => {
+ return (
+ <div className='flex flex-col gap-y-1'>
+ <div className='flex h-5 w-full items-center bg-state-base-hover'>
+ <span className='h-5 w-[30px] bg-state-base-hover-alt' />
+ </div>
+ <div className='h-5 w-2/3 bg-state-base-hover' />
+ </div>
+ )
+})
+
+Slice.displayName = 'Slice'
+
+const FullDocListSkeleton = () => {
+ return (
+ <div className='relative z-10 flex w-full grow flex-col gap-y-3 overflow-y-hidden'>
+ <div className='absolute bottom-14 left-0 top-0 z-20 h-full w-full bg-dataset-chunk-list-mask-bg' />
+ {[...Array.from({ length: 15 })].map((_, index) => <Slice key={index} />)}
+ </div>
+ )
+}
+
+export default React.memo(FullDocListSkeleton)
diff --git a/app/components/datasets/documents/detail/completed/skeleton/general-list-skeleton.tsx b/app/components/datasets/documents/detail/completed/skeleton/general-list-skeleton.tsx
new file mode 100644
index 0000000..bf22a53
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/skeleton/general-list-skeleton.tsx
@@ -0,0 +1,74 @@
+import React from 'react'
+import {
+ SkeletonContainer,
+ SkeletonPoint,
+ SkeletonRectangle,
+ SkeletonRow,
+} from '@/app/components/base/skeleton'
+import Checkbox from '@/app/components/base/checkbox'
+import Divider from '@/app/components/base/divider'
+
+export const CardSkelton = React.memo(() => {
+ return (
+ <SkeletonContainer className='gap-y-0 p-1 pb-2'>
+ <SkeletonContainer className='gap-y-0.5 px-2 pt-1.5'>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-[72px] bg-text-quaternary' />
+ <SkeletonPoint className='opacity-20' />
+ <SkeletonRectangle className='w-24 bg-text-quaternary' />
+ <SkeletonPoint className='opacity-20' />
+ <SkeletonRectangle className='w-24 bg-text-quaternary' />
+ <SkeletonRow className='grow justify-end gap-1'>
+ <SkeletonRectangle className='w-12 bg-text-quaternary' />
+ <SkeletonRectangle className='mx-1 w-2 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-full bg-text-quaternary' />
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-full bg-text-quaternary' />
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-2/3 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonContainer>
+ <SkeletonContainer className='px-2 py-1.5'>
+ <SkeletonRow>
+ <SkeletonRectangle className='w-14 bg-text-quaternary' />
+ <SkeletonRectangle className='w-[88px] bg-text-quaternary' />
+ <SkeletonRectangle className='w-14 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonContainer>
+ </SkeletonContainer>
+ )
+})
+
+CardSkelton.displayName = 'CardSkelton'
+
+const GeneralListSkeleton = () => {
+ return (
+ <div className='relative z-10 flex grow flex-col overflow-y-hidden'>
+ <div className='absolute left-0 top-0 z-20 h-full w-full bg-dataset-chunk-list-mask-bg' />
+ {[...Array.from({ length: 10 })].map((_, index) => {
+ return (
+ <div key={index} className='flex items-start gap-x-2'>
+ <Checkbox
+ key={`${index}-checkbox`}
+ className='mt-3.5 shrink-0'
+ disabled
+ />
+ <div className='grow'>
+ <CardSkelton />
+ {index !== 9 && <div className='w-full px-3'>
+ <Divider type='horizontal' className='my-1 bg-divider-subtle' />
+ </div>}
+ </div>
+ </div>
+ )
+ })}
+ </div>
+ )
+}
+
+export default React.memo(GeneralListSkeleton)
diff --git a/app/components/datasets/documents/detail/completed/skeleton/paragraph-list-skeleton.tsx b/app/components/datasets/documents/detail/completed/skeleton/paragraph-list-skeleton.tsx
new file mode 100644
index 0000000..eb01feb
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/skeleton/paragraph-list-skeleton.tsx
@@ -0,0 +1,76 @@
+import React from 'react'
+import { RiArrowRightSLine } from '@remixicon/react'
+import {
+ SkeletonContainer,
+ SkeletonPoint,
+ SkeletonRectangle,
+ SkeletonRow,
+} from '@/app/components/base/skeleton'
+import Checkbox from '@/app/components/base/checkbox'
+import Divider from '@/app/components/base/divider'
+
+const CardSkelton = React.memo(() => {
+ return (
+ <SkeletonContainer className='gap-y-0 p-1 pb-2'>
+ <SkeletonContainer className='gap-y-0.5 px-2 pt-1.5'>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-[72px] bg-text-quaternary' />
+ <SkeletonPoint className='opacity-20' />
+ <SkeletonRectangle className='w-24 bg-text-quaternary' />
+ <SkeletonPoint className='opacity-20' />
+ <SkeletonRectangle className='w-24 bg-text-quaternary' />
+ <SkeletonRow className='grow justify-end gap-1'>
+ <SkeletonRectangle className='w-12 bg-text-quaternary' />
+ <SkeletonRectangle className='mx-1 w-2 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-full bg-text-quaternary' />
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-full bg-text-quaternary' />
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-2/3 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonContainer>
+ <SkeletonContainer className='p-1 pb-2'>
+ <SkeletonRow>
+ <SkeletonRow className='h-7 gap-x-0.5 rounded-lg bg-dataset-child-chunk-expand-btn-bg pl-1 pr-3'>
+ <RiArrowRightSLine className='h-4 w-4 text-text-secondary opacity-20' />
+ <SkeletonRectangle className='w-32 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonRow>
+ </SkeletonContainer>
+ </SkeletonContainer>
+ )
+})
+
+CardSkelton.displayName = 'CardSkelton'
+
+const ParagraphListSkeleton = () => {
+ return (
+ <div className='relative z-10 flex h-full flex-col overflow-y-hidden'>
+ <div className='absolute left-0 top-0 z-20 h-full w-full bg-dataset-chunk-list-mask-bg' />
+ {[...Array.from({ length: 10 })].map((_, index) => {
+ return (
+ <div key={index} className='flex items-start gap-x-2'>
+ <Checkbox
+ key={`${index}-checkbox`}
+ className='mt-3.5 shrink-0'
+ disabled
+ />
+ <div className='grow'>
+ <CardSkelton />
+ {index !== 9 && <div className='w-full px-3'>
+ <Divider type='horizontal' className='my-1 bg-divider-subtle' />
+ </div>}
+ </div>
+ </div>
+ )
+ })}
+ </div>
+ )
+}
+
+export default React.memo(ParagraphListSkeleton)
diff --git a/app/components/datasets/documents/detail/completed/skeleton/parent-chunk-card-skeleton.tsx b/app/components/datasets/documents/detail/completed/skeleton/parent-chunk-card-skeleton.tsx
new file mode 100644
index 0000000..f22024b
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/skeleton/parent-chunk-card-skeleton.tsx
@@ -0,0 +1,45 @@
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ SkeletonContainer,
+ SkeletonPoint,
+ SkeletonRectangle,
+ SkeletonRow,
+} from '@/app/components/base/skeleton'
+
+const ParentChunkCardSkelton = () => {
+ const { t } = useTranslation()
+ return (
+ <div className='flex flex-col pb-2'>
+ <SkeletonContainer className='gap-y-0 p-1 pb-0'>
+ <SkeletonContainer className='gap-y-0.5 px-2 pt-1.5'>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-[72px] bg-text-quaternary' />
+ <SkeletonPoint className='opacity-20' />
+ <SkeletonRectangle className='w-24 bg-text-quaternary' />
+ <SkeletonPoint className='opacity-20' />
+ <SkeletonRectangle className='w-24 bg-text-quaternary' />
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-full bg-text-quaternary' />
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-full bg-text-quaternary' />
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-2/3 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonContainer>
+ </SkeletonContainer>
+ <div className='mt-0.5 flex items-center px-3'>
+ <button type='button' className='system-xs-semibold-uppercase pt-0.5 text-components-button-secondary-accent-text-disabled' disabled>
+ {t('common.operation.viewMore')}
+ </button>
+ </div>
+ </div>
+ )
+}
+
+ParentChunkCardSkelton.displayName = 'ParentChunkCardSkelton'
+
+export default React.memo(ParentChunkCardSkelton)
diff --git a/app/components/datasets/documents/detail/completed/status-item.tsx b/app/components/datasets/documents/detail/completed/status-item.tsx
new file mode 100644
index 0000000..04fbea3
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/status-item.tsx
@@ -0,0 +1,22 @@
+import React, { type FC } from 'react'
+import { RiCheckLine } from '@remixicon/react'
+import type { Item } from '@/app/components/base/select'
+
+type IStatusItemProps = {
+ item: Item
+ selected: boolean
+}
+
+const StatusItem: FC<IStatusItemProps> = ({
+ item,
+ selected,
+}) => {
+ return (
+ <div className='flex items-center justify-between px-2 py-1.5'>
+ <span className='system-md-regular'>{item.name}</span>
+ {selected && <RiCheckLine className='h-4 w-4 text-text-accent' />}
+ </div>
+ )
+}
+
+export default React.memo(StatusItem)
diff --git a/app/components/datasets/documents/detail/completed/style.module.css b/app/components/datasets/documents/detail/completed/style.module.css
new file mode 100644
index 0000000..902ef22
--- /dev/null
+++ b/app/components/datasets/documents/detail/completed/style.module.css
@@ -0,0 +1,146 @@
+.docSearchWrapper {
+ @apply sticky w-full -top-3 flex items-center mb-3 justify-between z-[11] flex-wrap gap-y-1 pr-3;
+}
+.listContainer {
+ height: calc(100% - 3.25rem);
+ @apply box-border pb-[30px];
+}
+.cardWrapper {
+ @apply grid gap-4 grid-cols-3 min-w-[902px] last:mb-[30px];
+}
+.segWrapper {
+ @apply box-border h-[180px] w-full xl:min-w-[290px] bg-gray-50 px-4 pt-4 flex flex-col text-opacity-50 rounded-xl border border-transparent hover:border-gray-200 hover:shadow-lg hover:cursor-pointer hover:bg-white;
+}
+.segTitleWrapper {
+ @apply flex items-center justify-between;
+}
+.segStatusWrapper {
+ @apply flex items-center box-border;
+}
+.segContent {
+ white-space: wrap;
+ @apply flex-1 h-0 min-h-0 mt-2 text-sm text-gray-800 overflow-ellipsis overflow-hidden from-gray-800 to-white;
+}
+.segData {
+ @apply hidden text-gray-500 text-xs pt-2;
+}
+.segDataText {
+ @apply max-w-[80px] truncate;
+}
+.chartLinkText {
+ background: linear-gradient(to left, white, 90%, transparent);
+ @apply text-primary-600 font-semibold text-xs absolute right-0 hidden h-12 pl-12 items-center;
+}
+.select {
+ @apply h-8 py-0 pr-5 w-[100px] shadow-none !important;
+}
+.segModalContent {
+ @apply h-96 text-gray-800 text-base break-all overflow-y-scroll;
+ white-space: pre-line;
+}
+.footer {
+ @apply flex items-center justify-between box-border border-t-gray-200 border-t-[0.5px] pt-3 mt-4 flex-wrap gap-y-2;
+}
+.numberInfo {
+ @apply text-gray-500 text-xs font-medium;
+}
+.keywordTitle {
+ @apply text-gray-500 mb-2 mt-1 text-xs uppercase;
+}
+.keywordWrapper {
+ @apply text-gray-700 w-full max-h-[200px] overflow-auto flex flex-wrap;
+}
+.keyword {
+ @apply text-sm border border-gray-200 max-w-[200px] max-h-[100px] whitespace-pre-line overflow-y-auto mr-1 mb-2 last:mr-0 px-2 py-1 rounded-lg;
+}
+.hashText {
+ @apply w-48 inline-block truncate;
+}
+.commonIcon {
+ @apply w-3 h-3 inline-block align-middle mr-1 bg-gray-500;
+ mask-repeat: no-repeat;
+ mask-size: contain;
+ mask-position: center center;
+}
+.targetIcon {
+ mask-image: url(../../assets/target.svg);
+}
+.typeSquareIcon {
+ mask-image: url(../../assets/typeSquare.svg);
+}
+.bezierCurveIcon {
+ mask-image: url(../../assets/bezierCurve.svg);
+}
+.cardLoadingWrapper {
+ @apply relative w-full h-full inline-block rounded-b-xl;
+ background-position: center center;
+ background-repeat: no-repeat;
+ background-size: 100% 100%;
+ background-origin: content-box;
+}
+.cardLoadingIcon {
+ background-image: url(../../assets/cardLoading.svg);
+}
+/* .hitLoadingIcon {
+ background-image: url(../../assets/hitLoading.svg);
+} */
+.cardLoadingBg {
+ @apply h-full relative rounded-b-xl mt-4;
+ left: calc(-1rem - 1px);
+ width: calc(100% + 2rem + 2px);
+ height: calc(100% - 1rem + 1px);
+ background: linear-gradient(
+ 180deg,
+ rgba(252, 252, 253, 0) 0%,
+ #fcfcfd 74.15%
+ );
+}
+
+.hitTitleWrapper {
+ @apply w-full flex items-center justify-between mb-2;
+}
+.progressWrapper {
+ @apply flex items-center justify-between w-full;
+}
+.progress {
+ border-radius: 3px;
+ @apply relative h-1.5 box-border border border-gray-300 flex-1 mr-2;
+}
+.progressLoading {
+ @apply border-[#EAECF0] bg-[#EAECF0];
+}
+.progressInner {
+ @apply absolute top-0 h-full bg-gray-300;
+}
+.progressText {
+ font-size: 13px;
+ @apply text-gray-700 font-bold;
+}
+.progressTextLoading {
+ border-radius: 5px;
+ @apply h-3.5 w-3.5 bg-[#EAECF0];
+}
+.editTip {
+ box-shadow: 0px 4px 6px -2px rgba(16, 24, 40, 0.03), 0px 12px 16px -4px rgba(16, 24, 40, 0.08);
+}
+
+.delModal {
+ background: linear-gradient(
+ 180deg,
+ rgba(217, 45, 32, 0.05) 0%,
+ rgba(217, 45, 32, 0) 24.02%
+ ),
+ #f9fafb;
+ box-shadow: 0px 20px 24px -4px rgba(16, 24, 40, 0.08),
+ 0px 8px 8px -4px rgba(16, 24, 40, 0.03);
+ @apply rounded-2xl p-8;
+}
+.warningWrapper {
+ box-shadow: 0px 20px 24px -4px rgba(16, 24, 40, 0.08),
+ 0px 8px 8px -4px rgba(16, 24, 40, 0.03);
+ background: rgba(255, 255, 255, 0.9);
+ @apply h-12 w-12 border-[0.5px] border-gray-100 rounded-xl mb-3 flex items-center justify-center;
+}
+.warningIcon {
+ @apply w-[22px] h-[22px] fill-current text-red-600;
+}
diff --git a/app/components/datasets/documents/detail/embedding/index.tsx b/app/components/datasets/documents/detail/embedding/index.tsx
new file mode 100644
index 0000000..e9ea72b
--- /dev/null
+++ b/app/components/datasets/documents/detail/embedding/index.tsx
@@ -0,0 +1,314 @@
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import useSWR from 'swr'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { omit } from 'lodash-es'
+import { RiLoader2Line, RiPauseCircleLine, RiPlayCircleLine } from '@remixicon/react'
+import Image from 'next/image'
+import { FieldInfo } from '../metadata'
+import { useDocumentContext } from '../index'
+import { IndexingType } from '../../../create/step-two'
+import { indexMethodIcon, retrievalIcon } from '../../../create/icons'
+import EmbeddingSkeleton from './skeleton'
+import { RETRIEVE_METHOD } from '@/types/app'
+import cn from '@/utils/classnames'
+import Divider from '@/app/components/base/divider'
+import { ToastContext } from '@/app/components/base/toast'
+import type { IndexingStatusResponse } from '@/models/datasets'
+import { ProcessMode, type ProcessRuleResponse } from '@/models/datasets'
+import type { CommonResponse } from '@/models/common'
+import { asyncRunSafe, sleep } from '@/utils'
+import {
+ fetchIndexingStatus as doFetchIndexingStatus,
+ fetchProcessRule,
+ pauseDocIndexing,
+ resumeDocIndexing,
+} from '@/service/datasets'
+
+type IEmbeddingDetailProps = {
+ datasetId?: string
+ documentId?: string
+ indexingType?: IndexingType
+ retrievalMethod?: RETRIEVE_METHOD
+ detailUpdate: VoidFunction
+}
+
+type IRuleDetailProps = {
+ sourceData?: ProcessRuleResponse
+ indexingType?: IndexingType
+ retrievalMethod?: RETRIEVE_METHOD
+}
+
+const RuleDetail: FC<IRuleDetailProps> = React.memo(({
+ sourceData,
+ indexingType,
+ retrievalMethod,
+}) => {
+ const { t } = useTranslation()
+
+ const segmentationRuleMap = {
+ mode: t('datasetDocuments.embedding.mode'),
+ segmentLength: t('datasetDocuments.embedding.segmentLength'),
+ textCleaning: t('datasetDocuments.embedding.textCleaning'),
+ }
+
+ const getRuleName = (key: string) => {
+ if (key === 'remove_extra_spaces')
+ return t('datasetCreation.stepTwo.removeExtraSpaces')
+
+ if (key === 'remove_urls_emails')
+ return t('datasetCreation.stepTwo.removeUrlEmails')
+
+ if (key === 'remove_stopwords')
+ return t('datasetCreation.stepTwo.removeStopwords')
+ }
+
+ const isNumber = (value: unknown) => {
+ return typeof value === 'number'
+ }
+
+ const getValue = useCallback((field: string) => {
+ let value: string | number | undefined = '-'
+ const maxTokens = isNumber(sourceData?.rules?.segmentation?.max_tokens)
+ ? sourceData.rules.segmentation.max_tokens
+ : value
+ const childMaxTokens = isNumber(sourceData?.rules?.subchunk_segmentation?.max_tokens)
+ ? sourceData.rules.subchunk_segmentation.max_tokens
+ : value
+ switch (field) {
+ case 'mode':
+ value = !sourceData?.mode
+ ? value
+ : sourceData.mode === ProcessMode.general
+ ? (t('datasetDocuments.embedding.custom') as string)
+ : `${t('datasetDocuments.embedding.hierarchical')} 路 ${sourceData?.rules?.parent_mode === 'paragraph'
+ ? t('dataset.parentMode.paragraph')
+ : t('dataset.parentMode.fullDoc')}`
+ break
+ case 'segmentLength':
+ value = !sourceData?.mode
+ ? value
+ : sourceData.mode === ProcessMode.general
+ ? maxTokens
+ : `${t('datasetDocuments.embedding.parentMaxTokens')} ${maxTokens}; ${t('datasetDocuments.embedding.childMaxTokens')} ${childMaxTokens}`
+ break
+ default:
+ value = !sourceData?.mode
+ ? value
+ : sourceData?.rules?.pre_processing_rules?.filter(rule =>
+ rule.enabled).map(rule => getRuleName(rule.id)).join(',')
+ break
+ }
+ return value
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [sourceData])
+
+ return <div className='py-3'>
+ <div className='flex flex-col gap-y-1'>
+ {Object.keys(segmentationRuleMap).map((field) => {
+ return <FieldInfo
+ key={field}
+ label={segmentationRuleMap[field as keyof typeof segmentationRuleMap]}
+ displayedValue={String(getValue(field))}
+ />
+ })}
+ </div>
+ <Divider type='horizontal' className='bg-divider-subtle' />
+ <FieldInfo
+ label={t('datasetCreation.stepTwo.indexMode')}
+ displayedValue={t(`datasetCreation.stepTwo.${indexingType === IndexingType.ECONOMICAL ? 'economical' : 'qualified'}`) as string}
+ valueIcon={
+ <Image
+ className='size-4'
+ src={
+ indexingType === IndexingType.ECONOMICAL
+ ? indexMethodIcon.economical
+ : indexMethodIcon.high_quality
+ }
+ alt=''
+ />
+ }
+ />
+ <FieldInfo
+ label={t('datasetSettings.form.retrievalSetting.title')}
+ displayedValue={t(`dataset.retrieval.${indexingType === IndexingType.ECONOMICAL ? 'invertedIndex' : retrievalMethod}.title`) as string}
+ valueIcon={
+ <Image
+ className='size-4'
+ src={
+ retrievalMethod === RETRIEVE_METHOD.fullText
+ ? retrievalIcon.fullText
+ : retrievalMethod === RETRIEVE_METHOD.hybrid
+ ? retrievalIcon.hybrid
+ : retrievalIcon.vector
+ }
+ alt=''
+ />
+ }
+ />
+ </div>
+})
+
+RuleDetail.displayName = 'RuleDetail'
+
+const EmbeddingDetail: FC<IEmbeddingDetailProps> = ({
+ datasetId: dstId,
+ documentId: docId,
+ detailUpdate,
+ indexingType,
+ retrievalMethod,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+
+ const datasetId = useDocumentContext(s => s.datasetId)
+ const documentId = useDocumentContext(s => s.documentId)
+ const localDatasetId = dstId ?? datasetId
+ const localDocumentId = docId ?? documentId
+
+ const [indexingStatusDetail, setIndexingStatusDetail] = useState<IndexingStatusResponse | null>(null)
+ const fetchIndexingStatus = async () => {
+ const status = await doFetchIndexingStatus({ datasetId: localDatasetId, documentId: localDocumentId })
+ setIndexingStatusDetail(status)
+ return status
+ }
+
+ const isStopQuery = useRef(false)
+ const stopQueryStatus = useCallback(() => {
+ isStopQuery.current = true
+ }, [])
+
+ const startQueryStatus = useCallback(async () => {
+ if (isStopQuery.current)
+ return
+
+ try {
+ const indexingStatusDetail = await fetchIndexingStatus()
+ if (['completed', 'error', 'paused'].includes(indexingStatusDetail?.indexing_status)) {
+ stopQueryStatus()
+ detailUpdate()
+ return
+ }
+
+ await sleep(2500)
+ await startQueryStatus()
+ }
+ catch {
+ await sleep(2500)
+ await startQueryStatus()
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [stopQueryStatus])
+
+ useEffect(() => {
+ isStopQuery.current = false
+ startQueryStatus()
+ return () => {
+ stopQueryStatus()
+ }
+ }, [startQueryStatus, stopQueryStatus])
+
+ const { data: ruleDetail } = useSWR({
+ action: 'fetchProcessRule',
+ params: { documentId: localDocumentId },
+ }, apiParams => fetchProcessRule(omit(apiParams, 'action')), {
+ revalidateOnFocus: false,
+ })
+
+ const isEmbedding = useMemo(() => ['indexing', 'splitting', 'parsing', 'cleaning'].includes(indexingStatusDetail?.indexing_status || ''), [indexingStatusDetail])
+ const isEmbeddingCompleted = useMemo(() => ['completed'].includes(indexingStatusDetail?.indexing_status || ''), [indexingStatusDetail])
+ const isEmbeddingPaused = useMemo(() => ['paused'].includes(indexingStatusDetail?.indexing_status || ''), [indexingStatusDetail])
+ const isEmbeddingError = useMemo(() => ['error'].includes(indexingStatusDetail?.indexing_status || ''), [indexingStatusDetail])
+ const percent = useMemo(() => {
+ const completedCount = indexingStatusDetail?.completed_segments || 0
+ const totalCount = indexingStatusDetail?.total_segments || 0
+ if (totalCount === 0)
+ return 0
+ const percent = Math.round(completedCount * 100 / totalCount)
+ return percent > 100 ? 100 : percent
+ }, [indexingStatusDetail])
+
+ const handleSwitch = async () => {
+ const opApi = isEmbedding ? pauseDocIndexing : resumeDocIndexing
+ const [e] = await asyncRunSafe<CommonResponse>(opApi({ datasetId: localDatasetId, documentId: localDocumentId }) as Promise<CommonResponse>)
+ if (!e) {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ // if the embedding is resumed from paused, we need to start the query status
+ if (isEmbeddingPaused) {
+ isStopQuery.current = false
+ startQueryStatus()
+ detailUpdate()
+ }
+ setIndexingStatusDetail(null)
+ }
+ else {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ }
+ }
+
+ return (
+ <>
+ <div className='flex flex-col gap-y-2 px-16 py-12'>
+ <div className='flex h-6 items-center gap-x-1'>
+ {isEmbedding && <RiLoader2Line className='h-4 w-4 animate-spin text-text-secondary' />}
+ <span className='system-md-semibold-uppercase grow text-text-secondary'>
+ {isEmbedding && t('datasetDocuments.embedding.processing')}
+ {isEmbeddingCompleted && t('datasetDocuments.embedding.completed')}
+ {isEmbeddingPaused && t('datasetDocuments.embedding.paused')}
+ {isEmbeddingError && t('datasetDocuments.embedding.error')}
+ </span>
+ {isEmbedding && (
+ <button
+ type='button'
+ className={`flex items-center gap-x-1 rounded-md border-[0.5px]
+ border-components-button-secondary-border bg-components-button-secondary-bg px-1.5 py-1 shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px]`}
+ onClick={handleSwitch}
+ >
+ <RiPauseCircleLine className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <span className='system-xs-medium pr-[3px] text-components-button-secondary-text'>
+ {t('datasetDocuments.embedding.pause')}
+ </span>
+ </button>
+ )}
+ {isEmbeddingPaused && (
+ <button
+ type='button'
+ className={`flex items-center gap-x-1 rounded-md border-[0.5px]
+ border-components-button-secondary-border bg-components-button-secondary-bg px-1.5 py-1 shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px]`}
+ onClick={handleSwitch}
+ >
+ <RiPlayCircleLine className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <span className='system-xs-medium pr-[3px] text-components-button-secondary-text'>
+ {t('datasetDocuments.embedding.resume')}
+ </span>
+ </button>
+ )}
+ </div>
+ {/* progress bar */}
+ <div className={cn(
+ 'flex h-2 w-full items-center overflow-hidden rounded-md border border-components-progress-bar-border',
+ isEmbedding ? 'bg-components-progress-bar-bg bg-opacity-50' : 'bg-components-progress-bar-bg',
+ )}>
+ <div
+ className={cn(
+ 'h-full',
+ (isEmbedding || isEmbeddingCompleted) && 'bg-components-progress-bar-progress-solid',
+ (isEmbeddingPaused || isEmbeddingError) && 'bg-components-progress-bar-progress-highlight',
+ )}
+ style={{ width: `${percent}%` }}
+ />
+ </div>
+ <div className={'flex w-full items-center'}>
+ <span className='system-xs-medium text-text-secondary'>
+ {`${t('datasetDocuments.embedding.segments')} ${indexingStatusDetail?.completed_segments || '--'}/${indexingStatusDetail?.total_segments || '--'} 路 ${percent}%`}
+ </span>
+ </div>
+ <RuleDetail sourceData={ruleDetail} indexingType={indexingType} retrievalMethod={retrievalMethod} />
+ </div>
+ <EmbeddingSkeleton />
+ </>
+ )
+}
+
+export default React.memo(EmbeddingDetail)
diff --git a/app/components/datasets/documents/detail/embedding/skeleton/index.tsx b/app/components/datasets/documents/detail/embedding/skeleton/index.tsx
new file mode 100644
index 0000000..523af54
--- /dev/null
+++ b/app/components/datasets/documents/detail/embedding/skeleton/index.tsx
@@ -0,0 +1,66 @@
+import React from 'react'
+import {
+ SkeletonContainer,
+ SkeletonPoint,
+ SkeletonRectangle,
+ SkeletonRow,
+} from '@/app/components/base/skeleton'
+import Divider from '@/app/components/base/divider'
+
+const CardSkelton = React.memo(() => {
+ return (
+ <SkeletonContainer className='gap-y-0 p-1 pb-2'>
+ <SkeletonContainer className='gap-y-0.5 px-2 pt-1.5'>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-[72px] bg-text-quaternary' />
+ <SkeletonPoint className='opacity-20' />
+ <SkeletonRectangle className='w-24 bg-text-quaternary' />
+ <SkeletonPoint className='opacity-20' />
+ <SkeletonRectangle className='w-24 bg-text-quaternary' />
+ <SkeletonRow className='grow justify-end gap-1'>
+ <SkeletonRectangle className='w-12 bg-text-quaternary' />
+ <SkeletonRectangle className='mx-1 w-2 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-full bg-text-quaternary' />
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-full bg-text-quaternary' />
+ </SkeletonRow>
+ <SkeletonRow className='py-0.5'>
+ <SkeletonRectangle className='w-2/3 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonContainer>
+ <SkeletonContainer className='px-2 py-1.5'>
+ <SkeletonRow>
+ <SkeletonRectangle className='w-14 bg-text-quaternary' />
+ <SkeletonRectangle className='w-[88px] bg-text-quaternary' />
+ <SkeletonRectangle className='w-14 bg-text-quaternary' />
+ </SkeletonRow>
+ </SkeletonContainer>
+ </SkeletonContainer>
+ )
+})
+
+CardSkelton.displayName = 'CardSkelton'
+
+const EmbeddingSkeleton = () => {
+ return (
+ <div className='relative z-10 flex grow flex-col overflow-y-hidden'>
+ <div className='absolute left-0 top-0 z-20 h-full w-full bg-dataset-chunk-list-mask-bg' />
+ {[...Array.from({ length: 5 })].map((_, index) => {
+ return (
+ <div key={index} className='w-full px-11'>
+ <CardSkelton />
+ {index !== 9 && <div className='w-full px-3'>
+ <Divider type='horizontal' className='my-1 bg-divider-subtle' />
+ </div>}
+ </div>
+ )
+ })}
+ </div>
+ )
+}
+
+export default React.memo(EmbeddingSkeleton)
diff --git a/app/components/datasets/documents/detail/embedding/style.module.css b/app/components/datasets/documents/detail/embedding/style.module.css
new file mode 100644
index 0000000..c24444a
--- /dev/null
+++ b/app/components/datasets/documents/detail/embedding/style.module.css
@@ -0,0 +1,59 @@
+.progressBar {
+ @apply absolute top-0 h-4;
+}
+.barPaused {
+ background: linear-gradient(
+ 270deg,
+ rgba(208, 213, 221, 0.8) -2.21%,
+ rgba(208, 213, 221, 0.5) 100%
+ );
+}
+.barProcessing {
+ background: linear-gradient(
+ 90deg,
+ rgba(41, 112, 255, 0.9) 0%,
+ rgba(21, 94, 239, 0.9) 100%
+ );
+}
+.opBtn {
+ @apply w-fit h-6 text-xs px-2 py-1 text-gray-700 rounded-md !important;
+}
+.opIcon {
+ @apply mr-1 stroke-current text-gray-700 w-3 h-3;
+}
+.progressContainer {
+ @apply relative flex mb-2 h-4 rounded-md w-full;
+}
+.progressBgItem {
+ @apply flex-1 border-r border-r-white first:rounded-l-md;
+}
+.progressBgItem:nth-last-child(2) {
+ @apply rounded-r-md;
+}
+.progressData {
+ @apply w-full flex items-center text-xs text-gray-700;
+}
+.previewTip {
+ @apply pb-1 pt-12 text-gray-900 text-sm font-medium;
+}
+.embeddingStatus {
+ @apply flex items-center justify-between text-gray-900 font-medium text-base mb-3;
+}
+.commonIcon {
+ @apply w-3 h-3 mr-1 inline-block align-middle;
+}
+.highIcon {
+ mask-image: url(../../assets/star.svg);
+ @apply bg-orange-500;
+}
+.economyIcon {
+ background-color: #444ce7;
+ mask-image: url(../../assets/normal.svg);
+}
+.tokens {
+ @apply text-xs font-medium px-1;
+}
+.price {
+ color: #f79009;
+ @apply text-xs font-medium;
+}
diff --git a/app/components/datasets/documents/detail/index.tsx b/app/components/datasets/documents/detail/index.tsx
new file mode 100644
index 0000000..aff7403
--- /dev/null
+++ b/app/components/datasets/documents/detail/index.tsx
@@ -0,0 +1,300 @@
+'use client'
+import type { FC } from 'react'
+import React, { useMemo, useState } from 'react'
+import { createContext, useContext, useContextSelector } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { useRouter } from 'next/navigation'
+import { RiArrowLeftLine, RiLayoutLeft2Line, RiLayoutRight2Line } from '@remixicon/react'
+import { OperationAction, StatusItem } from '../list'
+import DocumentPicker from '../../common/document-picker'
+import Completed from './completed'
+import Embedding from './embedding'
+import Metadata from '@/app/components/datasets/metadata/metadata-document'
+import SegmentAdd, { ProcessStatus } from './segment-add'
+import BatchModal from './batch-modal'
+import style from './style.module.css'
+import cn from '@/utils/classnames'
+import Divider from '@/app/components/base/divider'
+import Loading from '@/app/components/base/loading'
+import { ToastContext } from '@/app/components/base/toast'
+import type { ChunkingMode, ParentMode, ProcessMode } from '@/models/datasets'
+import { useDatasetDetailContext } from '@/context/dataset-detail'
+import FloatRightContainer from '@/app/components/base/float-right-container'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import { useCheckSegmentBatchImportProgress, useChildSegmentListKey, useSegmentBatchImport, useSegmentListKey } from '@/service/knowledge/use-segment'
+import { useDocumentDetail, useDocumentMetadata, useInvalidDocumentList } from '@/service/knowledge/use-document'
+import { useInvalid } from '@/service/use-base'
+
+type DocumentContextValue = {
+ datasetId?: string
+ documentId?: string
+ docForm: string
+ mode?: ProcessMode
+ parentMode?: ParentMode
+}
+
+export const DocumentContext = createContext<DocumentContextValue>({ docForm: '' })
+
+export const useDocumentContext = (selector: (value: DocumentContextValue) => any) => {
+ return useContextSelector(DocumentContext, selector)
+}
+
+type DocumentTitleProps = {
+ datasetId: string
+ extension?: string
+ name?: string
+ processMode?: ProcessMode
+ parent_mode?: ParentMode
+ iconCls?: string
+ textCls?: string
+ wrapperCls?: string
+}
+
+export const DocumentTitle: FC<DocumentTitleProps> = ({ datasetId, extension, name, processMode, parent_mode, wrapperCls }) => {
+ const router = useRouter()
+ return (
+ <div className={cn('flex flex-1 items-center justify-start', wrapperCls)}>
+ <DocumentPicker
+ datasetId={datasetId}
+ value={{
+ name,
+ extension,
+ processMode,
+ parentMode: parent_mode,
+ }}
+ onChange={(doc) => {
+ router.push(`/datasets/${datasetId}/documents/${doc.id}`)
+ }}
+ />
+ </div>
+ )
+}
+
+type Props = {
+ datasetId: string
+ documentId: string
+}
+
+const DocumentDetail: FC<Props> = ({ datasetId, documentId }) => {
+ const router = useRouter()
+ const { t } = useTranslation()
+
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ const { notify } = useContext(ToastContext)
+ const { dataset } = useDatasetDetailContext()
+ const embeddingAvailable = !!dataset?.embedding_available
+ const [showMetadata, setShowMetadata] = useState(!isMobile)
+ const [newSegmentModalVisible, setNewSegmentModalVisible] = useState(false)
+ const [batchModalVisible, setBatchModalVisible] = useState(false)
+ const [importStatus, setImportStatus] = useState<ProcessStatus | string>()
+ const showNewSegmentModal = () => setNewSegmentModalVisible(true)
+ const showBatchModal = () => setBatchModalVisible(true)
+ const hideBatchModal = () => setBatchModalVisible(false)
+ const resetProcessStatus = () => setImportStatus('')
+
+ const { mutateAsync: checkSegmentBatchImportProgress } = useCheckSegmentBatchImportProgress()
+ const checkProcess = async (jobID: string) => {
+ await checkSegmentBatchImportProgress({ jobID }, {
+ onSuccess: (res) => {
+ setImportStatus(res.job_status)
+ if (res.job_status === ProcessStatus.WAITING || res.job_status === ProcessStatus.PROCESSING)
+ setTimeout(() => checkProcess(res.job_id), 2500)
+ if (res.job_status === ProcessStatus.ERROR)
+ notify({ type: 'error', message: `${t('datasetDocuments.list.batchModal.runError')}` })
+ },
+ onError: (e) => {
+ notify({ type: 'error', message: `${t('datasetDocuments.list.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` })
+ },
+ })
+ }
+
+ const { mutateAsync: segmentBatchImport } = useSegmentBatchImport()
+ const runBatch = async (csv: File) => {
+ const formData = new FormData()
+ formData.append('file', csv)
+ await segmentBatchImport({
+ url: `/datasets/${datasetId}/documents/${documentId}/segments/batch_import`,
+ body: formData,
+ }, {
+ onSuccess: (res) => {
+ setImportStatus(res.job_status)
+ checkProcess(res.job_id)
+ },
+ onError: (e) => {
+ notify({ type: 'error', message: `${t('datasetDocuments.list.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` })
+ },
+ })
+ }
+
+ const { data: documentDetail, error, refetch: detailMutate } = useDocumentDetail({
+ datasetId,
+ documentId,
+ params: { metadata: 'without' },
+ })
+
+ const { data: documentMetadata } = useDocumentMetadata({
+ datasetId,
+ documentId,
+ params: { metadata: 'only' },
+ })
+
+ const backToPrev = () => {
+ router.push(`/datasets/${datasetId}/documents`)
+ }
+
+ const isDetailLoading = !documentDetail && !error
+
+ const embedding = ['queuing', 'indexing', 'paused'].includes((documentDetail?.display_status || '').toLowerCase())
+
+ const invalidChunkList = useInvalid(useSegmentListKey)
+ const invalidChildChunkList = useInvalid(useChildSegmentListKey)
+ const invalidDocumentList = useInvalidDocumentList(datasetId)
+
+ const handleOperate = (operateName?: string) => {
+ invalidDocumentList()
+ if (operateName === 'delete') {
+ backToPrev()
+ }
+ else {
+ detailMutate()
+ // If operation is not rename, refresh the chunk list after 5 seconds
+ if (operateName) {
+ setTimeout(() => {
+ invalidChunkList()
+ invalidChildChunkList()
+ }, 5000)
+ }
+ }
+ }
+
+ const mode = useMemo(() => {
+ return documentDetail?.document_process_rule?.mode
+ }, [documentDetail?.document_process_rule])
+
+ const parentMode = useMemo(() => {
+ return documentDetail?.document_process_rule?.rules?.parent_mode
+ }, [documentDetail?.document_process_rule])
+
+ const isFullDocMode = useMemo(() => {
+ return mode === 'hierarchical' && parentMode === 'full-doc'
+ }, [mode, parentMode])
+
+ return (
+ <DocumentContext.Provider value={{
+ datasetId,
+ documentId,
+ docForm: documentDetail?.doc_form || '',
+ mode,
+ parentMode,
+ }}>
+ <div className='flex h-full flex-col bg-background-default'>
+ <div className='flex min-h-16 flex-wrap items-center justify-between border-b border-b-divider-subtle py-2.5 pl-3 pr-4'>
+ <div onClick={backToPrev} className={'flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-full hover:bg-components-button-tertiary-bg'}>
+ <RiArrowLeftLine className='h-4 w-4 text-components-button-ghost-text hover:text-text-tertiary' />
+ </div>
+ <DocumentTitle
+ datasetId={datasetId}
+ extension={documentDetail?.data_source_info?.upload_file?.extension}
+ name={documentDetail?.name}
+ wrapperCls='mr-2'
+ parent_mode={parentMode}
+ processMode={mode}
+ />
+ <div className='flex flex-wrap items-center'>
+ {embeddingAvailable && documentDetail && !documentDetail.archived && !isFullDocMode && (
+ <>
+ <SegmentAdd
+ importStatus={importStatus}
+ clearProcessStatus={resetProcessStatus}
+ showNewSegmentModal={showNewSegmentModal}
+ showBatchModal={showBatchModal}
+ embedding={embedding}
+ />
+ <Divider type='vertical' className='!mx-3 !h-[14px] !bg-divider-regular' />
+ </>
+ )}
+ <StatusItem
+ status={documentDetail?.display_status || 'available'}
+ scene='detail'
+ errorMessage={documentDetail?.error || ''}
+ textCls='font-semibold text-xs uppercase'
+ detail={{
+ enabled: documentDetail?.enabled || false,
+ archived: documentDetail?.archived || false,
+ id: documentId,
+ }}
+ datasetId={datasetId}
+ onUpdate={handleOperate}
+ />
+ <OperationAction
+ scene='detail'
+ embeddingAvailable={embeddingAvailable}
+ detail={{
+ name: documentDetail?.name || '',
+ enabled: documentDetail?.enabled || false,
+ archived: documentDetail?.archived || false,
+ id: documentId,
+ data_source_type: documentDetail?.data_source_type || '',
+ doc_form: documentDetail?.doc_form || '',
+ }}
+ datasetId={datasetId}
+ onUpdate={handleOperate}
+ className='!w-[200px]'
+ />
+ <button
+ className={style.layoutRightIcon}
+ onClick={() => setShowMetadata(!showMetadata)}
+ >
+ {
+ showMetadata
+ ? <RiLayoutLeft2Line className='h-4 w-4 text-components-button-secondary-text' />
+ : <RiLayoutRight2Line className='h-4 w-4 text-components-button-secondary-text' />
+ }
+ </button>
+ </div>
+ </div>
+ <div className='flex flex-1 flex-row' style={{ height: 'calc(100% - 4rem)' }}>
+ {isDetailLoading
+ ? <Loading type='app' />
+ : <div className={cn('flex h-full min-w-0 grow flex-col',
+ embedding ? '' : isFullDocMode ? 'relative pl-11 pr-11 pt-4' : 'relative pl-5 pr-11 pt-3',
+ )}>
+ {embedding
+ ? <Embedding
+ detailUpdate={detailMutate}
+ indexingType={dataset?.indexing_technique}
+ retrievalMethod={dataset?.retrieval_model_dict?.search_method}
+ />
+ : <Completed
+ embeddingAvailable={embeddingAvailable}
+ showNewSegmentModal={newSegmentModalVisible}
+ onNewSegmentModalChange={setNewSegmentModalVisible}
+ importStatus={importStatus}
+ archived={documentDetail?.archived}
+ />
+ }
+ </div>
+ }
+ <FloatRightContainer showClose isOpen={showMetadata} onClose={() => setShowMetadata(false)} isMobile={isMobile} panelClassName='!justify-start' footer={null}>
+ <Metadata
+ className='mr-2 mt-3'
+ datasetId={datasetId}
+ documentId={documentId}
+ docDetail={{ ...documentDetail, ...documentMetadata, doc_type: documentMetadata?.doc_type === 'others' ? '' : documentMetadata?.doc_type } as any}
+ />
+ </FloatRightContainer>
+ </div>
+ <BatchModal
+ isShow={batchModalVisible}
+ onCancel={hideBatchModal}
+ onConfirm={runBatch}
+ docForm={documentDetail?.doc_form as ChunkingMode}
+ />
+ </div>
+ </DocumentContext.Provider>
+ )
+}
+
+export default DocumentDetail
diff --git a/app/components/datasets/documents/detail/metadata/index.tsx b/app/components/datasets/documents/detail/metadata/index.tsx
new file mode 100644
index 0000000..da269fc
--- /dev/null
+++ b/app/components/datasets/documents/detail/metadata/index.tsx
@@ -0,0 +1,377 @@
+'use client'
+import type { FC, ReactNode } from 'react'
+import React, { useEffect, useState } from 'react'
+import { PencilIcon } from '@heroicons/react/24/outline'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { get } from 'lodash-es'
+import { useDocumentContext } from '../index'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import Input from '@/app/components/base/input'
+import Button from '@/app/components/base/button'
+import Tooltip from '@/app/components/base/tooltip'
+import Radio from '@/app/components/base/radio'
+import Divider from '@/app/components/base/divider'
+import { ToastContext } from '@/app/components/base/toast'
+import { SimpleSelect } from '@/app/components/base/select'
+import Loading from '@/app/components/base/loading'
+import AutoHeightTextarea from '@/app/components/base/auto-height-textarea'
+import { asyncRunSafe, getTextWidthWithCanvas } from '@/utils'
+import { modifyDocMetadata } from '@/service/datasets'
+import type { CommonResponse } from '@/models/common'
+import type { DocType, FullDocumentDetail } from '@/models/datasets'
+import { CUSTOMIZABLE_DOC_TYPES } from '@/models/datasets'
+import type { inputType, metadataType } from '@/hooks/use-metadata'
+import { useBookCategories, useBusinessDocCategories, useLanguages, useMetadataMap, usePersonalDocCategories } from '@/hooks/use-metadata'
+
+const map2Options = (map: { [key: string]: string }) => {
+ return Object.keys(map).map(key => ({ value: key, name: map[key] }))
+}
+
+type IFieldInfoProps = {
+ label: string
+ value?: string
+ valueIcon?: ReactNode
+ displayedValue?: string
+ defaultValue?: string
+ showEdit?: boolean
+ inputType?: inputType
+ selectOptions?: Array<{ value: string; name: string }>
+ onUpdate?: (v: any) => void
+}
+
+export const FieldInfo: FC<IFieldInfoProps> = ({
+ label,
+ value = '',
+ valueIcon,
+ displayedValue = '',
+ defaultValue,
+ showEdit = false,
+ inputType = 'input',
+ selectOptions = [],
+ onUpdate,
+}) => {
+ const { t } = useTranslation()
+ const textNeedWrap = getTextWidthWithCanvas(displayedValue) > 190
+ const editAlignTop = showEdit && inputType === 'textarea'
+ const readAlignTop = !showEdit && textNeedWrap
+
+ return (
+ <div className={cn('flex min-h-5 items-center gap-1 py-0.5 text-xs', editAlignTop && '!items-start', readAlignTop && '!items-start pt-1')}>
+ <div className={cn('w-[200px] shrink-0 overflow-hidden text-ellipsis whitespace-nowrap text-text-tertiary', editAlignTop && 'pt-1')}>{label}</div>
+ <div className="flex grow items-center gap-1 text-text-secondary">
+ {valueIcon}
+ {!showEdit
+ ? displayedValue
+ : inputType === 'select'
+ ? <SimpleSelect
+ onSelect={({ value }) => onUpdate && onUpdate(value as string)}
+ items={selectOptions}
+ defaultValue={value}
+ className={s.select}
+ wrapperClassName={s.selectWrapper}
+ placeholder={`${t('datasetDocuments.metadata.placeholder.select')}${label}`}
+ />
+ : inputType === 'textarea'
+ ? <AutoHeightTextarea
+ onChange={e => onUpdate && onUpdate(e.target.value)}
+ value={value}
+ className={s.textArea}
+ placeholder={`${t('datasetDocuments.metadata.placeholder.add')}${label}`}
+ />
+ : <Input
+ onChange={e => onUpdate?.(e.target.value)}
+ value={value}
+ defaultValue={defaultValue}
+ placeholder={`${t('datasetDocuments.metadata.placeholder.add')}${label}`}
+ />
+ }
+ </div>
+ </div>
+ )
+}
+
+const TypeIcon: FC<{ iconName: string; className?: string }> = ({ iconName, className = '' }) => {
+ return <div className={cn(s.commonIcon, s[`${iconName}Icon`], className)}
+ />
+}
+
+const IconButton: FC<{
+ type: DocType
+ isChecked: boolean
+}> = ({ type, isChecked = false }) => {
+ const metadataMap = useMetadataMap()
+
+ return (
+ <Tooltip
+ popupContent={metadataMap[type].text}
+ >
+ <button className={cn(s.iconWrapper, 'group', isChecked ? s.iconCheck : '')}>
+ <TypeIcon
+ iconName={metadataMap[type].iconName || ''}
+ className={`group-hover:bg-primary-600 ${isChecked ? '!bg-primary-600' : ''}`}
+ />
+ </button>
+ </Tooltip>
+ )
+}
+
+type IMetadataProps = {
+ docDetail?: FullDocumentDetail
+ loading: boolean
+ onUpdate: () => void
+}
+
+const Metadata: FC<IMetadataProps> = ({ docDetail, loading, onUpdate }) => {
+ const { doc_metadata = {} } = docDetail || {}
+ const doc_type = docDetail?.doc_type || ''
+
+ const { t } = useTranslation()
+ const metadataMap = useMetadataMap()
+ const languageMap = useLanguages()
+ const bookCategoryMap = useBookCategories()
+ const personalDocCategoryMap = usePersonalDocCategories()
+ const businessDocCategoryMap = useBusinessDocCategories()
+ const [editStatus, setEditStatus] = useState(!doc_type) // if no documentType, in editing status by default
+ // the initial values are according to the documentType
+ const [metadataParams, setMetadataParams] = useState<{
+ documentType?: DocType | ''
+ metadata: { [key: string]: string }
+ }>(
+ doc_type
+ ? {
+ documentType: doc_type,
+ metadata: doc_metadata || {},
+ }
+ : { metadata: {} })
+ const [showDocTypes, setShowDocTypes] = useState(!doc_type) // whether show doc types
+ const [tempDocType, setTempDocType] = useState<DocType | undefined | ''>('') // for remember icon click
+ const [saveLoading, setSaveLoading] = useState(false)
+
+ const { notify } = useContext(ToastContext)
+ const datasetId = useDocumentContext(s => s.datasetId)
+ const documentId = useDocumentContext(s => s.documentId)
+
+ useEffect(() => {
+ if (docDetail?.doc_type) {
+ setEditStatus(false)
+ setShowDocTypes(false)
+ setTempDocType(docDetail?.doc_type)
+ setMetadataParams({
+ documentType: docDetail?.doc_type,
+ metadata: docDetail?.doc_metadata || {},
+ })
+ }
+ }, [docDetail?.doc_type])
+
+ // confirm doc type
+ const confirmDocType = () => {
+ if (!tempDocType)
+ return
+ setMetadataParams({
+ documentType: tempDocType,
+ metadata: tempDocType === metadataParams.documentType ? metadataParams.metadata : {}, // change doc type, clear metadata
+ })
+ setEditStatus(true)
+ setShowDocTypes(false)
+ }
+
+ // cancel doc type
+ const cancelDocType = () => {
+ setTempDocType(metadataParams.documentType)
+ setEditStatus(true)
+ setShowDocTypes(false)
+ }
+
+ // show doc type select
+ const renderSelectDocType = () => {
+ const { documentType } = metadataParams
+
+ return (
+ <>
+ {!doc_type && !documentType && <>
+ <div className={s.desc}>{t('datasetDocuments.metadata.desc')}</div>
+ </>}
+ <div className={s.operationWrapper}>
+ {!doc_type && !documentType && <>
+ <span className={s.title}>{t('datasetDocuments.metadata.docTypeSelectTitle')}</span>
+ </>}
+ {documentType && <>
+ <span className={s.title}>{t('datasetDocuments.metadata.docTypeChangeTitle')}</span>
+ <span className={s.changeTip}>{t('datasetDocuments.metadata.docTypeSelectWarning')}</span>
+ </>}
+ <Radio.Group value={tempDocType ?? documentType} onChange={setTempDocType} className={s.radioGroup}>
+ {CUSTOMIZABLE_DOC_TYPES.map((type, index) => {
+ const currValue = tempDocType ?? documentType
+ return <Radio key={index} value={type} className={`${s.radio} ${currValue === type ? 'shadow-none' : ''}`}>
+ <IconButton
+ type={type}
+ isChecked={currValue === type}
+ />
+ </Radio>
+ })}
+ </Radio.Group>
+ {!doc_type && !documentType && (
+ <Button variant='primary'
+ onClick={confirmDocType}
+ disabled={!tempDocType}
+ >
+ {t('datasetDocuments.metadata.firstMetaAction')}
+ </Button>
+ )}
+ {documentType && <div className={s.opBtnWrapper}>
+ <Button onClick={confirmDocType} className={`${s.opBtn} ${s.opSaveBtn}`} variant='primary' >{t('common.operation.save')}</Button>
+ <Button onClick={cancelDocType} className={`${s.opBtn} ${s.opCancelBtn}`}>{t('common.operation.cancel')}</Button>
+ </div>}
+ </div >
+ </>
+ )
+ }
+
+ // show metadata info and edit
+ const renderFieldInfos = ({ mainField = 'book', canEdit }: { mainField?: metadataType | ''; canEdit?: boolean }) => {
+ if (!mainField)
+ return null
+ const fieldMap = metadataMap[mainField]?.subFieldsMap
+ const sourceData = ['originInfo', 'technicalParameters'].includes(mainField) ? docDetail : metadataParams.metadata
+
+ const getTargetMap = (field: string) => {
+ if (field === 'language')
+ return languageMap
+ if (field === 'category' && mainField === 'book')
+ return bookCategoryMap
+
+ if (field === 'document_type') {
+ if (mainField === 'personal_document')
+ return personalDocCategoryMap
+ if (mainField === 'business_document')
+ return businessDocCategoryMap
+ }
+ return {} as any
+ }
+
+ const getTargetValue = (field: string) => {
+ const val = get(sourceData, field, '')
+ if (!val && val !== 0)
+ return '-'
+ if (fieldMap[field]?.inputType === 'select')
+ return getTargetMap(field)[val]
+ if (fieldMap[field]?.render)
+ return fieldMap[field]?.render?.(val, field === 'hit_count' ? get(sourceData, 'segment_count', 0) as number : undefined)
+ return val
+ }
+
+ return <div className='flex flex-col gap-1'>
+ {Object.keys(fieldMap).map((field) => {
+ return <FieldInfo
+ key={fieldMap[field]?.label}
+ label={fieldMap[field]?.label}
+ displayedValue={getTargetValue(field)}
+ value={get(sourceData, field, '')}
+ inputType={fieldMap[field]?.inputType || 'input'}
+ showEdit={canEdit}
+ onUpdate={(val) => {
+ setMetadataParams(pre => ({ ...pre, metadata: { ...pre.metadata, [field]: val } }))
+ }}
+ selectOptions={map2Options(getTargetMap(field))}
+ />
+ })}
+ </div>
+ }
+
+ const enabledEdit = () => {
+ setEditStatus(true)
+ }
+
+ const onCancel = () => {
+ setMetadataParams({ documentType: doc_type || '', metadata: { ...(docDetail?.doc_metadata || {}) } })
+ setEditStatus(!doc_type)
+ if (!doc_type)
+ setShowDocTypes(true)
+ }
+
+ const onSave = async () => {
+ setSaveLoading(true)
+ const [e] = await asyncRunSafe<CommonResponse>(modifyDocMetadata({
+ datasetId,
+ documentId,
+ body: {
+ doc_type: metadataParams.documentType || doc_type || '',
+ doc_metadata: metadataParams.metadata,
+ },
+ }) as Promise<CommonResponse>)
+ if (!e)
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ else
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ onUpdate?.()
+ setEditStatus(false)
+ setSaveLoading(false)
+ }
+
+ return (
+ <div className={`${s.main} ${editStatus ? 'bg-white' : 'bg-gray-25'}`}>
+ {loading
+ ? (<Loading type='app' />)
+ : (
+ <>
+ <div className={s.titleWrapper}>
+ <span className={s.title}>{t('datasetDocuments.metadata.title')}</span>
+ {!editStatus
+ ? <Button onClick={enabledEdit} className={`${s.opBtn} ${s.opEditBtn}`}>
+ <PencilIcon className={s.opIcon} />
+ {t('common.operation.edit')}
+ </Button>
+ : showDocTypes
+ ? null
+ : <div className={s.opBtnWrapper}>
+ <Button onClick={onCancel} className={`${s.opBtn} ${s.opCancelBtn}`}>{t('common.operation.cancel')}</Button>
+ <Button onClick={onSave}
+ className={`${s.opBtn} ${s.opSaveBtn}`}
+ variant='primary'
+ loading={saveLoading}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>}
+ </div>
+ {/* show selected doc type and changing entry */}
+ {!editStatus
+ ? <div className={s.documentTypeShow}>
+ <TypeIcon iconName={metadataMap[doc_type || 'book']?.iconName || ''} className={s.iconShow} />
+ {metadataMap[doc_type || 'book'].text}
+ </div>
+ : showDocTypes
+ ? null
+ : <div className={s.documentTypeShow}>
+ {metadataParams.documentType && <>
+ <TypeIcon iconName={metadataMap[metadataParams.documentType || 'book'].iconName || ''} className={s.iconShow} />
+ {metadataMap[metadataParams.documentType || 'book'].text}
+ {editStatus && <div className='ml-1 inline-flex items-center gap-1'>
+ 路
+ <div
+ onClick={() => { setShowDocTypes(true) }}
+ className='cursor-pointer hover:text-text-accent'
+ >
+ {t('common.operation.change')}
+ </div>
+ </div>}
+ </>}
+ </div>
+ }
+ {(!doc_type && showDocTypes) ? null : <Divider />}
+ {showDocTypes ? renderSelectDocType() : renderFieldInfos({ mainField: metadataParams.documentType, canEdit: editStatus })}
+ {/* show fixed fields */}
+ <Divider />
+ {renderFieldInfos({ mainField: 'originInfo', canEdit: false })}
+ <div className={`${s.title} mt-8`}>{metadataMap.technicalParameters.text}</div>
+ <Divider />
+ {renderFieldInfos({ mainField: 'technicalParameters', canEdit: false })}
+ </>
+ )}
+ </div>
+ )
+}
+
+export default Metadata
diff --git a/app/components/datasets/documents/detail/metadata/style.module.css b/app/components/datasets/documents/detail/metadata/style.module.css
new file mode 100644
index 0000000..37796d3
--- /dev/null
+++ b/app/components/datasets/documents/detail/metadata/style.module.css
@@ -0,0 +1,103 @@
+.main {
+ @apply w-full sm:w-96 xl:w-[360px] flex-shrink-0 p-0 sm:px-6 sm:py-5 overflow-y-auto border-none sm:border-l-gray-100 sm:border-l;
+}
+.operationWrapper {
+ @apply flex flex-col items-center gap-4 mt-7 mb-8;
+}
+.iconWrapper {
+ @apply box-border cursor-pointer h-8 w-8 inline-flex items-center justify-center;
+ @apply border-[#EAECF5] border rounded-lg hover:border-primary-200 hover:bg-primary-25 hover:shadow-md;
+}
+.icon {
+ @apply h-4 w-4 stroke-current stroke-[2px] text-gray-700 group-hover:stroke-primary-600;
+}
+.iconCheck {
+ @apply border-primary-400 border-[1.5px] bg-primary-25 shadow-sm !important;
+}
+.commonIcon {
+ @apply w-4 h-4 inline-block align-middle bg-gray-700 hover:bg-primary-600;
+}
+.bookOpenIcon {
+ mask-image: url(../../assets/bookOpen.svg);
+}
+.globeIcon {
+ mask-image: url(../../assets/globe.svg);
+}
+.graduationHatIcon {
+ mask-image: url(../../assets/graduationHat.svg);
+}
+.fileIcon {
+ mask-image: url(../../assets/file.svg);
+}
+.briefcaseIcon {
+ mask-image: url(../../assets/briefcase.svg);
+}
+.atSignIcon {
+ mask-image: url(../../assets/atSign.svg);
+}
+.messageTextCircleIcon {
+ mask-image: url(../../assets/messageTextCircle.svg);
+}
+.radioGroup {
+ @apply !bg-transparent !gap-2;
+}
+.radio {
+ @apply !p-0 !mr-0 hover:bg-transparent !rounded-lg;
+}
+.title {
+ @apply text-sm text-gray-800 font-medium leading-6;
+}
+.titleWrapper {
+ @apply flex items-center justify-between;
+}
+.desc {
+ @apply text-gray-500 text-xs;
+}
+
+.changeTip {
+ @apply text-[#D92D20] text-xs text-center;
+}
+.opBtnWrapper {
+ @apply flex items-center justify-center gap-1;
+}
+.opBtn {
+ @apply h-6 w-14 px-0 text-xs font-medium rounded-md !important;
+}
+.opEditBtn {
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+ @apply border-[0.5px] border-gray-200 bg-white !important;
+}
+.opCancelBtn {
+ @apply border-none bg-gray-50 font-medium text-gray-700 hover:bg-gray-100 !important;
+}
+.opSaveBtn {
+ @apply border-primary-700 border-[0.5px] font-medium hover:border-none !important;
+}
+.opIcon {
+ @apply h-3 w-3 stroke-current stroke-2 mr-1;
+}
+.select {
+ @apply h-7 py-0 pl-2 text-xs bg-gray-50 hover:bg-gray-100 rounded-md shadow-none !important;
+}
+.selectWrapper {
+ @apply !h-7 w-full
+}
+.selectWrapper ul {
+ @apply text-xs
+}
+.selectWrapper li {
+ @apply flex items-center h-8
+}
+.documentTypeShow {
+ @apply flex items-center text-xs text-gray-500;
+}
+.iconShow {
+ mask-size: contain;
+ @apply w-3 h-3 bg-gray-500 hover:bg-none mr-1 !important;
+}
+.textArea {
+ @apply placeholder:text-gray-400 bg-gray-50 px-2 py-1 caret-primary-600 rounded-md hover:bg-gray-100 focus-visible:outline-none focus-visible:bg-white focus-visible:border focus-visible:border-gray-300 hover:shadow-[0_1px_2px_rgba(16,24,40,0.05);];
+}
+.input {
+ @apply bg-gray-50 hover:bg-gray-100 focus-visible:bg-white !important
+}
diff --git a/app/components/datasets/documents/detail/new-segment.tsx b/app/components/datasets/documents/detail/new-segment.tsx
new file mode 100644
index 0000000..7a08027
--- /dev/null
+++ b/app/components/datasets/documents/detail/new-segment.tsx
@@ -0,0 +1,205 @@
+import { memo, useMemo, useRef, useState } from 'react'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { useParams } from 'next/navigation'
+import { RiCloseLine, RiExpandDiagonalLine } from '@remixicon/react'
+import { useShallow } from 'zustand/react/shallow'
+import { useSegmentListContext } from './completed'
+import { SegmentIndexTag } from './completed/common/segment-index-tag'
+import ActionButtons from './completed/common/action-buttons'
+import Keywords from './completed/common/keywords'
+import ChunkContent from './completed/common/chunk-content'
+import AddAnother from './completed/common/add-another'
+import Dot from './completed/common/dot'
+import { useDocumentContext } from './index'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import { ToastContext } from '@/app/components/base/toast'
+import { ChunkingMode, type SegmentUpdater } from '@/models/datasets'
+import classNames from '@/utils/classnames'
+import { formatNumber } from '@/utils/format'
+import Divider from '@/app/components/base/divider'
+import { useAddSegment } from '@/service/knowledge/use-segment'
+
+type NewSegmentModalProps = {
+ onCancel: () => void
+ docForm: ChunkingMode
+ onSave: () => void
+ viewNewlyAddedChunk: () => void
+}
+
+const NewSegmentModal: FC<NewSegmentModalProps> = ({
+ onCancel,
+ docForm,
+ onSave,
+ viewNewlyAddedChunk,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const [question, setQuestion] = useState('')
+ const [answer, setAnswer] = useState('')
+ const { datasetId, documentId } = useParams<{ datasetId: string; documentId: string }>()
+ const [keywords, setKeywords] = useState<string[]>([])
+ const [loading, setLoading] = useState(false)
+ const [addAnother, setAddAnother] = useState(true)
+ const fullScreen = useSegmentListContext(s => s.fullScreen)
+ const toggleFullScreen = useSegmentListContext(s => s.toggleFullScreen)
+ const mode = useDocumentContext(s => s.mode)
+ const { appSidebarExpand } = useAppStore(useShallow(state => ({
+ appSidebarExpand: state.appSidebarExpand,
+ })))
+ const refreshTimer = useRef<any>(null)
+
+ const CustomButton = <>
+ <Divider type='vertical' className='mx-1 h-3 bg-divider-regular' />
+ <button
+ type='button'
+ className='system-xs-semibold text-text-accent'
+ onClick={() => {
+ clearTimeout(refreshTimer.current)
+ viewNewlyAddedChunk()
+ }}>
+ {t('common.operation.view')}
+ </button>
+ </>
+
+ const isQAModel = useMemo(() => {
+ return docForm === ChunkingMode.qa
+ }, [docForm])
+
+ const handleCancel = (actionType: 'esc' | 'add' = 'esc') => {
+ if (actionType === 'esc' || !addAnother)
+ onCancel()
+ }
+
+ const { mutateAsync: addSegment } = useAddSegment()
+
+ const handleSave = async () => {
+ const params: SegmentUpdater = { content: '' }
+ if (isQAModel) {
+ if (!question.trim()) {
+ return notify({
+ type: 'error',
+ message: t('datasetDocuments.segment.questionEmpty'),
+ })
+ }
+ if (!answer.trim()) {
+ return notify({
+ type: 'error',
+ message: t('datasetDocuments.segment.answerEmpty'),
+ })
+ }
+
+ params.content = question
+ params.answer = answer
+ }
+ else {
+ if (!question.trim()) {
+ return notify({
+ type: 'error',
+ message: t('datasetDocuments.segment.contentEmpty'),
+ })
+ }
+
+ params.content = question
+ }
+
+ if (keywords?.length)
+ params.keywords = keywords
+
+ setLoading(true)
+ await addSegment({ datasetId, documentId, body: params }, {
+ onSuccess() {
+ notify({
+ type: 'success',
+ message: t('datasetDocuments.segment.chunkAdded'),
+ className: `!w-[296px] !bottom-0 ${appSidebarExpand === 'expand' ? '!left-[216px]' : '!left-14'}
+ !top-auto !right-auto !mb-[52px] !ml-11`,
+ customComponent: CustomButton,
+ })
+ handleCancel('add')
+ refreshTimer.current = setTimeout(() => {
+ onSave()
+ }, 3000)
+ },
+ onSettled() {
+ setLoading(false)
+ },
+ })
+ }
+
+ const wordCountText = useMemo(() => {
+ const count = isQAModel ? (question.length + answer.length) : question.length
+ return `${formatNumber(count)} ${t('datasetDocuments.segment.characters', { count })}`
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [question.length, answer.length, isQAModel])
+
+ return (
+ <div className={'flex h-full flex-col'}>
+ <div className={classNames('flex items-center justify-between', fullScreen ? 'py-3 pr-4 pl-6 border border-divider-subtle' : 'pt-3 pr-3 pl-4')}>
+ <div className='flex flex-col'>
+ <div className='system-xl-semibold text-text-primary'>{
+ t('datasetDocuments.segment.addChunk')
+ }</div>
+ <div className='flex items-center gap-x-2'>
+ <SegmentIndexTag label={t('datasetDocuments.segment.newChunk')!} />
+ <Dot />
+ <span className='system-xs-medium text-text-tertiary'>{wordCountText}</span>
+ </div>
+ </div>
+ <div className='flex items-center'>
+ {fullScreen && (
+ <>
+ <AddAnother className='mr-3' isChecked={addAnother} onCheck={() => setAddAnother(!addAnother)} />
+ <ActionButtons
+ handleCancel={handleCancel.bind(null, 'esc')}
+ handleSave={handleSave}
+ loading={loading}
+ actionType='add'
+ />
+ <Divider type='vertical' className='ml-4 mr-2 h-3.5 bg-divider-regular' />
+ </>
+ )}
+ <div className='mr-1 flex h-8 w-8 cursor-pointer items-center justify-center p-1.5' onClick={toggleFullScreen}>
+ <RiExpandDiagonalLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div className='flex h-8 w-8 cursor-pointer items-center justify-center p-1.5' onClick={handleCancel.bind(null, 'esc')}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+ <div className={classNames('flex grow', fullScreen ? 'w-full flex-row justify-center px-6 pt-6 gap-x-8' : 'flex-col gap-y-1 py-3 px-4')}>
+ <div className={classNames('break-all overflow-hidden whitespace-pre-line', fullScreen ? 'w-1/2' : 'grow')}>
+ <ChunkContent
+ docForm={docForm}
+ question={question}
+ answer={answer}
+ onQuestionChange={question => setQuestion(question)}
+ onAnswerChange={answer => setAnswer(answer)}
+ isEditMode={true}
+ />
+ </div>
+ {mode === 'custom' && <Keywords
+ className={fullScreen ? 'w-1/5' : ''}
+ actionType='add'
+ keywords={keywords}
+ isEditMode={true}
+ onKeywordsChange={keywords => setKeywords(keywords)}
+ />}
+ </div>
+ {!fullScreen && (
+ <div className='flex items-center justify-between border-t-[1px] border-t-divider-subtle p-4 pt-3'>
+ <AddAnother isChecked={addAnother} onCheck={() => setAddAnother(!addAnother)} />
+ <ActionButtons
+ handleCancel={handleCancel.bind(null, 'esc')}
+ handleSave={handleSave}
+ loading={loading}
+ actionType='add'
+ />
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default memo(NewSegmentModal)
diff --git a/app/components/datasets/documents/detail/segment-add/index.tsx b/app/components/datasets/documents/detail/segment-add/index.tsx
new file mode 100644
index 0000000..d41118e
--- /dev/null
+++ b/app/components/datasets/documents/detail/segment-add/index.tsx
@@ -0,0 +1,135 @@
+'use client'
+import type { FC } from 'react'
+import React, { useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiAddLine,
+ RiArrowDownSLine,
+ RiErrorWarningFill,
+ RiLoader2Line,
+} from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/general'
+import Popover from '@/app/components/base/popover'
+
+export type ISegmentAddProps = {
+ importStatus: ProcessStatus | string | undefined
+ clearProcessStatus: () => void
+ showNewSegmentModal: () => void
+ showBatchModal: () => void
+ embedding: boolean
+}
+
+export enum ProcessStatus {
+ WAITING = 'waiting',
+ PROCESSING = 'processing',
+ COMPLETED = 'completed',
+ ERROR = 'error',
+}
+
+const SegmentAdd: FC<ISegmentAddProps> = ({
+ importStatus,
+ clearProcessStatus,
+ showNewSegmentModal,
+ showBatchModal,
+ embedding,
+}) => {
+ const { t } = useTranslation()
+ const textColor = useMemo(() => {
+ return embedding
+ ? 'text-components-button-secondary-accent-text-disabled'
+ : 'text-components-button-secondary-accent-text'
+ }, [embedding])
+
+ if (importStatus) {
+ return (
+ <>
+ {(importStatus === ProcessStatus.WAITING || importStatus === ProcessStatus.PROCESSING) && (
+ <div className='relative mr-2 inline-flex items-center overflow-hidden rounded-lg border-[0.5px] border-components-progress-bar-border
+ bg-components-progress-bar-border px-2.5 py-2 text-components-button-secondary-accent-text
+ shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px]'>
+ <div className={cn('absolute left-0 top-0 z-0 h-full border-r-[1.5px] border-r-components-progress-bar-progress-highlight bg-components-progress-bar-progress', importStatus === ProcessStatus.WAITING ? 'w-3/12' : 'w-2/3')} />
+ <RiLoader2Line className='mr-1 h-4 w-4 animate-spin' />
+ <span className='system-sm-medium z-10 pr-0.5'>{t('datasetDocuments.list.batchModal.processing')}</span>
+ </div>
+ )}
+ {importStatus === ProcessStatus.COMPLETED && (
+ <div className='relative mr-2 inline-flex items-center overflow-hidden rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px]'>
+ <div className='inline-flex items-center border-r border-r-divider-subtle px-2.5 py-2 text-text-success'>
+ <CheckCircle className='mr-1 h-4 w-4' />
+ <span className='system-sm-medium pr-0.5'>{t('datasetDocuments.list.batchModal.completed')}</span>
+ </div>
+ <div className='m-1 inline-flex items-center'>
+ <span className='system-xs-medium cursor-pointer rounded-md px-1.5 py-1 text-components-button-ghost-text hover:bg-components-button-ghost-bg-hover' onClick={clearProcessStatus}>{t('datasetDocuments.list.batchModal.ok')}</span>
+ </div>
+ <div className='absolute left-0 top-0 -z-10 h-full w-full bg-dataset-chunk-process-success-bg opacity-40' />
+ </div>
+ )}
+ {importStatus === ProcessStatus.ERROR && (
+ <div className='relative mr-2 inline-flex items-center overflow-hidden rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px]'>
+ <div className='inline-flex items-center border-r border-r-divider-subtle px-2.5 py-2 text-text-destructive'>
+ <RiErrorWarningFill className='mr-1 h-4 w-4' />
+ <span className='system-sm-medium pr-0.5'>{t('datasetDocuments.list.batchModal.error')}</span>
+ </div>
+ <div className='m-1 inline-flex items-center'>
+ <span className='system-xs-medium cursor-pointer rounded-md px-1.5 py-1 text-components-button-ghost-text hover:bg-components-button-ghost-bg-hover' onClick={clearProcessStatus}>{t('datasetDocuments.list.batchModal.ok')}</span>
+ </div>
+ <div className='absolute left-0 top-0 -z-10 h-full w-full bg-dataset-chunk-process-error-bg opacity-40' />
+ </div>
+ )}
+ </>
+ )
+ }
+
+ return (
+ <div className={cn(
+ 'relative z-20 flex items-center rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px]',
+ embedding && 'border-components-button-secondary-border-disabled bg-components-button-secondary-bg-disabled',
+ )}>
+ <button
+ type='button'
+ className={`inline-flex items-center rounded-l-lg border-r-[1px] border-r-divider-subtle px-2.5 py-2
+ hover:bg-state-base-hover disabled:cursor-not-allowed disabled:hover:bg-transparent`}
+ onClick={showNewSegmentModal}
+ disabled={embedding}
+ >
+ <RiAddLine className={cn('h-4 w-4', textColor)} />
+ <span className={cn('ml-0.5 px-0.5 text-[13px] font-medium capitalize leading-[16px]', textColor)}>
+ {t('datasetDocuments.list.action.addButton')}
+ </span>
+ </button>
+ <Popover
+ position='br'
+ manualClose
+ trigger='click'
+ htmlContent={
+ // need to wrapper the button with div when manualClose is true
+ <div className='w-full p-1'>
+ <button
+ type='button'
+ className='system-md-regular flex w-full items-center rounded-lg px-2 py-1.5 text-text-secondary'
+ onClick={showBatchModal}
+ >
+ {t('datasetDocuments.list.action.batchAdd')}
+ </button>
+ </div>
+ }
+ btnElement={
+ <div className='flex items-center justify-center' >
+ <RiArrowDownSLine className={cn('h-4 w-4', textColor)}/>
+ </div>
+ }
+ btnClassName={open => cn(
+ `!hover:bg-state-base-hover !rounded-l-none !rounded-r-lg !border-0 !p-2 backdrop-blur-[5px]
+ disabled:cursor-not-allowed disabled:bg-transparent disabled:hover:bg-transparent`,
+ open ? '!bg-state-base-hover' : '',
+ )}
+ popupClassName='!min-w-[128px] !bg-components-panel-bg-blur !rounded-xl border-[0.5px] !ring-0
+ border-components-panel-border !shadow-xl !shadow-shadow-shadow-5 backdrop-blur-[5px]'
+ className='h-fit min-w-[128px]'
+ disabled={embedding}
+ />
+ </div>
+ )
+}
+export default React.memo(SegmentAdd)
diff --git a/app/components/datasets/documents/detail/settings/index.tsx b/app/components/datasets/documents/detail/settings/index.tsx
new file mode 100644
index 0000000..d45e4d8
--- /dev/null
+++ b/app/components/datasets/documents/detail/settings/index.tsx
@@ -0,0 +1,96 @@
+'use client'
+import React, { useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import { useContext } from 'use-context-selector'
+import { useRouter } from 'next/navigation'
+import DatasetDetailContext from '@/context/dataset-detail'
+import type { CrawlOptions, CustomFile } from '@/models/datasets'
+
+import Loading from '@/app/components/base/loading'
+import StepTwo from '@/app/components/datasets/create/step-two'
+import AccountSetting from '@/app/components/header/account-setting'
+import AppUnavailable from '@/app/components/base/app-unavailable'
+import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import type { NotionPage } from '@/models/common'
+import { useDocumentDetail, useInvalidDocumentDetailKey } from '@/service/knowledge/use-document'
+
+type DocumentSettingsProps = {
+ datasetId: string
+ documentId: string
+}
+
+const DocumentSettings = ({ datasetId, documentId }: DocumentSettingsProps) => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const [isShowSetAPIKey, { setTrue: showSetAPIKey, setFalse: hideSetAPIkey }] = useBoolean()
+ const { indexingTechnique, dataset } = useContext(DatasetDetailContext)
+ const { data: embeddingsDefaultModel } = useDefaultModel(ModelTypeEnum.textEmbedding)
+
+ const invalidDocumentDetail = useInvalidDocumentDetailKey()
+ const saveHandler = () => {
+ invalidDocumentDetail()
+ router.push(`/datasets/${datasetId}/documents/${documentId}`)
+ }
+
+ const cancelHandler = () => router.back()
+
+ const { data: documentDetail, error } = useDocumentDetail({
+ datasetId,
+ documentId,
+ params: { metadata: 'without' },
+ })
+
+ const currentPage = useMemo(() => {
+ return {
+ workspace_id: documentDetail?.data_source_info.notion_workspace_id,
+ page_id: documentDetail?.data_source_info.notion_page_id,
+ page_name: documentDetail?.name,
+ page_icon: documentDetail?.data_source_info.notion_page_icon,
+ type: documentDetail?.data_source_type,
+ }
+ }, [documentDetail])
+
+ if (error)
+ return <AppUnavailable code={500} unknownReason={t('datasetCreation.error.unavailable') as string} />
+
+ return (
+ <div className='flex' style={{ height: 'calc(100vh - 56px)' }}>
+ <div className="grow">
+ {!documentDetail && <Loading type='app' />}
+ {dataset && documentDetail && (
+ <StepTwo
+ isAPIKeySet={!!embeddingsDefaultModel}
+ onSetting={showSetAPIKey}
+ datasetId={datasetId}
+ dataSourceType={documentDetail.data_source_type}
+ notionPages={[currentPage as unknown as NotionPage]}
+ websitePages={[
+ {
+ title: documentDetail.name,
+ source_url: documentDetail.data_source_info?.url,
+ markdown: '',
+ description: '',
+ },
+ ]}
+ websiteCrawlProvider={documentDetail.data_source_info?.provider}
+ websiteCrawlJobId={documentDetail.data_source_info?.job_id}
+ crawlOptions={documentDetail.data_source_info as unknown as CrawlOptions}
+ indexingType={indexingTechnique}
+ isSetting
+ documentDetail={documentDetail}
+ files={[documentDetail.data_source_info.upload_file as CustomFile]}
+ onSave={saveHandler}
+ onCancel={cancelHandler}
+ />
+ )}
+ </div>
+ {isShowSetAPIKey && <AccountSetting activeTab="provider" onCancel={async () => {
+ hideSetAPIkey()
+ }} />}
+ </div>
+ )
+}
+
+export default DocumentSettings
diff --git a/app/components/datasets/documents/detail/style.module.css b/app/components/datasets/documents/detail/style.module.css
new file mode 100644
index 0000000..8a59ef6
--- /dev/null
+++ b/app/components/datasets/documents/detail/style.module.css
@@ -0,0 +1,11 @@
+.titleIcon {
+ background-position-x: center;
+ background-repeat: no-repeat;
+ background-size: 28px 28px;
+ @apply h-6 w-6 !important;
+}
+.layoutRightIcon {
+ @apply p-2 ml-2 border-[0.5px] border-components-button-secondary-border hover:border-components-button-secondary-border-hover
+ rounded-lg bg-components-button-secondary-bg hover:bg-components-button-secondary-bg-hover cursor-pointer
+ shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px];
+}
diff --git a/app/components/datasets/documents/index.tsx b/app/components/datasets/documents/index.tsx
new file mode 100644
index 0000000..32980ee
--- /dev/null
+++ b/app/components/datasets/documents/index.tsx
@@ -0,0 +1,350 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useRouter } from 'next/navigation'
+import { useDebounce, useDebounceFn } from 'ahooks'
+import { groupBy } from 'lodash-es'
+import { PlusIcon } from '@heroicons/react/24/solid'
+import { RiDraftLine, RiExternalLinkLine } from '@remixicon/react'
+import AutoDisabledDocument from '../common/document-status-with-action/auto-disabled-document'
+import List from './list'
+import s from './style.module.css'
+import Loading from '@/app/components/base/loading'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import { get } from '@/service/base'
+import { createDocument } from '@/service/datasets'
+import { useDatasetDetailContext } from '@/context/dataset-detail'
+import { NotionPageSelectorModal } from '@/app/components/base/notion-page-selector'
+import type { NotionPage } from '@/models/common'
+import type { CreateDocumentReq } from '@/models/datasets'
+import { DataSourceType, ProcessMode } from '@/models/datasets'
+import IndexFailed from '@/app/components/datasets/common/document-status-with-action/index-failed'
+import { useProviderContext } from '@/context/provider-context'
+import cn from '@/utils/classnames'
+import { useDocumentList, useInvalidDocumentDetailKey, useInvalidDocumentList } from '@/service/knowledge/use-document'
+import { useInvalid } from '@/service/use-base'
+import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/use-segment'
+import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata'
+import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer'
+import StatusWithAction from '../common/document-status-with-action/status-with-action'
+import { LanguagesSupported } from '@/i18n/language'
+import { getLocaleOnClient } from '@/i18n'
+
+const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => {
+ return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
+ <path d="M10.8332 5.83333L9.90355 3.9741C9.63601 3.439 9.50222 3.17144 9.30265 2.97597C9.12615 2.80311 8.91344 2.67164 8.6799 2.59109C8.41581 2.5 8.11668 2.5 7.51841 2.5H4.33317C3.39975 2.5 2.93304 2.5 2.57652 2.68166C2.26292 2.84144 2.00795 3.09641 1.84816 3.41002C1.6665 3.76654 1.6665 4.23325 1.6665 5.16667V5.83333M1.6665 5.83333H14.3332C15.7333 5.83333 16.4334 5.83333 16.9681 6.10582C17.4386 6.3455 17.821 6.72795 18.0607 7.19836C18.3332 7.73314 18.3332 8.4332 18.3332 9.83333V13.5C18.3332 14.9001 18.3332 15.6002 18.0607 16.135C17.821 16.6054 17.4386 16.9878 16.9681 17.2275C16.4334 17.5 15.7333 17.5 14.3332 17.5H5.6665C4.26637 17.5 3.56631 17.5 3.03153 17.2275C2.56112 16.9878 2.17867 16.6054 1.93899 16.135C1.6665 15.6002 1.6665 14.9001 1.6665 13.5V5.83333ZM9.99984 14.1667V9.16667M7.49984 11.6667H12.4998" stroke="#667085" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+}
+
+const ThreeDotsIcon = ({ className }: React.SVGProps<SVGElement>) => {
+ return <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
+ <path d="M5 6.5V5M8.93934 7.56066L10 6.5M10.0103 11.5H11.5103" stroke="#374151" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+}
+
+const NotionIcon = ({ className }: React.SVGProps<SVGElement>) => {
+ return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
+ <g clipPath="url(#clip0_2164_11263)">
+ <path fillRule="evenodd" clipRule="evenodd" d="M3.5725 18.2611L1.4229 15.5832C0.905706 14.9389 0.625 14.1466 0.625 13.3312V3.63437C0.625 2.4129 1.60224 1.39936 2.86295 1.31328L12.8326 0.632614C13.5569 0.583164 14.2768 0.775682 14.8717 1.17794L18.3745 3.5462C19.0015 3.97012 19.375 4.66312 19.375 5.40266V16.427C19.375 17.6223 18.4141 18.6121 17.1798 18.688L6.11458 19.3692C5.12958 19.4298 4.17749 19.0148 3.5725 18.2611Z" fill="white" />
+ <path d="M7.03006 8.48669V8.35974C7.03006 8.03794 7.28779 7.77104 7.61997 7.74886L10.0396 7.58733L13.3857 12.5147V8.19009L12.5244 8.07528V8.01498C12.5244 7.68939 12.788 7.42074 13.1244 7.4035L15.326 7.29073V7.60755C15.326 7.75628 15.2154 7.88349 15.0638 7.90913L14.534 7.99874V15.0023L13.8691 15.231C13.3136 15.422 12.6952 15.2175 12.3772 14.7377L9.12879 9.83574V14.5144L10.1287 14.7057L10.1147 14.7985C10.0711 15.089 9.82028 15.3087 9.51687 15.3222L7.03006 15.4329C6.99718 15.1205 7.23132 14.841 7.55431 14.807L7.88143 14.7727V8.53453L7.03006 8.48669Z" fill="black" />
+ <path fillRule="evenodd" clipRule="evenodd" d="M12.9218 1.85424L2.95217 2.53491C2.35499 2.57568 1.89209 3.05578 1.89209 3.63437V13.3312C1.89209 13.8748 2.07923 14.403 2.42402 14.8325L4.57362 17.5104C4.92117 17.9434 5.46812 18.1818 6.03397 18.147L17.0991 17.4658C17.6663 17.4309 18.1078 16.9762 18.1078 16.427V5.40266C18.1078 5.06287 17.9362 4.74447 17.6481 4.54969L14.1453 2.18143C13.7883 1.94008 13.3564 1.82457 12.9218 1.85424ZM3.44654 3.78562C3.30788 3.68296 3.37387 3.46909 3.54806 3.4566L12.9889 2.77944C13.2897 2.75787 13.5886 2.8407 13.8318 3.01305L15.7261 4.35508C15.798 4.40603 15.7642 4.51602 15.6752 4.52086L5.67742 5.0646C5.37485 5.08106 5.0762 4.99217 4.83563 4.81406L3.44654 3.78562ZM5.20848 6.76919C5.20848 6.4444 5.47088 6.1761 5.80642 6.15783L16.3769 5.58216C16.7039 5.56435 16.9792 5.81583 16.9792 6.13239V15.6783C16.9792 16.0025 16.7177 16.2705 16.3829 16.2896L5.8793 16.8872C5.51537 16.9079 5.20848 16.6283 5.20848 16.2759V6.76919Z" fill="black" />
+ </g>
+ <defs>
+ <clipPath id="clip0_2164_11263">
+ <rect width="20" height="20" fill="white" />
+ </clipPath>
+ </defs>
+ </svg>
+}
+
+const EmptyElement: FC<{ canAdd: boolean; onClick: () => void; type?: 'upload' | 'sync' }> = ({ canAdd = true, onClick, type = 'upload' }) => {
+ const { t } = useTranslation()
+ return <div className={s.emptyWrapper}>
+ <div className={s.emptyElement}>
+ <div className={s.emptySymbolIconWrapper}>
+ {type === 'upload' ? <FolderPlusIcon /> : <NotionIcon />}
+ </div>
+ <span className={s.emptyTitle}>{t('datasetDocuments.list.empty.title')}<ThreeDotsIcon className='relative -left-1.5 -top-3 inline' /></span>
+ <div className={s.emptyTip}>
+ {t(`datasetDocuments.list.empty.${type}.tip`)}
+ </div>
+ {type === 'upload' && canAdd && <Button onClick={onClick} className={s.addFileBtn}>
+ <PlusIcon className={s.plusIcon} />{t('datasetDocuments.list.addFile')}
+ </Button>}
+ </div>
+ </div>
+}
+
+type IDocumentsProps = {
+ datasetId: string
+}
+
+export const fetcher = (url: string) => get(url, {}, {})
+const DEFAULT_LIMIT = 10
+
+const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+ const isFreePlan = plan.type === 'sandbox'
+ const [inputValue, setInputValue] = useState<string>('') // the input value
+ const [searchValue, setSearchValue] = useState<string>('')
+ const [currPage, setCurrPage] = React.useState<number>(0)
+ const [limit, setLimit] = useState<number>(DEFAULT_LIMIT)
+ const router = useRouter()
+ const { dataset } = useDatasetDetailContext()
+ const [notionPageSelectorModalVisible, setNotionPageSelectorModalVisible] = useState(false)
+ const [timerCanRun, setTimerCanRun] = useState(true)
+ const isDataSourceNotion = dataset?.data_source_type === DataSourceType.NOTION
+ const isDataSourceWeb = dataset?.data_source_type === DataSourceType.WEB
+ const isDataSourceFile = dataset?.data_source_type === DataSourceType.FILE
+ const embeddingAvailable = !!dataset?.embedding_available
+ const locale = getLocaleOnClient()
+ const debouncedSearchValue = useDebounce(searchValue, { wait: 500 })
+
+ const { data: documentsRes, isFetching: isListLoading } = useDocumentList({
+ datasetId,
+ query: {
+ page: currPage + 1,
+ limit,
+ keyword: debouncedSearchValue,
+ },
+ refetchInterval: (isDataSourceNotion && timerCanRun) ? 2500 : 0,
+ })
+
+ const invalidDocumentList = useInvalidDocumentList(datasetId)
+
+ useEffect(() => {
+ if (documentsRes) {
+ const totalPages = Math.ceil(documentsRes.total / limit)
+ if (totalPages < currPage + 1)
+ setCurrPage(totalPages === 0 ? 0 : totalPages - 1)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [documentsRes])
+
+ const invalidDocumentDetail = useInvalidDocumentDetailKey()
+ const invalidChunkList = useInvalid(useSegmentListKey)
+ const invalidChildChunkList = useInvalid(useChildSegmentListKey)
+
+ const handleUpdate = useCallback(() => {
+ invalidDocumentList()
+ invalidDocumentDetail()
+ setTimeout(() => {
+ invalidChunkList()
+ invalidChildChunkList()
+ }, 5000)
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+
+ const documentsWithProgress = useMemo(() => {
+ let completedNum = 0
+ let percent = 0
+ const documentsData = documentsRes?.data?.map((documentItem) => {
+ const { indexing_status, completed_segments, total_segments } = documentItem
+ const isEmbedded = indexing_status === 'completed' || indexing_status === 'paused' || indexing_status === 'error'
+
+ if (isEmbedded)
+ completedNum++
+
+ const completedCount = completed_segments || 0
+ const totalCount = total_segments || 0
+ if (totalCount === 0 && completedCount === 0) {
+ percent = isEmbedded ? 100 : 0
+ }
+ else {
+ const per = Math.round(completedCount * 100 / totalCount)
+ percent = per > 100 ? 100 : per
+ }
+ return {
+ ...documentItem,
+ percent,
+ }
+ })
+ if (completedNum === documentsRes?.data?.length)
+ setTimerCanRun(false)
+ return {
+ ...documentsRes,
+ data: documentsData,
+ }
+ }, [documentsRes])
+ const total = documentsRes?.total || 0
+
+ const routeToDocCreate = () => {
+ if (isDataSourceNotion) {
+ setNotionPageSelectorModalVisible(true)
+ return
+ }
+ router.push(`/datasets/${datasetId}/documents/create`)
+ }
+
+ const handleSaveNotionPageSelected = async (selectedPages: NotionPage[]) => {
+ const workspacesMap = groupBy(selectedPages, 'workspace_id')
+ const workspaces = Object.keys(workspacesMap).map((workspaceId) => {
+ return {
+ workspaceId,
+ pages: workspacesMap[workspaceId],
+ }
+ })
+ const params = {
+ data_source: {
+ type: dataset?.data_source_type,
+ info_list: {
+ data_source_type: dataset?.data_source_type,
+ notion_info_list: workspaces.map((workspace) => {
+ return {
+ workspace_id: workspace.workspaceId,
+ pages: workspace.pages.map((page) => {
+ const { page_id, page_name, page_icon, type } = page
+ return {
+ page_id,
+ page_name,
+ page_icon,
+ type,
+ }
+ }),
+ }
+ }),
+ },
+ },
+ indexing_technique: dataset?.indexing_technique,
+ process_rule: {
+ rules: {},
+ mode: ProcessMode.general,
+ },
+ } as CreateDocumentReq
+
+ await createDocument({
+ datasetId,
+ body: params,
+ })
+ invalidDocumentList()
+ setTimerCanRun(true)
+ // mutateDatasetIndexingStatus(undefined, { revalidate: true })
+ setNotionPageSelectorModalVisible(false)
+ }
+
+ const documentsList = isDataSourceNotion ? documentsWithProgress?.data : documentsRes?.data
+ const [selectedIds, setSelectedIds] = useState<string[]>([])
+ const { run: handleSearch } = useDebounceFn(() => {
+ setSearchValue(inputValue)
+ }, { wait: 500 })
+
+ const handleInputChange = (value: string) => {
+ setInputValue(value)
+ handleSearch()
+ }
+
+ const {
+ isShowEditModal: isShowEditMetadataModal,
+ showEditModal: showEditMetadataModal,
+ hideEditModal: hideEditMetadataModal,
+ datasetMetaData,
+ handleAddMetaData,
+ handleRename,
+ handleDeleteMetaData,
+ builtInEnabled,
+ setBuiltInEnabled,
+ builtInMetaData,
+ } = useEditDocumentMetadata({
+ datasetId,
+ dataset,
+ onUpdateDocList: invalidDocumentList,
+ })
+
+ return (
+ <div className='flex h-full flex-col overflow-y-auto'>
+ <div className='flex flex-col justify-center gap-1 px-6 pt-4'>
+ <h1 className='text-base font-semibold text-text-primary'>{t('datasetDocuments.list.title')}</h1>
+ <div className='flex items-center space-x-0.5 text-sm font-normal text-text-tertiary'>
+ <span>{t('datasetDocuments.list.desc')}</span>
+ <a
+ className='flex items-center text-text-accent'
+ target='_blank'
+ href={
+ locale === LanguagesSupported[1]
+ ? 'https://docs.dify.ai/zh-hans/guides/knowledge-base/integrate-knowledge-within-application'
+ : 'https://docs.dify.ai/en/guides/knowledge-base/integrate-knowledge-within-application'
+ }
+ >
+ <span>{t('datasetDocuments.list.learnMore')}</span>
+ <RiExternalLinkLine className='h-3 w-3' />
+ </a>
+ </div>
+ </div>
+ <div className='flex flex-1 flex-col px-6 py-4'>
+ <div className='flex flex-wrap items-center justify-between'>
+ <Input
+ showLeftIcon
+ showClearIcon
+ wrapperClassName='!w-[200px]'
+ value={inputValue}
+ onChange={e => handleInputChange(e.target.value)}
+ onClear={() => handleInputChange('')}
+ />
+ <div className='flex !h-8 items-center justify-center gap-2'>
+ {!isFreePlan && <AutoDisabledDocument datasetId={datasetId} />}
+ <IndexFailed datasetId={datasetId} />
+ {!embeddingAvailable && <StatusWithAction type='warning' description={t('dataset.embeddingModelNotAvailable')} />}
+ {embeddingAvailable && (
+ <Button variant='secondary' className='shrink-0' onClick={showEditMetadataModal}>
+ <RiDraftLine className='mr-1 size-4' />
+ {t('dataset.metadata.metadata')}
+ </Button>
+ )}
+ {isShowEditMetadataModal && (
+ <DatasetMetadataDrawer
+ userMetadata={datasetMetaData || []}
+ onClose={hideEditMetadataModal}
+ onAdd={handleAddMetaData}
+ onRename={handleRename}
+ onRemove={handleDeleteMetaData}
+ builtInMetadata={builtInMetaData || []}
+ isBuiltInEnabled={!!builtInEnabled}
+ onIsBuiltInEnabledChange={setBuiltInEnabled}
+ />
+ )}
+ {embeddingAvailable && (
+ <Button variant='primary' onClick={routeToDocCreate} className='shrink-0'>
+ <PlusIcon className={cn('mr-2 h-4 w-4 stroke-current')} />
+ {isDataSourceNotion && t('datasetDocuments.list.addPages')}
+ {isDataSourceWeb && t('datasetDocuments.list.addUrl')}
+ {(!dataset?.data_source_type || isDataSourceFile) && t('datasetDocuments.list.addFile')}
+ </Button>
+ )}
+ </div>
+ </div>
+ {isListLoading
+ ? <Loading type='app' />
+ : total > 0
+ ? <List
+ embeddingAvailable={embeddingAvailable}
+ documents={documentsList || []}
+ datasetId={datasetId}
+ onUpdate={handleUpdate}
+ selectedIds={selectedIds}
+ onSelectedIdChange={setSelectedIds}
+ pagination={{
+ total,
+ limit,
+ onLimitChange: setLimit,
+ current: currPage,
+ onChange: setCurrPage,
+ }}
+ onManageMetadata={showEditMetadataModal}
+ />
+ : <EmptyElement canAdd={embeddingAvailable} onClick={routeToDocCreate} type={isDataSourceNotion ? 'sync' : 'upload'} />
+ }
+ <NotionPageSelectorModal
+ isShow={notionPageSelectorModalVisible}
+ onClose={() => setNotionPageSelectorModalVisible(false)}
+ onSave={handleSaveNotionPageSelected}
+ datasetId={dataset?.id || ''}
+ />
+ </div>
+ </div>
+ )
+}
+
+export default Documents
diff --git a/app/components/datasets/documents/list.tsx b/app/components/datasets/documents/list.tsx
new file mode 100644
index 0000000..cb349ee
--- /dev/null
+++ b/app/components/datasets/documents/list.tsx
@@ -0,0 +1,687 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import { useBoolean, useDebounceFn } from 'ahooks'
+import { ArrowDownIcon } from '@heroicons/react/24/outline'
+import { pick, uniq } from 'lodash-es'
+import {
+ RiArchive2Line,
+ RiDeleteBinLine,
+ RiEditLine,
+ RiEqualizer2Line,
+ RiLoopLeftLine,
+ RiMoreFill,
+} from '@remixicon/react'
+import { useContext } from 'use-context-selector'
+import { useRouter } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import dayjs from 'dayjs'
+import { Globe01 } from '../../base/icons/src/vender/line/mapsAndTravel'
+import ChunkingModeLabel from '../common/chunking-mode-label'
+import FileTypeIcon from '../../base/file-uploader/file-type-icon'
+import s from './style.module.css'
+import RenameModal from './rename-modal'
+import BatchAction from './detail/completed/common/batch-action'
+import cn from '@/utils/classnames'
+import Switch from '@/app/components/base/switch'
+import Divider from '@/app/components/base/divider'
+import Popover from '@/app/components/base/popover'
+import Confirm from '@/app/components/base/confirm'
+import Tooltip from '@/app/components/base/tooltip'
+import Toast, { ToastContext } from '@/app/components/base/toast'
+import type { ColorMap, IndicatorProps } from '@/app/components/header/indicator'
+import Indicator from '@/app/components/header/indicator'
+import { asyncRunSafe } from '@/utils'
+import { formatNumber } from '@/utils/format'
+import NotionIcon from '@/app/components/base/notion-icon'
+import ProgressBar from '@/app/components/base/progress-bar'
+import { ChunkingMode, DataSourceType, DocumentActionType, type DocumentDisplayStatus, type SimpleDocumentDetail } from '@/models/datasets'
+import type { CommonResponse } from '@/models/common'
+import useTimestamp from '@/hooks/use-timestamp'
+import { useDatasetDetailContextWithSelector as useDatasetDetailContext } from '@/context/dataset-detail'
+import type { Props as PaginationProps } from '@/app/components/base/pagination'
+import Pagination from '@/app/components/base/pagination'
+import Checkbox from '@/app/components/base/checkbox'
+import { useDocumentArchive, useDocumentDelete, useDocumentDisable, useDocumentEnable, useDocumentUnArchive, useSyncDocument, useSyncWebsite } from '@/service/knowledge/use-document'
+import { extensionToFileType } from '@/app/components/datasets/hit-testing/utils/extension-to-file-type'
+import useBatchEditDocumentMetadata from '../metadata/hooks/use-batch-edit-document-metadata'
+import EditMetadataBatchModal from '@/app/components/datasets/metadata/edit-metadata-batch/modal'
+import { noop } from 'lodash-es'
+
+export const useIndexStatus = () => {
+ const { t } = useTranslation()
+ return {
+ queuing: { color: 'orange', text: t('datasetDocuments.list.status.queuing') }, // waiting
+ indexing: { color: 'blue', text: t('datasetDocuments.list.status.indexing') }, // indexing splitting parsing cleaning
+ paused: { color: 'orange', text: t('datasetDocuments.list.status.paused') }, // paused
+ error: { color: 'red', text: t('datasetDocuments.list.status.error') }, // error
+ available: { color: 'green', text: t('datasetDocuments.list.status.available') }, // completed锛宎rchived = false锛宔nabled = true
+ enabled: { color: 'green', text: t('datasetDocuments.list.status.enabled') }, // completed锛宎rchived = false锛宔nabled = true
+ disabled: { color: 'gray', text: t('datasetDocuments.list.status.disabled') }, // completed锛宎rchived = false锛宔nabled = false
+ archived: { color: 'gray', text: t('datasetDocuments.list.status.archived') }, // completed锛宎rchived = true
+ }
+}
+
+const STATUS_TEXT_COLOR_MAP: ColorMap = {
+ green: 'text-util-colors-green-green-600',
+ orange: 'text-util-colors-warning-warning-600',
+ red: 'text-util-colors-red-red-600',
+ blue: 'text-util-colors-blue-light-blue-light-600',
+ yellow: 'text-util-colors-warning-warning-600',
+ gray: 'text-text-tertiary',
+}
+
+// status item for list
+export const StatusItem: FC<{
+ status: DocumentDisplayStatus
+ reverse?: boolean
+ scene?: 'list' | 'detail'
+ textCls?: string
+ errorMessage?: string
+ detail?: {
+ enabled: boolean
+ archived: boolean
+ id: string
+ }
+ datasetId?: string
+ onUpdate?: (operationName?: string) => void
+
+}> = ({ status, reverse = false, scene = 'list', textCls = '', errorMessage, datasetId = '', detail, onUpdate }) => {
+ const DOC_INDEX_STATUS_MAP = useIndexStatus()
+ const localStatus = status.toLowerCase() as keyof typeof DOC_INDEX_STATUS_MAP
+ const { enabled = false, archived = false, id = '' } = detail || {}
+ const { notify } = useContext(ToastContext)
+ const { t } = useTranslation()
+ const { mutateAsync: enableDocument } = useDocumentEnable()
+ const { mutateAsync: disableDocument } = useDocumentDisable()
+ const { mutateAsync: deleteDocument } = useDocumentDelete()
+
+ const onOperate = async (operationName: OperationName) => {
+ let opApi = deleteDocument
+ switch (operationName) {
+ case 'enable':
+ opApi = enableDocument
+ break
+ case 'disable':
+ opApi = disableDocument
+ break
+ }
+ const [e] = await asyncRunSafe<CommonResponse>(opApi({ datasetId, documentId: id }) as Promise<CommonResponse>)
+ if (!e) {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ onUpdate?.()
+ // onUpdate?.(operationName)
+ }
+ else { notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) }
+ }
+
+ const { run: handleSwitch } = useDebounceFn((operationName: OperationName) => {
+ if (operationName === 'enable' && enabled)
+ return
+ if (operationName === 'disable' && !enabled)
+ return
+ onOperate(operationName)
+ }, { wait: 500 })
+
+ const embedding = useMemo(() => {
+ return ['queuing', 'indexing', 'paused'].includes(localStatus)
+ }, [localStatus])
+
+ return <div className={
+ cn('flex items-center',
+ reverse ? 'flex-row-reverse' : '',
+ scene === 'detail' ? s.statusItemDetail : '')
+ }>
+ <Indicator color={DOC_INDEX_STATUS_MAP[localStatus]?.color as IndicatorProps['color']} className={reverse ? 'ml-2' : 'mr-2'} />
+ <span className={cn(`${STATUS_TEXT_COLOR_MAP[DOC_INDEX_STATUS_MAP[localStatus].color as keyof typeof STATUS_TEXT_COLOR_MAP]} text-sm`, textCls)}>
+ {DOC_INDEX_STATUS_MAP[localStatus]?.text}
+ </span>
+ {
+ errorMessage && (
+ <Tooltip
+ popupContent={
+ <div className='max-w-[260px] break-all'>{errorMessage}</div>
+ }
+ triggerClassName='ml-1 w-4 h-4'
+ />
+ )
+ }
+ {
+ scene === 'detail' && (
+ <div className='ml-1.5 flex items-center justify-between'>
+ <Tooltip
+ popupContent={t('datasetDocuments.list.action.enableWarning')}
+ popupClassName='text-text-secondary system-xs-medium'
+ needsDelay
+ disabled={!archived}
+ >
+ <Switch
+ defaultValue={archived ? false : enabled}
+ onChange={v => !archived && handleSwitch(v ? 'enable' : 'disable')}
+ disabled={embedding || archived}
+ size='md'
+ />
+ </Tooltip>
+ </div>
+ )
+ }
+ </div>
+}
+
+type OperationName = 'delete' | 'archive' | 'enable' | 'disable' | 'sync' | 'un_archive'
+
+// operation action for list and detail
+export const OperationAction: FC<{
+ embeddingAvailable: boolean
+ detail: {
+ name: string
+ enabled: boolean
+ archived: boolean
+ id: string
+ data_source_type: string
+ doc_form: string
+ }
+ datasetId: string
+ onUpdate: (operationName?: string) => void
+ scene?: 'list' | 'detail'
+ className?: string
+}> = ({ embeddingAvailable, datasetId, detail, onUpdate, scene = 'list', className = '' }) => {
+ const { id, enabled = false, archived = false, data_source_type } = detail || {}
+ const [showModal, setShowModal] = useState(false)
+ const [deleting, setDeleting] = useState(false)
+ const { notify } = useContext(ToastContext)
+ const { t } = useTranslation()
+ const router = useRouter()
+ const { mutateAsync: archiveDocument } = useDocumentArchive()
+ const { mutateAsync: unArchiveDocument } = useDocumentUnArchive()
+ const { mutateAsync: enableDocument } = useDocumentEnable()
+ const { mutateAsync: disableDocument } = useDocumentDisable()
+ const { mutateAsync: deleteDocument } = useDocumentDelete()
+ const { mutateAsync: syncDocument } = useSyncDocument()
+ const { mutateAsync: syncWebsite } = useSyncWebsite()
+ const isListScene = scene === 'list'
+
+ const onOperate = async (operationName: OperationName) => {
+ let opApi
+ switch (operationName) {
+ case 'archive':
+ opApi = archiveDocument
+ break
+ case 'un_archive':
+ opApi = unArchiveDocument
+ break
+ case 'enable':
+ opApi = enableDocument
+ break
+ case 'disable':
+ opApi = disableDocument
+ break
+ case 'sync':
+ if (data_source_type === 'notion_import')
+ opApi = syncDocument
+ else
+ opApi = syncWebsite
+ break
+ default:
+ opApi = deleteDocument
+ setDeleting(true)
+ break
+ }
+ const [e] = await asyncRunSafe<CommonResponse>(opApi({ datasetId, documentId: id }) as Promise<CommonResponse>)
+ if (!e) {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ onUpdate(operationName)
+ }
+ else { notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) }
+ if (operationName === 'delete')
+ setDeleting(false)
+ }
+
+ const { run: handleSwitch } = useDebounceFn((operationName: OperationName) => {
+ if (operationName === 'enable' && enabled)
+ return
+ if (operationName === 'disable' && !enabled)
+ return
+ onOperate(operationName)
+ }, { wait: 500 })
+
+ const [currDocument, setCurrDocument] = useState<{
+ id: string
+ name: string
+ } | null>(null)
+ const [isShowRenameModal, {
+ setTrue: setShowRenameModalTrue,
+ setFalse: setShowRenameModalFalse,
+ }] = useBoolean(false)
+ const handleShowRenameModal = useCallback((doc: {
+ id: string
+ name: string
+ }) => {
+ setCurrDocument(doc)
+ setShowRenameModalTrue()
+ }, [setShowRenameModalTrue])
+ const handleRenamed = useCallback(() => {
+ onUpdate()
+ }, [onUpdate])
+
+ return <div className='flex items-center' onClick={e => e.stopPropagation()}>
+ {isListScene && !embeddingAvailable && (
+ <Switch defaultValue={false} onChange={noop} disabled={true} size='md' />
+ )}
+ {isListScene && embeddingAvailable && (
+ <>
+ {archived
+ ? <Tooltip
+ popupContent={t('datasetDocuments.list.action.enableWarning')}
+ popupClassName='!font-semibold'
+ needsDelay
+ >
+ <div>
+ <Switch defaultValue={false} onChange={noop} disabled={true} size='md' />
+ </div>
+ </Tooltip>
+ : <Switch defaultValue={enabled} onChange={v => handleSwitch(v ? 'enable' : 'disable')} size='md' />
+ }
+ <Divider className='!ml-4 !mr-2 !h-3' type='vertical' />
+ </>
+ )}
+ {embeddingAvailable && (
+ <>
+ <Tooltip
+ popupContent={t('datasetDocuments.list.action.settings')}
+ popupClassName='text-text-secondary system-xs-medium'
+ >
+ <button
+ className={cn('mr-2 cursor-pointer rounded-lg',
+ !isListScene
+ ? 'border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg p-2 shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px] hover:border-components-button-secondary-border-hover hover:bg-components-button-secondary-bg-hover'
+ : 'p-0.5 hover:bg-state-base-hover')}
+ onClick={() => router.push(`/datasets/${datasetId}/documents/${detail.id}/settings`)}>
+ <RiEqualizer2Line className='h-4 w-4 text-components-button-secondary-text' />
+ </button>
+ </Tooltip>
+ <Popover
+ htmlContent={
+ <div className='w-full py-1'>
+ {!archived && (
+ <>
+ <div className={s.actionItem} onClick={() => {
+ handleShowRenameModal({
+ id: detail.id,
+ name: detail.name,
+ })
+ }}>
+ <RiEditLine className='h-4 w-4 text-text-tertiary' />
+ <span className={s.actionName}>{t('datasetDocuments.list.table.rename')}</span>
+ </div>
+ {['notion_import', DataSourceType.WEB].includes(data_source_type) && (
+ <div className={s.actionItem} onClick={() => onOperate('sync')}>
+ <RiLoopLeftLine className='h-4 w-4 text-text-tertiary' />
+ <span className={s.actionName}>{t('datasetDocuments.list.action.sync')}</span>
+ </div>
+ )}
+ <Divider className='my-1' />
+ </>
+ )}
+ {!archived && <div className={s.actionItem} onClick={() => onOperate('archive')}>
+ <RiArchive2Line className='h-4 w-4 text-text-tertiary' />
+ <span className={s.actionName}>{t('datasetDocuments.list.action.archive')}</span>
+ </div>}
+ {archived && (
+ <div className={s.actionItem} onClick={() => onOperate('un_archive')}>
+ <RiArchive2Line className='h-4 w-4 text-text-tertiary' />
+ <span className={s.actionName}>{t('datasetDocuments.list.action.unarchive')}</span>
+ </div>
+ )}
+ <div className={cn(s.actionItem, s.deleteActionItem, 'group')} onClick={() => setShowModal(true)}>
+ <RiDeleteBinLine className={'h-4 w-4 text-text-tertiary group-hover:text-text-destructive'} />
+ <span className={cn(s.actionName, 'group-hover:text-text-destructive')}>{t('datasetDocuments.list.action.delete')}</span>
+ </div>
+ </div>
+ }
+ trigger='click'
+ position='br'
+ btnElement={
+ <div className={cn(s.commonIcon)}>
+ <RiMoreFill className='h-4 w-4 text-components-button-secondary-text' />
+ </div>
+ }
+ btnClassName={open => cn(isListScene ? s.actionIconWrapperList : s.actionIconWrapperDetail, open ? '!hover:bg-state-base-hover !shadow-none' : '!bg-transparent')}
+ popupClassName='!w-full'
+ className={`!z-20 flex h-fit !w-[200px] justify-end ${className}`}
+ />
+ </>
+ )}
+ {showModal
+ && <Confirm
+ isShow={showModal}
+ isLoading={deleting}
+ isDisabled={deleting}
+ title={t('datasetDocuments.list.delete.title')}
+ content={t('datasetDocuments.list.delete.content')}
+ confirmText={t('common.operation.sure')}
+ onConfirm={() => onOperate('delete')}
+ onCancel={() => setShowModal(false)}
+ />
+ }
+
+ {isShowRenameModal && currDocument && (
+ <RenameModal
+ datasetId={datasetId}
+ documentId={currDocument.id}
+ name={currDocument.name}
+ onClose={setShowRenameModalFalse}
+ onSaved={handleRenamed}
+ />
+ )}
+ </div>
+}
+
+export const renderTdValue = (value: string | number | null, isEmptyStyle = false) => {
+ return (
+ <div className={cn(isEmptyStyle ? 'text-text-tertiary' : 'text-text-secondary', s.tdValue)}>
+ {value ?? '-'}
+ </div>
+ )
+}
+
+const renderCount = (count: number | undefined) => {
+ if (!count)
+ return renderTdValue(0, true)
+
+ if (count < 1000)
+ return count
+
+ return `${formatNumber((count / 1000).toFixed(1))}k`
+}
+
+type LocalDoc = SimpleDocumentDetail & { percent?: number }
+type IDocumentListProps = {
+ embeddingAvailable: boolean
+ documents: LocalDoc[]
+ selectedIds: string[]
+ onSelectedIdChange: (selectedIds: string[]) => void
+ datasetId: string
+ pagination: PaginationProps
+ onUpdate: () => void
+ onManageMetadata: () => void
+}
+
+/**
+ * Document list component including basic information
+ */
+const DocumentList: FC<IDocumentListProps> = ({
+ embeddingAvailable,
+ documents = [],
+ selectedIds,
+ onSelectedIdChange,
+ datasetId,
+ pagination,
+ onUpdate,
+ onManageMetadata,
+}) => {
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+ const router = useRouter()
+ const [datasetConfig] = useDatasetDetailContext(s => [s.dataset])
+ const chunkingMode = datasetConfig?.doc_form
+ const isGeneralMode = chunkingMode !== ChunkingMode.parentChild
+ const isQAMode = chunkingMode === ChunkingMode.qa
+ const [localDocs, setLocalDocs] = useState<LocalDoc[]>(documents)
+ const [enableSort, setEnableSort] = useState(true)
+ const {
+ isShowEditModal,
+ showEditModal,
+ hideEditModal,
+ originalList,
+ handleSave,
+ } = useBatchEditDocumentMetadata({
+ datasetId,
+ docList: documents.filter(item => selectedIds.includes(item.id)),
+ onUpdate,
+ })
+
+ useEffect(() => {
+ setLocalDocs(documents)
+ }, [documents])
+
+ const onClickSort = () => {
+ setEnableSort(!enableSort)
+ if (enableSort) {
+ const sortedDocs = [...localDocs].sort((a, b) => dayjs(a.created_at).isBefore(dayjs(b.created_at)) ? -1 : 1)
+ setLocalDocs(sortedDocs)
+ }
+ else {
+ setLocalDocs(documents)
+ }
+ }
+
+ const [currDocument, setCurrDocument] = useState<LocalDoc | null>(null)
+ const [isShowRenameModal, {
+ setTrue: setShowRenameModalTrue,
+ setFalse: setShowRenameModalFalse,
+ }] = useBoolean(false)
+ const handleShowRenameModal = useCallback((doc: LocalDoc) => {
+ setCurrDocument(doc)
+ setShowRenameModalTrue()
+ }, [setShowRenameModalTrue])
+ const handleRenamed = useCallback(() => {
+ onUpdate()
+ }, [onUpdate])
+
+ const isAllSelected = useMemo(() => {
+ return localDocs.length > 0 && localDocs.every(doc => selectedIds.includes(doc.id))
+ }, [localDocs, selectedIds])
+
+ const isSomeSelected = useMemo(() => {
+ return localDocs.some(doc => selectedIds.includes(doc.id))
+ }, [localDocs, selectedIds])
+
+ const onSelectedAll = useCallback(() => {
+ if (isAllSelected)
+ onSelectedIdChange([])
+ else
+ onSelectedIdChange(uniq([...selectedIds, ...localDocs.map(doc => doc.id)]))
+ }, [isAllSelected, localDocs, onSelectedIdChange, selectedIds])
+ const { mutateAsync: archiveDocument } = useDocumentArchive()
+ const { mutateAsync: enableDocument } = useDocumentEnable()
+ const { mutateAsync: disableDocument } = useDocumentDisable()
+ const { mutateAsync: deleteDocument } = useDocumentDelete()
+
+ const handleAction = (actionName: DocumentActionType) => {
+ return async () => {
+ let opApi
+ switch (actionName) {
+ case DocumentActionType.archive:
+ opApi = archiveDocument
+ break
+ case DocumentActionType.enable:
+ opApi = enableDocument
+ break
+ case DocumentActionType.disable:
+ opApi = disableDocument
+ break
+ default:
+ opApi = deleteDocument
+ break
+ }
+ const [e] = await asyncRunSafe<CommonResponse>(opApi({ datasetId, documentIds: selectedIds }) as Promise<CommonResponse>)
+
+ if (!e) {
+ Toast.notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ onUpdate()
+ }
+ else { Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) }
+ }
+ }
+
+ return (
+ <div className='relative flex h-full w-full flex-col'>
+ <div className='relative grow overflow-x-auto'>
+ <table className={`mt-3 w-full min-w-[700px] max-w-full border-collapse border-0 text-sm ${s.documentTable}`}>
+ <thead className="h-8 border-b border-divider-subtle text-xs font-medium uppercase leading-8 text-text-tertiary">
+ <tr>
+ <td className='w-12'>
+ <div className='flex items-center' onClick={e => e.stopPropagation()}>
+ {embeddingAvailable && (
+ <Checkbox
+ className='mr-2 shrink-0'
+ checked={isAllSelected}
+ indeterminate={!isAllSelected && isSomeSelected}
+ onCheck={onSelectedAll}
+ />
+ )}
+ #
+ </div>
+ </td>
+ <td>
+ <div className='flex'>
+ {t('datasetDocuments.list.table.header.fileName')}
+ </div>
+ </td>
+ <td className='w-[130px]'>{t('datasetDocuments.list.table.header.chunkingMode')}</td>
+ <td className='w-24'>{t('datasetDocuments.list.table.header.words')}</td>
+ <td className='w-44'>{t('datasetDocuments.list.table.header.hitCount')}</td>
+ <td className='w-44'>
+ <div className='flex items-center' onClick={onClickSort}>
+ {t('datasetDocuments.list.table.header.uploadTime')}
+ <ArrowDownIcon className={cn('ml-0.5 h-3 w-3 cursor-pointer stroke-current stroke-2', enableSort ? 'text-text-tertiary' : 'text-text-disabled')} />
+ </div>
+ </td>
+ <td className='w-40'>{t('datasetDocuments.list.table.header.status')}</td>
+ <td className='w-20'>{t('datasetDocuments.list.table.header.action')}</td>
+ </tr>
+ </thead>
+ <tbody className="text-text-secondary">
+ {localDocs.map((doc, index) => {
+ const isFile = doc.data_source_type === DataSourceType.FILE
+ const fileType = isFile ? doc.data_source_detail_dict?.upload_file?.extension : ''
+ return <tr
+ key={doc.id}
+ className={'h-8 cursor-pointer border-b border-divider-subtle hover:bg-background-default-hover'}
+ onClick={() => {
+ router.push(`/datasets/${datasetId}/documents/${doc.id}`)
+ }}>
+ <td className='text-left align-middle text-xs text-text-tertiary'>
+ <div className='flex items-center' onClick={e => e.stopPropagation()}>
+ <Checkbox
+ className='mr-2 shrink-0'
+ checked={selectedIds.includes(doc.id)}
+ onCheck={() => {
+ onSelectedIdChange(
+ selectedIds.includes(doc.id)
+ ? selectedIds.filter(id => id !== doc.id)
+ : [...selectedIds, doc.id],
+ )
+ }}
+ />
+ {/* {doc.position} */}
+ {index + 1}
+ </div>
+ </td>
+ <td>
+ <div className={'group mr-6 flex max-w-[460px] items-center hover:mr-0'}>
+ <div className='shrink-0'>
+ {doc?.data_source_type === DataSourceType.NOTION && <NotionIcon className='mr-1.5 mt-[-3px] inline-flex align-middle' type='page' src={doc.data_source_info.notion_page_icon} />}
+ {doc?.data_source_type === DataSourceType.FILE && <FileTypeIcon type={extensionToFileType(doc?.data_source_info?.upload_file?.extension ?? fileType)} className='mr-1.5' />}
+ {doc?.data_source_type === DataSourceType.WEB && <Globe01 className='mr-1.5 mt-[-3px] inline-flex align-middle' />}
+ </div>
+ <span className='grow-1 truncate text-sm'>{doc.name}</span>
+ <div className='hidden shrink-0 group-hover:ml-auto group-hover:flex'>
+ <Tooltip
+ popupContent={t('datasetDocuments.list.table.rename')}
+ >
+ <div
+ className='cursor-pointer rounded-md p-1 hover:bg-state-base-hover'
+ onClick={(e) => {
+ e.stopPropagation()
+ handleShowRenameModal(doc)
+ }}
+ >
+ <RiEditLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </Tooltip>
+ </div>
+ </div>
+ </td>
+ <td>
+ <ChunkingModeLabel
+ isGeneralMode={isGeneralMode}
+ isQAMode={isQAMode}
+ />
+ </td>
+ <td>{renderCount(doc.word_count)}</td>
+ <td>{renderCount(doc.hit_count)}</td>
+ <td className='text-[13px] text-text-secondary'>
+ {formatTime(doc.created_at, t('datasetHitTesting.dateTimeFormat') as string)}
+ </td>
+ <td>
+ {
+ (['indexing', 'splitting', 'parsing', 'cleaning'].includes(doc.indexing_status) && doc?.data_source_type === DataSourceType.NOTION)
+ ? <ProgressBar percent={doc.percent || 0} />
+ : <StatusItem status={doc.display_status} />
+ }
+ </td>
+ <td>
+ <OperationAction
+ embeddingAvailable={embeddingAvailable}
+ datasetId={datasetId}
+ detail={pick(doc, ['name', 'enabled', 'archived', 'id', 'data_source_type', 'doc_form'])}
+ onUpdate={onUpdate}
+ />
+ </td>
+ </tr>
+ })}
+ </tbody>
+ </table>
+ </div>
+ {(selectedIds.length > 0) && (
+ <BatchAction
+ className='absolute bottom-16 left-0 z-20'
+ selectedIds={selectedIds}
+ onArchive={handleAction(DocumentActionType.archive)}
+ onBatchEnable={handleAction(DocumentActionType.enable)}
+ onBatchDisable={handleAction(DocumentActionType.disable)}
+ onBatchDelete={handleAction(DocumentActionType.delete)}
+ onEditMetadata={showEditModal}
+ onCancel={() => {
+ onSelectedIdChange([])
+ }}
+ />
+ )}
+ {/* Show Pagination only if the total is more than the limit */}
+ {pagination.total && (
+ <Pagination
+ {...pagination}
+ className='w-full shrink-0 px-0 pb-0'
+ />
+ )}
+
+ {isShowRenameModal && currDocument && (
+ <RenameModal
+ datasetId={datasetId}
+ documentId={currDocument.id}
+ name={currDocument.name}
+ onClose={setShowRenameModalFalse}
+ onSaved={handleRenamed}
+ />
+ )}
+
+ {isShowEditModal && (
+ <EditMetadataBatchModal
+ datasetId={datasetId}
+ documentNum={selectedIds.length}
+ list={originalList}
+ onSave={handleSave}
+ onHide={hideEditModal}
+ onShowManage={() => {
+ hideEditModal()
+ onManageMetadata()
+ }}
+ />
+ )}
+ </div>
+ )
+}
+
+export default DocumentList
diff --git a/app/components/datasets/documents/rename-modal.tsx b/app/components/datasets/documents/rename-modal.tsx
new file mode 100644
index 0000000..ff50479
--- /dev/null
+++ b/app/components/datasets/documents/rename-modal.tsx
@@ -0,0 +1,76 @@
+'use client'
+import type { FC } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import Toast from '../../base/toast'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import { renameDocumentName } from '@/service/datasets'
+
+type Props = {
+ datasetId: string
+ documentId: string
+ name: string
+ onClose: () => void
+ onSaved: () => void
+}
+
+const RenameModal: FC<Props> = ({
+ documentId,
+ datasetId,
+ name,
+ onClose,
+ onSaved,
+}) => {
+ const { t } = useTranslation()
+
+ const [newName, setNewName] = useState(name)
+ const [saveLoading, {
+ setTrue: setSaveLoadingTrue,
+ setFalse: setSaveLoadingFalse,
+ }] = useBoolean(false)
+
+ const handleSave = async () => {
+ setSaveLoadingTrue()
+ try {
+ await renameDocumentName({
+ datasetId,
+ documentId,
+ name: newName,
+ })
+ Toast.notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ onSaved()
+ onClose()
+ }
+ catch (error) {
+ if (error)
+ Toast.notify({ type: 'error', message: error.toString() })
+ }
+ finally {
+ setSaveLoadingFalse()
+ }
+ }
+
+ return (
+ <Modal
+ title={t('datasetDocuments.list.table.rename')}
+ isShow
+ onClose={onClose}
+ >
+ <div className={'mt-6 text-sm font-medium leading-[21px] text-text-primary'}>{t('datasetDocuments.list.table.name')}</div>
+ <Input
+ className='mt-2 h-10'
+ value={newName}
+ onChange={e => setNewName(e.target.value)}
+ />
+
+ <div className='mt-10 flex justify-end'>
+ <Button className='mr-2 shrink-0' onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' className='shrink-0' onClick={handleSave} loading={saveLoading}>{t('common.operation.save')}</Button>
+ </div>
+ </Modal>
+ )
+}
+export default React.memo(RenameModal)
diff --git a/app/components/datasets/documents/style.module.css b/app/components/datasets/documents/style.module.css
new file mode 100644
index 0000000..ececd3a
--- /dev/null
+++ b/app/components/datasets/documents/style.module.css
@@ -0,0 +1,118 @@
+.documentTable tbody td {
+ padding: 5px 10px 5px 12px;
+ box-sizing: border-box;
+ max-width: 200px;
+}
+.documentTable thead td {
+ padding: 0px 10px 0px 12px;
+ box-sizing: border-box;
+ max-width: 200px;
+}
+.actionIconWrapperList {
+ @apply h-6 w-6 rounded-md border-none p-1 hover:bg-state-base-hover !important;
+}
+.actionIconWrapperDetail {
+ @apply p-2 bg-components-button-secondary-bg hover:bg-components-button-secondary-bg-hover
+ border-[0.5px] border-components-button-secondary-border hover:border-components-button-secondary-border-hover
+ shadow-xs shadow-shadow-shadow-3 !important;
+}
+.actionItem {
+ @apply h-9 py-2 px-3 mx-1 flex items-center gap-2 hover:bg-state-base-hover rounded-lg cursor-pointer;
+}
+.deleteActionItem {
+ @apply hover:bg-state-destructive-hover !important;
+}
+.actionName {
+ @apply text-text-secondary text-sm;
+}
+.addFileBtn {
+ @apply mt-4 w-fit !text-[13px] text-primary-600 font-medium bg-white border-[0.5px];
+}
+.plusIcon {
+ @apply w-4 h-4 mr-2 stroke-current stroke-[1.5px];
+}
+.emptyWrapper {
+ @apply flex items-center justify-center h-full;
+}
+.emptyElement {
+ @apply bg-gray-50 w-[560px] h-fit box-border px-5 py-4 rounded-2xl;
+}
+.emptyTitle {
+ @apply text-gray-700 font-semibold;
+}
+.emptyTip {
+ @apply mt-2 text-gray-500 text-sm font-normal;
+}
+.emptySymbolIconWrapper {
+ @apply w-[44px] h-[44px] border border-solid border-gray-100 rounded-lg flex items-center justify-center mb-2;
+}
+.commonIcon {
+ @apply w-4 h-4 inline-block align-middle;
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-size: contain;
+}
+.actionIcon {
+ @apply bg-gray-500;
+ mask-image: url(~@/assets/action.svg);
+}
+.pdfIcon {
+ background-image: url(~@/assets/pdf.svg);
+}
+.jsonIcon {
+ background-image: url(~@/assets/json.svg);
+}
+.htmlIcon {
+ background-image: url(~@/assets/html.svg);
+}
+.txtIcon {
+ background-image: url(~@/assets/txt.svg);
+}
+.markdownIcon {
+ background-image: url(~@/assets/md.svg);
+}
+.mdIcon {
+ background-image: url(~@/assets/md.svg);
+}
+.xlsIcon {
+ background-image: url(~@/assets/xlsx.svg);
+}
+.xlsxIcon {
+ background-image: url(~@/assets/xlsx.svg);
+}
+.csvIcon {
+ background-image: url(~@/assets/csv.svg);
+}
+.docIcon {
+ background-image: url(~@/assets/doc.svg);
+}
+.docxIcon {
+ background-image: url(~@/assets/docx.svg);
+}
+.statusItemDetail {
+ @apply border-[0.5px] border-components-button-secondary-border inline-flex items-center
+ rounded-lg pl-2.5 pr-2 py-2 mr-2 shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px];
+}
+.tdValue {
+ @apply text-sm overflow-hidden text-ellipsis whitespace-nowrap;
+}
+.delModal {
+ background: linear-gradient(
+ 180deg,
+ rgba(217, 45, 32, 0.05) 0%,
+ rgba(217, 45, 32, 0) 24.02%
+ ),
+ #f9fafb;
+ box-shadow: 0px 20px 24px -4px rgba(16, 24, 40, 0.08),
+ 0px 8px 8px -4px rgba(16, 24, 40, 0.03);
+ @apply rounded-2xl p-8;
+}
+.warningWrapper {
+ box-shadow: 0px 20px 24px -4px rgba(16, 24, 40, 0.08),
+ 0px 8px 8px -4px rgba(16, 24, 40, 0.03);
+ background: rgba(255, 255, 255, 0.9);
+ @apply h-12 w-12 border-[0.5px] border-gray-100 rounded-xl mb-3 flex items-center justify-center;
+}
+.warningIcon {
+ @apply w-[22px] h-[22px] fill-current text-red-600;
+}
diff --git a/app/components/datasets/external-api/declarations.ts b/app/components/datasets/external-api/declarations.ts
new file mode 100644
index 0000000..ded736d
--- /dev/null
+++ b/app/components/datasets/external-api/declarations.ts
@@ -0,0 +1,16 @@
+export type CreateExternalAPIReq = {
+ name: string
+ settings: {
+ endpoint: string
+ api_key: string
+ }
+}
+
+export type FormSchema = {
+ variable: string
+ type: 'text' | 'secret'
+ label: {
+ [key: string]: string
+ }
+ required: boolean
+}
diff --git a/app/components/datasets/external-api/external-api-modal/Form.tsx b/app/components/datasets/external-api/external-api-modal/Form.tsx
new file mode 100644
index 0000000..2746a32
--- /dev/null
+++ b/app/components/datasets/external-api/external-api-modal/Form.tsx
@@ -0,0 +1,92 @@
+import React, { useState } from 'react'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiBookOpenLine } from '@remixicon/react'
+import type { CreateExternalAPIReq, FormSchema } from '../declarations'
+import Input from '@/app/components/base/input'
+import cn from '@/utils/classnames'
+
+type FormProps = {
+ className?: string
+ itemClassName?: string
+ fieldLabelClassName?: string
+ value: CreateExternalAPIReq
+ onChange: (val: CreateExternalAPIReq) => void
+ formSchemas: FormSchema[]
+ inputClassName?: string
+}
+
+const Form: FC<FormProps> = React.memo(({
+ className,
+ itemClassName,
+ fieldLabelClassName,
+ value,
+ onChange,
+ formSchemas,
+ inputClassName,
+}) => {
+ const { t, i18n } = useTranslation()
+ const [changeKey, setChangeKey] = useState('')
+
+ const handleFormChange = (key: string, val: string) => {
+ setChangeKey(key)
+ if (key === 'name') {
+ onChange({ ...value, [key]: val })
+ }
+ else {
+ onChange({
+ ...value,
+ settings: {
+ ...value.settings,
+ [key]: val,
+ },
+ })
+ }
+ }
+
+ const renderField = (formSchema: FormSchema) => {
+ const { variable, type, label, required } = formSchema
+ const fieldValue = variable === 'name' ? value[variable] : (value.settings[variable as keyof typeof value.settings] || '')
+
+ return (
+ <div key={variable} className={cn(itemClassName, 'flex flex-col items-start gap-1 self-stretch')}>
+ <div className="flex w-full items-center justify-between">
+ <label className={cn(fieldLabelClassName, 'system-sm-semibold text-text-secondary')} htmlFor={variable}>
+ {label[i18n.language] || label.en_US}
+ {required && <span className='ml-1 text-red-500'>*</span>}
+ </label>
+ {variable === 'endpoint' && (
+ <a
+ href={'https://docs.dify.ai/guides/knowledge-base/external-knowledge-api-documentation' || '/'}
+ target='_blank'
+ rel='noopener noreferrer'
+ className='body-xs-regular flex items-center text-text-accent'
+ >
+ <RiBookOpenLine className='mr-1 h-3 w-3 text-text-accent' />
+ {t('dataset.externalAPIPanelDocumentation')}
+ </a>
+ )}
+ </div>
+ <Input
+ type={type === 'secret' ? 'password' : 'text'}
+ id={variable}
+ name={variable}
+ value={fieldValue}
+ onChange={val => handleFormChange(variable, val.target.value)}
+ required={required}
+ className={cn(inputClassName)}
+ />
+ </div>
+ )
+ }
+
+ return (
+ <form className={cn('flex flex-col items-start justify-center gap-4 self-stretch', className)}>
+ {formSchemas.map(formSchema => renderField(formSchema))}
+ </form>
+ )
+})
+
+Form.displayName = 'Form'
+
+export default Form
diff --git a/app/components/datasets/external-api/external-api-modal/index.tsx b/app/components/datasets/external-api/external-api-modal/index.tsx
new file mode 100644
index 0000000..8614664
--- /dev/null
+++ b/app/components/datasets/external-api/external-api-modal/index.tsx
@@ -0,0 +1,218 @@
+import type { FC } from 'react'
+import {
+ memo,
+ useEffect,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiBook2Line,
+ RiCloseLine,
+ RiInformation2Line,
+ RiLock2Fill,
+} from '@remixicon/react'
+import type { CreateExternalAPIReq, FormSchema } from '../declarations'
+import Form from './Form'
+import ActionButton from '@/app/components/base/action-button'
+import Confirm from '@/app/components/base/confirm'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+} from '@/app/components/base/portal-to-follow-elem'
+import { createExternalAPI } from '@/service/datasets'
+import { useToastContext } from '@/app/components/base/toast'
+import Button from '@/app/components/base/button'
+import Tooltip from '@/app/components/base/tooltip'
+
+type AddExternalAPIModalProps = {
+ data?: CreateExternalAPIReq
+ onSave: (formValue: CreateExternalAPIReq) => void
+ onCancel: () => void
+ onEdit?: (formValue: CreateExternalAPIReq) => Promise<void>
+ datasetBindings?: { id: string; name: string }[]
+ isEditMode: boolean
+}
+
+const formSchemas: FormSchema[] = [
+ {
+ variable: 'name',
+ type: 'text',
+ label: {
+ en_US: 'Name',
+ },
+ required: true,
+ },
+ {
+ variable: 'endpoint',
+ type: 'text',
+ label: {
+ en_US: 'API Endpoint',
+ },
+ required: true,
+ },
+ {
+ variable: 'api_key',
+ type: 'secret',
+ label: {
+ en_US: 'API Key',
+ },
+ required: true,
+ },
+]
+
+const AddExternalAPIModal: FC<AddExternalAPIModalProps> = ({ data, onSave, onCancel, datasetBindings, isEditMode, onEdit }) => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const [loading, setLoading] = useState(false)
+ const [showConfirm, setShowConfirm] = useState(false)
+ const [formData, setFormData] = useState<CreateExternalAPIReq>({ name: '', settings: { endpoint: '', api_key: '' } })
+
+ useEffect(() => {
+ if (isEditMode && data)
+ setFormData(data)
+ }, [isEditMode, data])
+
+ const hasEmptyInputs = Object.values(formData).some(value =>
+ typeof value === 'string' ? value.trim() === '' : Object.values(value).some(v => v.trim() === ''),
+ )
+ const handleDataChange = (val: CreateExternalAPIReq) => {
+ setFormData(val)
+ }
+
+ const handleSave = async () => {
+ if (formData && formData.settings.api_key && formData.settings.api_key?.length < 5) {
+ notify({ type: 'error', message: t('common.apiBasedExtension.modal.apiKey.lengthError') })
+ setLoading(false)
+ return
+ }
+ try {
+ setLoading(true)
+ if (isEditMode && onEdit) {
+ await onEdit(
+ {
+ ...formData,
+ settings: { ...formData.settings, api_key: formData.settings.api_key ? '[__HIDDEN__]' : formData.settings.api_key },
+ },
+ )
+ notify({ type: 'success', message: 'External API updated successfully' })
+ }
+ else {
+ const res = await createExternalAPI({ body: formData })
+ if (res && res.id) {
+ notify({ type: 'success', message: 'External API saved successfully' })
+ onSave(res)
+ }
+ }
+ onCancel()
+ }
+ catch (error) {
+ console.error('Error saving/updating external API:', error)
+ notify({ type: 'error', message: 'Failed to save/update External API' })
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ return (
+ <PortalToFollowElem open>
+ <PortalToFollowElemContent className='z-[60] h-full w-full'>
+ <div className='fixed inset-0 flex items-center justify-center bg-black/[.25]'>
+ <div className='shadows-shadow-xl relative flex w-[480px] flex-col items-start rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg'>
+ <div className='flex flex-col items-start gap-2 self-stretch pb-3 pl-6 pr-14 pt-6'>
+ <div className='title-2xl-semi-bold grow self-stretch text-text-primary'>
+ {
+ isEditMode ? t('dataset.editExternalAPIFormTitle') : t('dataset.createExternalAPI')
+ }
+ </div>
+ {isEditMode && (datasetBindings?.length ?? 0) > 0 && (
+ <div className='system-xs-regular flex items-center text-text-tertiary'>
+ {t('dataset.editExternalAPIFormWarning.front')}
+ <span className='flex cursor-pointer items-center text-text-accent'>
+ {datasetBindings?.length} {t('dataset.editExternalAPIFormWarning.end')}
+ <Tooltip
+ popupClassName='flex items-center self-stretch w-[320px]'
+ popupContent={
+ <div className='p-1'>
+ <div className='flex items-start self-stretch pb-0.5 pl-2 pr-3 pt-1'>
+ <div className='system-xs-medium-uppercase text-text-tertiary'>{`${datasetBindings?.length} ${t('dataset.editExternalAPITooltipTitle')}`}</div>
+ </div>
+ {datasetBindings?.map(binding => (
+ <div key={binding.id} className='flex items-center gap-1 self-stretch px-2 py-1'>
+ <RiBook2Line className='h-4 w-4 text-text-secondary' />
+ <div className='system-sm-medium text-text-secondary'>{binding.name}</div>
+ </div>
+ ))}
+ </div>
+ }
+ asChild={false}
+ position='bottom'
+ >
+ <RiInformation2Line className='h-3.5 w-3.5' />
+ </Tooltip>
+ </span>
+ </div>
+ )}
+ </div>
+ <ActionButton className='absolute right-5 top-5' onClick={onCancel}>
+ <RiCloseLine className='h-[18px] w-[18px] shrink-0 text-text-tertiary' />
+ </ActionButton>
+ <Form
+ value={formData}
+ onChange={handleDataChange}
+ formSchemas={formSchemas}
+ className='flex flex-col items-start justify-center gap-4 self-stretch px-6 py-3'
+ />
+ <div className='flex items-center justify-end gap-2 self-stretch p-6 pt-5'>
+ <Button type='button' variant='secondary' onClick={onCancel}>
+ {t('dataset.externalAPIForm.cancel')}
+ </Button>
+ <Button
+ type='submit'
+ variant='primary'
+ onClick={() => {
+ if (isEditMode && (datasetBindings?.length ?? 0) > 0)
+ setShowConfirm(true)
+ else if (isEditMode && onEdit)
+ onEdit(formData)
+
+ else
+ handleSave()
+ }}
+ disabled={hasEmptyInputs || loading}
+ >
+ {t('dataset.externalAPIForm.save')}
+ </Button>
+ </div>
+ <div className='system-xs-regular flex items-center justify-center gap-1 self-stretch rounded-b-2xl border-t-[0.5px]
+ border-divider-subtle bg-background-soft px-2 py-3 text-text-tertiary'
+ >
+ <RiLock2Fill className='h-3 w-3 text-text-quaternary' />
+ {t('dataset.externalAPIForm.encrypted.front')}
+ <a
+ className='text-text-accent'
+ target='_blank' rel='noopener noreferrer'
+ href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
+ >
+ PKCS1_OAEP
+ </a>
+ {t('dataset.externalAPIForm.encrypted.end')}
+ </div>
+ </div>
+ {showConfirm && (datasetBindings?.length ?? 0) > 0 && (
+ <Confirm
+ isShow={showConfirm}
+ type='warning'
+ title='Warning'
+ content={`${t('dataset.editExternalAPIConfirmWarningContent.front')} ${datasetBindings?.length} ${t('dataset.editExternalAPIConfirmWarningContent.end')}`}
+ onCancel={() => setShowConfirm(false)}
+ onConfirm={handleSave}
+ />
+ )}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default memo(AddExternalAPIModal)
diff --git a/app/components/datasets/external-api/external-api-panel/index.tsx b/app/components/datasets/external-api/external-api-panel/index.tsx
new file mode 100644
index 0000000..d4af34f
--- /dev/null
+++ b/app/components/datasets/external-api/external-api-panel/index.tsx
@@ -0,0 +1,90 @@
+import React from 'react'
+import {
+ RiAddLine,
+ RiBookOpenLine,
+ RiCloseLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import ExternalKnowledgeAPICard from '../external-knowledge-api-card'
+import cn from '@/utils/classnames'
+import { useExternalKnowledgeApi } from '@/context/external-knowledge-api-context'
+import ActionButton from '@/app/components/base/action-button'
+import Button from '@/app/components/base/button'
+import Loading from '@/app/components/base/loading'
+import { useModalContext } from '@/context/modal-context'
+
+type ExternalAPIPanelProps = {
+ onClose: () => void
+}
+
+const ExternalAPIPanel: React.FC<ExternalAPIPanelProps> = ({ onClose }) => {
+ const { t } = useTranslation()
+ const { setShowExternalKnowledgeAPIModal } = useModalContext()
+ const { externalKnowledgeApiList, mutateExternalKnowledgeApis, isLoading } = useExternalKnowledgeApi()
+
+ const handleOpenExternalAPIModal = () => {
+ setShowExternalKnowledgeAPIModal({
+ payload: { name: '', settings: { endpoint: '', api_key: '' } },
+ datasetBindings: [],
+ onSaveCallback: () => {
+ mutateExternalKnowledgeApis()
+ },
+ onCancelCallback: () => {
+ mutateExternalKnowledgeApis()
+ },
+ isEditMode: false,
+ })
+ }
+
+ return (
+ <div
+ tabIndex={-1}
+ className={cn('absolute bottom-2 right-0 top-14 z-10 flex outline-none')}
+ >
+ <div
+ className={cn(
+ 'relative flex h-full w-[420px] flex-col rounded-l-2xl border border-components-panel-border bg-components-panel-bg-alt',
+ )}
+ >
+ <div className='flex items-start self-stretch p-4 pb-0'>
+ <div className='flex grow flex-col items-start gap-1'>
+ <div className='system-xl-semibold self-stretch text-text-primary'>{t('dataset.externalAPIPanelTitle')}</div>
+ <div className='body-xs-regular self-stretch text-text-tertiary'>{t('dataset.externalAPIPanelDescription')}</div>
+ <a className='flex cursor-pointer items-center justify-center gap-1 self-stretch' href='https://docs.dify.ai/guides/knowledge-base/external-knowledge-api-documentation' target='_blank'>
+ <RiBookOpenLine className='h-3 w-3 text-text-accent' />
+ <div className='body-xs-regular grow text-text-accent'>{t('dataset.externalAPIPanelDocumentation')}</div>
+ </a>
+ </div>
+ <div className='flex items-center'>
+ <ActionButton onClick={() => onClose()}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </ActionButton>
+ </div>
+ </div>
+ <div className='flex flex-col items-start justify-center gap-2 self-stretch px-4 py-3'>
+ <Button
+ variant={'primary'}
+ className='flex items-center justify-center gap-0.5 px-3 py-2'
+ onClick={handleOpenExternalAPIModal}
+ >
+ <RiAddLine className='h-4 w-4 text-components-button-primary-text' />
+ <div className='system-sm-medium text-components-button-primary-text'>{t('dataset.createExternalAPI')}</div>
+ </Button>
+ </div>
+ <div className='flex grow flex-col items-start gap-1 self-stretch px-4 py-0'>
+ {isLoading
+ ? (
+ <Loading />
+ )
+ : (
+ externalKnowledgeApiList.map(api => (
+ <ExternalKnowledgeAPICard key={api.id} api={api} />
+ ))
+ )}
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default ExternalAPIPanel
diff --git a/app/components/datasets/external-api/external-knowledge-api-card/index.tsx b/app/components/datasets/external-api/external-knowledge-api-card/index.tsx
new file mode 100644
index 0000000..bb50631
--- /dev/null
+++ b/app/components/datasets/external-api/external-knowledge-api-card/index.tsx
@@ -0,0 +1,151 @@
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiDeleteBinLine,
+ RiEditLine,
+} from '@remixicon/react'
+import type { CreateExternalAPIReq } from '../declarations'
+import type { ExternalAPIItem } from '@/models/datasets'
+import { checkUsageExternalAPI, deleteExternalAPI, fetchExternalAPI, updateExternalAPI } from '@/service/datasets'
+import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
+import { useExternalKnowledgeApi } from '@/context/external-knowledge-api-context'
+import { useModalContext } from '@/context/modal-context'
+import ActionButton from '@/app/components/base/action-button'
+import Confirm from '@/app/components/base/confirm'
+
+type ExternalKnowledgeAPICardProps = {
+ api: ExternalAPIItem
+}
+
+const ExternalKnowledgeAPICard: React.FC<ExternalKnowledgeAPICardProps> = ({ api }) => {
+ const { setShowExternalKnowledgeAPIModal } = useModalContext()
+ const [showConfirm, setShowConfirm] = useState(false)
+ const [isHovered, setIsHovered] = useState(false)
+ const [usageCount, setUsageCount] = useState(0)
+ const { mutateExternalKnowledgeApis } = useExternalKnowledgeApi()
+
+ const { t } = useTranslation()
+
+ const handleEditClick = async () => {
+ try {
+ const response = await fetchExternalAPI({ apiTemplateId: api.id })
+ const formValue: CreateExternalAPIReq = {
+ name: response.name,
+ settings: {
+ endpoint: response.settings.endpoint,
+ api_key: response.settings.api_key,
+ },
+ }
+
+ setShowExternalKnowledgeAPIModal({
+ payload: formValue,
+ onSaveCallback: () => {
+ mutateExternalKnowledgeApis()
+ },
+ onCancelCallback: () => {
+ mutateExternalKnowledgeApis()
+ },
+ isEditMode: true,
+ datasetBindings: response.dataset_bindings,
+ onEditCallback: async (updatedData: CreateExternalAPIReq) => {
+ try {
+ await updateExternalAPI({
+ apiTemplateId: api.id,
+ body: {
+ ...response,
+ name: updatedData.name,
+ settings: {
+ ...response.settings,
+ endpoint: updatedData.settings.endpoint,
+ api_key: updatedData.settings.api_key,
+ },
+ },
+ })
+ mutateExternalKnowledgeApis()
+ }
+ catch (error) {
+ console.error('Error updating external knowledge API:', error)
+ }
+ },
+ })
+ }
+ catch (error) {
+ console.error('Error fetching external knowledge API data:', error)
+ }
+ }
+
+ const handleDeleteClick = async () => {
+ try {
+ const usage = await checkUsageExternalAPI({ apiTemplateId: api.id })
+ if (usage.is_using)
+ setUsageCount(usage.count)
+
+ setShowConfirm(true)
+ }
+ catch (error) {
+ console.error('Error checking external API usage:', error)
+ }
+ }
+
+ const handleConfirmDelete = async () => {
+ try {
+ const response = await deleteExternalAPI({ apiTemplateId: api.id })
+ if (response && response.result === 'success') {
+ setShowConfirm(false)
+ mutateExternalKnowledgeApis()
+ }
+ else {
+ console.error('Failed to delete external API')
+ }
+ }
+ catch (error) {
+ console.error('Error deleting external knowledge API:', error)
+ }
+ }
+
+ return (
+ <>
+ <div className={`shadows-shadow-xs flex items-start self-stretch rounded-lg border-[0.5px] border-components-panel-border-subtle
+ bg-components-panel-on-panel-item-bg p-2
+ pl-3 ${isHovered ? 'border-state-destructive-border bg-state-destructive-hover' : ''}`}
+ >
+ <div className='flex grow flex-col items-start justify-center gap-1.5 py-1'>
+ <div className='flex items-center gap-1 self-stretch text-text-secondary'>
+ <ApiConnectionMod className='h-4 w-4' />
+ <div className='system-sm-medium'>{api.name}</div>
+ </div>
+ <div className='system-xs-regular self-stretch text-text-tertiary'>{api.settings.endpoint}</div>
+ </div>
+ <div className='flex items-start gap-1'>
+ <ActionButton onClick={handleEditClick}>
+ <RiEditLine className='h-4 w-4 text-text-tertiary hover:text-text-secondary' />
+ </ActionButton>
+ <ActionButton
+ className='hover:bg-state-destructive-hover'
+ onClick={handleDeleteClick}
+ onMouseEnter={() => setIsHovered(true)}
+ onMouseLeave={() => setIsHovered(false)}
+ >
+ <RiDeleteBinLine className='h-4 w-4 text-text-tertiary hover:text-text-destructive' />
+ </ActionButton>
+ </div>
+ </div>
+ {showConfirm && (
+ <Confirm
+ isShow={showConfirm}
+ title={`${t('dataset.deleteExternalAPIConfirmWarningContent.title.front')} ${api.name}${t('dataset.deleteExternalAPIConfirmWarningContent.title.end')}`}
+ content={
+ usageCount > 0
+ ? `${t('dataset.deleteExternalAPIConfirmWarningContent.content.front')} ${usageCount} ${t('dataset.deleteExternalAPIConfirmWarningContent.content.end')}`
+ : t('dataset.deleteExternalAPIConfirmWarningContent.noConnectionContent')
+ }
+ type='warning'
+ onConfirm={handleConfirmDelete}
+ onCancel={() => setShowConfirm(false)}
+ />
+ )}
+ </>
+ )
+}
+
+export default ExternalKnowledgeAPICard
diff --git a/app/components/datasets/external-knowledge-base/connector/index.tsx b/app/components/datasets/external-knowledge-base/connector/index.tsx
new file mode 100644
index 0000000..33f57d0
--- /dev/null
+++ b/app/components/datasets/external-knowledge-base/connector/index.tsx
@@ -0,0 +1,36 @@
+'use client'
+
+import React, { useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { useToastContext } from '@/app/components/base/toast'
+import ExternalKnowledgeBaseCreate from '@/app/components/datasets/external-knowledge-base/create'
+import type { CreateKnowledgeBaseReq } from '@/app/components/datasets/external-knowledge-base/create/declarations'
+import { createExternalKnowledgeBase } from '@/service/datasets'
+
+const ExternalKnowledgeBaseConnector = () => {
+ const { notify } = useToastContext()
+ const [loading, setLoading] = useState(false)
+ const router = useRouter()
+
+ const handleConnect = async (formValue: CreateKnowledgeBaseReq) => {
+ try {
+ setLoading(true)
+ const result = await createExternalKnowledgeBase({ body: formValue })
+ if (result && result.id) {
+ notify({ type: 'success', message: 'External Knowledge Base Connected Successfully' })
+ router.back()
+ }
+ else { throw new Error('Failed to create external knowledge base') }
+ }
+ catch (error) {
+ console.error('Error creating external knowledge base:', error)
+ notify({ type: 'error', message: 'Failed to connect External Knowledge Base' })
+ }
+ setLoading(false)
+ }
+ return (
+ <ExternalKnowledgeBaseCreate onConnect={handleConnect} loading={loading} />
+ )
+}
+
+export default ExternalKnowledgeBaseConnector
diff --git a/app/components/datasets/external-knowledge-base/create/ExternalApiSelect.tsx b/app/components/datasets/external-knowledge-base/create/ExternalApiSelect.tsx
new file mode 100644
index 0000000..d459061
--- /dev/null
+++ b/app/components/datasets/external-knowledge-base/create/ExternalApiSelect.tsx
@@ -0,0 +1,110 @@
+import React, { useEffect, useState } from 'react'
+import {
+ RiAddLine,
+ RiArrowDownSLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { useRouter } from 'next/navigation'
+import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
+import { useModalContext } from '@/context/modal-context'
+import { useExternalKnowledgeApi } from '@/context/external-knowledge-api-context'
+
+type ApiItem = {
+ value: string
+ name: string
+ url: string
+}
+
+type ExternalApiSelectProps = {
+ items: ApiItem[]
+ value?: string
+ onSelect: (item: ApiItem) => void
+}
+
+const ExternalApiSelect: React.FC<ExternalApiSelectProps> = ({ items, value, onSelect }) => {
+ const { t } = useTranslation()
+ const [isOpen, setIsOpen] = useState(false)
+ const [selectedItem, setSelectedItem] = useState<ApiItem | null>(
+ items.find(item => item.value === value) || null,
+ )
+ const { setShowExternalKnowledgeAPIModal } = useModalContext()
+ const { mutateExternalKnowledgeApis } = useExternalKnowledgeApi()
+ const router = useRouter()
+
+ useEffect(() => {
+ const newSelectedItem = items.find(item => item.value === value) || null
+ setSelectedItem(newSelectedItem)
+ }, [value, items])
+
+ const handleAddNewAPI = () => {
+ setShowExternalKnowledgeAPIModal({
+ payload: { name: '', settings: { endpoint: '', api_key: '' } },
+ onSaveCallback: async () => {
+ mutateExternalKnowledgeApis()
+ router.refresh()
+ },
+ onCancelCallback: () => {
+ mutateExternalKnowledgeApis()
+ },
+ isEditMode: false,
+ })
+ }
+
+ const handleSelect = (item: ApiItem) => {
+ setSelectedItem(item)
+ onSelect(item)
+ setIsOpen(false)
+ }
+
+ return (
+ <div className="relative w-full">
+ <div
+ className={`flex cursor-pointer items-center justify-between gap-0.5 self-stretch rounded-lg bg-components-input-bg-normal px-2
+ py-1 hover:bg-state-base-hover-alt ${isOpen && 'bg-state-base-hover-alt'}`}
+ onClick={() => setIsOpen(!isOpen)}
+ >
+ {selectedItem
+ ? (
+ <div className="flex items-center gap-2 self-stretch rounded-lg p-1">
+ <ApiConnectionMod className='h-4 w-4 text-text-secondary' />
+ <div className='flex grow items-center'>
+ <span className='system-sm-regular overflow-hidden text-ellipsis text-components-input-text-filled'>{selectedItem.name}</span>
+ </div>
+ </div>
+ )
+ : (
+ <span className='system-sm-regular text-components-input-text-placeholder'>{t('dataset.selectExternalKnowledgeAPI.placeholder')}</span>
+ )}
+ <RiArrowDownSLine className={`h-4 w-4 text-text-quaternary transition-transform ${isOpen ? 'text-text-secondary' : ''}`} />
+ </div>
+ {isOpen && (
+ <div className="absolute z-10 mt-1 w-full rounded-xl border bg-components-panel-bg-blur shadow-lg">
+ {items.map(item => (
+ <div
+ key={item.value}
+ className="flex cursor-pointer items-center p-1"
+ onClick={() => handleSelect(item)}
+ >
+ <div className="flex w-full items-center gap-2 self-stretch rounded-lg p-2 hover:bg-state-base-hover">
+ <ApiConnectionMod className='h-4 w-4 text-text-secondary' />
+ <span className='system-sm-medium grow overflow-hidden text-ellipsis text-text-secondary'>{item.name}</span>
+ <span className='system-xs-regular overflow-hidden text-ellipsis text-right text-text-tertiary'>{item.url}</span>
+ </div>
+ </div>
+ ))}
+ <div className='flex flex-col items-start self-stretch p-1'>
+ <div
+ className='flex cursor-pointer items-center gap-2 self-stretch rounded-lg p-2 hover:bg-state-base-hover'
+ onClick={handleAddNewAPI}
+ >
+ <RiAddLine className='h-4 w-4 text-text-secondary' />
+ <span className='system-sm-medium grow overflow-hidden text-ellipsis text-text-secondary'>{t('dataset.createNewExternalAPI')}</span>
+ </div>
+ </div>
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default ExternalApiSelect
diff --git a/app/components/datasets/external-knowledge-base/create/ExternalApiSelection.tsx b/app/components/datasets/external-knowledge-base/create/ExternalApiSelection.tsx
new file mode 100644
index 0000000..d70f612
--- /dev/null
+++ b/app/components/datasets/external-knowledge-base/create/ExternalApiSelection.tsx
@@ -0,0 +1,96 @@
+'use client'
+
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiAddLine } from '@remixicon/react'
+import { useRouter } from 'next/navigation'
+import ExternalApiSelect from './ExternalApiSelect'
+import Input from '@/app/components/base/input'
+import Button from '@/app/components/base/button'
+import { useModalContext } from '@/context/modal-context'
+import { useExternalKnowledgeApi } from '@/context/external-knowledge-api-context'
+
+type ExternalApiSelectionProps = {
+ external_knowledge_api_id: string
+ external_knowledge_id: string
+ onChange: (data: { external_knowledge_api_id?: string; external_knowledge_id?: string }) => void
+}
+
+const ExternalApiSelection: React.FC<ExternalApiSelectionProps> = ({ external_knowledge_api_id, external_knowledge_id, onChange }) => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const { externalKnowledgeApiList } = useExternalKnowledgeApi()
+ const [selectedApiId, setSelectedApiId] = useState(external_knowledge_api_id)
+ const { setShowExternalKnowledgeAPIModal } = useModalContext()
+ const { mutateExternalKnowledgeApis } = useExternalKnowledgeApi()
+
+ const apiItems = externalKnowledgeApiList.map(api => ({
+ value: api.id,
+ name: api.name,
+ url: api.settings.endpoint,
+ }))
+
+ useEffect(() => {
+ if (apiItems.length > 0) {
+ const newSelectedId = external_knowledge_api_id || apiItems[0].value
+ setSelectedApiId(newSelectedId)
+ if (newSelectedId !== external_knowledge_api_id)
+ onChange({ external_knowledge_api_id: newSelectedId, external_knowledge_id })
+ }
+ }, [apiItems, external_knowledge_api_id, external_knowledge_id, onChange])
+
+ const handleAddNewAPI = () => {
+ setShowExternalKnowledgeAPIModal({
+ payload: { name: '', settings: { endpoint: '', api_key: '' } },
+ onSaveCallback: async () => {
+ mutateExternalKnowledgeApis()
+ router.refresh()
+ },
+ onCancelCallback: () => {
+ mutateExternalKnowledgeApis()
+ },
+ isEditMode: false,
+ })
+ }
+
+ useEffect(() => {
+ if (!external_knowledge_api_id && apiItems.length > 0)
+ onChange({ external_knowledge_api_id: apiItems[0].value, external_knowledge_id })
+ }, [])
+
+ return (
+ <form className='flex flex-col gap-4 self-stretch'>
+ <div className='flex flex-col gap-1 self-stretch'>
+ <div className='flex flex-col self-stretch'>
+ <label className='system-sm-semibold text-text-secondary'>{t('dataset.externalAPIPanelTitle')}</label>
+ </div>
+ {apiItems.length > 0
+ ? <ExternalApiSelect
+ items={apiItems}
+ value={selectedApiId}
+ onSelect={(e) => {
+ setSelectedApiId(e.value)
+ onChange({ external_knowledge_api_id: e.value, external_knowledge_id })
+ }}
+ />
+ : <Button variant={'tertiary'} onClick={handleAddNewAPI} className='justify-start gap-0.5'>
+ <RiAddLine className='h-4 w-4 text-text-tertiary' />
+ <span className='system-sm-regular text-text-tertiary'>{t('dataset.noExternalKnowledge')}</span>
+ </Button>
+ }
+ </div>
+ <div className='flex flex-col gap-1 self-stretch'>
+ <div className='flex flex-col self-stretch'>
+ <label className='system-sm-semibold text-text-secondary'>{t('dataset.externalKnowledgeId')}</label>
+ </div>
+ <Input
+ value={external_knowledge_id}
+ onChange={e => onChange({ external_knowledge_id: e.target.value, external_knowledge_api_id })}
+ placeholder={t('dataset.externalKnowledgeIdPlaceholder') ?? ''}
+ />
+ </div>
+ </form>
+ )
+}
+
+export default ExternalApiSelection
diff --git a/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx b/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx
new file mode 100644
index 0000000..5c3c126
--- /dev/null
+++ b/app/components/datasets/external-knowledge-base/create/InfoPanel.tsx
@@ -0,0 +1,33 @@
+import { RiBookOpenLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+
+const InfoPanel = () => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex w-[360px] flex-col items-start pb-2 pr-8 pt-[108px]'>
+ <div className='flex w-full min-w-[240px] flex-col items-start gap-3 self-stretch rounded-xl bg-background-section p-6'>
+ <div className='flex h-10 w-10 grow items-center justify-center gap-2 self-stretch rounded-lg border-[0.5px] border-components-card-border bg-components-card-bg p-1'>
+ <RiBookOpenLine className='h-5 w-5 text-text-accent' />
+ </div>
+ <p className='flex flex-col items-start gap-2 self-stretch'>
+ <span className='system-xl-semibold self-stretch text-text-secondary'>
+ {t('dataset.connectDatasetIntro.title')}
+ </span>
+ <span className='system-sm-regular text-text-tertiary'>
+ {t('dataset.connectDatasetIntro.content.front')}
+ <a className='system-sm-regular ml-1 text-text-accent' href='https://docs.dify.ai/en/guides/knowledge-base/external-knowledge-api' target='_blank' rel="noopener noreferrer">
+ {t('dataset.connectDatasetIntro.content.link')}
+ </a>
+ {t('dataset.connectDatasetIntro.content.end')}
+ </span>
+ <a className='system-sm-regular self-stretch text-text-accent' href='https://docs.dify.ai/en/guides/knowledge-base/connect-external-knowledge-base' target='_blank' rel="noopener noreferrer">
+ {t('dataset.connectDatasetIntro.learnMore')}
+ </a>
+ </p>
+ </div>
+ </div>
+ )
+}
+
+export default InfoPanel
diff --git a/app/components/datasets/external-knowledge-base/create/KnowledgeBaseInfo.tsx b/app/components/datasets/external-knowledge-base/create/KnowledgeBaseInfo.tsx
new file mode 100644
index 0000000..4261208
--- /dev/null
+++ b/app/components/datasets/external-knowledge-base/create/KnowledgeBaseInfo.tsx
@@ -0,0 +1,53 @@
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Input from '@/app/components/base/input'
+
+type KnowledgeBaseInfoProps = {
+ name: string
+ description?: string
+ onChange: (data: { name?: string; description?: string }) => void
+}
+
+const KnowledgeBaseInfo: React.FC<KnowledgeBaseInfoProps> = ({ name, description, onChange }) => {
+ const { t } = useTranslation()
+
+ const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ onChange({ name: e.target.value })
+ }
+
+ const handleDescriptionChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
+ onChange({ description: e.target.value })
+ }
+
+ return (
+ <form className='flex flex-col gap-4 self-stretch'>
+ <div className='flex flex-col gap-4 self-stretch'>
+ <div className='flex flex-col gap-1 self-stretch'>
+ <div className='flex flex-col justify-center self-stretch'>
+ <label className='system-sm-semibold text-text-secondary'>{t('dataset.externalKnowledgeName')}</label>
+ </div>
+ <Input
+ value={name}
+ onChange={handleNameChange}
+ placeholder={t('dataset.externalKnowledgeNamePlaceholder') ?? ''}
+ />
+ </div>
+ <div className='flex flex-col gap-1 self-stretch'>
+ <div className='flex flex-col justify-center self-stretch'>
+ <label className='system-sm-semibold text-text-secondary'>{t('dataset.externalKnowledgeDescription')}</label>
+ </div>
+ <div className='flex flex-col gap-1 self-stretch'>
+ <textarea
+ value={description}
+ onChange={ e => handleDescriptionChange(e)}
+ placeholder={t('dataset.externalKnowledgeDescriptionPlaceholder') ?? ''}
+ className={`flex h-20 items-start self-stretch rounded-lg bg-components-input-bg-normal p-3 py-2 ${description ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder'} system-sm-regular`}
+ />
+ </div>
+ </div>
+ </div>
+ </form>
+ )
+}
+
+export default KnowledgeBaseInfo
diff --git a/app/components/datasets/external-knowledge-base/create/RetrievalSettings.tsx b/app/components/datasets/external-knowledge-base/create/RetrievalSettings.tsx
new file mode 100644
index 0000000..1c43d7e
--- /dev/null
+++ b/app/components/datasets/external-knowledge-base/create/RetrievalSettings.tsx
@@ -0,0 +1,67 @@
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import TopKItem from '@/app/components/base/param-item/top-k-item'
+import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item'
+import cn from '@/utils/classnames'
+
+type RetrievalSettingsProps = {
+ topK: number
+ scoreThreshold: number
+ scoreThresholdEnabled: boolean
+ isInHitTesting?: boolean
+ isInRetrievalSetting?: boolean
+ onChange: (data: { top_k?: number; score_threshold?: number; score_threshold_enabled?: boolean }) => void
+}
+
+const RetrievalSettings: FC<RetrievalSettingsProps> = ({
+ topK,
+ scoreThreshold,
+ scoreThresholdEnabled,
+ onChange,
+ isInHitTesting = false,
+ isInRetrievalSetting = false,
+}) => {
+ const { t } = useTranslation()
+
+ const handleScoreThresholdChange = (enabled: boolean) => {
+ onChange({ score_threshold_enabled: enabled })
+ }
+
+ return (
+ <div className={cn('flex flex-col gap-2 self-stretch', isInRetrievalSetting && 'w-full max-w-[480px]')}>
+ {!isInHitTesting && !isInRetrievalSetting && <div className='flex h-7 flex-col gap-2 self-stretch pt-1'>
+ <label className='system-sm-semibold text-text-secondary'>{t('dataset.retrievalSettings')}</label>
+ </div>}
+ <div className={cn(
+ 'flex gap-4 self-stretch',
+ {
+ 'flex-col': isInHitTesting,
+ 'flex-row': isInRetrievalSetting,
+ 'flex-col sm:flex-row': !isInHitTesting && !isInRetrievalSetting,
+ },
+ )}>
+ <div className='flex grow flex-col gap-1'>
+ <TopKItem
+ className='grow'
+ value={topK}
+ onChange={(_key, v) => onChange({ top_k: v })}
+ enable={true}
+ />
+ </div>
+ <div className='flex grow flex-col gap-1'>
+ <ScoreThresholdItem
+ className='grow'
+ value={scoreThreshold}
+ onChange={(_key, v) => onChange({ score_threshold: v })}
+ enable={scoreThresholdEnabled}
+ hasSwitch={true}
+ onSwitchChange={(_key, v) => handleScoreThresholdChange(v)}
+ />
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default RetrievalSettings
diff --git a/app/components/datasets/external-knowledge-base/create/declarations.ts b/app/components/datasets/external-knowledge-base/create/declarations.ts
new file mode 100644
index 0000000..271caf3
--- /dev/null
+++ b/app/components/datasets/external-knowledge-base/create/declarations.ts
@@ -0,0 +1,12 @@
+export type CreateKnowledgeBaseReq = {
+ name: string
+ description?: string
+ external_knowledge_api_id: string
+ provider: 'external'
+ external_knowledge_id: string
+ external_retrieval_model: {
+ top_k: number
+ score_threshold: number
+ score_threshold_enabled: boolean
+ }
+}
diff --git a/app/components/datasets/external-knowledge-base/create/index.tsx b/app/components/datasets/external-knowledge-base/create/index.tsx
new file mode 100644
index 0000000..5fbddea
--- /dev/null
+++ b/app/components/datasets/external-knowledge-base/create/index.tsx
@@ -0,0 +1,128 @@
+'use client'
+
+import { useCallback, useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { RiArrowLeftLine, RiArrowRightLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import KnowledgeBaseInfo from './KnowledgeBaseInfo'
+import ExternalApiSelection from './ExternalApiSelection'
+import RetrievalSettings from './RetrievalSettings'
+import InfoPanel from './InfoPanel'
+import type { CreateKnowledgeBaseReq } from './declarations'
+import Divider from '@/app/components/base/divider'
+import Button from '@/app/components/base/button'
+
+type ExternalKnowledgeBaseCreateProps = {
+ onConnect: (formValue: CreateKnowledgeBaseReq) => void
+ loading: boolean
+}
+
+const ExternalKnowledgeBaseCreate: React.FC<ExternalKnowledgeBaseCreateProps> = ({ onConnect, loading }) => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const [formData, setFormData] = useState<CreateKnowledgeBaseReq>({
+ name: '',
+ description: '',
+ external_knowledge_api_id: '',
+ external_knowledge_id: '',
+ external_retrieval_model: {
+ top_k: 2,
+ score_threshold: 0.5,
+ score_threshold_enabled: false,
+ },
+ provider: 'external',
+
+ })
+
+ const navBackHandle = useCallback(() => {
+ router.replace('/datasets')
+ }, [router])
+
+ const handleFormChange = (newData: CreateKnowledgeBaseReq) => {
+ setFormData(newData)
+ }
+
+ const isFormValid = formData.name.trim() !== ''
+ && formData.external_knowledge_api_id !== ''
+ && formData.external_knowledge_id !== ''
+ && formData.external_retrieval_model.top_k !== undefined
+ && formData.external_retrieval_model.score_threshold !== undefined
+
+ return (
+ <div className='flex grow flex-col self-stretch rounded-t-2xl border-t border-effects-highlight bg-components-panel-bg'>
+ <div className='flex grow justify-center self-stretch'>
+ <div className='flex w-full max-w-[960px] flex-col items-center px-14 py-0'>
+ <div className='flex w-full max-w-[640px] grow flex-col items-center gap-4 pb-8 pt-6'>
+ <div className='relative flex flex-col items-center gap-[2px] self-stretch py-2'>
+ <div className='system-xl-semibold grow self-stretch text-text-primary'>{t('dataset.connectDataset')}</div>
+ <p className='system-sm-regular text-text-tertiary'>
+ <span>{t('dataset.connectHelper.helper1')}</span>
+ <span className='system-sm-medium text-text-secondary'>{t('dataset.connectHelper.helper2')}</span>
+ <span>{t('dataset.connectHelper.helper3')}</span>
+ <a className='system-sm-regular self-stretch text-text-accent' href='https://docs.dify.ai/en/guides/knowledge-base/connect-external-knowledge-base' target='_blank' rel="noopener noreferrer">
+ {t('dataset.connectHelper.helper4')}
+ </a>
+ <span>{t('dataset.connectHelper.helper5')} </span>
+ </p>
+ <Button
+ className='absolute left-[-44px] top-1 flex h-8 w-8 items-center justify-center rounded-full p-2'
+ variant='tertiary'
+ onClick={navBackHandle}
+ >
+ <RiArrowLeftLine className='h-4 w-4 text-text-tertiary' />
+ </Button>
+ </div>
+ <KnowledgeBaseInfo
+ name={formData.name}
+ description={formData.description ?? ''}
+ onChange={data => handleFormChange({
+ ...formData,
+ ...data,
+ })}
+ />
+ <Divider />
+ <ExternalApiSelection
+ external_knowledge_api_id={formData.external_knowledge_api_id}
+ external_knowledge_id={formData.external_knowledge_id}
+ onChange={data => handleFormChange({
+ ...formData,
+ ...data,
+ })}
+ />
+ <RetrievalSettings
+ topK={formData.external_retrieval_model.top_k}
+ scoreThreshold={formData.external_retrieval_model.score_threshold}
+ scoreThresholdEnabled={formData.external_retrieval_model.score_threshold_enabled}
+ onChange={data => handleFormChange({
+ ...formData,
+ external_retrieval_model: {
+ ...formData.external_retrieval_model,
+ ...data,
+ },
+ })}
+ />
+ <div className='flex items-center justify-end gap-2 self-stretch py-2'>
+ <Button variant='secondary' onClick={navBackHandle}>
+ <div className='system-sm-medium text-components-button-secondary-text'>{t('dataset.externalKnowledgeForm.cancel')}</div>
+ </Button>
+ <Button
+ variant='primary'
+ onClick={() => {
+ onConnect(formData)
+ }}
+ disabled={!isFormValid}
+ loading={loading}
+ >
+ <div className='system-sm-medium text-components-button-primary-text'>{t('dataset.externalKnowledgeForm.connect')}</div>
+ <RiArrowRightLine className='h-4 w-4 text-components-button-primary-text' />
+ </Button>
+ </div>
+ </div>
+ </div>
+ <InfoPanel />
+ </div>
+ </div>
+ )
+}
+
+export default ExternalKnowledgeBaseCreate
diff --git a/app/components/datasets/formatted-text/flavours/edit-slice.tsx b/app/components/datasets/formatted-text/flavours/edit-slice.tsx
new file mode 100644
index 0000000..44bd170
--- /dev/null
+++ b/app/components/datasets/formatted-text/flavours/edit-slice.tsx
@@ -0,0 +1,115 @@
+import { useState } from 'react'
+import type { FC, ReactNode } from 'react'
+import { FloatingFocusManager, type OffsetOptions, autoUpdate, flip, offset, shift, useDismiss, useFloating, useHover, useInteractions, useRole } from '@floating-ui/react'
+import { RiDeleteBinLine } from '@remixicon/react'
+// @ts-expect-error no types available
+import lineClamp from 'line-clamp'
+import type { SliceProps } from './type'
+import { SliceContainer, SliceContent, SliceDivider, SliceLabel } from './shared'
+import classNames from '@/utils/classnames'
+import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
+
+type EditSliceProps = SliceProps<{
+ label: ReactNode
+ onDelete: () => void
+ labelClassName?: string
+ labelInnerClassName?: string
+ contentClassName?: string
+ showDivider?: boolean
+ offsetOptions?: OffsetOptions
+}>
+
+export const EditSlice: FC<EditSliceProps> = (props) => {
+ const {
+ label,
+ className,
+ text,
+ onDelete,
+ labelClassName,
+ labelInnerClassName,
+ contentClassName,
+ showDivider = true,
+ offsetOptions,
+ ...rest
+ } = props
+ const [delBtnShow, setDelBtnShow] = useState(false)
+ const [isDelBtnHover, setDelBtnHover] = useState(false)
+
+ const { refs, floatingStyles, context } = useFloating({
+ open: delBtnShow,
+ onOpenChange: setDelBtnShow,
+ placement: 'right-start',
+ whileElementsMounted: autoUpdate,
+ middleware: [
+ flip(),
+ shift(),
+ offset(offsetOptions),
+ ],
+ })
+ const hover = useHover(context, {})
+ const dismiss = useDismiss(context)
+ const role = useRole(context)
+ const { getReferenceProps, getFloatingProps } = useInteractions([hover, dismiss, role])
+
+ const isDestructive = delBtnShow && isDelBtnHover
+
+ return (
+ <>
+ <SliceContainer {...rest}
+ className={classNames('block mr-0', className)}
+ ref={(ref) => {
+ refs.setReference(ref)
+ if (ref)
+ lineClamp(ref, 4)
+ }}
+ {...getReferenceProps()}
+ >
+ <SliceLabel
+ className={classNames(
+ isDestructive && '!bg-state-destructive-solid !text-text-primary-on-surface',
+ labelClassName,
+ )}
+ labelInnerClassName={labelInnerClassName}
+ >
+ {label}
+ </SliceLabel>
+ <SliceContent
+ className={classNames(
+ isDestructive && '!bg-state-destructive-hover-alt',
+ contentClassName,
+ )}
+ >
+ {text}
+ </SliceContent>
+ {showDivider && <SliceDivider
+ className={classNames(
+ isDestructive && '!bg-state-destructive-hover-alt',
+ )}
+ />}
+ {delBtnShow && <FloatingFocusManager
+ context={context}
+ >
+ <span
+ ref={refs.setFloating}
+ style={floatingStyles}
+ {...getFloatingProps()}
+ className='inline-flex items-center justify-center rounded-lg bg-components-actionbar-bg p-1 shadow'
+ onMouseEnter={() => setDelBtnHover(true)}
+ onMouseLeave={() => setDelBtnHover(false)}
+ >
+ <ActionButton
+ onClick={(e) => {
+ e.stopPropagation()
+ onDelete()
+ setDelBtnShow(false)
+ }}
+ state={ActionButtonState.Destructive}
+ >
+ <RiDeleteBinLine className='h-4 w-4' />
+ </ActionButton>
+ </span>
+ </FloatingFocusManager>}
+ </SliceContainer>
+ </>
+ )
+}
diff --git a/app/components/datasets/formatted-text/flavours/preview-slice.tsx b/app/components/datasets/formatted-text/flavours/preview-slice.tsx
new file mode 100644
index 0000000..d3fa1f4
--- /dev/null
+++ b/app/components/datasets/formatted-text/flavours/preview-slice.tsx
@@ -0,0 +1,56 @@
+import { useState } from 'react'
+import type { FC, ReactNode } from 'react'
+import { autoUpdate, flip, inline, shift, useDismiss, useFloating, useHover, useInteractions, useRole } from '@floating-ui/react'
+import type { SliceProps } from './type'
+import { SliceContainer, SliceContent, SliceDivider, SliceLabel } from './shared'
+
+type PreviewSliceProps = SliceProps<{
+ label: ReactNode
+ tooltip: ReactNode
+ labelInnerClassName?: string
+ dividerClassName?: string
+}>
+
+export const PreviewSlice: FC<PreviewSliceProps> = (props) => {
+ const { label, className, text, tooltip, labelInnerClassName, dividerClassName, ...rest } = props
+ const [tooltipOpen, setTooltipOpen] = useState(false)
+ const { refs, floatingStyles, context } = useFloating({
+ open: tooltipOpen,
+ onOpenChange: setTooltipOpen,
+ whileElementsMounted: autoUpdate,
+ placement: 'top',
+ middleware: [
+ inline(),
+ flip(),
+ shift(),
+ ],
+ })
+ const hover = useHover(context, {
+ delay: { open: 500 },
+ move: true,
+ })
+ const dismiss = useDismiss(context)
+ const role = useRole(context, { role: 'tooltip' })
+ const { getReferenceProps, getFloatingProps } = useInteractions([hover, dismiss, role])
+ return (
+ <>
+ <SliceContainer {...rest}
+ className={className}
+ ref={refs.setReference}
+ {...getReferenceProps()}
+ >
+ <SliceLabel labelInnerClassName={labelInnerClassName}>{label}</SliceLabel>
+ <SliceContent>{text}</SliceContent>
+ <SliceDivider className={dividerClassName} />
+ </SliceContainer>
+ {tooltipOpen && <span
+ ref={refs.setFloating}
+ style={floatingStyles}
+ {...getFloatingProps()}
+ className='rounded-md border-[0.5px] border-components-panel-border bg-components-tooltip-bg p-2 text-xs leading-4 text-text-secondary shadow shadow-shadow-shadow-5 backdrop-blur-[5px]'
+ >
+ {tooltip}
+ </span>}
+ </>
+ )
+}
diff --git a/app/components/datasets/formatted-text/flavours/shared.tsx b/app/components/datasets/formatted-text/flavours/shared.tsx
new file mode 100644
index 0000000..1154857
--- /dev/null
+++ b/app/components/datasets/formatted-text/flavours/shared.tsx
@@ -0,0 +1,80 @@
+import type { ComponentProps, FC } from 'react'
+import classNames from '@/utils/classnames'
+
+const baseStyle = 'py-[3px]'
+
+export type SliceContainerProps = ComponentProps<'span'>
+
+export const SliceContainer: FC<SliceContainerProps> = (
+ {
+ ref,
+ ...props
+ },
+) => {
+ const { className, ...rest } = props
+ return <span {...rest} ref={ref} className={classNames(
+ 'group align-bottom mr-1 select-none text-sm',
+ className,
+ )} />
+}
+SliceContainer.displayName = 'SliceContainer'
+
+export type SliceLabelProps = ComponentProps<'span'> & { labelInnerClassName?: string }
+
+export const SliceLabel: FC<SliceLabelProps> = (
+ {
+ ref,
+ ...props
+ },
+) => {
+ const { className, children, labelInnerClassName, ...rest } = props
+ return <span {...rest} ref={ref} className={classNames(
+ baseStyle,
+ 'px-1 bg-state-base-hover-alt group-hover:bg-state-accent-solid group-hover:text-text-primary-on-surface uppercase text-text-tertiary',
+ className,
+ )}>
+ <span className={classNames('text-nowrap', labelInnerClassName)}>
+ {children}
+ </span>
+ </span>
+}
+SliceLabel.displayName = 'SliceLabel'
+
+export type SliceContentProps = ComponentProps<'span'>
+
+export const SliceContent: FC<SliceContentProps> = (
+ {
+ ref,
+ ...props
+ },
+) => {
+ const { className, children, ...rest } = props
+ return <span {...rest} ref={ref} className={classNames(
+ baseStyle,
+ 'px-1 bg-state-base-hover group-hover:bg-state-accent-hover-alt group-hover:text-text-primary leading-7 whitespace-pre-line break-all',
+ className,
+ )}>
+ {children}
+ </span>
+}
+SliceContent.displayName = 'SliceContent'
+
+export type SliceDividerProps = ComponentProps<'span'>
+
+export const SliceDivider: FC<SliceDividerProps> = (
+ {
+ ref,
+ ...props
+ },
+) => {
+ const { className, ...rest } = props
+ return <span {...rest} ref={ref} className={classNames(
+ baseStyle,
+ 'bg-state-base-active group-hover:bg-state-accent-solid text-sm px-[1px]',
+ className,
+ )}>
+ {/* use a zero-width space to make the hover area bigger */}
+ ​
+ </span>
+}
+SliceDivider.displayName = 'SliceDivider'
diff --git a/app/components/datasets/formatted-text/flavours/type.ts b/app/components/datasets/formatted-text/flavours/type.ts
new file mode 100644
index 0000000..8d2fb43
--- /dev/null
+++ b/app/components/datasets/formatted-text/flavours/type.ts
@@ -0,0 +1,5 @@
+import type { ComponentProps } from 'react'
+
+export type SliceProps<T = {}> = T & {
+ text: string
+} & ComponentProps<'span'>
diff --git a/app/components/datasets/formatted-text/formatted.tsx b/app/components/datasets/formatted-text/formatted.tsx
new file mode 100644
index 0000000..14d339e
--- /dev/null
+++ b/app/components/datasets/formatted-text/formatted.tsx
@@ -0,0 +1,12 @@
+import type { ComponentProps, FC } from 'react'
+import classNames from '@/utils/classnames'
+
+export type FormattedTextProps = ComponentProps<'p'>
+
+export const FormattedText: FC<FormattedTextProps> = (props) => {
+ const { className, ...rest } = props
+ return <p
+ {...rest}
+ className={classNames('leading-7', className)}
+ >{props.children}</p>
+}
diff --git a/app/components/datasets/hit-testing/assets/clock.svg b/app/components/datasets/hit-testing/assets/clock.svg
new file mode 100644
index 0000000..b81dbec
--- /dev/null
+++ b/app/components/datasets/hit-testing/assets/clock.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M18.9166 9.58333L17.2505 11.25L15.5833 9.58333M17.4542 10.8333C17.4845 10.5597 17.5 10.2817 17.5 10C17.5 5.85786 14.1421 2.5 10 2.5C5.85786 2.5 2.5 5.85786 2.5 10C2.5 14.1421 5.85786 17.5 10 17.5C12.3561 17.5 14.4584 16.4136 15.8333 14.7144M10 5.83333V10L12.5 11.6667" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/hit-testing/assets/grid.svg b/app/components/datasets/hit-testing/assets/grid.svg
new file mode 100644
index 0000000..a165677
--- /dev/null
+++ b/app/components/datasets/hit-testing/assets/grid.svg
@@ -0,0 +1,6 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.9 1.75H2.68333C2.35664 1.75 2.19329 1.75 2.06851 1.81358C1.95874 1.86951 1.86951 1.95874 1.81358 2.06851C1.75 2.19329 1.75 2.35664 1.75 2.68333V4.9C1.75 5.2267 1.75 5.39005 1.81358 5.51483C1.86951 5.62459 1.95874 5.71383 2.06851 5.76975C2.19329 5.83333 2.35664 5.83333 2.68333 5.83333H4.9C5.2267 5.83333 5.39005 5.83333 5.51483 5.76975C5.62459 5.71383 5.71383 5.62459 5.76975 5.51483C5.83333 5.39005 5.83333 5.2267 5.83333 4.9V2.68333C5.83333 2.35664 5.83333 2.19329 5.76975 2.06851C5.71383 1.95874 5.62459 1.86951 5.51483 1.81358C5.39005 1.75 5.2267 1.75 4.9 1.75Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M11.3167 1.75H9.1C8.7733 1.75 8.60995 1.75 8.48517 1.81358C8.37541 1.86951 8.28617 1.95874 8.23025 2.06851C8.16667 2.19329 8.16667 2.35664 8.16667 2.68333V4.9C8.16667 5.2267 8.16667 5.39005 8.23025 5.51483C8.28617 5.62459 8.37541 5.71383 8.48517 5.76975C8.60995 5.83333 8.7733 5.83333 9.1 5.83333H11.3167C11.6434 5.83333 11.8067 5.83333 11.9315 5.76975C12.0413 5.71383 12.1305 5.62459 12.1864 5.51483C12.25 5.39005 12.25 5.2267 12.25 4.9V2.68333C12.25 2.35664 12.25 2.19329 12.1864 2.06851C12.1305 1.95874 12.0413 1.86951 11.9315 1.81358C11.8067 1.75 11.6434 1.75 11.3167 1.75Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M11.3167 8.16667H9.1C8.7733 8.16667 8.60995 8.16667 8.48517 8.23025C8.37541 8.28617 8.28617 8.37541 8.23025 8.48517C8.16667 8.60995 8.16667 8.7733 8.16667 9.1V11.3167C8.16667 11.6434 8.16667 11.8067 8.23025 11.9315C8.28617 12.0413 8.37541 12.1305 8.48517 12.1864C8.60995 12.25 8.7733 12.25 9.1 12.25H11.3167C11.6434 12.25 11.8067 12.25 11.9315 12.1864C12.0413 12.1305 12.1305 12.0413 12.1864 11.9315C12.25 11.8067 12.25 11.6434 12.25 11.3167V9.1C12.25 8.7733 12.25 8.60995 12.1864 8.48517C12.1305 8.37541 12.0413 8.28617 11.9315 8.23025C11.8067 8.16667 11.6434 8.16667 11.3167 8.16667Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M4.9 8.16667H2.68333C2.35664 8.16667 2.19329 8.16667 2.06851 8.23025C1.95874 8.28617 1.86951 8.37541 1.81358 8.48517C1.75 8.60995 1.75 8.7733 1.75 9.1V11.3167C1.75 11.6434 1.75 11.8067 1.81358 11.9315C1.86951 12.0413 1.95874 12.1305 2.06851 12.1864C2.19329 12.25 2.35664 12.25 2.68333 12.25H4.9C5.2267 12.25 5.39005 12.25 5.51483 12.1864C5.62459 12.1305 5.71383 12.0413 5.76975 11.9315C5.83333 11.8067 5.83333 11.6434 5.83333 11.3167V9.1C5.83333 8.7733 5.83333 8.60995 5.76975 8.48517C5.71383 8.37541 5.62459 8.28617 5.51483 8.23025C5.39005 8.16667 5.2267 8.16667 4.9 8.16667Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/datasets/hit-testing/assets/plugin.svg b/app/components/datasets/hit-testing/assets/plugin.svg
new file mode 100644
index 0000000..2bd15ed
--- /dev/null
+++ b/app/components/datasets/hit-testing/assets/plugin.svg
@@ -0,0 +1,10 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_4151_6854)">
+<path d="M4.37484 2.62484C4.37484 1.81942 5.02776 1.1665 5.83317 1.1665C6.63859 1.1665 7.2915 1.81942 7.2915 2.62484V3.49984H7.87484C8.69023 3.49984 9.09793 3.49984 9.41953 3.63305C9.84833 3.81066 10.189 4.15134 10.3666 4.58014C10.4998 4.90174 10.4998 5.30944 10.4998 6.12484H11.3748C12.1803 6.12484 12.8332 6.77776 12.8332 7.58317C12.8332 8.38859 12.1803 9.0415 11.3748 9.0415H10.4998V10.0332C10.4998 11.0133 10.4998 11.5033 10.3091 11.8777C10.1413 12.2069 9.8736 12.4747 9.54432 12.6424C9.16997 12.8332 8.67993 12.8332 7.69984 12.8332H7.2915V11.8123C7.2915 11.0875 6.70388 10.4998 5.979 10.4998C5.25413 10.4998 4.6665 11.0875 4.6665 11.8123V12.8332H3.9665C2.98641 12.8332 2.49637 12.8332 2.12202 12.6424C1.79274 12.4747 1.52502 12.2069 1.35724 11.8777C1.1665 11.5033 1.1665 11.0133 1.1665 10.0332V9.0415H2.0415C2.84692 9.0415 3.49984 8.38859 3.49984 7.58317C3.49984 6.77776 2.84692 6.12484 2.0415 6.12484H1.1665C1.1665 5.30944 1.1665 4.90174 1.29971 4.58014C1.47733 4.15134 1.81801 3.81066 2.24681 3.63305C2.56841 3.49984 2.97611 3.49984 3.7915 3.49984H4.37484V2.62484Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_4151_6854">
+<rect width="14" height="14" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/datasets/hit-testing/components/child-chunks-item.tsx b/app/components/datasets/hit-testing/components/child-chunks-item.tsx
new file mode 100644
index 0000000..3ccd638
--- /dev/null
+++ b/app/components/datasets/hit-testing/components/child-chunks-item.tsx
@@ -0,0 +1,30 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { SliceContent } from '../../formatted-text/flavours/shared'
+import Score from './score'
+import type { HitTestingChildChunk } from '@/models/datasets'
+
+type Props = {
+ payload: HitTestingChildChunk
+ isShowAll: boolean
+}
+
+const ChildChunks: FC<Props> = ({
+ payload,
+ isShowAll,
+}) => {
+ const { score, content, position } = payload
+ return (
+ <div
+ className={!isShowAll ? 'line-clamp-2 break-all' : ''}
+ >
+ <div className='relative top-[-2px] inline-flex items-center'>
+ <div className='system-2xs-semibold-uppercase flex h-[20.5px] items-center bg-state-accent-solid px-1 text-text-primary-on-surface'>C-{position}</div>
+ <Score value={score} besideChunkName />
+ </div>
+ <SliceContent className='bg-state-accent-hover py-0.5 text-sm font-normal text-text-secondary group-hover:bg-state-accent-hover'>{content}</SliceContent>
+ </div>
+ )
+}
+export default React.memo(ChildChunks)
diff --git a/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx b/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx
new file mode 100644
index 0000000..4fd62bb
--- /dev/null
+++ b/app/components/datasets/hit-testing/components/chunk-detail-modal.tsx
@@ -0,0 +1,92 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { SegmentIndexTag } from '../../documents/detail/completed/common/segment-index-tag'
+import Dot from '../../documents/detail/completed/common/dot'
+import Score from './score'
+import ChildChunksItem from './child-chunks-item'
+import Modal from '@/app/components/base/modal'
+import type { HitTesting } from '@/models/datasets'
+import FileIcon from '@/app/components/base/file-uploader/file-type-icon'
+import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types'
+import cn from '@/utils/classnames'
+import Tag from '@/app/components/datasets/documents/detail/completed/common/tag'
+import { Markdown } from '@/app/components/base/markdown'
+
+const i18nPrefix = 'datasetHitTesting'
+
+type Props = {
+ payload: HitTesting
+ onHide: () => void
+}
+
+const ChunkDetailModal: FC<Props> = ({
+ payload,
+ onHide,
+}) => {
+ const { t } = useTranslation()
+ const { segment, score, child_chunks } = payload
+ const { position, content, sign_content, keywords, document } = segment
+ const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0)
+ const extension = document.name.split('.').slice(-1)[0] as FileAppearanceTypeEnum
+ const heighClassName = isParentChildRetrieval ? 'h-[min(627px,_80vh)] overflow-y-auto' : 'h-[min(539px,_80vh)] overflow-y-auto'
+ return (
+ <Modal
+ title={t(`${i18nPrefix}.chunkDetail`)}
+ isShow
+ closable
+ onClose={onHide}
+ className={cn(isParentChildRetrieval ? '!min-w-[1200px]' : '!min-w-[800px]')}
+ >
+ <div className='mt-4 flex'>
+ <div className={cn('flex-1', isParentChildRetrieval && 'pr-6')}>
+ {/* Meta info */}
+ <div className='flex items-center justify-between'>
+ <div className='flex grow items-center space-x-2'>
+ <SegmentIndexTag
+ labelPrefix={`${isParentChildRetrieval ? 'Parent-' : ''}Chunk`}
+ positionId={position}
+ className={cn('w-fit group-hover:opacity-100')}
+ />
+ <Dot />
+ <div className='flex grow items-center space-x-1'>
+ <FileIcon type={extension} size='sm' />
+ <span className='w-0 grow truncate text-[13px] font-normal text-text-secondary'>{document.name}</span>
+ </div>
+ </div>
+ <Score value={score} />
+ </div>
+ <Markdown
+ className={cn('!mt-2 !text-text-secondary', heighClassName)}
+ content={sign_content || content}
+ customDisallowedElements={['input']}
+ />
+ {!isParentChildRetrieval && keywords && keywords.length > 0 && (
+ <div className='mt-6'>
+ <div className='text-xs font-medium uppercase text-text-tertiary'>{t(`${i18nPrefix}.keyword`)}</div>
+ <div className='mt-1 flex flex-wrap'>
+ {keywords.map(keyword => (
+ <Tag key={keyword} text={keyword} className='mr-2' />
+ ))}
+ </div>
+ </div>
+ )}
+ </div>
+
+ {isParentChildRetrieval && (
+ <div className='flex-1 pb-6 pl-6'>
+ <div className='system-xs-semibold-uppercase text-text-secondary'>{t(`${i18nPrefix}.hitChunks`, { num: child_chunks.length })}</div>
+ <div className={cn('mt-1 space-y-2', heighClassName)}>
+ {child_chunks.map(item => (
+ <ChildChunksItem key={item.id} payload={item} isShowAll />
+ ))}
+ </div>
+ </div>
+ )}
+ </div>
+ </Modal>
+ )
+}
+
+export default React.memo(ChunkDetailModal)
diff --git a/app/components/datasets/hit-testing/components/result-item-external.tsx b/app/components/datasets/hit-testing/components/result-item-external.tsx
new file mode 100644
index 0000000..2c793cd
--- /dev/null
+++ b/app/components/datasets/hit-testing/components/result-item-external.tsx
@@ -0,0 +1,60 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import ResultItemMeta from './result-item-meta'
+import ResultItemFooter from './result-item-footer'
+import type { ExternalKnowledgeBaseHitTesting } from '@/models/datasets'
+import cn from '@/utils/classnames'
+import Modal from '@/app/components/base/modal'
+import { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types'
+
+const i18nPrefix = 'datasetHitTesting'
+type Props = {
+ payload: ExternalKnowledgeBaseHitTesting
+ positionId: number
+}
+
+const ResultItemExternal: FC<Props> = ({ payload, positionId }) => {
+ const { t } = useTranslation()
+ const { content, title, score } = payload
+ const [
+ isShowDetailModal,
+ { setTrue: showDetailModal, setFalse: hideDetailModal },
+ ] = useBoolean(false)
+
+ return (
+ <div className={cn('cursor-pointer rounded-xl bg-chat-bubble-bg pt-3 hover:shadow-lg')} onClick={showDetailModal}>
+ {/* Meta info */}
+ <ResultItemMeta className='px-3' labelPrefix={'Chunk'} positionId={positionId} wordCount={content.length} score={score} />
+
+ {/* Main */}
+ <div className='mt-1 px-3'>
+ <div className='body-md-regular line-clamp-2 break-all'>{content}</div>
+ </div>
+
+ {/* Foot */}
+ <ResultItemFooter docType={FileAppearanceTypeEnum.custom} docTitle={title} showDetailModal={showDetailModal} />
+
+ {isShowDetailModal && (
+ <Modal
+ title={t(`${i18nPrefix}.chunkDetail`)}
+ className={'!min-w-[800px]'}
+ closable
+ onClose={hideDetailModal}
+ isShow={isShowDetailModal}
+ >
+ <div className='mt-4 flex-1'>
+ <ResultItemMeta labelPrefix={'Chunk'} positionId={positionId} wordCount={content.length} score={score} />
+ <div className={cn('body-md-regular mt-2 break-all text-text-secondary', 'h-[min(539px,_80vh)] overflow-y-auto')}>
+ {content}
+ </div>
+ </div>
+ </Modal>
+ )}
+ </div>
+ )
+}
+
+export default React.memo(ResultItemExternal)
diff --git a/app/components/datasets/hit-testing/components/result-item-footer.tsx b/app/components/datasets/hit-testing/components/result-item-footer.tsx
new file mode 100644
index 0000000..c06c5aa
--- /dev/null
+++ b/app/components/datasets/hit-testing/components/result-item-footer.tsx
@@ -0,0 +1,42 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowRightUpLine } from '@remixicon/react'
+import FileIcon from '@/app/components/base/file-uploader/file-type-icon'
+import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types'
+
+type Props = {
+ docType: FileAppearanceTypeEnum
+ docTitle: string
+ showDetailModal: () => void
+}
+const i18nPrefix = 'datasetHitTesting'
+
+const ResultItemFooter: FC<Props> = ({
+ docType,
+ docTitle,
+ showDetailModal,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className="mt-3 flex h-10 items-center justify-between border-t border-divider-subtle pl-3 pr-2">
+ <div className="flex grow items-center space-x-1">
+ <FileIcon type={docType} size="sm" />
+ <span className="w-0 grow truncate text-[13px] font-normal text-text-secondary">
+ {docTitle}
+ </span>
+ </div>
+ <div
+ className="flex cursor-pointer items-center space-x-1 text-text-tertiary"
+ onClick={showDetailModal}
+ >
+ <div className="text-xs uppercase">{t(`${i18nPrefix}.open`)}</div>
+ <RiArrowRightUpLine className="size-3.5" />
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(ResultItemFooter)
diff --git a/app/components/datasets/hit-testing/components/result-item-meta.tsx b/app/components/datasets/hit-testing/components/result-item-meta.tsx
new file mode 100644
index 0000000..617aa77
--- /dev/null
+++ b/app/components/datasets/hit-testing/components/result-item-meta.tsx
@@ -0,0 +1,45 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { SegmentIndexTag } from '../../documents/detail/completed/common/segment-index-tag'
+import Dot from '../../documents/detail/completed/common/dot'
+import Score from './score'
+import cn from '@/utils/classnames'
+
+type Props = {
+ labelPrefix: string
+ positionId: number
+ wordCount: number
+ score: number
+ className?: string
+}
+
+const ResultItemMeta: FC<Props> = ({
+ labelPrefix,
+ positionId,
+ wordCount,
+ score,
+ className,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={cn('flex items-center justify-between', className)}>
+ <div className="flex items-center space-x-2">
+ <SegmentIndexTag
+ labelPrefix={labelPrefix}
+ positionId={positionId}
+ className={cn('w-fit group-hover:opacity-100')}
+ />
+ <Dot />
+ <div className="system-xs-medium text-text-tertiary">
+ {wordCount} {t('datasetDocuments.segment.characters', { count: wordCount })}
+ </div>
+ </div>
+ <Score value={score} />
+ </div>
+ )
+}
+
+export default React.memo(ResultItemMeta)
diff --git a/app/components/datasets/hit-testing/components/result-item.tsx b/app/components/datasets/hit-testing/components/result-item.tsx
new file mode 100644
index 0000000..03a0023
--- /dev/null
+++ b/app/components/datasets/hit-testing/components/result-item.tsx
@@ -0,0 +1,100 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react'
+import { useBoolean } from 'ahooks'
+import ChildChunkItem from './child-chunks-item'
+import ChunkDetailModal from './chunk-detail-modal'
+import ResultItemMeta from './result-item-meta'
+import ResultItemFooter from './result-item-footer'
+import type { HitTesting } from '@/models/datasets'
+import cn from '@/utils/classnames'
+import type { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types'
+import Tag from '@/app/components/datasets/documents/detail/completed/common/tag'
+import { extensionToFileType } from '@/app/components/datasets/hit-testing/utils/extension-to-file-type'
+import { Markdown } from '@/app/components/base/markdown'
+
+const i18nPrefix = 'datasetHitTesting'
+type Props = {
+ payload: HitTesting
+}
+
+const ResultItem: FC<Props> = ({
+ payload,
+}) => {
+ const { t } = useTranslation()
+ const { segment, score, child_chunks } = payload
+ const data = segment
+ const { position, word_count, content, sign_content, keywords, document } = data
+ const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0)
+ const extension = document.name.split('.').slice(-1)[0] as FileAppearanceTypeEnum
+ const fileType = extensionToFileType(extension)
+ const [isFold, {
+ toggle: toggleFold,
+ }] = useBoolean(false)
+ const Icon = isFold ? RiArrowRightSLine : RiArrowDownSLine
+
+ const [isShowDetailModal, {
+ setTrue: showDetailModal,
+ setFalse: hideDetailModal,
+ }] = useBoolean(false)
+
+ return (
+ <div className={cn('cursor-pointer rounded-xl bg-chat-bubble-bg pt-3 hover:shadow-lg')} onClick={showDetailModal}>
+ {/* Meta info */}
+ <ResultItemMeta className='px-3' labelPrefix={`${isParentChildRetrieval ? 'Parent-' : ''}Chunk`} positionId={position} wordCount={word_count} score={score} />
+
+ {/* Main */}
+ <div className='mt-1 px-3'>
+ <Markdown
+ className='line-clamp-2'
+ content={sign_content || content}
+ customDisallowedElements={['input']}
+ />
+ {isParentChildRetrieval && (
+ <div className='mt-1'>
+ <div
+ className={cn('inline-flex h-6 cursor-pointer select-none items-center space-x-0.5 rounded-lg text-text-secondary', isFold && 'bg-workflow-process-bg pl-1')}
+ onClick={(e) => {
+ e.stopPropagation()
+ toggleFold()
+ }}
+ >
+ <Icon className={cn('h-4 w-4', isFold && 'opacity-50')} />
+ <div className='text-xs font-semibold uppercase'>{t(`${i18nPrefix}.hitChunks`, { num: child_chunks.length })}</div>
+ </div>
+ {!isFold && (
+ <div className='space-y-2'>
+ {child_chunks.map(item => (
+ <div key={item.id} className='ml-[7px] border-l-[2px] border-text-accent-secondary pl-[7px]'>
+ <ChildChunkItem payload={item} isShowAll={false} />
+ </div>
+ ))}
+ </div>
+ )}
+ </div>
+ )}
+ {!isParentChildRetrieval && keywords && keywords.length > 0 && (
+ <div className='mt-2 flex flex-wrap'>
+ {keywords.map(keyword => (
+ <Tag key={keyword} text={keyword} className='mr-2' />
+ ))}
+ </div>
+ )}
+ </div>
+ {/* Foot */}
+ <ResultItemFooter docType={fileType} docTitle={document.name} showDetailModal={showDetailModal} />
+
+ {
+ isShowDetailModal && (
+ <ChunkDetailModal
+ payload={payload}
+ onHide={hideDetailModal}
+ />
+ )
+ }
+ </div >
+ )
+}
+export default React.memo(ResultItem)
diff --git a/app/components/datasets/hit-testing/components/score.tsx b/app/components/datasets/hit-testing/components/score.tsx
new file mode 100644
index 0000000..05e470b
--- /dev/null
+++ b/app/components/datasets/hit-testing/components/score.tsx
@@ -0,0 +1,28 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+
+type Props = {
+ value: number | null
+ besideChunkName?: boolean
+}
+
+const Score: FC<Props> = ({
+ value,
+ besideChunkName,
+}) => {
+ if (!value || isNaN(value))
+ return null
+ return (
+ <div className={cn('relative items-center overflow-hidden border border-components-progress-bar-border px-[5px]',
+ besideChunkName ? 'h-[20.5px] border-l-0' : 'h-[20px] rounded-md')}>
+ <div className={cn('absolute left-0 top-0 h-full border-r-[1.5px] border-components-progress-brand-progress bg-util-colors-blue-brand-blue-brand-100', value === 1 && 'border-r-0')} style={{ width: `${value * 100}%` }} />
+ <div className={cn('relative flex h-full items-center space-x-0.5 text-util-colors-blue-brand-blue-brand-700')}>
+ <div className='system-2xs-medium-uppercase'>score</div>
+ <div className='system-xs-semibold'>{value?.toFixed(2)}</div>
+ </div>
+ </div>
+ )
+}
+export default React.memo(Score)
diff --git a/app/components/datasets/hit-testing/index.tsx b/app/components/datasets/hit-testing/index.tsx
new file mode 100644
index 0000000..fef69a5
--- /dev/null
+++ b/app/components/datasets/hit-testing/index.tsx
@@ -0,0 +1,216 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import { omit } from 'lodash-es'
+import { useBoolean } from 'ahooks'
+import { useContext } from 'use-context-selector'
+import { RiApps2Line, RiFocus2Line, RiHistoryLine } from '@remixicon/react'
+import Textarea from './textarea'
+import s from './style.module.css'
+import ModifyRetrievalModal from './modify-retrieval-modal'
+import ResultItem from './components/result-item'
+import ResultItemExternal from './components/result-item-external'
+import cn from '@/utils/classnames'
+import type { ExternalKnowledgeBaseHitTesting, ExternalKnowledgeBaseHitTestingResponse, HitTesting, HitTestingResponse } from '@/models/datasets'
+import Loading from '@/app/components/base/loading'
+import Drawer from '@/app/components/base/drawer'
+import Pagination from '@/app/components/base/pagination'
+import FloatRightContainer from '@/app/components/base/float-right-container'
+import { fetchTestingRecords } from '@/service/datasets'
+import DatasetDetailContext from '@/context/dataset-detail'
+import type { RetrievalConfig } from '@/types/app'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import useTimestamp from '@/hooks/use-timestamp'
+import docStyle from '@/app/components/datasets/documents/detail/completed/style.module.css'
+import { CardSkelton } from '../documents/detail/completed/skeleton/general-list-skeleton'
+
+const limit = 10
+
+type Props = {
+ datasetId: string
+}
+
+const RecordsEmpty: FC = () => {
+ const { t } = useTranslation()
+ return <div className='rounded-2xl bg-workflow-process-bg p-5'>
+ <div className='flex h-10 w-10 items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg p-1 shadow-lg shadow-shadow-shadow-5 backdrop-blur-[5px]'>
+ <RiHistoryLine className='h-5 w-5 text-text-tertiary' />
+ </div>
+ <div className='my-2 text-[13px] font-medium leading-4 text-text-tertiary'>{t('datasetHitTesting.noRecentTip')}</div>
+ </div>
+}
+
+const HitTestingPage: FC<Props> = ({ datasetId }: Props) => {
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ const [hitResult, setHitResult] = useState<HitTestingResponse | undefined>() // 鍒濆鍖栬褰曚负绌烘暟缁�
+ const [externalHitResult, setExternalHitResult] = useState<ExternalKnowledgeBaseHitTestingResponse | undefined>()
+ const [submitLoading, setSubmitLoading] = useState(false)
+ const [text, setText] = useState('')
+
+ const [currPage, setCurrPage] = React.useState<number>(0)
+ const { data: recordsRes, error, mutate: recordsMutate } = useSWR({
+ action: 'fetchTestingRecords',
+ datasetId,
+ params: { limit, page: currPage + 1 },
+ }, apiParams => fetchTestingRecords(omit(apiParams, 'action')))
+
+ const total = recordsRes?.total || 0
+
+ const { dataset: currentDataset } = useContext(DatasetDetailContext)
+ const isExternal = currentDataset?.provider === 'external'
+
+ const [retrievalConfig, setRetrievalConfig] = useState(currentDataset?.retrieval_model_dict as RetrievalConfig)
+ const [isShowModifyRetrievalModal, setIsShowModifyRetrievalModal] = useState(false)
+ const [isShowRightPanel, { setTrue: showRightPanel, setFalse: hideRightPanel, set: setShowRightPanel }] = useBoolean(!isMobile)
+ const renderHitResults = (results: HitTesting[] | ExternalKnowledgeBaseHitTesting[]) => (
+ <div className='flex h-full flex-col rounded-t-2xl bg-background-body px-4 py-3'>
+ <div className='mb-2 shrink-0 pl-2 font-semibold leading-6 text-text-primary'>
+ {t('datasetHitTesting.hit.title', { num: results.length })}
+ </div>
+ <div className='grow space-y-2 overflow-y-auto'>
+ {results.map((record, idx) =>
+ isExternal
+ ? (
+ <ResultItemExternal
+ key={idx}
+ positionId={idx + 1}
+ payload={record as ExternalKnowledgeBaseHitTesting}
+ />
+ )
+ : (
+ <ResultItem key={idx} payload={record as HitTesting} />
+ ),
+ )}
+ </div>
+ </div>
+ )
+
+ const renderEmptyState = () => (
+ <div className='flex h-full flex-col items-center justify-center rounded-t-2xl bg-background-body px-4 py-3'>
+ <div className={cn(docStyle.commonIcon, docStyle.targetIcon, '!h-14 !w-14 !bg-text-quaternary')} />
+ <div className='mt-3 text-[13px] text-text-quaternary'>
+ {t('datasetHitTesting.hit.emptyTip')}
+ </div>
+ </div>
+ )
+
+ useEffect(() => {
+ setShowRightPanel(!isMobile)
+ }, [isMobile, setShowRightPanel])
+
+ return (
+ <div className={s.container}>
+ <div className='flex flex-col px-6 py-3'>
+ <div className='mb-4 flex flex-col justify-center'>
+ <h1 className='text-base font-semibold text-text-primary'>{t('datasetHitTesting.title')}</h1>
+ <p className='mt-0.5 text-[13px] font-normal leading-4 text-text-tertiary'>{t('datasetHitTesting.desc')}</p>
+ </div>
+ <Textarea
+ datasetId={datasetId}
+ setHitResult={setHitResult}
+ setExternalHitResult={setExternalHitResult}
+ onSubmit={showRightPanel}
+ onUpdateList={recordsMutate}
+ loading={submitLoading}
+ setLoading={setSubmitLoading}
+ setText={setText}
+ text={text}
+ isExternal={isExternal}
+ onClickRetrievalMethod={() => setIsShowModifyRetrievalModal(true)}
+ retrievalConfig={retrievalConfig}
+ isEconomy={currentDataset?.indexing_technique === 'economy'}
+ />
+ <div className='mb-3 mt-6 text-base font-semibold text-text-primary'>{t('datasetHitTesting.records')}</div>
+ {(!recordsRes && !error)
+ ? (
+ <div className='flex-1'><Loading type='app' /></div>
+ )
+ : recordsRes?.data?.length
+ ? (
+ <>
+ <div className='grow overflow-y-auto'>
+ <table className={'w-full border-collapse border-0 text-[13px] leading-4 text-text-secondary '}>
+ <thead className='sticky top-0 h-7 text-xs font-medium uppercase leading-7 text-text-tertiary'>
+ <tr>
+ <td className='w-[128px] rounded-l-lg bg-background-section-burn pl-3'>{t('datasetHitTesting.table.header.source')}</td>
+ <td className='bg-background-section-burn'>{t('datasetHitTesting.table.header.text')}</td>
+ <td className='w-48 rounded-r-lg bg-background-section-burn pl-2'>{t('datasetHitTesting.table.header.time')}</td>
+ </tr>
+ </thead>
+ <tbody>
+ {recordsRes?.data?.map((record) => {
+ const SourceIcon = record.source === 'app' ? RiApps2Line : RiFocus2Line
+ return <tr
+ key={record.id}
+ className='group h-10 cursor-pointer border-b border-divider-subtle hover:bg-background-default-hover'
+ onClick={() => setText(record.content)}
+ >
+ <td className='w-[128px] pl-3'>
+ <div className='flex items-center'>
+ <SourceIcon className='mr-1 size-4 text-text-tertiary' />
+ <span className='capitalize'>{record.source.replace('_', ' ').replace('hit testing', 'retrieval test')}</span>
+ </div>
+ </td>
+ <td className='max-w-xs py-2'>{record.content}</td>
+ <td className='w-36 pl-2'>
+ {formatTime(record.created_at, t('datasetHitTesting.dateTimeFormat') as string)}
+ </td>
+ </tr>
+ })}
+ </tbody>
+ </table>
+ </div>
+ {(total && total > limit)
+ ? <Pagination current={currPage} onChange={setCurrPage} total={total} limit={limit} />
+ : null}
+ </>
+ )
+ : (
+ <RecordsEmpty />
+ )}
+ </div>
+ <FloatRightContainer panelClassName='!justify-start !overflow-y-auto' showClose isMobile={isMobile} isOpen={isShowRightPanel} onClose={hideRightPanel} footer={null}>
+ <div className='flex flex-col pt-3'>
+ {/* {renderHitResults(generalResultData)} */}
+ {submitLoading
+ ? <div className='flex h-full flex-col rounded-t-2xl bg-background-body px-4 py-3'>
+ <CardSkelton />
+ </div>
+ : (
+ (() => {
+ if (!hitResult?.records.length && !externalHitResult?.records.length)
+ return renderEmptyState()
+
+ if (hitResult?.records.length)
+ return renderHitResults(hitResult.records)
+
+ return renderHitResults(externalHitResult?.records || [])
+ })()
+ )
+ }
+ </div>
+ </FloatRightContainer>
+ <Drawer unmount={true} isOpen={isShowModifyRetrievalModal} onClose={() => setIsShowModifyRetrievalModal(false)} footer={null} mask={isMobile} panelClassName='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'>
+ <ModifyRetrievalModal
+ indexMethod={currentDataset?.indexing_technique || ''}
+ value={retrievalConfig}
+ isShow={isShowModifyRetrievalModal}
+ onHide={() => setIsShowModifyRetrievalModal(false)}
+ onSave={(value) => {
+ setRetrievalConfig(value)
+ setIsShowModifyRetrievalModal(false)
+ }}
+ />
+ </Drawer>
+ </div>
+ )
+}
+
+export default HitTestingPage
diff --git a/app/components/datasets/hit-testing/modify-external-retrieval-modal.tsx b/app/components/datasets/hit-testing/modify-external-retrieval-modal.tsx
new file mode 100644
index 0000000..db06dc0
--- /dev/null
+++ b/app/components/datasets/hit-testing/modify-external-retrieval-modal.tsx
@@ -0,0 +1,71 @@
+import { useState } from 'react'
+import {
+ RiCloseLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import RetrievalSettings from '../external-knowledge-base/create/RetrievalSettings'
+import Button from '@/app/components/base/button'
+import ActionButton from '@/app/components/base/action-button'
+
+type ModifyExternalRetrievalModalProps = {
+ onClose: () => void
+ onSave: (data: { top_k: number; score_threshold: number; score_threshold_enabled: boolean }) => void
+ initialTopK: number
+ initialScoreThreshold: number
+ initialScoreThresholdEnabled: boolean
+}
+
+const ModifyExternalRetrievalModal: React.FC<ModifyExternalRetrievalModalProps> = ({
+ onClose,
+ onSave,
+ initialTopK,
+ initialScoreThreshold,
+ initialScoreThresholdEnabled,
+}) => {
+ const { t } = useTranslation()
+ const [topK, setTopK] = useState(initialTopK)
+ const [scoreThreshold, setScoreThreshold] = useState(initialScoreThreshold)
+ const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(initialScoreThresholdEnabled)
+
+ const handleSettingsChange = (data: { top_k?: number; score_threshold?: number; score_threshold_enabled?: boolean }) => {
+ if (data.top_k !== undefined)
+ setTopK(data.top_k)
+ if (data.score_threshold !== undefined)
+ setScoreThreshold(data.score_threshold)
+ if (data.score_threshold_enabled !== undefined)
+ setScoreThresholdEnabled(data.score_threshold_enabled)
+ }
+
+ const handleSave = () => {
+ onSave({ top_k: topK, score_threshold: scoreThreshold, score_threshold_enabled: scoreThresholdEnabled })
+ onClose()
+ }
+
+ return (
+ <div className='shadows-shadow-2xl absolute right-[14px] top-[36px] z-10 flex w-[320px] flex-col items-start rounded-2xl
+ border-[0.5px] border-components-panel-border bg-components-panel-bg'
+ >
+ <div className='flex items-center justify-between self-stretch p-4 pb-2'>
+ <div className='system-xl-semibold grow text-text-primary'>{t('datasetHitTesting.settingTitle')}</div>
+ <ActionButton className='ml-auto' onClick={onClose}>
+ <RiCloseLine className='h-4 w-4 shrink-0' />
+ </ActionButton>
+ </div>
+ <div className='flex flex-col items-start justify-center gap-4 self-stretch p-4 pt-2'>
+ <RetrievalSettings
+ topK={topK}
+ scoreThreshold={scoreThreshold}
+ scoreThresholdEnabled={scoreThresholdEnabled}
+ onChange={handleSettingsChange}
+ isInHitTesting={true}
+ />
+ </div>
+ <div className='flex w-full items-end justify-end gap-1 p-4 pt-2'>
+ <Button className='min-w-[72px] shrink-0' onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' className='min-w-[72px] shrink-0' onClick={handleSave}>{t('common.operation.save')}</Button>
+ </div>
+ </div>
+ )
+}
+
+export default ModifyExternalRetrievalModal
diff --git a/app/components/datasets/hit-testing/modify-retrieval-modal.tsx b/app/components/datasets/hit-testing/modify-retrieval-modal.tsx
new file mode 100644
index 0000000..e66448b
--- /dev/null
+++ b/app/components/datasets/hit-testing/modify-retrieval-modal.tsx
@@ -0,0 +1,118 @@
+'use client'
+import type { FC } from 'react'
+import React, { useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
+import Toast from '../../base/toast'
+import { ModelTypeEnum } from '../../header/account-setting/model-provider-page/declarations'
+import type { RetrievalConfig } from '@/types/app'
+import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
+import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
+import Button from '@/app/components/base/button'
+import { isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
+import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
+
+type Props = {
+ indexMethod: string
+ value: RetrievalConfig
+ isShow: boolean
+ onHide: () => void
+ onSave: (value: RetrievalConfig) => void
+}
+
+const ModifyRetrievalModal: FC<Props> = ({
+ indexMethod,
+ value,
+ isShow,
+ onHide,
+ onSave,
+}) => {
+ const ref = useRef(null)
+ const { t } = useTranslation()
+ const [retrievalConfig, setRetrievalConfig] = useState(value)
+
+ // useClickAway(() => {
+ // if (ref)
+ // onHide()
+ // }, ref)
+
+ const {
+ modelList: rerankModelList,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
+
+ const handleSave = () => {
+ if (
+ !isReRankModelSelected({
+ rerankModelList,
+ retrievalConfig,
+ indexMethod,
+ })
+ ) {
+ Toast.notify({ type: 'error', message: t('appDebug.datasetConfig.rerankModelRequired') })
+ return
+ }
+ onSave(retrievalConfig)
+ }
+
+ if (!isShow)
+ return null
+
+ return (
+ <div
+ className='flex w-full flex-col rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-2xl shadow-shadow-shadow-9'
+ style={{
+ height: 'calc(100vh - 72px)',
+ }}
+ ref={ref}
+ >
+ <div className='h-15 flex shrink-0 justify-between px-3 pb-1 pt-3.5'>
+ <div className='text-base font-semibold text-text-primary'>
+ <div>{t('datasetSettings.form.retrievalSetting.title')}</div>
+ <div className='text-xs font-normal leading-[18px] text-text-tertiary'>
+ <a
+ target='_blank'
+ rel='noopener noreferrer'
+ href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings'
+ className='text-text-accent'
+ >
+ {t('datasetSettings.form.retrievalSetting.learnMore')}
+ </a>
+ {t('datasetSettings.form.retrievalSetting.description')}
+ </div>
+ </div>
+ <div className='flex'>
+ <div
+ onClick={onHide}
+ className='flex h-8 w-8 cursor-pointer items-center justify-center'
+ >
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </div>
+ </div>
+
+ <div className='px-4 py-2'>
+ <div className='mb-1 text-[13px] font-semibold leading-6 text-text-secondary'>
+ {t('datasetSettings.form.retrievalSetting.method')}
+ </div>
+ {indexMethod === 'high_quality'
+ ? (
+ <RetrievalMethodConfig
+ value={retrievalConfig}
+ onChange={setRetrievalConfig}
+ />
+ )
+ : (
+ <EconomicalRetrievalMethodConfig
+ value={retrievalConfig}
+ onChange={setRetrievalConfig}
+ />
+ )}
+ </div>
+ <div className='flex justify-end p-4 pt-2'>
+ <Button className='mr-2 shrink-0' onClick={onHide}>{t('common.operation.cancel')}</Button>
+ <Button variant='primary' className='shrink-0' onClick={handleSave} >{t('common.operation.save')}</Button>
+ </div>
+ </div>
+ )
+}
+export default React.memo(ModifyRetrievalModal)
diff --git a/app/components/datasets/hit-testing/style.module.css b/app/components/datasets/hit-testing/style.module.css
new file mode 100644
index 0000000..a421962
--- /dev/null
+++ b/app/components/datasets/hit-testing/style.module.css
@@ -0,0 +1,43 @@
+.container {
+ @apply flex h-full w-full relative overflow-y-auto;
+}
+
+.container>div {
+ @apply flex-1 h-full;
+}
+
+.commonIcon {
+ @apply w-3.5 h-3.5 inline-block align-middle;
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-size: contain;
+}
+
+.app_icon {
+ background-image: url(./assets/grid.svg);
+}
+
+.hit_testing_icon {
+ background-image: url(../documents/assets/target.svg);
+}
+
+.plugin_icon {
+ background-image: url(./assets/plugin.svg);
+}
+
+.cardWrapper {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(284px, auto));
+ grid-gap: 16px;
+ grid-auto-rows: 216px;
+}
+
+.clockWrapper {
+ border: 0.5px solid #eaecf5;
+ @apply rounded-lg w-11 h-11 flex justify-center items-center;
+}
+
+.clockIcon {
+ mask-image: url(./assets/clock.svg);
+ @apply bg-gray-500;
+}
diff --git a/app/components/datasets/hit-testing/textarea.tsx b/app/components/datasets/hit-testing/textarea.tsx
new file mode 100644
index 0000000..c92e107
--- /dev/null
+++ b/app/components/datasets/hit-testing/textarea.tsx
@@ -0,0 +1,200 @@
+import type { ChangeEvent } from 'react'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiEqualizer2Line,
+} from '@remixicon/react'
+import Image from 'next/image'
+import Button from '../../base/button'
+import { getIcon } from '../common/retrieval-method-info'
+import ModifyExternalRetrievalModal from './modify-external-retrieval-modal'
+import Tooltip from '@/app/components/base/tooltip'
+import cn from '@/utils/classnames'
+import type { ExternalKnowledgeBaseHitTestingResponse, HitTestingResponse } from '@/models/datasets'
+import { externalKnowledgeBaseHitTesting, hitTesting } from '@/service/datasets'
+import { asyncRunSafe } from '@/utils'
+import { RETRIEVE_METHOD, type RetrievalConfig } from '@/types/app'
+
+type TextAreaWithButtonIProps = {
+ datasetId: string
+ onUpdateList: () => void
+ setHitResult: (res: HitTestingResponse) => void
+ setExternalHitResult: (res: ExternalKnowledgeBaseHitTestingResponse) => void
+ loading: boolean
+ setLoading: (v: boolean) => void
+ text: string
+ setText: (v: string) => void
+ isExternal?: boolean
+ onClickRetrievalMethod: () => void
+ retrievalConfig: RetrievalConfig
+ isEconomy: boolean
+ onSubmit?: () => void
+}
+
+const TextAreaWithButton = ({
+ datasetId,
+ onUpdateList,
+ setHitResult,
+ setExternalHitResult,
+ setLoading,
+ loading,
+ text,
+ setText,
+ isExternal = false,
+ onClickRetrievalMethod,
+ retrievalConfig,
+ isEconomy,
+ onSubmit: _onSubmit,
+}: TextAreaWithButtonIProps) => {
+ const { t } = useTranslation()
+ const [isSettingsOpen, setIsSettingsOpen] = useState(false)
+ const [externalRetrievalSettings, setExternalRetrievalSettings] = useState({
+ top_k: 2,
+ score_threshold: 0.5,
+ score_threshold_enabled: false,
+ })
+
+ const handleSaveExternalRetrievalSettings = (data: { top_k: number; score_threshold: number; score_threshold_enabled: boolean }) => {
+ setExternalRetrievalSettings(data)
+ setIsSettingsOpen(false)
+ }
+
+ function handleTextChange(event: ChangeEvent<HTMLTextAreaElement>) {
+ setText(event.target.value)
+ }
+
+ const onSubmit = async () => {
+ setLoading(true)
+ const [e, res] = await asyncRunSafe<HitTestingResponse>(
+ hitTesting({
+ datasetId,
+ queryText: text,
+ retrieval_model: {
+ ...retrievalConfig,
+ search_method: isEconomy ? RETRIEVE_METHOD.keywordSearch : retrievalConfig.search_method,
+ },
+ }) as Promise<HitTestingResponse>,
+ )
+ if (!e) {
+ setHitResult(res)
+ onUpdateList?.()
+ }
+ setLoading(false)
+ _onSubmit && _onSubmit()
+ }
+
+ const externalRetrievalTestingOnSubmit = async () => {
+ setLoading(true)
+ const [e, res] = await asyncRunSafe<ExternalKnowledgeBaseHitTestingResponse>(
+ externalKnowledgeBaseHitTesting({
+ datasetId,
+ query: text,
+ external_retrieval_model: {
+ top_k: externalRetrievalSettings.top_k,
+ score_threshold: externalRetrievalSettings.score_threshold,
+ score_threshold_enabled: externalRetrievalSettings.score_threshold_enabled,
+ },
+ }) as Promise<ExternalKnowledgeBaseHitTestingResponse>,
+ )
+ if (!e) {
+ setExternalHitResult(res)
+ onUpdateList?.()
+ }
+ setLoading(false)
+ }
+
+ const retrievalMethod = isEconomy ? RETRIEVE_METHOD.invertedIndex : retrievalConfig.search_method
+ const icon = <Image className='size-3.5 text-util-colors-purple-purple-600' src={getIcon(retrievalMethod)} alt='' />
+ return (
+ <>
+ <div className={cn('relative rounded-xl bg-gradient-to-r from-components-input-border-active-prompt-1 to-components-input-border-active-prompt-2 p-0.5 shadow-xs')}>
+ <div className='relative rounded-t-xl bg-background-section-burn pt-1.5'>
+ <div className="flex h-8 items-center justify-between pb-1 pl-4 pr-1.5">
+ <span className="text-[13px] font-semibold uppercase leading-4 text-text-secondary">
+ {t('datasetHitTesting.input.title')}
+ </span>
+ {isExternal
+ ? <Button
+ variant='secondary'
+ size='small'
+ onClick={() => setIsSettingsOpen(!isSettingsOpen)}
+ >
+ <RiEqualizer2Line className='h-3.5 w-3.5 text-components-button-secondary-text' />
+ <div className='flex items-center justify-center gap-1 px-[3px]'>
+ <span className='system-xs-medium text-components-button-secondary-text'>{t('datasetHitTesting.settingTitle')}</span>
+ </div>
+ </Button>
+ : <div
+ onClick={onClickRetrievalMethod}
+ className='flex h-7 cursor-pointer items-center space-x-0.5 rounded-lg border-[0.5px] border-components-button-secondary-bg bg-components-button-secondary-bg px-1.5 shadow-xs backdrop-blur-[5px] hover:bg-components-button-secondary-bg-hover'
+ >
+ {icon}
+ <div className='text-xs font-medium uppercase text-text-secondary'>{t(`dataset.retrieval.${retrievalMethod}.title`)}</div>
+ <RiEqualizer2Line className='size-4 text-components-menu-item-text'></RiEqualizer2Line>
+ </div>
+ }
+ </div>
+ {
+ isSettingsOpen && (
+ <ModifyExternalRetrievalModal
+ onClose={() => setIsSettingsOpen(false)}
+ onSave={handleSaveExternalRetrievalSettings}
+ initialTopK={externalRetrievalSettings.top_k}
+ initialScoreThreshold={externalRetrievalSettings.score_threshold}
+ initialScoreThresholdEnabled={externalRetrievalSettings.score_threshold_enabled}
+ />
+ )
+ }
+ <div className='h-2 rounded-t-xl bg-background-default'></div>
+ </div>
+ <div className='rounded-b-xl bg-background-default px-4 pb-11'>
+ <textarea
+ className='h-[220px] w-full resize-none border-none bg-transparent text-sm font-normal text-text-secondary caret-[#295EFF] placeholder:text-sm placeholder:font-normal placeholder:text-components-input-text-placeholder focus-visible:outline-none'
+ value={text}
+ onChange={handleTextChange}
+ placeholder={t('datasetHitTesting.input.placeholder') as string}
+ />
+ <div className="absolute inset-x-0 bottom-0 mx-4 mb-2 mt-2 flex items-center justify-between">
+ {text?.length > 200
+ ? (
+ <Tooltip
+ popupContent={t('datasetHitTesting.input.countWarning')}
+ >
+ <div
+ className={cn('flex h-5 items-center rounded-md bg-background-section-burn px-1 text-xs font-medium text-red-600', !text?.length && 'opacity-50')}
+ >
+ {text?.length}
+ <span className="mx-0.5 text-red-300">/</span>
+ 200
+ </div>
+ </Tooltip>
+ )
+ : (
+ <div
+ className={cn('flex h-5 items-center rounded-md bg-background-section-burn px-1 text-xs font-medium text-text-tertiary', !text?.length && 'opacity-50')}
+ >
+ {text?.length}
+ <span className="mx-0.5 text-divider-deep">/</span>
+ 200
+ </div>
+ )}
+
+ <div>
+ <Button
+ onClick={isExternal ? externalRetrievalTestingOnSubmit : onSubmit}
+ variant="primary"
+ loading={loading}
+ disabled={(!text?.length || text?.length > 200)}
+ className='w-[88px]'
+ >
+ {t('datasetHitTesting.input.testing')}
+ </Button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </>
+ )
+}
+
+export default TextAreaWithButton
diff --git a/app/components/datasets/hit-testing/utils/extension-to-file-type.ts b/app/components/datasets/hit-testing/utils/extension-to-file-type.ts
new file mode 100644
index 0000000..68db742
--- /dev/null
+++ b/app/components/datasets/hit-testing/utils/extension-to-file-type.ts
@@ -0,0 +1,31 @@
+import { FileAppearanceTypeEnum } from '@/app/components/base/file-uploader/types'
+
+export const extensionToFileType = (extension: string): FileAppearanceTypeEnum => {
+ switch (extension) {
+ case 'pdf':
+ return FileAppearanceTypeEnum.pdf
+ case 'doc':
+ case 'docx':
+ return FileAppearanceTypeEnum.word
+ case 'txt':
+ case 'epub':
+ return FileAppearanceTypeEnum.document
+ case 'md':
+ case 'mdx':
+ case 'markdown':
+ return FileAppearanceTypeEnum.markdown
+ case 'csv':
+ case 'xls':
+ case 'xlsx':
+ return FileAppearanceTypeEnum.excel
+ case 'html':
+ case 'htm':
+ case 'xml':
+ return FileAppearanceTypeEnum.document
+ case 'ppt':
+ case 'pptx':
+ return FileAppearanceTypeEnum.ppt
+ default:
+ return FileAppearanceTypeEnum.custom
+ }
+}
diff --git a/app/components/datasets/loading.tsx b/app/components/datasets/loading.tsx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/components/datasets/loading.tsx
diff --git a/app/components/datasets/metadata/add-metadata-button.tsx b/app/components/datasets/metadata/add-metadata-button.tsx
new file mode 100644
index 0000000..c342750
--- /dev/null
+++ b/app/components/datasets/metadata/add-metadata-button.tsx
@@ -0,0 +1,31 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import Button from '../../base/button'
+import { RiAddLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { useTranslation } from 'react-i18next'
+
+type Props = {
+ className?: string
+ onClick?: () => void
+}
+
+const AddedMetadataButton: FC<Props> = ({
+ className,
+ onClick,
+}) => {
+ const { t } = useTranslation()
+ return (
+ <Button
+ className={cn('flex w-full items-center', className)}
+ size='small'
+ variant='tertiary'
+ onClick={onClick}
+ >
+ <RiAddLine className='mr-1 size-3.5' />
+ <div>{t('dataset.metadata.addMetadata')}</div>
+ </Button>
+ )
+}
+export default React.memo(AddedMetadataButton)
diff --git a/app/components/datasets/metadata/base/date-picker.tsx b/app/components/datasets/metadata/base/date-picker.tsx
new file mode 100644
index 0000000..f2bf1e4
--- /dev/null
+++ b/app/components/datasets/metadata/base/date-picker.tsx
@@ -0,0 +1,76 @@
+import { useCallback } from 'react'
+import dayjs from 'dayjs'
+import {
+ RiCalendarLine,
+ RiCloseCircleFill,
+} from '@remixicon/react'
+import DatePicker from '@/app/components/base/date-and-time-picker/date-picker'
+import cn from '@/utils/classnames'
+import type { TriggerProps } from '@/app/components/base/date-and-time-picker/types'
+import useTimestamp from '@/hooks/use-timestamp'
+import { useTranslation } from 'react-i18next'
+
+type Props = {
+ className?: string
+ value?: number
+ onChange: (date: number | null) => void
+}
+const WrappedDatePicker = ({
+ className,
+ value,
+ onChange,
+}: Props) => {
+ const { t } = useTranslation()
+ // const { userProfile: { timezone } } = useAppContext()
+ const { formatTime: formatTimestamp } = useTimestamp()
+
+ const handleDateChange = useCallback((date?: dayjs.Dayjs) => {
+ if (date)
+ onChange(date.unix())
+ else
+ onChange(null)
+ }, [onChange])
+
+ const renderTrigger = useCallback(({
+ handleClickTrigger,
+ }: TriggerProps) => {
+ return (
+ <div onClick={handleClickTrigger} className={cn('group flex items-center rounded-md bg-components-input-bg-normal', className)}>
+ <div
+ className={cn(
+ 'grow',
+ value ? 'text-text-secondary' : 'text-text-tertiary',
+ )}
+ >
+ {value ? formatTimestamp(value, t('datasetDocuments.metadata.dateTimeFormat')) : t('dataset.metadata.chooseTime')}
+ </div>
+ <RiCloseCircleFill
+ className={cn(
+ 'hidden h-4 w-4 cursor-pointer hover:text-components-input-text-filled group-hover:block',
+ value && 'text-text-quaternary',
+ )}
+ onClick={() => handleDateChange()}
+ />
+ <RiCalendarLine
+ className={cn(
+ 'block h-4 w-4 shrink-0 group-hover:hidden',
+ value ? 'text-text-quaternary' : 'text-text-tertiary',
+ )}
+ />
+ </div>
+ )
+ }, [className, value, formatTimestamp, t, handleDateChange])
+
+ return (
+ <DatePicker
+ value={dayjs(value ? value * 1000 : Date.now())}
+ onChange={handleDateChange}
+ onClear={handleDateChange}
+ renderTrigger={renderTrigger}
+ triggerWrapClassName='w-full'
+ popupZIndexClassname='z-[1000]'
+ />
+ )
+}
+
+export default WrappedDatePicker
diff --git a/app/components/datasets/metadata/edit-metadata-batch/add-row.tsx b/app/components/datasets/metadata/edit-metadata-batch/add-row.tsx
new file mode 100644
index 0000000..500bca3
--- /dev/null
+++ b/app/components/datasets/metadata/edit-metadata-batch/add-row.tsx
@@ -0,0 +1,45 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import type { MetadataItemWithEdit } from '../types'
+import cn from '@/utils/classnames'
+import Label from './label'
+import InputCombined from './input-combined'
+import { RiIndeterminateCircleLine } from '@remixicon/react'
+
+type Props = {
+ className?: string
+ payload: MetadataItemWithEdit
+ onChange: (value: MetadataItemWithEdit) => void
+ onRemove: () => void
+}
+
+const AddRow: FC<Props> = ({
+ className,
+ payload,
+ onChange,
+ onRemove,
+}) => {
+ return (
+ <div className={cn('flex h-6 items-center space-x-0.5', className)}>
+ <Label text={payload.name} />
+ <InputCombined
+ type={payload.type}
+ value={payload.value}
+ onChange={value => onChange({ ...payload, value })}
+ />
+ <div
+ className={
+ cn(
+ 'cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive',
+ )
+ }
+ onClick={onRemove}
+ >
+ <RiIndeterminateCircleLine className='size-4' />
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(AddRow)
diff --git a/app/components/datasets/metadata/edit-metadata-batch/edit-row.tsx b/app/components/datasets/metadata/edit-metadata-batch/edit-row.tsx
new file mode 100644
index 0000000..63b4338
--- /dev/null
+++ b/app/components/datasets/metadata/edit-metadata-batch/edit-row.tsx
@@ -0,0 +1,56 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { type MetadataItemWithEdit, UpdateType } from '../types'
+import Label from './label'
+import { RiDeleteBinLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import InputHasSetMultipleValue from './input-has-set-multiple-value'
+import InputCombined from './input-combined'
+import EditedBeacon from './edited-beacon'
+
+type Props = {
+ payload: MetadataItemWithEdit
+ onChange: (payload: MetadataItemWithEdit) => void
+ onRemove: (id: string) => void
+ onReset: (id: string) => void
+}
+
+const EditMetadatabatchItem: FC<Props> = ({
+ payload,
+ onChange,
+ onRemove,
+ onReset,
+}) => {
+ const isUpdated = payload.isUpdated
+ const isDeleted = payload.updateType === UpdateType.delete
+ return (
+ <div className='flex h-6 items-center space-x-0.5'>
+ {isUpdated ? <EditedBeacon onReset={() => onReset(payload.id)} /> : <div className='size-4 shrink-0' />}
+ <Label text={payload.name} isDeleted={isDeleted} />
+ {payload.isMultipleValue
+ ? <InputHasSetMultipleValue
+ onClear={() => onChange({ ...payload, value: null, isMultipleValue: false })}
+ readOnly={isDeleted}
+ />
+ : <InputCombined
+ type={payload.type}
+ value={payload.value}
+ onChange={v => onChange({ ...payload, value: v as string })}
+ readOnly={isDeleted}
+ />}
+
+ <div
+ className={
+ cn(
+ 'cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive',
+ isDeleted && 'cursor-default bg-state-destructive-hover text-text-destructive')
+ }
+ onClick={() => onRemove(payload.id)}
+ >
+ <RiDeleteBinLine className='size-4' />
+ </div>
+ </div>
+ )
+}
+export default React.memo(EditMetadatabatchItem)
diff --git a/app/components/datasets/metadata/edit-metadata-batch/edited-beacon.tsx b/app/components/datasets/metadata/edit-metadata-batch/edited-beacon.tsx
new file mode 100644
index 0000000..ba41918
--- /dev/null
+++ b/app/components/datasets/metadata/edit-metadata-batch/edited-beacon.tsx
@@ -0,0 +1,36 @@
+'use client'
+import type { FC } from 'react'
+import React, { useRef } from 'react'
+import { useHover } from 'ahooks'
+import { RiResetLeftLine } from '@remixicon/react'
+import Tooltip from '@/app/components/base/tooltip'
+import { useTranslation } from 'react-i18next'
+
+type Props = {
+ onReset: () => void
+}
+
+const EditedBeacon: FC<Props> = ({
+ onReset,
+}) => {
+ const { t } = useTranslation()
+ const ref = useRef(null)
+ const isHovering = useHover(ref)
+
+ return (
+ <div ref={ref} className='size-4 cursor-pointer'>
+ {isHovering ? (
+ <Tooltip popupContent={t('common.operation.reset')}>
+ <div className='flex size-4 items-center justify-center rounded-full bg-text-accent-secondary' onClick={onReset}>
+ <RiResetLeftLine className='size-[10px] text-text-primary-on-surface' />
+ </div>
+ </Tooltip>
+ ) : (
+ <div className='flex size-4 items-center justify-center'>
+ <div className='size-1 rounded-full bg-text-accent-secondary'></div>
+ </div>
+ )}
+ </div>
+ )
+}
+export default React.memo(EditedBeacon)
diff --git a/app/components/datasets/metadata/edit-metadata-batch/input-combined.tsx b/app/components/datasets/metadata/edit-metadata-batch/input-combined.tsx
new file mode 100644
index 0000000..fd7bb89
--- /dev/null
+++ b/app/components/datasets/metadata/edit-metadata-batch/input-combined.tsx
@@ -0,0 +1,61 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { DataType } from '../types'
+import Input from '@/app/components/base/input'
+import { InputNumber } from '@/app/components/base/input-number'
+import cn from '@/utils/classnames'
+import Datepicker from '../base/date-picker'
+
+type Props = {
+ className?: string
+ type: DataType
+ value: any
+ onChange: (value: any) => void
+ readOnly?: boolean
+}
+
+const InputCombined: FC<Props> = ({
+ className: configClassName,
+ type,
+ value,
+ onChange,
+ readOnly,
+}) => {
+ const className = cn('h-6 grow p-0.5 text-xs')
+ if (type === DataType.time) {
+ return (
+ <Datepicker
+ className={className}
+ value={value}
+ onChange={onChange}
+ />
+ )
+ }
+
+ if (type === DataType.number) {
+ return (
+ <div className='grow text-[0]'>
+ <InputNumber
+ className={cn(className, 'rounded-l-md')}
+ value={value}
+ onChange={onChange}
+ size='regular'
+ controlWrapClassName='overflow-hidden'
+ controlClassName='pt-0 pb-0'
+ readOnly={readOnly}
+ />
+ </div>
+ )
+ }
+ return (
+ <Input
+ wrapperClassName={configClassName}
+ className={cn(className, 'rounded-md')}
+ value={value}
+ onChange={e => onChange(e.target.value)}
+ readOnly={readOnly}
+ />
+ )
+}
+export default React.memo(InputCombined)
diff --git a/app/components/datasets/metadata/edit-metadata-batch/input-has-set-multiple-value.tsx b/app/components/datasets/metadata/edit-metadata-batch/input-has-set-multiple-value.tsx
new file mode 100644
index 0000000..1e6d457
--- /dev/null
+++ b/app/components/datasets/metadata/edit-metadata-batch/input-has-set-multiple-value.tsx
@@ -0,0 +1,34 @@
+'use client'
+import { RiCloseLine } from '@remixicon/react'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+
+type Props = {
+ onClear: () => void
+ readOnly?: boolean
+}
+
+const InputHasSetMultipleValue: FC<Props> = ({
+ onClear,
+ readOnly,
+}) => {
+ const { t } = useTranslation()
+ return (
+ <div className='h-6 grow rounded-md bg-components-input-bg-normal p-0.5 text-[0]'>
+ <div className={cn('inline-flex h-5 items-center space-x-0.5 rounded-[5px] border-[0.5px] border-components-panel-border bg-components-badge-white-to-dark pl-1.5 pr-0.5 shadow-xs', readOnly && 'pr-1.5')}>
+ <div className='system-xs-regular text-text-secondary'>{t('dataset.metadata.batchEditMetadata.multipleValue')}</div>
+ {!readOnly && (
+ <div className='cursor-pointer rounded-[4px] p-px text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary'>
+ <RiCloseLine
+ className='size-3.5 '
+ onClick={onClear}
+ />
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+export default React.memo(InputHasSetMultipleValue)
diff --git a/app/components/datasets/metadata/edit-metadata-batch/label.tsx b/app/components/datasets/metadata/edit-metadata-batch/label.tsx
new file mode 100644
index 0000000..a6d134d
--- /dev/null
+++ b/app/components/datasets/metadata/edit-metadata-batch/label.tsx
@@ -0,0 +1,27 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import cn from '@/utils/classnames'
+
+type Props = {
+ isDeleted?: boolean,
+ className?: string,
+ text: string
+}
+
+const Label: FC<Props> = ({
+ isDeleted,
+ className,
+ text,
+}) => {
+ return (
+ <div className={cn(
+ 'system-xs-medium w-[136px] shrink-0 truncate text-text-tertiary',
+ isDeleted && 'text-text-quaternary line-through',
+ className,
+ )}>
+ {text}
+ </div>
+ )
+}
+export default React.memo(Label)
diff --git a/app/components/datasets/metadata/edit-metadata-batch/modal.tsx b/app/components/datasets/metadata/edit-metadata-batch/modal.tsx
new file mode 100644
index 0000000..c80bd61
--- /dev/null
+++ b/app/components/datasets/metadata/edit-metadata-batch/modal.tsx
@@ -0,0 +1,189 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import Modal from '../../../base/modal'
+import type { BuiltInMetadataItem, MetadataItemInBatchEdit } from '../types'
+import { type MetadataItemWithEdit, UpdateType } from '../types'
+import EditMetadataBatchItem from './edit-row'
+import AddedMetadataItem from './add-row'
+import Button from '../../../base/button'
+import { useTranslation } from 'react-i18next'
+import Checkbox from '../../../base/checkbox'
+import Tooltip from '../../../base/tooltip'
+import SelectMetadataModal from '../metadata-dataset/select-metadata-modal'
+import { RiQuestionLine } from '@remixicon/react'
+import Divider from '@/app/components/base/divider'
+import AddMetadataButton from '../add-metadata-button'
+import produce from 'immer'
+import useCheckMetadataName from '../hooks/use-check-metadata-name'
+import Toast from '@/app/components/base/toast'
+import { useCreateMetaData } from '@/service/knowledge/use-metadata'
+
+const i18nPrefix = 'dataset.metadata.batchEditMetadata'
+
+type Props = {
+ datasetId: string,
+ documentNum: number
+ list: MetadataItemInBatchEdit[]
+ onSave: (editedList: MetadataItemInBatchEdit[], addedList: MetadataItemInBatchEdit[], isApplyToAllSelectDocument: boolean) => void
+ onHide: () => void
+ onShowManage: () => void
+}
+
+const EditMetadataBatchModal: FC<Props> = ({
+ datasetId,
+ documentNum,
+ list,
+ onSave,
+ onHide,
+ onShowManage,
+}) => {
+ const { t } = useTranslation()
+ const [templeList, setTempleList] = useState<MetadataItemWithEdit[]>(list)
+ const handleTemplesChange = useCallback((payload: MetadataItemWithEdit) => {
+ const newTempleList = produce(templeList, (draft) => {
+ const index = draft.findIndex(i => i.id === payload.id)
+ if (index !== -1) {
+ draft[index] = payload
+ draft[index].isUpdated = true
+ draft[index].updateType = UpdateType.changeValue
+ }
+ },
+ )
+ setTempleList(newTempleList)
+ }, [templeList])
+ const handleTempleItemRemove = useCallback((id: string) => {
+ const newTempleList = produce(templeList, (draft) => {
+ const index = draft.findIndex(i => i.id === id)
+ if (index !== -1) {
+ draft[index].isUpdated = true
+ draft[index].updateType = UpdateType.delete
+ }
+ })
+ setTempleList(newTempleList)
+ }, [templeList])
+
+ const handleItemReset = useCallback((id: string) => {
+ const newTempleList = produce(templeList, (draft) => {
+ const index = draft.findIndex(i => i.id === id)
+ if (index !== -1) {
+ draft[index] = { ...list[index] }
+ draft[index].isUpdated = false
+ delete draft[index].updateType
+ }
+ })
+ setTempleList(newTempleList)
+ }, [list, templeList])
+
+ const { checkName } = useCheckMetadataName()
+ const { mutate: doAddMetaData } = useCreateMetaData(datasetId)
+ const handleAddMetaData = useCallback(async (payload: BuiltInMetadataItem) => {
+ const errorMsg = checkName(payload.name).errorMsg
+ if (errorMsg) {
+ Toast.notify({
+ message: errorMsg,
+ type: 'error',
+ })
+ return Promise.reject(new Error(errorMsg))
+ }
+ await doAddMetaData(payload)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.actionSuccess'),
+ })
+ }, [checkName, doAddMetaData, t])
+
+ const [addedList, setAddedList] = useState<MetadataItemWithEdit[]>([])
+ const handleAddedListChange = useCallback((payload: MetadataItemWithEdit) => {
+ const newAddedList = addedList.map(i => i.id === payload.id ? payload : i)
+ setAddedList(newAddedList)
+ }, [addedList])
+ const handleAddedItemRemove = useCallback((removeIndex: number) => {
+ return () => {
+ const newAddedList = addedList.filter((i, index) => index !== removeIndex)
+ setAddedList(newAddedList)
+ }
+ }, [addedList])
+
+ const [isApplyToAllSelectDocument, setIsApplyToAllSelectDocument] = useState(false)
+
+ const handleSave = useCallback(() => {
+ onSave(templeList.filter(item => item.updateType !== UpdateType.delete), addedList, isApplyToAllSelectDocument)
+ }, [templeList, addedList, isApplyToAllSelectDocument, onSave])
+ return (
+ <Modal
+ title={t(`${i18nPrefix}.editMetadata`)}
+ isShow
+ closable
+ onClose={onHide}
+ className='!max-w-[640px]'
+ >
+ <div className='system-xs-medium mt-1 text-text-accent'>{t(`${i18nPrefix}.editDocumentsNum`, { num: documentNum })}</div>
+ <div className='ml-[-16px] max-h-[305px] overflow-y-auto'>
+ <div className='mt-4 space-y-2'>
+ {templeList.map(item => (
+ <EditMetadataBatchItem
+ key={item.id}
+ payload={item}
+ onChange={handleTemplesChange}
+ onRemove={handleTempleItemRemove}
+ onReset={handleItemReset}
+ />
+ ))}
+ </div>
+ <div className='mt-4 pl-[18px]'>
+ <div className='flex items-center'>
+ <div className='system-xs-medium-uppercase mr-2 shrink-0 text-text-tertiary'>{t('dataset.metadata.createMetadata.title')}</div>
+ <Divider bgStyle='gradient' />
+ </div>
+ <div className='mt-2 space-y-2'>
+ {addedList.map((item, i) => (
+ <AddedMetadataItem
+ key={i}
+ payload={item}
+ onChange={handleAddedListChange}
+ onRemove={handleAddedItemRemove(i)}
+ />
+ ))}
+ </div>
+ <div className='mt-3'>
+ <SelectMetadataModal
+ datasetId={datasetId}
+ popupPlacement='top-start'
+ popupOffset={{ mainAxis: 4, crossAxis: 0 }}
+ trigger={
+ <AddMetadataButton />
+ }
+ onSave={handleAddMetaData}
+ onSelect={data => setAddedList([...addedList, data as MetadataItemWithEdit])}
+ onManage={onShowManage}
+ />
+ </div>
+ </div>
+ </div>
+
+ <div className='mt-4 flex items-center justify-between'>
+ <div className='flex select-none items-center'>
+ <Checkbox checked={isApplyToAllSelectDocument} onCheck={() => setIsApplyToAllSelectDocument(!isApplyToAllSelectDocument)} />
+ <div className='system-xs-medium ml-2 mr-1 text-text-secondary'>{t(`${i18nPrefix}.applyToAllSelectDocument`)}</div>
+ <Tooltip popupContent={
+ <div className='max-w-[240px]'>{t(`${i18nPrefix}.applyToAllSelectDocumentTip`)}</div>
+ } >
+ <div className='cursor-pointer p-px'>
+ <RiQuestionLine className='size-3.5 text-text-tertiary' />
+ </div>
+ </Tooltip>
+ </div>
+ <div className='flex items-center space-x-2'>
+ <Button
+ onClick={onHide}>{t('common.operation.cancel')}</Button>
+ <Button
+ onClick={handleSave}
+ variant='primary'
+ >{t('common.operation.save')}</Button>
+ </div>
+ </div>
+ </Modal>
+ )
+}
+export default React.memo(EditMetadataBatchModal)
diff --git a/app/components/datasets/metadata/hooks/use-batch-edit-document-metadata.ts b/app/components/datasets/metadata/hooks/use-batch-edit-document-metadata.ts
new file mode 100644
index 0000000..3bb6e1d
--- /dev/null
+++ b/app/components/datasets/metadata/hooks/use-batch-edit-document-metadata.ts
@@ -0,0 +1,143 @@
+import { useBoolean } from 'ahooks'
+import { type MetadataBatchEditToServer, type MetadataItemInBatchEdit, type MetadataItemWithEdit, type MetadataItemWithValue, UpdateType } from '../types'
+import type { SimpleDocumentDetail } from '@/models/datasets'
+import { useMemo } from 'react'
+import { useBatchUpdateDocMetadata } from '@/service/knowledge/use-metadata'
+import Toast from '@/app/components/base/toast'
+import { t } from 'i18next'
+
+type Props = {
+ datasetId: string
+ docList: SimpleDocumentDetail[]
+ onUpdate: () => void
+}
+
+const useBatchEditDocumentMetadata = ({
+ datasetId,
+ docList,
+ onUpdate,
+}: Props) => {
+ const [isShowEditModal, {
+ setTrue: showEditModal,
+ setFalse: hideEditModal,
+ }] = useBoolean(false)
+
+ const metaDataList: MetadataItemWithValue[][] = (() => {
+ const res: MetadataItemWithValue[][] = []
+ docList.forEach((item) => {
+ if (item.doc_metadata) {
+ res.push(item.doc_metadata.filter(item => item.id !== 'built-in'))
+ return
+ }
+ res.push([])
+ })
+ return res
+ })()
+
+ // To check is key has multiple value
+ const originalList: MetadataItemInBatchEdit[] = useMemo(() => {
+ const idNameValue: Record<string, { value: string | number | null, isMultipleValue: boolean }> = {}
+
+ const res: MetadataItemInBatchEdit[] = []
+ metaDataList.forEach((metaData) => {
+ metaData.forEach((item) => {
+ if (idNameValue[item.id]?.isMultipleValue)
+ return
+ const itemInRes = res.find(i => i.id === item.id)
+ if (!idNameValue[item.id]) {
+ idNameValue[item.id] = {
+ value: item.value,
+ isMultipleValue: false,
+ }
+ }
+
+ if (itemInRes && itemInRes.value !== item.value) {
+ idNameValue[item.id].isMultipleValue = true
+ itemInRes.isMultipleValue = true
+ itemInRes.value = null
+ return
+ }
+ if (!itemInRes) {
+ res.push({
+ ...item,
+ isMultipleValue: false,
+ })
+ }
+ })
+ })
+ return res
+ }, [metaDataList])
+
+ const formateToBackendList = (editedList: MetadataItemWithEdit[], addedList: MetadataItemInBatchEdit[], isApplyToAllSelectDocument: boolean) => {
+ const updatedList = editedList.filter((editedItem) => {
+ return editedItem.updateType === UpdateType.changeValue
+ })
+ const removedList = originalList.filter((originalItem) => {
+ const editedItem = editedList.find(i => i.id === originalItem.id)
+ if (!editedItem) // removed item
+ return true
+ return false
+ })
+
+ const res: MetadataBatchEditToServer = docList.map((item, i) => {
+ // the new metadata will override the old one
+ const oldMetadataList = metaDataList[i]
+ let newMetadataList: MetadataItemWithValue[] = [...oldMetadataList, ...addedList]
+ .filter((item) => {
+ return !removedList.find(removedItem => removedItem.id === item.id)
+ })
+ .map(item => ({
+ id: item.id,
+ name: item.name,
+ type: item.type,
+ value: item.value,
+ }))
+ if (isApplyToAllSelectDocument) {
+ // add missing metadata item
+ updatedList.forEach((editedItem) => {
+ if (!newMetadataList.find(i => i.id === editedItem.id) && !editedItem.isMultipleValue)
+ newMetadataList.push(editedItem)
+ })
+ }
+
+ newMetadataList = newMetadataList.map((item) => {
+ const editedItem = updatedList.find(i => i.id === item.id)
+ if (editedItem)
+ return editedItem
+ return item
+ })
+
+ return {
+ document_id: item.id,
+ metadata_list: newMetadataList,
+ }
+ })
+ return res
+ }
+
+ const { mutateAsync } = useBatchUpdateDocMetadata()
+
+ const handleSave = async (editedList: MetadataItemInBatchEdit[], addedList: MetadataItemInBatchEdit[], isApplyToAllSelectDocument: boolean) => {
+ const backendList = formateToBackendList(editedList, addedList, isApplyToAllSelectDocument)
+ await mutateAsync({
+ dataset_id: datasetId,
+ metadata_list: backendList,
+ })
+ onUpdate()
+ hideEditModal()
+ Toast.notify({
+ type: 'success',
+ message: t('common.actionMsg.modifiedSuccessfully'),
+ })
+ }
+
+ return {
+ isShowEditModal,
+ showEditModal,
+ hideEditModal,
+ originalList,
+ handleSave,
+ }
+}
+
+export default useBatchEditDocumentMetadata
diff --git a/app/components/datasets/metadata/hooks/use-check-metadata-name.ts b/app/components/datasets/metadata/hooks/use-check-metadata-name.ts
new file mode 100644
index 0000000..45fe767
--- /dev/null
+++ b/app/components/datasets/metadata/hooks/use-check-metadata-name.ts
@@ -0,0 +1,28 @@
+import { useTranslation } from 'react-i18next'
+
+const i18nPrefix = 'dataset.metadata.checkName'
+
+const useCheckMetadataName = () => {
+ const { t } = useTranslation()
+ return {
+ checkName: (name: string) => {
+ if (!name) {
+ return {
+ errorMsg: t(`${i18nPrefix}.empty`),
+ }
+ }
+
+ if (!/^[a-z][a-z0-9_]*$/.test(name)) {
+ return {
+ errorMsg: t(`${i18nPrefix}.invalid`),
+ }
+ }
+
+ return {
+ errorMsg: '',
+ }
+ },
+ }
+}
+
+export default useCheckMetadataName
diff --git a/app/components/datasets/metadata/hooks/use-edit-dataset-metadata.ts b/app/components/datasets/metadata/hooks/use-edit-dataset-metadata.ts
new file mode 100644
index 0000000..dd1cd0f
--- /dev/null
+++ b/app/components/datasets/metadata/hooks/use-edit-dataset-metadata.ts
@@ -0,0 +1,96 @@
+import { useBoolean } from 'ahooks'
+import { useBuiltInMetaDataFields, useCreateMetaData, useDatasetMetaData, useDeleteMetaData, useRenameMeta, useUpdateBuiltInStatus } from '@/service/knowledge/use-metadata'
+import type { DataSet } from '@/models/datasets'
+import { useCallback, useEffect, useState } from 'react'
+import { type BuiltInMetadataItem, type MetadataItemWithValueLength, isShowManageMetadataLocalStorageKey } from '../types'
+import useCheckMetadataName from './use-check-metadata-name'
+import Toast from '@/app/components/base/toast'
+import { useTranslation } from 'react-i18next'
+
+const useEditDatasetMetadata = ({
+ datasetId,
+ // dataset,
+ onUpdateDocList,
+}: {
+ datasetId: string,
+ dataset?: DataSet,
+ onUpdateDocList: () => void
+}) => {
+ const { t } = useTranslation()
+ const [isShowEditModal, {
+ setTrue: showEditModal,
+ setFalse: hideEditModal,
+ }] = useBoolean(false)
+
+ useEffect(() => {
+ const isShowManageMetadata = localStorage.getItem(isShowManageMetadataLocalStorageKey)
+ if (isShowManageMetadata) {
+ showEditModal()
+ localStorage.removeItem(isShowManageMetadataLocalStorageKey)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+
+ const { data: datasetMetaData } = useDatasetMetaData(datasetId)
+ const { mutate: doAddMetaData } = useCreateMetaData(datasetId)
+ const { checkName } = useCheckMetadataName()
+ const handleAddMetaData = useCallback(async (payload: BuiltInMetadataItem) => {
+ const errorMsg = checkName(payload.name).errorMsg
+ if (errorMsg) {
+ Toast.notify({
+ message: errorMsg,
+ type: 'error',
+ })
+ return Promise.reject(new Error(errorMsg))
+ }
+ await doAddMetaData(payload)
+ }, [checkName, doAddMetaData])
+
+ const { mutate: doRenameMetaData } = useRenameMeta(datasetId)
+ const handleRename = useCallback(async (payload: MetadataItemWithValueLength) => {
+ const errorMsg = checkName(payload.name).errorMsg
+ if (errorMsg) {
+ Toast.notify({
+ message: errorMsg,
+ type: 'error',
+ })
+ return Promise.reject(new Error(errorMsg))
+ }
+ await doRenameMetaData(payload)
+ onUpdateDocList()
+ }, [checkName, doRenameMetaData, onUpdateDocList])
+
+ const { mutateAsync: doDeleteMetaData } = useDeleteMetaData(datasetId)
+ const handleDeleteMetaData = useCallback(async (metaDataId: string) => {
+ await doDeleteMetaData(metaDataId)
+ onUpdateDocList()
+ }, [doDeleteMetaData, onUpdateDocList])
+
+ const [builtInEnabled, setBuiltInEnabled] = useState(datasetMetaData?.built_in_field_enabled)
+ useEffect(() => { // wait for api response to set the right value
+ setBuiltInEnabled(datasetMetaData?.built_in_field_enabled)
+ }, [datasetMetaData])
+ const { mutateAsync: toggleBuiltInStatus } = useUpdateBuiltInStatus(datasetId)
+ const { data: builtInMetaData } = useBuiltInMetaDataFields()
+ return {
+ isShowEditModal,
+ showEditModal,
+ hideEditModal,
+ datasetMetaData: datasetMetaData?.doc_metadata,
+ handleAddMetaData,
+ handleRename,
+ handleDeleteMetaData,
+ builtInMetaData: builtInMetaData?.fields,
+ builtInEnabled,
+ setBuiltInEnabled: async (enable: boolean) => {
+ await toggleBuiltInStatus(enable)
+ setBuiltInEnabled(enable)
+ Toast.notify({
+ message: t('common.actionMsg.modifiedSuccessfully'),
+ type: 'success',
+ })
+ },
+ }
+}
+
+export default useEditDatasetMetadata
diff --git a/app/components/datasets/metadata/hooks/use-metadata-document.ts b/app/components/datasets/metadata/hooks/use-metadata-document.ts
new file mode 100644
index 0000000..f52806e
--- /dev/null
+++ b/app/components/datasets/metadata/hooks/use-metadata-document.ts
@@ -0,0 +1,159 @@
+import { useBatchUpdateDocMetadata, useDatasetMetaData, useDocumentMetaData } from '@/service/knowledge/use-metadata'
+import { useDatasetDetailContext } from '@/context/dataset-detail'
+import type { BuiltInMetadataItem } from '../types'
+import { DataType, type MetadataItemWithValue } from '../types'
+import { useCallback, useState } from 'react'
+import Toast from '@/app/components/base/toast'
+import type { FullDocumentDetail } from '@/models/datasets'
+import { useTranslation } from 'react-i18next'
+import { useLanguages, useMetadataMap } from '@/hooks/use-metadata'
+import { get } from 'lodash-es'
+import { useCreateMetaData } from '@/service/knowledge/use-metadata'
+import useCheckMetadataName from './use-check-metadata-name'
+
+type Props = {
+ datasetId: string
+ documentId: string
+ docDetail: FullDocumentDetail
+}
+
+const useMetadataDocument = ({
+ datasetId,
+ documentId,
+ docDetail,
+}: Props) => {
+ const { t } = useTranslation()
+
+ const { dataset } = useDatasetDetailContext()
+ const embeddingAvailable = !!dataset?.embedding_available
+
+ const { mutateAsync } = useBatchUpdateDocMetadata()
+ const { checkName } = useCheckMetadataName()
+
+ const [isEdit, setIsEdit] = useState(false)
+ const { data: documentDetail } = useDocumentMetaData({
+ datasetId,
+ documentId,
+ })
+
+ const allList = documentDetail?.doc_metadata || []
+ const list = allList.filter(item => item.id !== 'built-in')
+ const builtList = allList.filter(item => item.id === 'built-in')
+ const [tempList, setTempList] = useState<MetadataItemWithValue[]>(list)
+ const { mutateAsync: doAddMetaData } = useCreateMetaData(datasetId)
+ const handleSelectMetaData = useCallback((metaData: MetadataItemWithValue) => {
+ setTempList((prev) => {
+ const index = prev.findIndex(item => item.id === metaData.id)
+ if (index === -1)
+ return [...prev, metaData]
+
+ return prev
+ })
+ }, [])
+ const handleAddMetaData = useCallback(async (payload: BuiltInMetadataItem) => {
+ const errorMsg = checkName(payload.name).errorMsg
+ if (errorMsg) {
+ Toast.notify({
+ message: errorMsg,
+ type: 'error',
+ })
+ return Promise.reject(new Error(errorMsg))
+ }
+ await doAddMetaData(payload)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.actionSuccess'),
+ })
+ }, [checkName, doAddMetaData, t])
+
+ const hasData = list.length > 0
+ const handleSave = async () => {
+ await mutateAsync({
+ dataset_id: datasetId,
+ metadata_list: [{
+ document_id: documentId,
+ metadata_list: tempList,
+ }],
+ })
+ setIsEdit(false)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.actionSuccess'),
+ })
+ }
+
+ const handleCancel = () => {
+ setTempList(list)
+ setIsEdit(false)
+ }
+
+ const startToEdit = () => {
+ setTempList(list)
+ setIsEdit(true)
+ }
+
+ // built in enabled is set in dataset
+ const { data: datasetMetaData } = useDatasetMetaData(datasetId)
+ const builtInEnabled = datasetMetaData?.built_in_field_enabled
+
+ // old metadata and technical params
+ const metadataMap = useMetadataMap()
+ const languageMap = useLanguages()
+
+ const getReadOnlyMetaData = (mainField: 'originInfo' | 'technicalParameters') => {
+ const fieldMap = metadataMap[mainField]?.subFieldsMap
+ const sourceData = docDetail
+ const getTargetMap = (field: string) => {
+ if (field === 'language')
+ return languageMap
+
+ return {} as any
+ }
+
+ const getTargetValue = (field: string) => {
+ const val = get(sourceData, field, '')
+ if (!val && val !== 0)
+ return '-'
+ if (fieldMap[field]?.inputType === 'select')
+ return getTargetMap(field)[val]
+ if (fieldMap[field]?.render)
+ return fieldMap[field]?.render?.(val, field === 'hit_count' ? get(sourceData, 'segment_count', 0) as number : undefined)
+ return val
+ }
+ const fieldList = Object.keys(fieldMap).map((key) => {
+ const field = fieldMap[key]
+ return {
+ id: field?.label,
+ type: DataType.string,
+ name: field?.label,
+ value: getTargetValue(key),
+ }
+ })
+
+ return fieldList
+ }
+
+ const originInfo = getReadOnlyMetaData('originInfo')
+ const technicalParameters = getReadOnlyMetaData('technicalParameters')
+
+ return {
+ embeddingAvailable,
+ isEdit,
+ setIsEdit,
+ list,
+ tempList,
+ setTempList,
+ handleSelectMetaData,
+ handleAddMetaData,
+ hasData,
+ builtList,
+ builtInEnabled,
+ startToEdit,
+ handleSave,
+ handleCancel,
+ originInfo,
+ technicalParameters,
+ }
+}
+
+export default useMetadataDocument
diff --git a/app/components/datasets/metadata/metadata-dataset/create-content.tsx b/app/components/datasets/metadata/metadata-dataset/create-content.tsx
new file mode 100644
index 0000000..3ac1a04
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-dataset/create-content.tsx
@@ -0,0 +1,90 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { DataType } from '../types'
+import ModalLikeWrap from '../../../base/modal-like-wrap'
+import Field from './field'
+import OptionCard from '../../../workflow/nodes/_base/components/option-card'
+import Input from '@/app/components/base/input'
+import { RiArrowLeftLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { noop } from 'lodash-es'
+
+const i18nPrefix = 'dataset.metadata.createMetadata'
+
+export type Props = {
+ onClose?: () => void
+ onSave: (data: any) => void
+ hasBack?: boolean
+ onBack?: () => void
+}
+
+const CreateContent: FC<Props> = ({
+ onClose = noop,
+ hasBack,
+ onBack,
+ onSave,
+}) => {
+ const { t } = useTranslation()
+ const [type, setType] = useState(DataType.string)
+
+ const handleTypeChange = useCallback((newType: DataType) => {
+ return () => setType(newType)
+ }, [setType])
+ const [name, setName] = useState('')
+ const handleNameChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
+ setName(e.target.value)
+ }, [setName])
+
+ const handleSave = useCallback(() => {
+ onSave({
+ type,
+ name,
+ })
+ }, [onSave, type, name])
+
+ return (
+ <ModalLikeWrap
+ title={t(`${i18nPrefix}.title`)}
+ onClose={onClose}
+ onConfirm={handleSave}
+ hideCloseBtn={hasBack}
+ beforeHeader={hasBack && (
+ <div className='relative left-[-4px] mb-1 flex cursor-pointer items-center space-x-1 py-1 text-text-accent' onClick={onBack}>
+ <RiArrowLeftLine className='size-4' />
+ <div className='system-xs-semibold-uppercase'>{t(`${i18nPrefix}.back`)}</div>
+ </div>
+ )}
+ >
+ <div className='space-y-3'>
+ <Field label={t(`${i18nPrefix}.type`)}>
+ <div className='grid grid-cols-3 gap-2'>
+ <OptionCard
+ title='String'
+ selected={type === DataType.string}
+ onSelect={handleTypeChange(DataType.string)}
+ />
+ <OptionCard
+ title='Number'
+ selected={type === DataType.number}
+ onSelect={handleTypeChange(DataType.number)}
+ />
+ <OptionCard
+ title='Time'
+ selected={type === DataType.time}
+ onSelect={handleTypeChange(DataType.time)}
+ />
+ </div>
+ </Field>
+ <Field label={t(`${i18nPrefix}.name`)}>
+ <Input
+ value={name}
+ onChange={handleNameChange}
+ placeholder={t(`${i18nPrefix}.namePlaceholder`)}
+ />
+ </Field>
+ </div>
+ </ModalLikeWrap>
+ )
+}
+export default React.memo(CreateContent)
diff --git a/app/components/datasets/metadata/metadata-dataset/create-metadata-modal.tsx b/app/components/datasets/metadata/metadata-dataset/create-metadata-modal.tsx
new file mode 100644
index 0000000..6e00aa4
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-dataset/create-metadata-modal.tsx
@@ -0,0 +1,45 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import type { Props as CreateContentProps } from './create-content'
+import CreateContent from './create-content'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '../../../base/portal-to-follow-elem'
+
+type Props = {
+ open: boolean
+ setOpen: (open: boolean) => void
+ onSave: (data: any) => void
+ trigger: React.ReactNode
+ popupLeft?: number
+} & CreateContentProps
+
+const CreateMetadataModal: FC<Props> = ({
+ open,
+ setOpen,
+ trigger,
+ popupLeft = 20,
+ ...createContentProps
+}) => {
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='left-start'
+ offset={{
+ mainAxis: popupLeft,
+ crossAxis: -38,
+ }}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(!open)}
+ >
+ {trigger}
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1000]'>
+ <CreateContent {...createContentProps} onClose={() => setOpen(false)} onBack={() => setOpen(false)} />
+ </PortalToFollowElemContent>
+ </PortalToFollowElem >
+
+ )
+}
+export default React.memo(CreateMetadataModal)
diff --git a/app/components/datasets/metadata/metadata-dataset/dataset-metadata-drawer.tsx b/app/components/datasets/metadata/metadata-dataset/dataset-metadata-drawer.tsx
new file mode 100644
index 0000000..b5e4d17
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-dataset/dataset-metadata-drawer.tsx
@@ -0,0 +1,248 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useRef, useState } from 'react'
+import type { BuiltInMetadataItem, MetadataItemWithValueLength } from '../types'
+import Drawer from '@/app/components/base/drawer'
+import Button from '@/app/components/base/button'
+import { RiAddLine, RiDeleteBinLine, RiEditLine } from '@remixicon/react'
+import { getIcon } from '../utils/get-icon'
+import cn from '@/utils/classnames'
+import Modal from '@/app/components/base/modal'
+import Field from './field'
+import Input from '@/app/components/base/input'
+import { useTranslation } from 'react-i18next'
+import Switch from '@/app/components/base/switch'
+import Tooltip from '@/app/components/base/tooltip'
+import CreateModal from '@/app/components/datasets/metadata/metadata-dataset/create-metadata-modal'
+import { useBoolean, useHover } from 'ahooks'
+import Confirm from '@/app/components/base/confirm'
+import Toast from '@/app/components/base/toast'
+
+const i18nPrefix = 'dataset.metadata.datasetMetadata'
+
+type Props = {
+ userMetadata: MetadataItemWithValueLength[]
+ builtInMetadata: BuiltInMetadataItem[]
+ isBuiltInEnabled: boolean
+ onIsBuiltInEnabledChange: (value: boolean) => void
+ onClose: () => void
+ onAdd: (payload: BuiltInMetadataItem) => void
+ onRename: (payload: MetadataItemWithValueLength) => void
+ onRemove: (metaDataId: string) => void
+}
+
+type ItemProps = {
+ readonly?: boolean
+ disabled?: boolean
+ payload: MetadataItemWithValueLength
+ onRename?: () => void
+ onDelete?: () => void
+}
+const Item: FC<ItemProps> = ({
+ readonly,
+ disabled,
+ payload,
+ onRename,
+ onDelete,
+}) => {
+ const { t } = useTranslation()
+ const Icon = getIcon(payload.type)
+
+ const handleRename = useCallback(() => {
+ onRename?.()
+ }, [onRename])
+
+ const deleteBtnRef = useRef<HTMLDivElement>(null)
+ const isDeleteHovering = useHover(deleteBtnRef)
+ const [isShowDeleteConfirm, {
+ setTrue: showDeleteConfirm,
+ setFalse: hideDeleteConfirm,
+ }] = useBoolean(false)
+ const handleDelete = useCallback(() => {
+ hideDeleteConfirm()
+ onDelete?.()
+ }, [hideDeleteConfirm, onDelete])
+
+ return (
+ <div
+ key={payload.name}
+ className={cn(
+ !readonly && !disabled && 'group/item cursor-pointer hover:shadow-xs',
+ 'rounded-md border border-components-panel-border-subtle bg-components-panel-on-panel-item-bg',
+ isDeleteHovering && 'border border-state-destructive-border bg-state-destructive-hover',
+ )}
+ >
+ <div
+ className={cn(
+ 'flex h-8 items-center justify-between px-2',
+ disabled && 'opacity-30', // not include border and bg
+ )}
+ >
+ <div className='flex h-full items-center space-x-1 text-text-tertiary'>
+ <Icon className='size-4 shrink-0' />
+ <div className='system-sm-medium max-w-[250px] truncate text-text-primary'>{payload.name}</div>
+ <div className='system-xs-regular shrink-0'>{payload.type}</div>
+ </div>
+ {(!readonly || disabled) && (
+ <div className='system-xs-regular ml-2 shrink-0 text-text-tertiary group-hover/item:hidden'>
+ {disabled ? t(`${i18nPrefix}.disabled`) : t(`${i18nPrefix}.values`, { num: payload.count || 0 })}
+ </div>
+ )}
+ <div className='ml-2 hidden items-center space-x-1 text-text-tertiary group-hover/item:flex'>
+ <RiEditLine className='size-4 cursor-pointer' onClick={handleRename} />
+ <div ref={deleteBtnRef} className='hover:text-text-destructive'>
+ <RiDeleteBinLine className='size-4 cursor-pointer' onClick={showDeleteConfirm} />
+ </div>
+ </div>
+ {isShowDeleteConfirm && (
+ <Confirm
+ isShow
+ type='warning'
+ title={t('dataset.metadata.datasetMetadata.deleteTitle')}
+ content={t('dataset.metadata.datasetMetadata.deleteContent', { name: payload.name })}
+ onConfirm={handleDelete}
+ onCancel={hideDeleteConfirm}
+ />
+ )}
+ </div>
+ </div>
+ )
+}
+
+const DatasetMetadataDrawer: FC<Props> = ({
+ userMetadata,
+ builtInMetadata,
+ isBuiltInEnabled,
+ onIsBuiltInEnabledChange,
+ onClose,
+ onAdd,
+ onRename,
+ onRemove,
+}) => {
+ const { t } = useTranslation()
+ const [isShowRenameModal, setIsShowRenameModal] = useState(false)
+ const [currPayload, setCurrPayload] = useState<MetadataItemWithValueLength | null>(null)
+ const [templeName, setTempleName] = useState('')
+ const handleRename = useCallback((payload: MetadataItemWithValueLength) => {
+ return () => {
+ setCurrPayload(payload)
+ setTempleName(payload.name)
+ setIsShowRenameModal(true)
+ }
+ }, [setCurrPayload, setIsShowRenameModal])
+
+ const [open, setOpen] = useState(false)
+ const handleAdd = useCallback(async (data: MetadataItemWithValueLength) => {
+ await onAdd(data)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.actionSuccess'),
+ })
+ setOpen(false)
+ }, [onAdd, t])
+
+ const handleRenamed = useCallback(async () => {
+ const item = userMetadata.find(p => p.id === currPayload?.id)
+ if (item) {
+ await onRename({
+ ...item,
+ name: templeName,
+ })
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.actionSuccess'),
+ })
+ }
+ setIsShowRenameModal(false)
+ }, [userMetadata, currPayload?.id, onRename, templeName, t])
+
+ const handleDelete = useCallback((payload: MetadataItemWithValueLength) => {
+ return async () => {
+ await onRemove(payload.id)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.actionSuccess'),
+ })
+ }
+ }, [onRemove, t])
+
+ return (
+ <Drawer
+ isOpen={true}
+ onClose={onClose}
+ showClose
+ title={t('dataset.metadata.metadata')}
+ footer={null}
+ panelClassName='px-4 block !max-w-[420px] my-2 rounded-l-2xl'
+ >
+ <div className='h-full overflow-y-auto'>
+ <div className='system-sm-regular text-text-tertiary'>{t(`${i18nPrefix}.description`)}</div>
+ <CreateModal
+ open={open}
+ setOpen={setOpen}
+ trigger={<Button variant='primary' className='mt-3'>
+ <RiAddLine className='mr-1' />
+ {t(`${i18nPrefix}.addMetaData`)}
+ </Button>} hasBack onSave={handleAdd}
+ />
+
+ <div className='mt-3 space-y-1'>
+ {userMetadata.map(payload => (
+ <Item
+ key={payload.id}
+ payload={payload}
+ onRename={handleRename(payload)}
+ onDelete={handleDelete(payload)}
+ />
+ ))}
+ </div>
+
+ <div className='mt-3 flex h-6 items-center'>
+ <Switch
+ defaultValue={isBuiltInEnabled}
+ onChange={onIsBuiltInEnabledChange}
+ />
+ <div className='system-sm-semibold ml-2 mr-0.5 text-text-secondary'>{t(`${i18nPrefix}.builtIn`)}</div>
+ <Tooltip popupContent={<div className='max-w-[100px]'>{t(`${i18nPrefix}.builtInDescription`)}</div>} />
+ </div>
+
+ <div className='mt-1 space-y-1'>
+ {builtInMetadata.map(payload => (
+ <Item
+ key={payload.name}
+ readonly
+ disabled={!isBuiltInEnabled}
+ payload={payload as MetadataItemWithValueLength}
+ />
+ ))}
+ </div>
+
+ {isShowRenameModal && (
+ <Modal isShow title={t(`${i18nPrefix}.rename`)} onClose={() => setIsShowRenameModal(false)}>
+ <Field label={t(`${i18nPrefix}.name`)} className='mt-4'>
+ <Input
+ value={templeName}
+ onChange={e => setTempleName(e.target.value)}
+ placeholder={t(`${i18nPrefix}.namePlaceholder`)}
+ />
+ </Field>
+ <div className='mt-4 flex justify-end'>
+ <Button
+ className='mr-2'
+ onClick={() => {
+ setIsShowRenameModal(false)
+ setTempleName(currPayload!.name)
+ }}>{t('common.operation.cancel')}</Button>
+ <Button
+ onClick={handleRenamed}
+ variant='primary'
+ disabled={!templeName}
+ >{t('common.operation.save')}</Button>
+ </div>
+ </Modal>
+ )}
+ </div>
+ </Drawer>
+ )
+}
+export default React.memo(DatasetMetadataDrawer)
diff --git a/app/components/datasets/metadata/metadata-dataset/field.tsx b/app/components/datasets/metadata/metadata-dataset/field.tsx
new file mode 100644
index 0000000..d7f0e47
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-dataset/field.tsx
@@ -0,0 +1,23 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+
+type Props = {
+ className?: string
+ label: string
+ children: React.ReactNode
+}
+
+const Field: FC<Props> = ({
+ className,
+ label,
+ children,
+}) => {
+ return (
+ <div className={className}>
+ <div className='system-sm-semibold py-1 text-text-secondary'>{label}</div>
+ <div className='mt-1'>{children}</div>
+ </div>
+ )
+}
+export default React.memo(Field)
diff --git a/app/components/datasets/metadata/metadata-dataset/select-metadata-modal.tsx b/app/components/datasets/metadata/metadata-dataset/select-metadata-modal.tsx
new file mode 100644
index 0000000..91c9715
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-dataset/select-metadata-modal.tsx
@@ -0,0 +1,82 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import type { Props as CreateContentProps } from './create-content'
+import CreateContent from './create-content'
+import SelectMetadata from './select-metadata'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '../../../base/portal-to-follow-elem'
+import type { MetadataItem } from '../types'
+import type { Placement } from '@floating-ui/react'
+import { useDatasetMetaData } from '@/service/knowledge/use-metadata'
+
+type Props = {
+ datasetId: string
+ popupPlacement?: Placement
+ popupOffset?: { mainAxis: number, crossAxis: number }
+ onSelect: (data: MetadataItem) => void
+ onSave: (data: MetadataItem) => void
+ trigger: React.ReactNode
+ onManage: () => void
+} & CreateContentProps
+
+enum Step {
+ select = 'select',
+ create = 'create',
+}
+
+const SelectMetadataModal: FC<Props> = ({
+ datasetId,
+ popupPlacement = 'left-start',
+ popupOffset = { mainAxis: -38, crossAxis: 4 },
+ trigger,
+ onSelect,
+ onSave,
+ onManage,
+}) => {
+ const { data: datasetMetaData } = useDatasetMetaData(datasetId)
+
+ const [open, setOpen] = useState(false)
+ const [step, setStep] = useState(Step.select)
+
+ const handleSave = useCallback(async (data: MetadataItem) => {
+ await onSave(data)
+ setStep(Step.select)
+ }, [onSave])
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement={popupPlacement}
+ offset={popupOffset}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(!open)}
+ className='block'
+ >
+ {trigger}
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1000]'>
+ {step === Step.select ? (
+ <SelectMetadata
+ onSelect={(data) => {
+ onSelect(data)
+ setOpen(false)
+ }}
+ list={datasetMetaData?.doc_metadata || []}
+ onNew={() => setStep(Step.create)}
+ onManage={onManage}
+ />
+ ) : (
+ <CreateContent
+ onSave={handleSave}
+ hasBack
+ onBack={() => setStep(Step.select)}
+ onClose={() => setStep(Step.select)}
+ />
+ )}
+ </PortalToFollowElemContent>
+ </PortalToFollowElem >
+
+ )
+}
+export default React.memo(SelectMetadataModal)
diff --git a/app/components/datasets/metadata/metadata-dataset/select-metadata.tsx b/app/components/datasets/metadata/metadata-dataset/select-metadata.tsx
new file mode 100644
index 0000000..d3580cf
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-dataset/select-metadata.tsx
@@ -0,0 +1,82 @@
+'use client'
+import type { FC } from 'react'
+import React, { useMemo, useState } from 'react'
+import type { MetadataItem } from '../types'
+import SearchInput from '@/app/components/base/search-input'
+import { RiAddLine, RiArrowRightUpLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { getIcon } from '../utils/get-icon'
+
+const i18nPrefix = 'dataset.metadata.selectMetadata'
+
+type Props = {
+ list: MetadataItem[]
+ onSelect: (data: MetadataItem) => void
+ onNew: () => void
+ onManage: () => void
+}
+
+const SelectMetadata: FC<Props> = ({
+ list: notFilteredList,
+ onSelect,
+ onNew,
+ onManage,
+}) => {
+ const { t } = useTranslation()
+
+ const [query, setQuery] = useState('')
+ const list = useMemo(() => {
+ if (!query) return notFilteredList
+ return notFilteredList.filter((item) => {
+ return item.name.toLowerCase().includes(query.toLowerCase())
+ })
+ }, [query, notFilteredList])
+ return (
+ <div className='w-[320px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur pb-0 pt-2 shadow-lg backdrop-blur-[5px]'>
+ <SearchInput
+ className='mx-2'
+ value={query}
+ onChange={setQuery}
+ placeholder={t(`${i18nPrefix}.search`)}
+ />
+ <div className='mt-2'>
+ {list.map((item) => {
+ const Icon = getIcon(item.type)
+ return (
+ <div
+ key={item.id}
+ className='mx-1 flex h-6 cursor-pointer items-center justify-between rounded-md px-3 hover:bg-state-base-hover'
+ onClick={() => onSelect({
+ id: item.id,
+ name: item.name,
+ type: item.type,
+ })}
+ >
+ <div className='flex h-full w-0 grow items-center text-text-secondary'>
+ <Icon className='mr-[5px] size-3.5 shrink-0' />
+ <div className='system-sm-medium w-0 grow truncate'>{item.name}</div>
+ </div>
+ <div className='system-xs-regular ml-1 shrink-0 text-text-tertiary'>
+ {item.type}
+ </div>
+ </div>
+ )
+ })}
+ </div>
+ <div className='mt-1 flex justify-between border-t border-divider-subtle p-1'>
+ <div className='flex h-6 cursor-pointer items-center space-x-1 rounded-md px-3 text-text-secondary hover:bg-state-base-hover' onClick={onNew}>
+ <RiAddLine className='size-3.5' />
+ <div className='system-sm-medium'>{t(`${i18nPrefix}.newAction`)}</div>
+ </div>
+ <div className='flex h-6 items-center text-text-secondary '>
+ <div className='mr-[3px] h-3 w-px bg-divider-regular'></div>
+ <div className='flex h-full cursor-pointer items-center rounded-md px-1.5 hover:bg-state-base-hover' onClick={onManage}>
+ <div className='system-sm-medium mr-1'>{t(`${i18nPrefix}.manageAction`)}</div>
+ <RiArrowRightUpLine className='size-3.5' />
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+}
+export default React.memo(SelectMetadata)
diff --git a/app/components/datasets/metadata/metadata-document/field.tsx b/app/components/datasets/metadata/metadata-document/field.tsx
new file mode 100644
index 0000000..1ef1d7c
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-document/field.tsx
@@ -0,0 +1,26 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+
+type Props = {
+ label: string
+ children: React.ReactNode
+}
+
+const Field: FC<Props> = ({
+ label,
+ children,
+}) => {
+ return (
+ <div className='flex items-start space-x-2'>
+ <div className='system-xs-medium w-[128px] shrink-0 items-center truncate py-1 text-text-tertiary'>
+ {label}
+ </div>
+ <div className='w-[244px] shrink-0'>
+ {children}
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(Field)
diff --git a/app/components/datasets/metadata/metadata-document/index.tsx b/app/components/datasets/metadata/metadata-document/index.tsx
new file mode 100644
index 0000000..bf82e27
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-document/index.tsx
@@ -0,0 +1,120 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import InfoGroup from './info-group'
+import NoData from './no-data'
+import Button from '@/app/components/base/button'
+import { RiEditLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import Divider from '@/app/components/base/divider'
+import useMetadataDocument from '../hooks/use-metadata-document'
+import type { FullDocumentDetail } from '@/models/datasets'
+import cn from '@/utils/classnames'
+
+const i18nPrefix = 'dataset.metadata.documentMetadata'
+
+type Props = {
+ datasetId: string
+ documentId: string
+ className?: string
+ docDetail: FullDocumentDetail
+}
+const MetadataDocument: FC<Props> = ({
+ datasetId,
+ documentId,
+ className,
+ docDetail,
+}) => {
+ const { t } = useTranslation()
+
+ const {
+ embeddingAvailable,
+ isEdit,
+ setIsEdit,
+ list,
+ tempList,
+ setTempList,
+ handleSelectMetaData,
+ handleAddMetaData,
+ hasData,
+ builtList,
+ builtInEnabled,
+ startToEdit,
+ handleSave,
+ handleCancel,
+ originInfo,
+ technicalParameters,
+ } = useMetadataDocument({ datasetId, documentId, docDetail })
+
+ return (
+ <div className={cn('w-[388px] space-y-4', className)}>
+ {(hasData || isEdit) ? (
+ <div className='pl-2'>
+ <InfoGroup
+ title={t('dataset.metadata.metadata')}
+ uppercaseTitle={false}
+ titleTooltip={t(`${i18nPrefix}.metadataToolTip`)}
+ list={isEdit ? tempList : list}
+ dataSetId={datasetId}
+ headerRight={embeddingAvailable && (isEdit ? (
+ <div className='flex space-x-1'>
+ <Button variant='ghost' size='small' onClick={handleCancel}>
+ <div>{t('common.operation.cancel')}</div>
+ </Button>
+ <Button variant='primary' size='small' onClick={handleSave}>
+ <div>{t('common.operation.save')}</div>
+ </Button>
+ </div>
+ ) : (
+ <Button variant='ghost' size='small' onClick={startToEdit}>
+ <RiEditLine className='mr-1 size-3.5 cursor-pointer text-text-tertiary' />
+ <div>{t('common.operation.edit')}</div>
+ </Button>
+ ))}
+ isEdit={isEdit}
+ contentClassName='mt-5'
+ onChange={(item) => {
+ const newList = tempList.map(i => (i.name === item.name ? item : i))
+ setTempList(newList)
+ }}
+ onDelete={(item) => {
+ const newList = tempList.filter(i => i.name !== item.name)
+ setTempList(newList)
+ }}
+ onAdd={handleAddMetaData}
+ onSelect={handleSelectMetaData}
+ />
+ </div>
+ ) : (
+ embeddingAvailable && <NoData onStart={() => setIsEdit(true)} />
+ )}
+ {builtInEnabled && (
+ <div className='pl-2'>
+ <Divider className='my-3' bgStyle='gradient' />
+ <InfoGroup
+ noHeader
+ titleTooltip='Built-in metadata is system-generated metadata that is automatically added to the document. You can enable or disable built-in metadata here.'
+ list={builtList}
+ dataSetId={datasetId}
+ />
+ </div>
+ )}
+
+ {/* Old Metadata */}
+ <InfoGroup
+ className='pl-2'
+ title={t(`${i18nPrefix}.documentInformation`)}
+ list={originInfo}
+ dataSetId={datasetId}
+ />
+ <InfoGroup
+ className='pl-2'
+ title={t(`${i18nPrefix}.technicalParameters`)}
+ list={technicalParameters}
+ dataSetId={datasetId}
+ />
+ </div>
+ )
+}
+
+export default React.memo(MetadataDocument)
diff --git a/app/components/datasets/metadata/metadata-document/info-group.tsx b/app/components/datasets/metadata/metadata-document/info-group.tsx
new file mode 100644
index 0000000..9078c43
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-document/info-group.tsx
@@ -0,0 +1,111 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useRouter } from 'next/navigation'
+import { DataType, type MetadataItemWithValue, isShowManageMetadataLocalStorageKey } from '../types'
+import Field from './field'
+import InputCombined from '../edit-metadata-batch/input-combined'
+import { RiDeleteBinLine, RiQuestionLine } from '@remixicon/react'
+import Tooltip from '@/app/components/base/tooltip'
+import cn from '@/utils/classnames'
+import Divider from '@/app/components/base/divider'
+import SelectMetadataModal from '../metadata-dataset/select-metadata-modal'
+import AddMetadataButton from '../add-metadata-button'
+import useTimestamp from '@/hooks/use-timestamp'
+import { useTranslation } from 'react-i18next'
+
+type Props = {
+ dataSetId: string
+ className?: string
+ noHeader?: boolean
+ title?: string
+ uppercaseTitle?: boolean
+ titleTooltip?: string
+ headerRight?: React.ReactNode
+ contentClassName?: string
+ list: MetadataItemWithValue[]
+ isEdit?: boolean
+ onChange?: (item: MetadataItemWithValue) => void
+ onDelete?: (item: MetadataItemWithValue) => void
+ onSelect?: (item: MetadataItemWithValue) => void
+ onAdd?: (item: MetadataItemWithValue) => void
+}
+
+const InfoGroup: FC<Props> = ({
+ dataSetId,
+ className,
+ noHeader,
+ title,
+ uppercaseTitle = true,
+ titleTooltip,
+ headerRight,
+ contentClassName,
+ list,
+ isEdit,
+ onChange,
+ onDelete,
+ onSelect,
+ onAdd,
+}) => {
+ const router = useRouter()
+ const { t } = useTranslation()
+ const { formatTime: formatTimestamp } = useTimestamp()
+
+ const handleMangeMetadata = () => {
+ localStorage.setItem(isShowManageMetadataLocalStorageKey, 'true')
+ router.push(`/datasets/${dataSetId}/documents`)
+ }
+
+ return (
+ <div className={cn(className)}>
+ {!noHeader && (
+ <div className='flex items-center justify-between'>
+ <div className='flex items-center space-x-1'>
+ <div className={cn('text-text-secondary', uppercaseTitle ? 'system-xs-semibold-uppercase' : 'system-md-semibold')}>{title}</div>
+ {titleTooltip && (
+ <Tooltip popupContent={<div className='max-w-[240px]'>{titleTooltip}</div>}>
+ <div><RiQuestionLine className='size-3.5 text-text-tertiary' /></div>
+ </Tooltip>
+ )}
+ </div>
+ {headerRight}
+ </div>
+ )}
+
+ <div className={cn('mt-3 space-y-1', contentClassName)}>
+ {isEdit && (
+ <div>
+ <SelectMetadataModal
+ datasetId={dataSetId}
+ trigger={
+ <AddMetadataButton />
+ }
+ onSelect={data => onSelect?.(data as MetadataItemWithValue)}
+ onSave={data => onAdd?.(data)}
+ onManage={handleMangeMetadata}
+ />
+ {list.length > 0 && <Divider className='my-3 ' bgStyle='gradient' />}
+ </div>
+ )}
+ {list.map((item, i) => (
+ <Field key={(item.id && item.id !== 'built-in') ? item.id : `${i}`} label={item.name}>
+ {isEdit ? (
+ <div className='flex items-center space-x-0.5'>
+ <InputCombined
+ className='h-6'
+ type={item.type}
+ value={item.value}
+ onChange={value => onChange?.({ ...item, value })}
+ />
+ <div className='shrink-0 cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive'>
+ <RiDeleteBinLine className='size-4' onClick={() => onDelete?.(item)} />
+ </div>
+ </div>
+ ) : (<div className='system-xs-regular py-1 text-text-secondary'>{(item.value && item.type === DataType.time) ? formatTimestamp((item.value as number), t('datasetDocuments.metadata.dateTimeFormat')) : item.value}</div>)}
+ </Field>
+ ))}
+ </div>
+ </div>
+ )
+}
+export default React.memo(InfoGroup)
diff --git a/app/components/datasets/metadata/metadata-document/no-data.tsx b/app/components/datasets/metadata/metadata-document/no-data.tsx
new file mode 100644
index 0000000..624abf3
--- /dev/null
+++ b/app/components/datasets/metadata/metadata-document/no-data.tsx
@@ -0,0 +1,27 @@
+'use client'
+import Button from '@/app/components/base/button'
+import { RiArrowRightLine } from '@remixicon/react'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+
+type Props = {
+ onStart: () => void
+}
+
+const NoData: FC<Props> = ({
+ onStart,
+}) => {
+ const { t } = useTranslation()
+ return (
+ <div className='rounded-xl bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2 p-4 pt-3'>
+ <div className='text-xs font-semibold leading-5 text-text-secondary'>{t('dataset.metadata.metadata')}</div>
+ <div className='system-xs-regular mt-1 text-text-tertiary'>{t('dataset.metadata.documentMetadata.metadataToolTip')}</div>
+ <Button variant='primary' className='mt-2' onClick={onStart}>
+ <div>{t('dataset.metadata.documentMetadata.startLabeling')}</div>
+ <RiArrowRightLine className='ml-1 size-4' />
+ </Button>
+ </div>
+ )
+}
+export default React.memo(NoData)
diff --git a/app/components/datasets/metadata/types.ts b/app/components/datasets/metadata/types.ts
new file mode 100644
index 0000000..00688e2
--- /dev/null
+++ b/app/components/datasets/metadata/types.ts
@@ -0,0 +1,41 @@
+export enum DataType {
+ string = 'string',
+ number = 'number',
+ time = 'time',
+}
+
+export type BuiltInMetadataItem = {
+ type: DataType
+ name: string
+}
+
+export type MetadataItem = BuiltInMetadataItem & {
+ id: string
+}
+
+export type MetadataItemWithValue = MetadataItem & {
+ value: string | number | null
+}
+
+export type MetadataItemWithValueLength = MetadataItem & {
+ count: number
+}
+
+export type MetadataItemInBatchEdit = MetadataItemWithValue & {
+ isMultipleValue?: boolean
+}
+
+export type MetadataBatchEditToServer = { document_id: string, metadata_list: MetadataItemWithValue[] }[]
+
+export enum UpdateType {
+ changeValue = 'changeValue',
+ delete = 'delete',
+}
+
+export type MetadataItemWithEdit = MetadataItemWithValue & {
+ isMultipleValue?: boolean
+ isUpdated?: boolean
+ updateType?: UpdateType
+}
+
+export const isShowManageMetadataLocalStorageKey = 'dify-isShowManageMetadata'
diff --git a/app/components/datasets/metadata/utils/get-icon.ts b/app/components/datasets/metadata/utils/get-icon.ts
new file mode 100644
index 0000000..69b9bb1
--- /dev/null
+++ b/app/components/datasets/metadata/utils/get-icon.ts
@@ -0,0 +1,10 @@
+import { DataType } from '../types'
+import { RiHashtag, RiTextSnippet, RiTimeLine } from '@remixicon/react'
+
+export const getIcon = (type: DataType) => {
+ return ({
+ [DataType.string]: RiTextSnippet,
+ [DataType.number]: RiHashtag,
+ [DataType.time]: RiTimeLine,
+ }[type] || RiTextSnippet)
+}
diff --git a/app/components/datasets/preview/container.tsx b/app/components/datasets/preview/container.tsx
new file mode 100644
index 0000000..f6c1f7d
--- /dev/null
+++ b/app/components/datasets/preview/container.tsx
@@ -0,0 +1,29 @@
+import type { ComponentProps, FC, ReactNode } from 'react'
+import { forwardRef } from 'react'
+import classNames from '@/utils/classnames'
+
+export type PreviewContainerProps = ComponentProps<'div'> & {
+ header: ReactNode
+ mainClassName?: string
+}
+
+export const PreviewContainer: FC<PreviewContainerProps> = forwardRef((props, ref) => {
+ const { children, className, header, mainClassName, ...rest } = props
+ return <div className={className}>
+ <div
+ {...rest}
+ ref={ref}
+ className={classNames(
+ 'flex flex-col w-full h-full overflow-y-auto rounded-l-xl border-t-[0.5px] border-l-[0.5px] border-components-panel-border bg-background-default-lighter shadow shadow-shadow-shadow-5',
+ )}
+ >
+ <header className='border-b border-divider-subtle pb-3 pl-5 pr-4 pt-4'>
+ {header}
+ </header>
+ <main className={classNames('py-5 px-6 w-full h-full', mainClassName)}>
+ {children}
+ </main>
+ </div>
+ </div>
+})
+PreviewContainer.displayName = 'PreviewContainer'
diff --git a/app/components/datasets/preview/header.tsx b/app/components/datasets/preview/header.tsx
new file mode 100644
index 0000000..eb3cd46
--- /dev/null
+++ b/app/components/datasets/preview/header.tsx
@@ -0,0 +1,23 @@
+import type { ComponentProps, FC } from 'react'
+import classNames from '@/utils/classnames'
+
+export type PreviewHeaderProps = Omit<ComponentProps<'div'>, 'title'> & {
+ title: string
+}
+
+export const PreviewHeader: FC<PreviewHeaderProps> = (props) => {
+ const { title, className, children, ...rest } = props
+ return <div
+ {...rest}
+ className={classNames(
+ className,
+ )}
+ >
+ <div
+ className='system-2xs-semibold-uppercase mb-1 px-1 uppercase text-text-accent'
+ >
+ {title}
+ </div>
+ {children}
+ </div>
+}
diff --git a/app/components/datasets/preview/index.tsx b/app/components/datasets/preview/index.tsx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/components/datasets/preview/index.tsx
diff --git a/app/components/datasets/rename-modal/index.tsx b/app/components/datasets/rename-modal/index.tsx
new file mode 100644
index 0000000..dd53baf
--- /dev/null
+++ b/app/components/datasets/rename-modal/index.tsx
@@ -0,0 +1,110 @@
+'use client'
+
+import type { MouseEventHandler } from 'react'
+import { useState } from 'react'
+import { RiCloseLine } from '@remixicon/react'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import Modal from '@/app/components/base/modal'
+import { ToastContext } from '@/app/components/base/toast'
+import type { DataSet } from '@/models/datasets'
+import { updateDatasetSetting } from '@/service/datasets'
+import { noop } from 'lodash-es'
+
+type RenameDatasetModalProps = {
+ show: boolean
+ dataset: DataSet
+ onSuccess?: () => void
+ onClose: () => void
+}
+
+const RenameDatasetModal = ({ show, dataset, onSuccess, onClose }: RenameDatasetModalProps) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const [loading, setLoading] = useState(false)
+ const [name, setName] = useState<string>(dataset.name)
+ const [description, setDescription] = useState<string>(dataset.description)
+ const [externalKnowledgeId, setExternalKnowledgeId] = useState<string>(dataset.external_knowledge_info.external_knowledge_id)
+ const [externalKnowledgeApiId, setExternalKnowledgeApiId] = useState<string>(dataset.external_knowledge_info.external_knowledge_api_id)
+
+ const onConfirm: MouseEventHandler = async () => {
+ if (!name.trim()) {
+ notify({ type: 'error', message: t('datasetSettings.form.nameError') })
+ return
+ }
+ try {
+ setLoading(true)
+ const body: Partial<DataSet> & { external_knowledge_id?: string; external_knowledge_api_id?: string } = {
+ name,
+ description,
+ }
+ if (externalKnowledgeId && externalKnowledgeApiId) {
+ body.external_knowledge_id = externalKnowledgeId
+ body.external_knowledge_api_id = externalKnowledgeApiId
+ }
+ await updateDatasetSetting({
+ datasetId: dataset.id,
+ body,
+ })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ if (onSuccess)
+ onSuccess()
+ onClose()
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ return (
+ <Modal
+ className='w-[520px] max-w-[520px] rounded-xl px-8 py-6'
+ isShow={show}
+ onClose={noop}
+ >
+ <div className='relative pb-2 text-xl font-medium leading-[30px] text-text-primary'>{t('datasetSettings.title')}</div>
+ <div className='absolute right-4 top-4 cursor-pointer p-2' onClick={onClose}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div>
+ <div className={cn('flex flex-wrap items-center justify-between py-4')}>
+ <div className='shrink-0 py-2 text-sm font-medium leading-[20px] text-text-primary'>
+ {t('datasetSettings.form.name')}
+ </div>
+ <Input
+ value={name}
+ onChange={e => setName(e.target.value)}
+ className='h-9'
+ placeholder={t('datasetSettings.form.namePlaceholder') || ''}
+ />
+ </div>
+ <div className={cn('flex flex-wrap items-center justify-between py-4')}>
+ <div className='shrink-0 py-2 text-sm font-medium leading-[20px] text-text-primary'>
+ {t('datasetSettings.form.desc')}
+ </div>
+ <div className='w-full'>
+ <Textarea
+ value={description}
+ onChange={e => setDescription(e.target.value)}
+ className='resize-none'
+ placeholder={t('datasetSettings.form.descPlaceholder') || ''}
+ />
+ </div>
+ </div>
+ </div>
+ <div className='flex justify-end pt-6'>
+ <Button className='mr-2' onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button disabled={loading} variant="primary" onClick={onConfirm}>{t('common.operation.save')}</Button>
+ </div>
+ </Modal>
+ )
+}
+
+export default RenameDatasetModal
diff --git a/app/components/datasets/settings/form/index.tsx b/app/components/datasets/settings/form/index.tsx
new file mode 100644
index 0000000..c36c16c
--- /dev/null
+++ b/app/components/datasets/settings/form/index.tsx
@@ -0,0 +1,354 @@
+'use client'
+import { useState } from 'react'
+import { useMount } from 'ahooks'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { useSWRConfig } from 'swr'
+import { unstable_serialize } from 'swr/infinite'
+import PermissionSelector from '../permission-selector'
+import IndexMethodRadio from '../index-method-radio'
+import RetrievalSettings from '../../external-knowledge-base/create/RetrievalSettings'
+import { IndexingType } from '../../create/step-two'
+import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
+import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
+import { ToastContext } from '@/app/components/base/toast'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
+import { updateDatasetSetting } from '@/service/datasets'
+import { type DataSetListResponse, DatasetPermission } from '@/models/datasets'
+import DatasetDetailContext from '@/context/dataset-detail'
+import type { RetrievalConfig } from '@/types/app'
+import { useAppContext } from '@/context/app-context'
+import { isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
+import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
+import {
+ useModelList,
+ useModelListAndDefaultModelAndCurrentProviderAndModel,
+} from '@/app/components/header/account-setting/model-provider-page/hooks'
+import type { DefaultModel } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { fetchMembers } from '@/service/common'
+import type { Member } from '@/models/common'
+import AlertTriangle from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle'
+
+const rowClass = 'flex'
+const labelClass = `
+ flex items-center shrink-0 w-[180px] h-9
+`
+
+const getKey = (pageIndex: number, previousPageData: DataSetListResponse) => {
+ if (!pageIndex || previousPageData.has_more)
+ return { url: 'datasets', params: { page: pageIndex + 1, limit: 30 } }
+ return null
+}
+
+const Form = () => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const { mutate } = useSWRConfig()
+ const { isCurrentWorkspaceDatasetOperator } = useAppContext()
+ const { dataset: currentDataset, mutateDatasetRes: mutateDatasets } = useContext(DatasetDetailContext)
+ const [loading, setLoading] = useState(false)
+ const [name, setName] = useState(currentDataset?.name ?? '')
+ const [description, setDescription] = useState(currentDataset?.description ?? '')
+ const [permission, setPermission] = useState(currentDataset?.permission)
+ const [topK, setTopK] = useState(currentDataset?.external_retrieval_model.top_k ?? 2)
+ const [scoreThreshold, setScoreThreshold] = useState(currentDataset?.external_retrieval_model.score_threshold ?? 0.5)
+ const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(currentDataset?.external_retrieval_model.score_threshold_enabled ?? false)
+ const [selectedMemberIDs, setSelectedMemberIDs] = useState<string[]>(currentDataset?.partial_member_list || [])
+ const [memberList, setMemberList] = useState<Member[]>([])
+ const [indexMethod, setIndexMethod] = useState(currentDataset?.indexing_technique)
+ const [retrievalConfig, setRetrievalConfig] = useState(currentDataset?.retrieval_model_dict as RetrievalConfig)
+ const [embeddingModel, setEmbeddingModel] = useState<DefaultModel>(
+ currentDataset?.embedding_model
+ ? {
+ provider: currentDataset.embedding_model_provider,
+ model: currentDataset.embedding_model,
+ }
+ : {
+ provider: '',
+ model: '',
+ },
+ )
+ const {
+ modelList: rerankModelList,
+ } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
+ const { data: embeddingModelList } = useModelList(ModelTypeEnum.textEmbedding)
+
+ const getMembers = async () => {
+ const { accounts } = await fetchMembers({ url: '/workspaces/current/members', params: {} })
+ if (!accounts)
+ setMemberList([])
+ else
+ setMemberList(accounts)
+ }
+
+ const handleSettingsChange = (data: { top_k?: number; score_threshold?: number; score_threshold_enabled?: boolean }) => {
+ if (data.top_k !== undefined)
+ setTopK(data.top_k)
+ if (data.score_threshold !== undefined)
+ setScoreThreshold(data.score_threshold)
+ if (data.score_threshold_enabled !== undefined)
+ setScoreThresholdEnabled(data.score_threshold_enabled)
+ }
+
+ useMount(() => {
+ getMembers()
+ })
+
+ const handleSave = async () => {
+ if (loading)
+ return
+ if (!name?.trim()) {
+ notify({ type: 'error', message: t('datasetSettings.form.nameError') })
+ return
+ }
+ if (
+ !isReRankModelSelected({
+ rerankModelList,
+ retrievalConfig,
+ indexMethod,
+ })
+ ) {
+ notify({ type: 'error', message: t('appDebug.datasetConfig.rerankModelRequired') })
+ return
+ }
+ if (retrievalConfig.weights) {
+ retrievalConfig.weights.vector_setting.embedding_provider_name = currentDataset?.embedding_model_provider || ''
+ retrievalConfig.weights.vector_setting.embedding_model_name = currentDataset?.embedding_model || ''
+ }
+ try {
+ setLoading(true)
+ const requestParams = {
+ datasetId: currentDataset!.id,
+ body: {
+ name,
+ description,
+ permission,
+ indexing_technique: indexMethod,
+ retrieval_model: {
+ ...retrievalConfig,
+ score_threshold: retrievalConfig.score_threshold_enabled ? retrievalConfig.score_threshold : 0,
+ },
+ embedding_model: embeddingModel.model,
+ embedding_model_provider: embeddingModel.provider,
+ ...(currentDataset!.provider === 'external' && {
+ external_knowledge_id: currentDataset!.external_knowledge_info.external_knowledge_id,
+ external_knowledge_api_id: currentDataset!.external_knowledge_info.external_knowledge_api_id,
+ external_retrieval_model: {
+ top_k: topK,
+ score_threshold: scoreThreshold,
+ score_threshold_enabled: scoreThresholdEnabled,
+ },
+ }),
+ },
+ } as any
+ if (permission === DatasetPermission.partialMembers) {
+ requestParams.body.partial_member_list = selectedMemberIDs.map((id) => {
+ return {
+ user_id: id,
+ role: memberList.find(member => member.id === id)?.role,
+ }
+ })
+ }
+ await updateDatasetSetting(requestParams)
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ if (mutateDatasets) {
+ await mutateDatasets()
+ mutate(unstable_serialize(getKey))
+ }
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ return (
+ <div className='flex w-full flex-col gap-y-4 px-14 py-8 sm:w-[880px]'>
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.name')}</div>
+ </div>
+ <div className='grow'>
+ <Input
+ disabled={!currentDataset?.embedding_available}
+ className='h-9'
+ value={name}
+ onChange={e => setName(e.target.value)}
+ />
+ </div>
+ </div>
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.desc')}</div>
+ </div>
+ <div className='grow'>
+ <Textarea
+ disabled={!currentDataset?.embedding_available}
+ className='h-[120px] resize-none'
+ placeholder={t('datasetSettings.form.descPlaceholder') || ''}
+ value={description}
+ onChange={e => setDescription(e.target.value)}
+ />
+ </div>
+ </div>
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.permissions')}</div>
+ </div>
+ <div className='grow'>
+ <PermissionSelector
+ disabled={!currentDataset?.embedding_available || isCurrentWorkspaceDatasetOperator}
+ permission={permission}
+ value={selectedMemberIDs}
+ onChange={v => setPermission(v)}
+ onMemberSelect={setSelectedMemberIDs}
+ memberList={memberList}
+ />
+ </div>
+ </div>
+ {currentDataset && currentDataset.indexing_technique && (
+ <>
+ <div className='my-1 h-0 w-full border-b border-divider-subtle' />
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.indexMethod')}</div>
+ </div>
+ <div className='grow'>
+ <IndexMethodRadio
+ disable={!currentDataset?.embedding_available}
+ value={indexMethod}
+ onChange={v => setIndexMethod(v!)}
+ docForm={currentDataset.doc_form}
+ currentValue={currentDataset.indexing_technique}
+ />
+ {currentDataset.indexing_technique === IndexingType.ECONOMICAL && indexMethod === IndexingType.QUALIFIED && <div className='mt-2 flex h-10 items-center gap-x-0.5 overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-2 shadow-xs backdrop-blur-[5px]'>
+ <div className='absolute bottom-0 left-0 right-0 top-0 bg-[linear-gradient(92deg,rgba(247,144,9,0.25)_0%,rgba(255,255,255,0.00)_100%)] opacity-40'></div>
+ <div className='p-1'>
+ <AlertTriangle className='size-4 text-text-warning-secondary' />
+ </div>
+ <span className='system-xs-medium'>{t('datasetSettings.form.upgradeHighQualityTip')}</span>
+ </div>}
+ </div>
+ </div>
+ </>
+ )}
+ {indexMethod === 'high_quality' && (
+ <>
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.embeddingModel')}</div>
+ </div>
+ <div className='grow'>
+ <ModelSelector
+ triggerClassName=''
+ defaultModel={embeddingModel}
+ modelList={embeddingModelList}
+ onSelect={(model: DefaultModel) => {
+ setEmbeddingModel(model)
+ }}
+ />
+ </div>
+ </div>
+ </>
+ )}
+ {/* Retrieval Method Config */}
+ {currentDataset?.provider === 'external'
+ ? <>
+ <div className='my-1 h-0 w-full border-b border-divider-subtle' />
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
+ </div>
+ <RetrievalSettings
+ topK={topK}
+ scoreThreshold={scoreThreshold}
+ scoreThresholdEnabled={scoreThresholdEnabled}
+ onChange={handleSettingsChange}
+ isInRetrievalSetting={true}
+ />
+ </div>
+ <div className='my-1 h-0 w-full border-b border-divider-subtle' />
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.externalKnowledgeAPI')}</div>
+ </div>
+ <div className='w-full'>
+ <div className='flex h-full items-center gap-1 rounded-lg bg-components-input-bg-normal px-3 py-2'>
+ <ApiConnectionMod className='h-4 w-4 text-text-secondary' />
+ <div className='system-sm-medium overflow-hidden text-ellipsis text-text-secondary'>
+ {currentDataset?.external_knowledge_info.external_knowledge_api_name}
+ </div>
+ <div className='system-xs-regular text-text-tertiary'>路</div>
+ <div className='system-xs-regular text-text-tertiary'>{currentDataset?.external_knowledge_info.external_knowledge_api_endpoint}</div>
+ </div>
+ </div>
+ </div>
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.externalKnowledgeID')}</div>
+ </div>
+ <div className='w-full'>
+ <div className='flex h-full items-center gap-1 rounded-lg bg-components-input-bg-normal px-3 py-2'>
+ <div className='system-xs-regular text-text-tertiary'>{currentDataset?.external_knowledge_info.external_knowledge_id}</div>
+ </div>
+ </div>
+ </div>
+ </>
+ : indexMethod
+ ? <>
+ <div className='my-1 h-0 w-full border-b border-divider-subtle' />
+ <div className={rowClass}>
+ <div className={labelClass}>
+ <div>
+ <div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
+ <div className='body-xs-regular text-text-tertiary'>
+ <a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
+ {t('datasetSettings.form.retrievalSetting.description')}
+ </div>
+ </div>
+ </div>
+ <div className='grow'>
+ {indexMethod === IndexingType.QUALIFIED
+ ? (
+ <RetrievalMethodConfig
+ value={retrievalConfig}
+ onChange={setRetrievalConfig}
+ />
+ )
+ : (
+ <EconomicalRetrievalMethodConfig
+ value={retrievalConfig}
+ onChange={setRetrievalConfig}
+ />
+ )}
+ </div>
+ </div>
+ </>
+ : null
+ }
+ <div className='my-1 h-0 w-full border-b border-divider-subtle' />
+ <div className={rowClass}>
+ <div className={labelClass} />
+ <div className='grow'>
+ <Button
+ className='min-w-24'
+ variant='primary'
+ loading={loading}
+ disabled={loading}
+ onClick={handleSave}
+ >
+ {t('datasetSettings.form.save')}
+ </Button>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default Form
diff --git a/app/components/datasets/settings/index-method-radio/assets/economy.svg b/app/components/datasets/settings/index-method-radio/assets/economy.svg
new file mode 100644
index 0000000..6b135bf
--- /dev/null
+++ b/app/components/datasets/settings/index-method-radio/assets/economy.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="8" fill="#EEF4FF"/>
+<path d="M11.6665 9.99998C12.9552 9.99998 13.9998 8.95531 13.9998 7.66665C13.9998 6.37798 12.9552 5.33331 11.6665 5.33331C10.3778 5.33331 9.33317 6.37798 9.33317 7.66665C9.33317 8.95531 10.3778 9.99998 11.6665 9.99998Z" fill="#444CE7"/>
+<path d="M8.65017 9.75198C8.49106 9.52227 8.4115 9.40741 8.32581 9.36947C8.24888 9.33541 8.1679 9.33124 8.08788 9.35723C7.99875 9.38618 7.92865 9.46797 7.78845 9.63154C7.22585 10.2879 6.84213 11.1027 6.71374 12.0001H6.6665C6.29831 12.0001 5.99984 11.7016 5.99984 11.3334C5.99984 11.0875 6.13265 10.8718 6.33365 10.7555C6.65236 10.5712 6.76127 10.1634 6.57691 9.84466C6.39255 9.52595 5.98473 9.41704 5.66602 9.60141C5.06996 9.94621 4.6665 10.5923 4.6665 11.3334C4.6665 12.438 5.56193 13.3334 6.6665 13.3334H6.71377C6.85773 14.3389 7.32239 15.2415 7.9998 15.9328L7.99979 17.4822C7.99976 17.5616 7.99973 17.6565 8.00655 17.74C8.01446 17.8368 8.03476 17.9755 8.10879 18.1208C8.20466 18.309 8.35764 18.4619 8.54581 18.5578C8.6911 18.6318 8.82976 18.6521 8.92658 18.6601C9.0101 18.6669 9.10492 18.6668 9.18432 18.6668H10.4819C10.5613 18.6668 10.6562 18.6669 10.7397 18.6601C10.8365 18.6521 10.9752 18.6318 11.1205 18.5578C11.3086 18.4619 11.4616 18.309 11.5575 18.1208C11.6315 17.9755 11.6518 17.8368 11.6597 17.74C11.6665 17.6565 11.6665 17.5616 11.6665 17.4822L11.6665 17.3335H12.3331L12.3331 17.482C12.3331 17.5614 12.3331 17.6562 12.3399 17.7398C12.3478 17.8366 12.3681 17.9753 12.4421 18.1205C12.538 18.3087 12.691 18.4617 12.8791 18.5576C13.0244 18.6316 13.1631 18.6519 13.2599 18.6598C13.3434 18.6666 13.4382 18.6666 13.5176 18.6666H14.8153C14.8947 18.6666 14.9896 18.6666 15.0731 18.6598C15.1699 18.6519 15.3085 18.6316 15.4538 18.5576C15.642 18.4617 15.795 18.3087 15.8909 18.1205C15.9649 17.9753 15.9852 17.8366 15.9931 17.7398C15.9999 17.6562 15.9999 17.5614 15.9999 17.482L15.9999 16.884C16.7373 16.5337 17.3676 15.9963 17.83 15.3332L18.1486 15.3332C18.228 15.3333 18.3229 15.3333 18.4064 15.3265C18.5032 15.3186 18.6419 15.2983 18.7872 15.2242C18.9753 15.1284 19.1283 14.9754 19.2242 14.7872C19.2982 14.6419 19.3185 14.5033 19.3264 14.4064C19.3333 14.3229 19.3332 14.2281 19.3332 14.1487V11.8424C19.3332 11.7668 19.3332 11.6765 19.327 11.5968C19.3199 11.5047 19.3015 11.3725 19.2341 11.2326C19.1358 11.0286 18.9712 10.8639 18.7671 10.7656C18.6272 10.6982 18.4951 10.6799 18.403 10.6727C18.3435 10.6681 18.2781 10.6669 18.2173 10.6666C17.9935 10.1955 17.6934 9.76819 17.3332 9.40057L17.3332 8.68818C17.3332 8.58496 17.3333 8.46813 17.3243 8.36763C17.3144 8.25667 17.2886 8.08512 17.1832 7.91509C17.0519 7.70309 16.846 7.54783 16.6061 7.47976C16.4137 7.42517 16.2416 7.44747 16.1322 7.46844C16.0331 7.48743 15.9208 7.51956 15.8216 7.54795L15.7177 7.57763C15.581 7.61667 15.5127 7.6362 15.4646 7.67139C15.4182 7.70536 15.3899 7.73885 15.364 7.7902C15.3371 7.84338 15.3279 7.92449 15.3094 8.08672C15.101 9.91393 13.5495 11.3333 11.6665 11.3333C10.4162 11.3333 9.31201 10.7075 8.65017 9.75198Z" fill="#444CE7"/>
+</svg>
diff --git a/app/components/datasets/settings/index-method-radio/assets/high-quality.svg b/app/components/datasets/settings/index-method-radio/assets/high-quality.svg
new file mode 100644
index 0000000..dcb9aa2
--- /dev/null
+++ b/app/components/datasets/settings/index-method-radio/assets/high-quality.svg
@@ -0,0 +1,12 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="8" fill="#FFF6ED"/>
+<path d="M11.9998 4.66669C12.368 4.66669 12.6665 4.96516 12.6665 5.33335V6.66669C12.6665 7.03488 12.368 7.33335 11.9998 7.33335C11.6316 7.33335 11.3332 7.03488 11.3332 6.66669V5.33335C11.3332 4.96516 11.6316 4.66669 11.9998 4.66669Z" fill="#FB6514"/>
+<path d="M7.75705 6.81459C7.4967 6.55424 7.07459 6.55424 6.81424 6.81459C6.55389 7.07494 6.55389 7.49705 6.81424 7.75739L7.75705 8.7002C8.0174 8.96055 8.43951 8.96055 8.69986 8.7002C8.96021 8.43985 8.96021 8.01774 8.69986 7.75739L7.75705 6.81459Z" fill="#FB6514"/>
+<path d="M4.6665 12C4.6665 11.6318 4.96498 11.3334 5.33317 11.3334H6.6665C7.03469 11.3334 7.33317 11.6318 7.33317 12C7.33317 12.3682 7.03469 12.6667 6.6665 12.6667H5.33317C4.96498 12.6667 4.6665 12.3682 4.6665 12Z" fill="#FB6514"/>
+<path d="M17.3332 11.3334C16.965 11.3334 16.6665 11.6318 16.6665 12C16.6665 12.3682 16.965 12.6667 17.3332 12.6667H18.6665C19.0347 12.6667 19.3332 12.3682 19.3332 12C19.3332 11.6318 19.0347 11.3334 18.6665 11.3334H17.3332Z" fill="#FB6514"/>
+<path d="M16.2424 15.2998C15.982 15.0394 15.5599 15.0394 15.2996 15.2998C15.0392 15.5601 15.0392 15.9822 15.2996 16.2426L16.2424 17.1854C16.5027 17.4457 16.9249 17.4457 17.1852 17.1854C17.4456 16.925 17.4456 16.5029 17.1852 16.2426L16.2424 15.2998Z" fill="#FB6514"/>
+<path d="M17.1852 7.75739C17.4456 7.49705 17.4456 7.07494 17.1852 6.81459C16.9249 6.55424 16.5027 6.55424 16.2424 6.81459L15.2996 7.75739C15.0392 8.01774 15.0392 8.43985 15.2996 8.7002C15.5599 8.96055 15.982 8.96055 16.2424 8.7002L17.1852 7.75739Z" fill="#FB6514"/>
+<path d="M11.9998 16.6667C12.368 16.6667 12.6665 16.9652 12.6665 17.3334V18.6667C12.6665 19.0349 12.368 19.3334 11.9998 19.3334C11.6316 19.3334 11.3332 19.0349 11.3332 18.6667V17.3334C11.3332 16.9652 11.6316 16.6667 11.9998 16.6667Z" fill="#FB6514"/>
+<path d="M8.69986 16.2426C8.96021 15.9822 8.96021 15.5601 8.69986 15.2998C8.43951 15.0394 8.0174 15.0394 7.75705 15.2998L6.81424 16.2426C6.55389 16.5029 6.55389 16.925 6.81424 17.1854C7.07459 17.4457 7.4967 17.4457 7.75705 17.1854L8.69986 16.2426Z" fill="#FB6514"/>
+<path d="M12.5977 8.3716C12.4853 8.14407 12.2536 8.00002 11.9999 8.00002C11.7461 8.00002 11.5144 8.14407 11.4021 8.3716L10.527 10.1443L8.5701 10.4304C8.31906 10.4671 8.11061 10.6431 8.03236 10.8844C7.95411 11.1257 8.01962 11.3906 8.20137 11.5676L9.61684 12.9463L9.28278 14.894C9.23988 15.1441 9.34271 15.3969 9.54803 15.5461C9.75335 15.6952 10.0255 15.7149 10.2502 15.5967L11.9999 14.6766L13.7496 15.5967C13.9742 15.7149 14.2464 15.6952 14.4517 15.5461C14.657 15.3969 14.7598 15.1441 14.7169 14.894L14.3829 12.9463L15.7983 11.5676C15.9801 11.3906 16.0456 11.1257 15.9674 10.8844C15.8891 10.6431 15.6806 10.4671 15.4296 10.4304L13.4727 10.1443L12.5977 8.3716Z" fill="#FB6514"/>
+</svg>
diff --git a/app/components/datasets/settings/index-method-radio/index.tsx b/app/components/datasets/settings/index-method-radio/index.tsx
new file mode 100644
index 0000000..f0d2b32
--- /dev/null
+++ b/app/components/datasets/settings/index-method-radio/index.tsx
@@ -0,0 +1,106 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import Image from 'next/image'
+import { useRef } from 'react'
+import { useHover } from 'ahooks'
+import { IndexingType } from '../../create/step-two'
+import { OptionCard } from '../../create/step-two/option-card'
+import { indexMethodIcon } from '../../create/icons'
+import classNames from '@/utils/classnames'
+import type { DataSet } from '@/models/datasets'
+import { ChunkingMode } from '@/models/datasets'
+import Badge from '@/app/components/base/badge'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
+
+type IIndexMethodRadioProps = {
+ value?: DataSet['indexing_technique']
+ onChange: (v?: DataSet['indexing_technique']) => void
+ disable?: boolean
+ docForm?: ChunkingMode
+ currentValue?: DataSet['indexing_technique']
+}
+
+const IndexMethodRadio = ({
+ value,
+ onChange,
+ disable,
+ docForm,
+ currentValue,
+}: IIndexMethodRadioProps) => {
+ const { t } = useTranslation()
+ const economyDomRef = useRef<HTMLDivElement>(null)
+ const isHoveringEconomy = useHover(economyDomRef)
+ const isEconomyDisabled = currentValue === IndexingType.QUALIFIED
+ const options = [
+ {
+ key: 'high_quality',
+ text: <div className='flex items-center'>
+ {t('datasetCreation.stepTwo.qualified')}
+ <Badge uppercase className='ml-auto border-text-accent-secondary text-text-accent-secondary'>
+ {t('datasetCreation.stepTwo.recommend')}
+ </Badge>
+ </div>,
+ desc: t('datasetSettings.form.indexMethodHighQualityTip'),
+ },
+ {
+ key: 'economy',
+ text: t('datasetSettings.form.indexMethodEconomy'),
+ desc: t('datasetSettings.form.indexMethodEconomyTip'),
+ },
+ ]
+
+ return (
+ <div className={classNames('flex justify-between w-full gap-2')}>
+ {
+ options.map((option) => {
+ const isParentChild = docForm === ChunkingMode.parentChild
+ return (
+ <PortalToFollowElem
+ key={option.key}
+ open={
+ isHoveringEconomy && option.key === 'economy'
+ }
+ placement={'top'}
+ >
+ <PortalToFollowElemTrigger>
+ <OptionCard
+ disabled={
+ disable
+ || (isEconomyDisabled && option.key === IndexingType.ECONOMICAL)
+ }
+ isActive={option.key === value}
+ onSwitched={() => {
+ if (isParentChild && option.key === IndexingType.ECONOMICAL)
+ return
+ if (isEconomyDisabled && option.key === IndexingType.ECONOMICAL)
+ return
+ if (!disable)
+ onChange(option.key as DataSet['indexing_technique'])
+ } }
+ icon={
+ <Image
+ src={option.key === 'high_quality' ? indexMethodIcon.high_quality : indexMethodIcon.economical}
+ alt={option.desc}
+ />
+ }
+ title={option.text}
+ description={option.desc}
+ ref={option.key === 'economy' ? economyDomRef : undefined}
+ className={classNames((isEconomyDisabled && option.key === 'economy') && 'cursor-not-allowed')}
+ >
+ </OptionCard>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent style={{ zIndex: 60 }}>
+ <div className='rounded-lg border-components-panel-border bg-components-tooltip-bg p-3 text-xs font-medium text-text-secondary shadow-lg'>
+ {t('datasetSettings.form.indexMethodChangeToEconomyDisabledTip')}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+ })
+ }
+ </div>
+ )
+}
+
+export default IndexMethodRadio
diff --git a/app/components/datasets/settings/permission-selector/index.tsx b/app/components/datasets/settings/permission-selector/index.tsx
new file mode 100644
index 0000000..9bb6f81
--- /dev/null
+++ b/app/components/datasets/settings/permission-selector/index.tsx
@@ -0,0 +1,195 @@
+import { useTranslation } from 'react-i18next'
+import cn from 'classnames'
+import React, { useMemo, useState } from 'react'
+import { useDebounceFn } from 'ahooks'
+import { RiArrowDownSLine } from '@remixicon/react'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import Avatar from '@/app/components/base/avatar'
+import Input from '@/app/components/base/input'
+import { Check } from '@/app/components/base/icons/src/vender/line/general'
+import { Users01, UsersPlus } from '@/app/components/base/icons/src/vender/solid/users'
+import { DatasetPermission } from '@/models/datasets'
+import { useAppContext } from '@/context/app-context'
+import type { Member } from '@/models/common'
+export type RoleSelectorProps = {
+ disabled?: boolean
+ permission?: DatasetPermission
+ value: string[]
+ memberList: Member[]
+ onChange: (permission?: DatasetPermission) => void
+ onMemberSelect: (v: string[]) => void
+}
+
+const PermissionSelector = ({ disabled, permission, value, memberList, onChange, onMemberSelect }: RoleSelectorProps) => {
+ const { t } = useTranslation()
+ const { userProfile } = useAppContext()
+ const [open, setOpen] = useState(false)
+
+ const [keywords, setKeywords] = useState('')
+ const [searchKeywords, setSearchKeywords] = useState('')
+ const { run: handleSearch } = useDebounceFn(() => {
+ setSearchKeywords(keywords)
+ }, { wait: 500 })
+ const handleKeywordsChange = (value: string) => {
+ setKeywords(value)
+ handleSearch()
+ }
+ const selectMember = (member: Member) => {
+ if (value.includes(member.id))
+ onMemberSelect(value.filter(v => v !== member.id))
+ else
+ onMemberSelect([...value, member.id])
+ }
+
+ const selectedMembers = useMemo(() => {
+ return [
+ userProfile,
+ ...memberList.filter(member => member.id !== userProfile.id).filter(member => value.includes(member.id)),
+ ].map(member => member.name).join(', ')
+ }, [userProfile, value, memberList])
+
+ const showMe = useMemo(() => {
+ return userProfile.name.includes(searchKeywords) || userProfile.email.includes(searchKeywords)
+ }, [searchKeywords, userProfile])
+
+ const filteredMemberList = useMemo(() => {
+ return memberList.filter(member => (member.name.includes(searchKeywords) || member.email.includes(searchKeywords)) && member.id !== userProfile.id && ['owner', 'admin', 'editor', 'dataset_operator'].includes(member.role))
+ }, [memberList, searchKeywords, userProfile])
+
+ const isOnlyMe = permission === DatasetPermission.onlyMe
+ const isAllTeamMembers = permission === DatasetPermission.allTeamMembers
+ const isPartialMembers = permission === DatasetPermission.partialMembers
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <div className='relative'>
+ <PortalToFollowElemTrigger
+ onClick={() => !disabled && setOpen(v => !v)}
+ className='block'
+ >
+ <div className={cn('flex cursor-pointer items-center rounded-lg bg-components-input-bg-normal px-3 py-[6px] hover:bg-state-base-hover-alt',
+ open && 'bg-state-base-hover-alt',
+ disabled && '!cursor-not-allowed !bg-components-input-bg-disabled hover:!bg-components-input-bg-disabled',
+ )}>
+ {
+ isOnlyMe && (
+ <>
+ <Avatar avatar={userProfile.avatar_url} name={userProfile.name} className='mr-2 shrink-0' size={24} />
+ <div className='mr-2 grow text-sm leading-5 text-components-input-text-filled'>{t('datasetSettings.form.permissionsOnlyMe')}</div>
+ </>
+ )
+ }
+ {
+ isAllTeamMembers && (
+ <>
+ <div className='mr-2 flex h-6 w-6 items-center justify-center rounded-lg bg-[#EEF4FF]'>
+ <Users01 className='h-3.5 w-3.5 text-[#444CE7]' />
+ </div>
+ <div className='mr-2 grow text-sm leading-5 text-components-input-text-filled'>{t('datasetSettings.form.permissionsAllMember')}</div>
+ </>
+ )
+ }
+ {
+ isPartialMembers && (
+ <>
+ <div className='mr-2 flex h-6 w-6 items-center justify-center rounded-lg bg-[#EEF4FF]'>
+ <Users01 className='h-3.5 w-3.5 text-[#444CE7]' />
+ </div>
+ <div title={selectedMembers} className='mr-2 grow truncate text-sm leading-5 text-components-input-text-filled'>{selectedMembers}</div>
+ </>
+ )
+ }
+ <RiArrowDownSLine className={cn('h-4 w-4 shrink-0 text-text-secondary', disabled && '!text-components-input-text-placeholder')} />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1002]'>
+ <div className='relative w-[480px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm'>
+ <div className='p-1'>
+ <div className='cursor-pointer rounded-lg py-1 pl-3 pr-2 hover:bg-state-base-hover' onClick={() => {
+ onChange(DatasetPermission.onlyMe)
+ setOpen(false)
+ }}>
+ <div className='flex items-center gap-2'>
+ <Avatar avatar={userProfile.avatar_url} name={userProfile.name} className='mr-2 shrink-0' size={24} />
+ <div className='mr-2 grow text-sm leading-5 text-text-primary'>{t('datasetSettings.form.permissionsOnlyMe')}</div>
+ {isOnlyMe && <Check className='h-4 w-4 text-primary-600' />}
+ </div>
+ </div>
+ <div className='cursor-pointer rounded-lg py-1 pl-3 pr-2 hover:bg-state-base-hover' onClick={() => {
+ onChange(DatasetPermission.allTeamMembers)
+ setOpen(false)
+ }}>
+ <div className='flex items-center gap-2'>
+ <div className='mr-2 flex h-6 w-6 items-center justify-center rounded-lg bg-[#EEF4FF]'>
+ <Users01 className='h-3.5 w-3.5 text-[#444CE7]' />
+ </div>
+ <div className='mr-2 grow text-sm leading-5 text-text-primary'>{t('datasetSettings.form.permissionsAllMember')}</div>
+ {isAllTeamMembers && <Check className='h-4 w-4 text-primary-600' />}
+ </div>
+ </div>
+ <div className='cursor-pointer rounded-lg py-1 pl-3 pr-2 hover:bg-state-base-hover' onClick={() => {
+ onChange(DatasetPermission.partialMembers)
+ onMemberSelect([userProfile.id])
+ }}>
+ <div className='flex items-center gap-2'>
+ <div className={cn('mr-2 flex h-6 w-6 items-center justify-center rounded-lg bg-[#FFF6ED]', isPartialMembers && '!bg-[#EEF4FF]')}>
+ <UsersPlus className={cn('h-3.5 w-3.5 text-[#FB6514]', isPartialMembers && '!text-[#444CE7]')} />
+ </div>
+ <div className='mr-2 grow text-sm leading-5 text-text-primary'>{t('datasetSettings.form.permissionsInvitedMembers')}</div>
+ {isPartialMembers && <Check className='h-4 w-4 text-primary-600' />}
+ </div>
+ </div>
+ </div>
+ {isPartialMembers && (
+ <div className='max-h-[360px] overflow-y-auto border-t-[1px] border-divider-regular pb-1 pl-1 pr-1'>
+ <div className='sticky left-0 top-0 z-10 bg-white p-2 pb-1'>
+ <Input
+ showLeftIcon
+ showClearIcon
+ value={keywords}
+ onChange={e => handleKeywordsChange(e.target.value)}
+ onClear={() => handleKeywordsChange('')}
+ />
+ </div>
+ {showMe && (
+ <div className='flex items-center gap-2 rounded-lg py-1 pl-3 pr-[10px]'>
+ <Avatar avatar={userProfile.avatar_url} name={userProfile.name} className='shrink-0' size={24} />
+ <div className='grow'>
+ <div className='truncate text-[13px] font-medium leading-[18px] text-text-secondary'>
+ {userProfile.name}
+ <span className='text-xs font-normal text-text-tertiary'>{t('datasetSettings.form.me')}</span>
+ </div>
+ <div className='truncate text-xs leading-[18px] text-text-tertiary'>{userProfile.email}</div>
+ </div>
+ <Check className='h-4 w-4 shrink-0 text-text-accent opacity-30' />
+ </div>
+ )}
+ {filteredMemberList.map(member => (
+ <div key={member.id} className='flex cursor-pointer items-center gap-2 rounded-lg py-1 pl-3 pr-[10px] hover:bg-state-base-hover' onClick={() => selectMember(member)}>
+ <Avatar avatar={userProfile.avatar_url} name={member.name} className='shrink-0' size={24} />
+ <div className='grow'>
+ <div className='truncate text-[13px] font-medium leading-[18px] text-text-secondary'>{member.name}</div>
+ <div className='truncate text-xs leading-[18px] text-text-tertiary'>{member.email}</div>
+ </div>
+ {value.includes(member.id) && <Check className='h-4 w-4 shrink-0 text-text-accent' />}
+ </div>
+ ))}
+ </div>
+ )}
+ </div>
+ </PortalToFollowElemContent>
+ </div>
+ </PortalToFollowElem>
+ )
+}
+
+export default PermissionSelector
diff --git a/app/components/develop/ApiServer.tsx b/app/components/develop/ApiServer.tsx
new file mode 100644
index 0000000..9f2c9cf
--- /dev/null
+++ b/app/components/develop/ApiServer.tsx
@@ -0,0 +1,36 @@
+'use client'
+
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import CopyFeedback from '@/app/components/base/copy-feedback'
+import SecretKeyButton from '@/app/components/develop/secret-key/secret-key-button'
+
+type ApiServerProps = {
+ apiBaseUrl: string
+ appId?: string
+}
+const ApiServer: FC<ApiServerProps> = ({
+ apiBaseUrl,
+ appId,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='flex flex-wrap items-center gap-y-2'>
+ <div className='mr-2 flex h-8 items-center rounded-lg border-[0.5px] border-components-input-border-active bg-components-input-bg-normal pl-1.5 pr-1 leading-5'>
+ <div className='mr-0.5 h-5 shrink-0 rounded-md border border-divider-subtle px-1.5 text-[11px] text-text-tertiary'>{t('appApi.apiServer')}</div>
+ <div className='w-fit truncate px-1 text-[13px] font-medium text-text-secondary sm:w-[248px]'>{apiBaseUrl}</div>
+ <div className='mx-1 h-[14px] w-[1px] bg-divider-regular'></div>
+ <CopyFeedback content={apiBaseUrl}/>
+ </div>
+ <div className='mr-2 flex h-8 items-center rounded-lg border-[0.5px] border-[#D1FADF] bg-[#ECFDF3] px-3 text-xs font-semibold text-[#039855]'>
+ {t('appApi.ok')}
+ </div>
+ <SecretKeyButton
+ className='!h-8 shrink-0' appId={appId}
+ />
+ </div>
+ )
+}
+
+export default ApiServer
diff --git a/app/components/develop/code.tsx b/app/components/develop/code.tsx
new file mode 100644
index 0000000..d187d78
--- /dev/null
+++ b/app/components/develop/code.tsx
@@ -0,0 +1,305 @@
+'use client'
+import {
+ Children,
+ createContext,
+ useContext,
+ useEffect,
+ useRef,
+ useState,
+} from 'react'
+import { Tab, TabList, TabPanel, TabPanels } from '@headlessui/react'
+import { Tag } from './tag'
+import classNames from '@/utils/classnames'
+import { writeTextToClipboard } from '@/utils/clipboard'
+
+const languageNames = {
+ js: 'JavaScript',
+ ts: 'TypeScript',
+ javascript: 'JavaScript',
+ typescript: 'TypeScript',
+ php: 'PHP',
+ python: 'Python',
+ ruby: 'Ruby',
+ go: 'Go',
+} as { [key: string]: string }
+
+type IChildrenProps = {
+ children: React.ReactNode
+ [key: string]: any
+}
+
+function getPanelTitle({ className }: { className: string }) {
+ const language = className.split('-')[1]
+ return languageNames[language] ?? 'Code'
+}
+
+function ClipboardIcon(props: any) {
+ return (
+ <svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
+ <path
+ strokeWidth="0"
+ d="M5.5 13.5v-5a2 2 0 0 1 2-2l.447-.894A2 2 0 0 1 9.737 4.5h.527a2 2 0 0 1 1.789 1.106l.447.894a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2Z"
+ />
+ <path
+ fill="none"
+ strokeLinejoin="round"
+ d="M12.5 6.5a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2m5 0-.447-.894a2 2 0 0 0-1.79-1.106h-.527a2 2 0 0 0-1.789 1.106L7.5 6.5m5 0-1 1h-3l-1-1"
+ />
+ </svg>
+ )
+}
+
+function CopyButton({ code }: { code: string }) {
+ const [copyCount, setCopyCount] = useState(0)
+ const copied = copyCount > 0
+
+ useEffect(() => {
+ if (copyCount > 0) {
+ const timeout = setTimeout(() => setCopyCount(0), 1000)
+ return () => {
+ clearTimeout(timeout)
+ }
+ }
+ }, [copyCount])
+
+ return (
+ <button
+ type="button"
+ className={classNames(
+ 'group/button absolute top-3.5 right-4 overflow-hidden rounded-full py-1 pl-2 pr-3 text-2xs font-medium opacity-0 backdrop-blur transition focus:opacity-100 group-hover:opacity-100',
+ copied
+ ? 'bg-emerald-400/10 ring-1 ring-inset ring-emerald-400/20'
+ : 'bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5',
+ )}
+ onClick={() => {
+ writeTextToClipboard(code).then(() => {
+ setCopyCount(count => count + 1)
+ })
+ }}
+ >
+ <span
+ aria-hidden={copied}
+ className={classNames(
+ 'pointer-events-none flex items-center gap-0.5 text-zinc-400 transition duration-300',
+ copied && '-translate-y-1.5 opacity-0',
+ )}
+ >
+ <ClipboardIcon className="h-5 w-5 fill-zinc-500/20 stroke-zinc-500 transition-colors group-hover/button:stroke-zinc-400" />
+ Copy
+ </span>
+ <span
+ aria-hidden={!copied}
+ className={classNames(
+ 'pointer-events-none absolute inset-0 flex items-center justify-center text-emerald-400 transition duration-300',
+ !copied && 'translate-y-1.5 opacity-0',
+ )}
+ >
+ Copied!
+ </span>
+ </button>
+ )
+}
+
+function CodePanelHeader({ tag, label }: { tag: string; label: string }) {
+ if (!tag && !label)
+ return null
+
+ return (
+ <div className="border-b-white/7.5 bg-white/2.5 dark:bg-white/1 flex h-9 items-center gap-2 border-y border-t-transparent bg-zinc-900 px-4 dark:border-b-white/5">
+ {tag && (
+ <div className="dark flex">
+ <Tag variant="small">{tag}</Tag>
+ </div>
+ )}
+ {tag && label && (
+ <span className="h-0.5 w-0.5 rounded-full bg-zinc-500" />
+ )}
+ {label && (
+ <span className="font-mono text-xs text-zinc-400">{label}</span>
+ )}
+ </div>
+ )
+}
+
+type ICodePanelProps = {
+ children: React.ReactNode
+ tag?: string
+ code?: string
+ label?: string
+ targetCode?: string
+}
+function CodePanel({ tag, label, code, children, targetCode }: ICodePanelProps) {
+ const child = Children.only(children)
+
+ return (
+ <div className="dark:bg-white/2.5 group">
+ <CodePanelHeader
+ tag={child.props.tag ?? tag}
+ label={child.props.label ?? label}
+ />
+ <div className="relative">
+ {/* <pre className="p-4 overflow-x-auto text-xs text-white">{children}</pre> */}
+ {/* <CopyButton code={child.props.code ?? code} /> */}
+ {/* <CopyButton code={child.props.children.props.children} /> */}
+ <pre className="overflow-x-auto p-4 text-xs text-white">{targetCode || children}</pre>
+ <CopyButton code={targetCode || child.props.children.props.children} />
+ </div>
+ </div>
+ )
+}
+
+function CodeGroupHeader({ title, children, selectedIndex }: IChildrenProps) {
+ const hasTabs = Children.count(children) > 1
+
+ if (!title && !hasTabs)
+ return null
+
+ return (
+ <div className="flex min-h-[calc(theme(spacing.12)+1px)] flex-wrap items-start gap-x-4 border-b border-zinc-700 bg-zinc-800 px-4 dark:border-zinc-800 dark:bg-transparent">
+ {title && (
+ <h3 className="mr-auto pt-3 text-xs font-semibold text-white">
+ {title}
+ </h3>
+ )}
+ {hasTabs && (
+ <TabList className="-mb-px flex gap-4 text-xs font-medium">
+ {Children.map(children, (child, childIndex) => (
+ <Tab
+ className={classNames(
+ 'border-b py-3 transition focus:[&:not(:focus-visible)]:outline-none',
+ childIndex === selectedIndex
+ ? 'border-emerald-500 text-emerald-400'
+ : 'border-transparent text-zinc-400 hover:text-zinc-300',
+ )}
+ >
+ {getPanelTitle(child.props.children.props)}
+ </Tab>
+ ))}
+ </TabList>
+ )}
+ </div>
+ )
+}
+
+type ICodeGroupPanelsProps = {
+ children: React.ReactNode
+ [key: string]: any
+}
+function CodeGroupPanels({ children, targetCode, ...props }: ICodeGroupPanelsProps) {
+ const hasTabs = Children.count(children) > 1
+
+ if (hasTabs) {
+ return (
+ <TabPanels>
+ {Children.map(children, child => (
+ <TabPanel>
+ <CodePanel {...props}>{child}</CodePanel>
+ </TabPanel>
+ ))}
+ </TabPanels>
+ )
+ }
+
+ return <CodePanel {...props} targetCode={targetCode}>{children}</CodePanel>
+}
+
+function usePreventLayoutShift() {
+ const positionRef = useRef<any>()
+ const rafRef = useRef<any>()
+
+ useEffect(() => {
+ return () => {
+ window.cancelAnimationFrame(rafRef.current)
+ }
+ }, [])
+
+ return {
+ positionRef,
+ preventLayoutShift(callback: () => {}) {
+ const initialTop = positionRef.current.getBoundingClientRect().top
+
+ callback()
+
+ rafRef.current = window.requestAnimationFrame(() => {
+ const newTop = positionRef.current.getBoundingClientRect().top
+ window.scrollBy(0, newTop - initialTop)
+ })
+ },
+ }
+}
+
+function useTabGroupProps(availableLanguages: string[]) {
+ const [preferredLanguages, addPreferredLanguage] = useState<any>([])
+ const [selectedIndex, setSelectedIndex] = useState(0)
+ const activeLanguage = [...availableLanguages].sort(
+ (a, z) => preferredLanguages.indexOf(z) - preferredLanguages.indexOf(a),
+ )[0]
+ const languageIndex = availableLanguages.indexOf(activeLanguage)
+ const newSelectedIndex = languageIndex === -1 ? selectedIndex : languageIndex
+ if (newSelectedIndex !== selectedIndex)
+ setSelectedIndex(newSelectedIndex)
+
+ const { positionRef, preventLayoutShift } = usePreventLayoutShift()
+
+ return {
+ as: 'div',
+ ref: positionRef,
+ selectedIndex,
+ onChange: (newSelectedIndex: number) => {
+ preventLayoutShift(() =>
+ (addPreferredLanguage(availableLanguages[newSelectedIndex]) as any),
+ )
+ },
+ }
+}
+
+const CodeGroupContext = createContext(false)
+
+export function CodeGroup({ children, title, inputs, targetCode, ...props }: IChildrenProps) {
+ const languages = Children.map(children, child =>
+ getPanelTitle(child.props.children.props),
+ )
+ const tabGroupProps = useTabGroupProps(languages)
+ const hasTabs = Children.count(children) > 1
+ const Container = hasTabs ? Tab.Group : 'div'
+ const containerProps = hasTabs ? tabGroupProps : {}
+ const headerProps = hasTabs
+ ? { selectedIndex: tabGroupProps.selectedIndex }
+ : {}
+
+ return (
+ <CodeGroupContext.Provider value={true}>
+ <Container
+ {...containerProps}
+ className="not-prose my-6 overflow-hidden rounded-2xl bg-zinc-900 shadow-md dark:ring-1 dark:ring-white/10"
+ >
+ <CodeGroupHeader title={title} {...headerProps}>
+ {children}
+ </CodeGroupHeader>
+ <CodeGroupPanels {...props} targetCode={targetCode}>{children}</CodeGroupPanels>
+ </Container>
+ </CodeGroupContext.Provider>
+ )
+}
+
+type IChildProps = {
+ children: string
+ [key: string]: any
+}
+export function Code({ children, ...props }: IChildProps) {
+ const isGrouped = useContext(CodeGroupContext)
+
+ if (isGrouped)
+ return <code {...props} dangerouslySetInnerHTML={{ __html: children }} />
+
+ return <code {...props}>{children}</code>
+}
+
+export function Pre({ children, ...props }: IChildrenProps) {
+ const isGrouped = useContext(CodeGroupContext)
+
+ if (isGrouped)
+ return children
+
+ return <CodeGroup {...props}>{children}</CodeGroup>
+}
diff --git a/app/components/develop/doc.tsx b/app/components/develop/doc.tsx
new file mode 100644
index 0000000..c61cc09
--- /dev/null
+++ b/app/components/develop/doc.tsx
@@ -0,0 +1,178 @@
+'use client'
+import { useEffect, useState } from 'react'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { RiListUnordered } from '@remixicon/react'
+import TemplateEn from './template/template.en.mdx'
+import TemplateZh from './template/template.zh.mdx'
+import TemplateJa from './template/template.ja.mdx'
+import TemplateAdvancedChatEn from './template/template_advanced_chat.en.mdx'
+import TemplateAdvancedChatZh from './template/template_advanced_chat.zh.mdx'
+import TemplateAdvancedChatJa from './template/template_advanced_chat.ja.mdx'
+import TemplateWorkflowEn from './template/template_workflow.en.mdx'
+import TemplateWorkflowZh from './template/template_workflow.zh.mdx'
+import TemplateWorkflowJa from './template/template_workflow.ja.mdx'
+import TemplateChatEn from './template/template_chat.en.mdx'
+import TemplateChatZh from './template/template_chat.zh.mdx'
+import TemplateChatJa from './template/template_chat.ja.mdx'
+import I18n from '@/context/i18n'
+import { LanguagesSupported } from '@/i18n/language'
+import useTheme from '@/hooks/use-theme'
+import { Theme } from '@/types/app'
+import cn from '@/utils/classnames'
+
+type IDocProps = {
+ appDetail: any
+}
+
+const Doc = ({ appDetail }: IDocProps) => {
+ const { locale } = useContext(I18n)
+ const { t } = useTranslation()
+ const [toc, setToc] = useState<Array<{ href: string; text: string }>>([])
+ const [isTocExpanded, setIsTocExpanded] = useState(false)
+ const { theme } = useTheme()
+
+ const variables = appDetail?.model_config?.configs?.prompt_variables || []
+ const inputs = variables.reduce((res: any, variable: any) => {
+ res[variable.key] = variable.name || ''
+ return res
+ }, {})
+
+ useEffect(() => {
+ const mediaQuery = window.matchMedia('(min-width: 1280px)')
+ setIsTocExpanded(mediaQuery.matches)
+ }, [])
+
+ useEffect(() => {
+ const extractTOC = () => {
+ const article = document.querySelector('article')
+ if (article) {
+ const headings = article.querySelectorAll('h2')
+ const tocItems = Array.from(headings).map((heading) => {
+ const anchor = heading.querySelector('a')
+ if (anchor) {
+ return {
+ href: anchor.getAttribute('href') || '',
+ text: anchor.textContent || '',
+ }
+ }
+ return null
+ }).filter((item): item is { href: string; text: string } => item !== null)
+ setToc(tocItems)
+ }
+ }
+
+ // Run after component has rendered
+ setTimeout(extractTOC, 0)
+ }, [appDetail, locale])
+
+ const handleTocClick = (e: React.MouseEvent<HTMLAnchorElement>, item: { href: string; text: string }) => {
+ e.preventDefault()
+ const targetId = item.href.replace('#', '')
+ const element = document.getElementById(targetId)
+ if (element) {
+ const scrollContainer = document.querySelector('.overflow-auto')
+ if (scrollContainer) {
+ const headerOffset = 80
+ const elementTop = element.offsetTop - headerOffset
+ scrollContainer.scrollTo({
+ top: elementTop,
+ behavior: 'smooth',
+ })
+ }
+ }
+ }
+ return (
+ <div className="flex">
+ <div className={`fixed right-8 top-32 z-10 transition-all ${isTocExpanded ? 'w-64' : 'w-10'}`}>
+ {isTocExpanded
+ ? (
+ <nav className="toc max-h-[calc(100vh-150px)] w-full overflow-y-auto rounded-lg bg-components-panel-bg p-4 shadow-md">
+ <div className="mb-4 flex items-center justify-between">
+ <h3 className="text-lg font-semibold text-text-primary">{t('appApi.develop.toc')}</h3>
+ <button
+ onClick={() => setIsTocExpanded(false)}
+ className="text-text-tertiary hover:text-text-secondary"
+ >
+ 鉁�
+ </button>
+ </div>
+ <ul className="space-y-2">
+ {toc.map((item, index) => (
+ <li key={index}>
+ <a
+ href={item.href}
+ className="text-text-secondary transition-colors duration-200 hover:text-text-primary hover:underline"
+ onClick={e => handleTocClick(e, item)}
+ >
+ {item.text}
+ </a>
+ </li>
+ ))}
+ </ul>
+ </nav>
+ )
+ : (
+ <button
+ onClick={() => setIsTocExpanded(true)}
+ className="flex h-10 w-10 items-center justify-center rounded-full bg-components-button-secondary-bg shadow-md transition-colors duration-200 hover:bg-components-button-secondary-bg-hover"
+ >
+ <RiListUnordered className="h-6 w-6 text-components-button-secondary-text" />
+ </button>
+ )}
+ </div>
+ <article className={cn('prose-xl prose', theme === Theme.dark && 'prose-invert')} >
+ {(appDetail?.mode === 'chat' || appDetail?.mode === 'agent-chat') && (
+ (() => {
+ switch (locale) {
+ case LanguagesSupported[1]:
+ return <TemplateChatZh appDetail={appDetail} variables={variables} inputs={inputs} />
+ case LanguagesSupported[7]:
+ return <TemplateChatJa appDetail={appDetail} variables={variables} inputs={inputs} />
+ default:
+ return <TemplateChatEn appDetail={appDetail} variables={variables} inputs={inputs} />
+ }
+ })()
+ )}
+ {appDetail?.mode === 'advanced-chat' && (
+ (() => {
+ switch (locale) {
+ case LanguagesSupported[1]:
+ return <TemplateAdvancedChatZh appDetail={appDetail} variables={variables} inputs={inputs} />
+ case LanguagesSupported[7]:
+ return <TemplateAdvancedChatJa appDetail={appDetail} variables={variables} inputs={inputs} />
+ default:
+ return <TemplateAdvancedChatEn appDetail={appDetail} variables={variables} inputs={inputs} />
+ }
+ })()
+ )}
+ {appDetail?.mode === 'workflow' && (
+ (() => {
+ switch (locale) {
+ case LanguagesSupported[1]:
+ return <TemplateWorkflowZh appDetail={appDetail} variables={variables} inputs={inputs} />
+ case LanguagesSupported[7]:
+ return <TemplateWorkflowJa appDetail={appDetail} variables={variables} inputs={inputs} />
+ default:
+ return <TemplateWorkflowEn appDetail={appDetail} variables={variables} inputs={inputs} />
+ }
+ })()
+ )}
+ {appDetail?.mode === 'completion' && (
+ (() => {
+ switch (locale) {
+ case LanguagesSupported[1]:
+ return <TemplateZh appDetail={appDetail} variables={variables} inputs={inputs} />
+ case LanguagesSupported[7]:
+ return <TemplateJa appDetail={appDetail} variables={variables} inputs={inputs} />
+ default:
+ return <TemplateEn appDetail={appDetail} variables={variables} inputs={inputs} />
+ }
+ })()
+ )}
+ </article>
+ </div>
+ )
+}
+
+export default Doc
diff --git a/app/components/develop/index.tsx b/app/components/develop/index.tsx
new file mode 100644
index 0000000..c3f88a1
--- /dev/null
+++ b/app/components/develop/index.tsx
@@ -0,0 +1,35 @@
+'use client'
+import Doc from '@/app/components/develop/doc'
+import Loading from '@/app/components/base/loading'
+import ApiServer from '@/app/components/develop/ApiServer'
+import { useStore as useAppStore } from '@/app/components/app/store'
+
+type IDevelopMainProps = {
+ appId: string
+}
+
+const DevelopMain = ({ appId }: IDevelopMainProps) => {
+ const appDetail = useAppStore(state => state.appDetail)
+
+ if (!appDetail) {
+ return (
+ <div className='flex h-full items-center justify-center bg-background-default'>
+ <Loading />
+ </div>
+ )
+ }
+
+ return (
+ <div className='relative flex h-full flex-col overflow-hidden'>
+ <div className='flex shrink-0 items-center justify-between border-b border-solid border-b-divider-regular px-6 py-2'>
+ <div className='text-lg font-medium text-text-primary'></div>
+ <ApiServer apiBaseUrl={appDetail.api_base_url} appId={appId} />
+ </div>
+ <div className='grow overflow-auto px-4 py-4 sm:px-10'>
+ <Doc appDetail={appDetail} />
+ </div>
+ </div>
+ )
+}
+
+export default DevelopMain
diff --git a/app/components/develop/md.tsx b/app/components/develop/md.tsx
new file mode 100644
index 0000000..a9b74a3
--- /dev/null
+++ b/app/components/develop/md.tsx
@@ -0,0 +1,151 @@
+'use client'
+import type { PropsWithChildren } from 'react'
+import classNames from '@/utils/classnames'
+
+type IChildrenProps = {
+ children: React.ReactNode
+ id?: string
+ tag?: any
+ label?: any
+ anchor: boolean
+}
+
+type IHeaderingProps = {
+ url: string
+ method: 'PUT' | 'DELETE' | 'GET' | 'POST' | 'PATCH'
+ title: string
+ name: string
+}
+
+export const Heading = function H2({
+ url,
+ method,
+ title,
+ name,
+}: IHeaderingProps) {
+ let style = ''
+ switch (method) {
+ case 'PUT':
+ style = 'ring-amber-300 bg-amber-400/10 text-amber-500 dark:ring-amber-400/30 dark:bg-amber-400/10 dark:text-amber-400'
+ break
+ case 'DELETE':
+ style = 'ring-rose-200 bg-rose-50 text-red-500 dark:ring-rose-500/20 dark:bg-rose-400/10 dark:text-rose-400'
+ break
+ case 'POST':
+ style = 'ring-sky-300 bg-sky-400/10 text-sky-500 dark:ring-sky-400/30 dark:bg-sky-400/10 dark:text-sky-400'
+ break
+ case 'PATCH':
+ style = 'ring-violet-300 bg-violet-400/10 text-violet-500 dark:ring-violet-400/30 dark:bg-violet-400/10 dark:text-violet-400'
+ break
+ default:
+ style = 'ring-emerald-300 dark:ring-emerald-400/30 bg-emerald-400/10 text-emerald-500 dark:text-emerald-400'
+ break
+ }
+ return (
+ <>
+ <span id={name?.replace(/^#/, '')} className='relative -top-28' />
+ <div className="flex items-center gap-x-3" >
+ <span className={`rounded-lg px-1.5 font-mono text-[0.625rem] font-semibold leading-6 ring-1 ring-inset ${style}`}>{method}</span>
+ {/* <span className="h-0.5 w-0.5 rounded-full bg-zinc-300 dark:bg-zinc-600"></span> */}
+ <span className="font-mono text-xs text-zinc-400">{url}</span>
+ </div>
+ <h2 className='mt-2 scroll-mt-32'>
+ <a href={name} className='group text-inherit no-underline hover:text-inherit'>{title}</a>
+ </h2>
+ </>
+
+ )
+}
+
+export function Row({ children }: IChildrenProps) {
+ return (
+ <div className="grid grid-cols-1 items-start gap-x-16 gap-y-10 xl:!max-w-none xl:grid-cols-2">
+ {children}
+ </div>
+ )
+}
+
+type IColProps = IChildrenProps & {
+ sticky: boolean
+}
+export function Col({ children, sticky = false }: IColProps) {
+ return (
+ <div
+ className={classNames(
+ '[&>:first-child]:mt-0 [&>:last-child]:mb-0',
+ sticky && 'xl:sticky xl:top-24',
+ )}
+ >
+ {children}
+ </div>
+ )
+}
+
+export function Properties({ children }: IChildrenProps) {
+ return (
+ <div className="my-6">
+ <ul
+ role="list"
+ className="m-0 max-w-[calc(theme(maxWidth.lg)-theme(spacing.8))] list-none divide-y divide-zinc-900/5 p-0 dark:divide-white/5"
+ >
+ {children}
+ </ul>
+ </div>
+ )
+}
+
+type IProperty = IChildrenProps & {
+ name: string
+ type: string
+}
+export function Property({ name, type, children }: IProperty) {
+ return (
+ <li className="m-0 px-0 py-4 first:pt-0 last:pb-0">
+ <dl className="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
+ <dt className="sr-only">Name</dt>
+ <dd>
+ <code>{name}</code>
+ </dd>
+ <dt className="sr-only">Type</dt>
+ <dd className="font-mono text-xs text-zinc-400 dark:text-zinc-500">
+ {type}
+ </dd>
+ <dt className="sr-only">Description</dt>
+ <dd className="w-full flex-none [&>:first-child]:mt-0 [&>:last-child]:mb-0">
+ {children}
+ </dd>
+ </dl>
+ </li>
+ )
+}
+
+type ISubProperty = IChildrenProps & {
+ name: string
+ type: string
+}
+export function SubProperty({ name, type, children }: ISubProperty) {
+ return (
+ <li className="m-0 px-0 py-1 last:pb-0">
+ <dl className="m-0 flex flex-wrap items-center gap-x-3">
+ <dt className="sr-only">Name</dt>
+ <dd>
+ <code>{name}</code>
+ </dd>
+ <dt className="sr-only">Type</dt>
+ <dd className="font-mono text-xs text-zinc-400 dark:text-zinc-500">
+ {type}
+ </dd>
+ <dt className="sr-only">Description</dt>
+ <dd className="w-full flex-none [&>:first-child]:mt-0 [&>:last-child]:mb-0">
+ {children}
+ </dd>
+ </dl>
+ </li>
+ )
+}
+
+export function PropertyInstruction({ children }: PropsWithChildren<{}>) {
+ return (
+ <li className="m-0 px-0 py-4 italic first:pt-0">{children}</li>
+ )
+}
diff --git a/app/components/develop/secret-key/assets/copied.svg b/app/components/develop/secret-key/assets/copied.svg
new file mode 100644
index 0000000..de5f86c
--- /dev/null
+++ b/app/components/develop/secret-key/assets/copied.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M10.6665 2.66683C11.2865 2.66683 11.5965 2.66683 11.8508 2.73498C12.541 2.91991 13.0801 3.45901 13.265 4.14919C13.3332 4.40352 13.3332 4.71352 13.3332 5.3335V11.4668C13.3332 12.5869 13.3332 13.147 13.1152 13.5748C12.9234 13.9511 12.6175 14.2571 12.2412 14.4488C11.8133 14.6668 11.2533 14.6668 10.1332 14.6668H5.8665C4.7464 14.6668 4.18635 14.6668 3.75852 14.4488C3.3822 14.2571 3.07624 13.9511 2.88449 13.5748C2.6665 13.147 2.6665 12.5869 2.6665 11.4668V5.3335C2.6665 4.71352 2.6665 4.40352 2.73465 4.14919C2.91959 3.45901 3.45868 2.91991 4.14887 2.73498C4.4032 2.66683 4.71319 2.66683 5.33317 2.66683M5.99984 10.0002L7.33317 11.3335L10.3332 8.3335M6.39984 4.00016H9.59984C9.9732 4.00016 10.1599 4.00016 10.3025 3.9275C10.4279 3.86359 10.5299 3.7616 10.5938 3.63616C10.6665 3.49355 10.6665 3.30686 10.6665 2.9335V2.40016C10.6665 2.02679 10.6665 1.84011 10.5938 1.6975C10.5299 1.57206 10.4279 1.47007 10.3025 1.40616C10.1599 1.3335 9.97321 1.3335 9.59984 1.3335H6.39984C6.02647 1.3335 5.83978 1.3335 5.69718 1.40616C5.57174 1.47007 5.46975 1.57206 5.40583 1.6975C5.33317 1.84011 5.33317 2.02679 5.33317 2.40016V2.9335C5.33317 3.30686 5.33317 3.49355 5.40583 3.63616C5.46975 3.7616 5.57174 3.86359 5.69718 3.9275C5.83978 4.00016 6.02647 4.00016 6.39984 4.00016Z" stroke="#1D2939" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/develop/secret-key/assets/copy-hover.svg b/app/components/develop/secret-key/assets/copy-hover.svg
new file mode 100644
index 0000000..ca8334a
--- /dev/null
+++ b/app/components/develop/secret-key/assets/copy-hover.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M10.6665 2.66634H11.9998C12.3535 2.66634 12.6926 2.80682 12.9426 3.05687C13.1927 3.30691 13.3332 3.64605 13.3332 3.99967V13.333C13.3332 13.6866 13.1927 14.0258 12.9426 14.2758C12.6926 14.5259 12.3535 14.6663 11.9998 14.6663H3.99984C3.64622 14.6663 3.30708 14.5259 3.05703 14.2758C2.80698 14.0258 2.6665 13.6866 2.6665 13.333V3.99967C2.6665 3.64605 2.80698 3.30691 3.05703 3.05687C3.30708 2.80682 3.64622 2.66634 3.99984 2.66634H5.33317M5.99984 1.33301H9.99984C10.368 1.33301 10.6665 1.63148 10.6665 1.99967V3.33301C10.6665 3.7012 10.368 3.99967 9.99984 3.99967H5.99984C5.63165 3.99967 5.33317 3.7012 5.33317 3.33301V1.99967C5.33317 1.63148 5.63165 1.33301 5.99984 1.33301Z" stroke="#1D2939" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/develop/secret-key/assets/copy.svg b/app/components/develop/secret-key/assets/copy.svg
new file mode 100644
index 0000000..18d2b4e
--- /dev/null
+++ b/app/components/develop/secret-key/assets/copy.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M10.6665 2.66634H11.9998C12.3535 2.66634 12.6926 2.80682 12.9426 3.05687C13.1927 3.30691 13.3332 3.64605 13.3332 3.99967V13.333C13.3332 13.6866 13.1927 14.0258 12.9426 14.2758C12.6926 14.5259 12.3535 14.6663 11.9998 14.6663H3.99984C3.64622 14.6663 3.30708 14.5259 3.05703 14.2758C2.80698 14.0258 2.6665 13.6866 2.6665 13.333V3.99967C2.6665 3.64605 2.80698 3.30691 3.05703 3.05687C3.30708 2.80682 3.64622 2.66634 3.99984 2.66634H5.33317M5.99984 1.33301H9.99984C10.368 1.33301 10.6665 1.63148 10.6665 1.99967V3.33301C10.6665 3.7012 10.368 3.99967 9.99984 3.99967H5.99984C5.63165 3.99967 5.33317 3.7012 5.33317 3.33301V1.99967C5.33317 1.63148 5.63165 1.33301 5.99984 1.33301Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/develop/secret-key/assets/pause.svg b/app/components/develop/secret-key/assets/pause.svg
new file mode 100644
index 0000000..a204b17
--- /dev/null
+++ b/app/components/develop/secret-key/assets/pause.svg
@@ -0,0 +1,10 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_129_2189)">
+<path d="M10.6666 14V10M13.3333 14V10M18.6666 12C18.6666 15.6819 15.6819 18.6667 12 18.6667C8.31808 18.6667 5.33331 15.6819 5.33331 12C5.33331 8.3181 8.31808 5.33333 12 5.33333C15.6819 5.33333 18.6666 8.3181 18.6666 12Z" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_129_2189">
+<rect width="16" height="16" fill="white" transform="translate(4 4)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/develop/secret-key/assets/play.svg b/app/components/develop/secret-key/assets/play.svg
new file mode 100644
index 0000000..b423e98
--- /dev/null
+++ b/app/components/develop/secret-key/assets/play.svg
@@ -0,0 +1,11 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_129_107)">
+<path d="M7.99998 14.6666C11.6819 14.6666 14.6666 11.6819 14.6666 7.99998C14.6666 4.31808 11.6819 1.33331 7.99998 1.33331C4.31808 1.33331 1.33331 4.31808 1.33331 7.99998C1.33331 11.6819 4.31808 14.6666 7.99998 14.6666Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M6.66665 5.33331L10.6666 7.99998L6.66665 10.6666V5.33331Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_129_107">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/develop/secret-key/assets/qrcode-hover.svg b/app/components/develop/secret-key/assets/qrcode-hover.svg
new file mode 100644
index 0000000..84e3ee7
--- /dev/null
+++ b/app/components/develop/secret-key/assets/qrcode-hover.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M4.33333 4.33333H4.34M11.6667 4.33333H11.6733M4.33333 11.6667H4.34M8.66667 8.66667H8.67333M11.6667 11.6667H11.6733M11.3333 14H14V11.3333M9.33333 11V14M14 9.33333H11M10.4 6.66667H12.9333C13.3067 6.66667 13.4934 6.66667 13.636 6.594C13.7614 6.53009 13.8634 6.4281 13.9273 6.30266C14 6.16005 14 5.97337 14 5.6V3.06667C14 2.6933 14 2.50661 13.9273 2.36401C13.8634 2.23856 13.7614 2.13658 13.636 2.07266C13.4934 2 13.3067 2 12.9333 2H10.4C10.0266 2 9.83995 2 9.69734 2.07266C9.5719 2.13658 9.46991 2.23856 9.406 2.36401C9.33333 2.50661 9.33333 2.6933 9.33333 3.06667V5.6C9.33333 5.97337 9.33333 6.16005 9.406 6.30266C9.46991 6.4281 9.5719 6.53009 9.69734 6.594C9.83995 6.66667 10.0266 6.66667 10.4 6.66667ZM3.06667 6.66667H5.6C5.97337 6.66667 6.16005 6.66667 6.30266 6.594C6.4281 6.53009 6.53009 6.4281 6.594 6.30266C6.66667 6.16005 6.66667 5.97337 6.66667 5.6V3.06667C6.66667 2.6933 6.66667 2.50661 6.594 2.36401C6.53009 2.23856 6.4281 2.13658 6.30266 2.07266C6.16005 2 5.97337 2 5.6 2H3.06667C2.6933 2 2.50661 2 2.36401 2.07266C2.23856 2.13658 2.13658 2.23856 2.07266 2.36401C2 2.50661 2 2.6933 2 3.06667V5.6C2 5.97337 2 6.16005 2.07266 6.30266C2.13658 6.4281 2.23856 6.53009 2.36401 6.594C2.50661 6.66667 2.6933 6.66667 3.06667 6.66667ZM3.06667 14H5.6C5.97337 14 6.16005 14 6.30266 13.9273C6.4281 13.8634 6.53009 13.7614 6.594 13.636C6.66667 13.4934 6.66667 13.3067 6.66667 12.9333V10.4C6.66667 10.0266 6.66667 9.83995 6.594 9.69734C6.53009 9.5719 6.4281 9.46991 6.30266 9.406C6.16005 9.33333 5.97337 9.33333 5.6 9.33333H3.06667C2.6933 9.33333 2.50661 9.33333 2.36401 9.406C2.23856 9.46991 2.13658 9.5719 2.07266 9.69734C2 9.83995 2 10.0266 2 10.4V12.9333C2 13.3067 2 13.4934 2.07266 13.636C2.13658 13.7614 2.23856 13.8634 2.36401 13.9273C2.50661 14 2.6933 14 3.06667 14Z" stroke="#1D2939" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+ </svg>
+
\ No newline at end of file
diff --git a/app/components/develop/secret-key/assets/qrcode.svg b/app/components/develop/secret-key/assets/qrcode.svg
new file mode 100644
index 0000000..57878d5
--- /dev/null
+++ b/app/components/develop/secret-key/assets/qrcode.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M4.33333 4.33333H4.34M11.6667 4.33333H11.6733M4.33333 11.6667H4.34M8.66667 8.66667H8.67333M11.6667 11.6667H11.6733M11.3333 14H14V11.3333M9.33333 11V14M14 9.33333H11M10.4 6.66667H12.9333C13.3067 6.66667 13.4934 6.66667 13.636 6.594C13.7614 6.53009 13.8634 6.4281 13.9273 6.30266C14 6.16005 14 5.97337 14 5.6V3.06667C14 2.6933 14 2.50661 13.9273 2.36401C13.8634 2.23856 13.7614 2.13658 13.636 2.07266C13.4934 2 13.3067 2 12.9333 2H10.4C10.0266 2 9.83995 2 9.69734 2.07266C9.5719 2.13658 9.46991 2.23856 9.406 2.36401C9.33333 2.50661 9.33333 2.6933 9.33333 3.06667V5.6C9.33333 5.97337 9.33333 6.16005 9.406 6.30266C9.46991 6.4281 9.5719 6.53009 9.69734 6.594C9.83995 6.66667 10.0266 6.66667 10.4 6.66667ZM3.06667 6.66667H5.6C5.97337 6.66667 6.16005 6.66667 6.30266 6.594C6.4281 6.53009 6.53009 6.4281 6.594 6.30266C6.66667 6.16005 6.66667 5.97337 6.66667 5.6V3.06667C6.66667 2.6933 6.66667 2.50661 6.594 2.36401C6.53009 2.23856 6.4281 2.13658 6.30266 2.07266C6.16005 2 5.97337 2 5.6 2H3.06667C2.6933 2 2.50661 2 2.36401 2.07266C2.23856 2.13658 2.13658 2.23856 2.07266 2.36401C2 2.50661 2 2.6933 2 3.06667V5.6C2 5.97337 2 6.16005 2.07266 6.30266C2.13658 6.4281 2.23856 6.53009 2.36401 6.594C2.50661 6.66667 2.6933 6.66667 3.06667 6.66667ZM3.06667 14H5.6C5.97337 14 6.16005 14 6.30266 13.9273C6.4281 13.8634 6.53009 13.7614 6.594 13.636C6.66667 13.4934 6.66667 13.3067 6.66667 12.9333V10.4C6.66667 10.0266 6.66667 9.83995 6.594 9.69734C6.53009 9.5719 6.4281 9.46991 6.30266 9.406C6.16005 9.33333 5.97337 9.33333 5.6 9.33333H3.06667C2.6933 9.33333 2.50661 9.33333 2.36401 9.406C2.23856 9.46991 2.13658 9.5719 2.07266 9.69734C2 9.83995 2 10.0266 2 10.4V12.9333C2 13.3067 2 13.4934 2.07266 13.636C2.13658 13.7614 2.23856 13.8634 2.36401 13.9273C2.50661 14 2.6933 14 3.06667 14Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+ </svg>
+
\ No newline at end of file
diff --git a/app/components/develop/secret-key/assets/svg.svg b/app/components/develop/secret-key/assets/svg.svg
new file mode 100644
index 0000000..bf401e0
--- /dev/null
+++ b/app/components/develop/secret-key/assets/svg.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1694177685288" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4415" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M192 384h640a42.666667 42.666667 0 0 1 42.666667 42.666667v362.666666a42.666667 42.666667 0 0 1-42.666667 42.666667H192v106.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h725.333334a21.333333 21.333333 0 0 0 21.333333-21.333333V308.821333L949.909333 298.666667h-126.528A98.048 98.048 0 0 1 725.333333 200.618667V72.661333L716.714667 64H213.333333a21.333333 21.333333 0 0 0-21.333333 21.333333v298.666667zM128 832H42.666667a42.666667 42.666667 0 0 1-42.666667-42.666667V426.666667a42.666667 42.666667 0 0 1 42.666667-42.666667h85.333333V85.333333a85.333333 85.333333 0 0 1 85.333333-85.333333h530.026667L1024 282.453333V938.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H213.333333a85.333333 85.333333 0 0 1-85.333333-85.333333v-106.666667z m61.376-364.885333c-27.434667 0-49.898667 6.528-67.712 19.968-19.221333 13.824-28.501333 33.024-28.501333 57.216s9.621333 42.624 29.226666 55.296c7.466667 4.608 27.093333 12.288 58.432 23.04 28.138667 9.216 44.522667 15.36 49.514667 18.048 15.68 8.448 23.872 19.968 23.872 34.56 0 11.52-5.696 20.352-16.384 27.264-10.688 6.528-25.664 9.984-44.181333 9.984-21.013333 0-36.352-4.224-46.314667-11.904-11.050667-8.832-17.813333-23.808-20.672-44.544H85.333333c1.792 34.944 13.546667 60.288 34.922667 76.416 17.450667 13.056 42.026667 19.584 73.386667 19.584 32.426667 0 57.706667-7.296 75.52-21.12 17.813333-14.208 26.730667-33.792 26.730666-58.368 0-25.344-11.050667-44.928-33.130666-59.136-9.984-6.144-32.064-15.36-66.624-26.88-23.509333-8.064-38.122667-13.824-43.477334-16.896-12.096-6.912-17.813333-16.512-17.813333-28.032 0-13.056 4.992-22.656 15.68-28.416 8.554667-4.992 20.672-7.296 36.693333-7.296 18.538667 0 32.789333 3.456 42.048 11.136 9.258667 7.296 16.021333 19.584 19.584 36.48h41.344c-2.496-29.952-12.821333-52.224-30.656-66.432-16.725333-13.44-40.256-19.968-70.186666-19.968z m118.976 5.376L398.848 746.666667h50.24l90.496-274.176h-45.226667l-69.845333 223.488h-1.066667l-69.845333-223.488h-45.226667z m368.405333-5.376c-37.76 0-67.690667 13.824-89.792 42.24-21.013333 26.496-31.36 60.288-31.36 101.376 0 40.704 10.346667 74.112 31.36 99.84 22.442667 27.648 53.802667 41.472 94.421334 41.472 22.805333 0 43.093333-3.072 61.632-9.216A143.829333 143.829333 0 0 0 789.333333 716.714667V600.746667h-109.013333v38.4h67.328v56.448c-8.533333 5.376-17.450667 9.6-27.434667 12.672a123.285333 123.285333 0 0 1-34.197333 4.608c-30.997333 0-53.802667-9.216-68.416-27.648-13.525333-17.28-20.309333-42.24-20.309333-74.496 0-33.792 7.488-59.52 22.826666-77.952 13.866667-17.664 32.768-26.112 56.64-26.112 19.221333 0 34.901333 4.224 46.656 13.056 11.413333 8.832 19.242667 21.888 22.826667 39.552h42.026667c-4.629333-30.72-16.042667-53.376-34.197334-68.736-18.88-15.744-44.544-23.424-77.312-23.424z" fill="#8a8a8a" p-id="4416"></path></svg>
\ No newline at end of file
diff --git a/app/components/develop/secret-key/assets/svged.svg b/app/components/develop/secret-key/assets/svged.svg
new file mode 100644
index 0000000..bca6210
--- /dev/null
+++ b/app/components/develop/secret-key/assets/svged.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1694177378730" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4206" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M192 384h640a42.666667 42.666667 0 0 1 42.666667 42.666667v362.666666a42.666667 42.666667 0 0 1-42.666667 42.666667H192v106.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h725.333334a21.333333 21.333333 0 0 0 21.333333-21.333333V308.821333L949.909333 298.666667h-126.528A98.048 98.048 0 0 1 725.333333 200.618667V72.661333L716.714667 64H213.333333a21.333333 21.333333 0 0 0-21.333333 21.333333v298.666667zM128 832H42.666667a42.666667 42.666667 0 0 1-42.666667-42.666667V426.666667a42.666667 42.666667 0 0 1 42.666667-42.666667h85.333333V85.333333a85.333333 85.333333 0 0 1 85.333333-85.333333h530.026667L1024 282.453333V938.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H213.333333a85.333333 85.333333 0 0 1-85.333333-85.333333v-106.666667z m61.376-364.885333c-27.434667 0-49.898667 6.528-67.712 19.968-19.221333 13.824-28.501333 33.024-28.501333 57.216s9.621333 42.624 29.226666 55.296c7.466667 4.608 27.093333 12.288 58.432 23.04 28.138667 9.216 44.522667 15.36 49.514667 18.048 15.68 8.448 23.872 19.968 23.872 34.56 0 11.52-5.696 20.352-16.384 27.264-10.688 6.528-25.664 9.984-44.181333 9.984-21.013333 0-36.352-4.224-46.314667-11.904-11.050667-8.832-17.813333-23.808-20.672-44.544H85.333333c1.792 34.944 13.546667 60.288 34.922667 76.416 17.450667 13.056 42.026667 19.584 73.386667 19.584 32.426667 0 57.706667-7.296 75.52-21.12 17.813333-14.208 26.730667-33.792 26.730666-58.368 0-25.344-11.050667-44.928-33.130666-59.136-9.984-6.144-32.064-15.36-66.624-26.88-23.509333-8.064-38.122667-13.824-43.477334-16.896-12.096-6.912-17.813333-16.512-17.813333-28.032 0-13.056 4.992-22.656 15.68-28.416 8.554667-4.992 20.672-7.296 36.693333-7.296 18.538667 0 32.789333 3.456 42.048 11.136 9.258667 7.296 16.021333 19.584 19.584 36.48h41.344c-2.496-29.952-12.821333-52.224-30.656-66.432-16.725333-13.44-40.256-19.968-70.186666-19.968z m118.976 5.376L398.848 746.666667h50.24l90.496-274.176h-45.226667l-69.845333 223.488h-1.066667l-69.845333-223.488h-45.226667z m368.405333-5.376c-37.76 0-67.690667 13.824-89.792 42.24-21.013333 26.496-31.36 60.288-31.36 101.376 0 40.704 10.346667 74.112 31.36 99.84 22.442667 27.648 53.802667 41.472 94.421334 41.472 22.805333 0 43.093333-3.072 61.632-9.216A143.829333 143.829333 0 0 0 789.333333 716.714667V600.746667h-109.013333v38.4h67.328v56.448c-8.533333 5.376-17.450667 9.6-27.434667 12.672a123.285333 123.285333 0 0 1-34.197333 4.608c-30.997333 0-53.802667-9.216-68.416-27.648-13.525333-17.28-20.309333-42.24-20.309333-74.496 0-33.792 7.488-59.52 22.826666-77.952 13.866667-17.664 32.768-26.112 56.64-26.112 19.221333 0 34.901333 4.224 46.656 13.056 11.413333 8.832 19.242667 21.888 22.826667 39.552h42.026667c-4.629333-30.72-16.042667-53.376-34.197334-68.736-18.88-15.744-44.544-23.424-77.312-23.424z" fill="#1A8EF7" p-id="4207"></path></svg>
\ No newline at end of file
diff --git a/app/components/develop/secret-key/assets/trash-gray.svg b/app/components/develop/secret-key/assets/trash-gray.svg
new file mode 100644
index 0000000..ef65c30
--- /dev/null
+++ b/app/components/develop/secret-key/assets/trash-gray.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M6 2H10M2 4H14M12.6667 4L12.1991 11.0129C12.129 12.065 12.0939 12.5911 11.8667 12.99C11.6666 13.3412 11.3648 13.6235 11.0011 13.7998C10.588 14 10.0607 14 9.00623 14H6.99377C5.93927 14 5.41202 14 4.99889 13.7998C4.63517 13.6235 4.33339 13.3412 4.13332 12.99C3.90607 12.5911 3.871 12.065 3.80086 11.0129L3.33333 4M6.66667 7V10.3333M9.33333 7V10.3333" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/develop/secret-key/assets/trash-red.svg b/app/components/develop/secret-key/assets/trash-red.svg
new file mode 100644
index 0000000..4266dde
--- /dev/null
+++ b/app/components/develop/secret-key/assets/trash-red.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M6 2H10M2 4H14M12.6667 4L12.1991 11.0129C12.129 12.065 12.0939 12.5911 11.8667 12.99C11.6666 13.3412 11.3648 13.6235 11.0011 13.7998C10.588 14 10.0607 14 9.00623 14H6.99377C5.93927 14 5.41202 14 4.99889 13.7998C4.63517 13.6235 4.33339 13.3412 4.13332 12.99C3.90607 12.5911 3.871 12.065 3.80086 11.0129L3.33333 4M6.66667 7V10.3333M9.33333 7V10.3333" stroke="#D92D20" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/develop/secret-key/input-copy.tsx b/app/components/develop/secret-key/input-copy.tsx
new file mode 100644
index 0000000..982c63f
--- /dev/null
+++ b/app/components/develop/secret-key/input-copy.tsx
@@ -0,0 +1,57 @@
+'use client'
+import React, { useEffect, useState } from 'react'
+import copy from 'copy-to-clipboard'
+import { t } from 'i18next'
+import Tooltip from '@/app/components/base/tooltip'
+import CopyFeedback from '@/app/components/base/copy-feedback'
+
+type IInputCopyProps = {
+ value?: string
+ className?: string
+ children?: React.ReactNode
+}
+
+const InputCopy = ({
+ value = '',
+ className,
+ children,
+}: IInputCopyProps) => {
+ const [isCopied, setIsCopied] = useState(false)
+
+ useEffect(() => {
+ if (isCopied) {
+ const timeout = setTimeout(() => {
+ setIsCopied(false)
+ }, 1000)
+
+ return () => {
+ clearTimeout(timeout)
+ }
+ }
+ }, [isCopied])
+
+ return (
+ <div className={`flex items-center rounded-lg bg-components-input-bg-normal py-2 hover:bg-state-base-hover ${className}`}>
+ <div className="flex h-5 grow items-center">
+ {children}
+ <div className='relative h-full grow text-[13px]'>
+ <div className='r-0 absolute left-0 top-0 w-full cursor-pointer truncate pl-2 pr-2' onClick={() => {
+ copy(value)
+ setIsCopied(true)
+ }}>
+ <Tooltip
+ popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
+ position='bottom'
+ >
+ <span className='text-text-secondary'>{value}</span>
+ </Tooltip>
+ </div>
+ </div>
+ <div className="h-4 w-px shrink-0 bg-divider-regular" />
+ <div className='mx-1'><CopyFeedback content={value} /></div>
+ </div>
+ </div>
+ )
+}
+
+export default InputCopy
diff --git a/app/components/develop/secret-key/secret-key-button.tsx b/app/components/develop/secret-key/secret-key-button.tsx
new file mode 100644
index 0000000..7d27c01
--- /dev/null
+++ b/app/components/develop/secret-key/secret-key-button.tsx
@@ -0,0 +1,35 @@
+'use client'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiKey2Line } from '@remixicon/react'
+import Button from '@/app/components/base/button'
+import SecretKeyModal from '@/app/components/develop/secret-key/secret-key-modal'
+
+type ISecretKeyButtonProps = {
+ className?: string
+ appId?: string
+ textCls?: string
+}
+
+const SecretKeyButton = ({ className, appId, textCls }: ISecretKeyButtonProps) => {
+ const [isVisible, setVisible] = useState(false)
+ const { t } = useTranslation()
+ return (
+ <>
+ <Button
+ className={`px-3 ${className}`}
+ onClick={() => setVisible(true)}
+ size='small'
+ variant='ghost'
+ >
+ <div className={'flex h-3.5 w-3.5 items-center justify-center'}>
+ <RiKey2Line className='h-3.5 w-3.5 text-text-tertiary' />
+ </div>
+ <div className={`system-xs-medium px-[3px] text-text-tertiary ${textCls}`}>{t('appApi.apiKey')}</div>
+ </Button>
+ <SecretKeyModal isShow={isVisible} onClose={() => setVisible(false)} appId={appId} />
+ </>
+ )
+}
+
+export default SecretKeyButton
diff --git a/app/components/develop/secret-key/secret-key-generate.tsx b/app/components/develop/secret-key/secret-key-generate.tsx
new file mode 100644
index 0000000..3d15b04
--- /dev/null
+++ b/app/components/develop/secret-key/secret-key-generate.tsx
@@ -0,0 +1,41 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { XMarkIcon } from '@heroicons/react/20/solid'
+import InputCopy from './input-copy'
+import s from './style.module.css'
+import Button from '@/app/components/base/button'
+import Modal from '@/app/components/base/modal'
+import type { CreateApiKeyResponse } from '@/models/app'
+
+type ISecretKeyGenerateModalProps = {
+ isShow: boolean
+ onClose: () => void
+ newKey?: CreateApiKeyResponse
+ className?: string
+}
+
+const SecretKeyGenerateModal = ({
+ isShow = false,
+ onClose,
+ newKey,
+ className,
+}: ISecretKeyGenerateModalProps) => {
+ const { t } = useTranslation()
+ return (
+ <Modal isShow={isShow} onClose={onClose} title={`${t('appApi.apiKeyModal.apiSecretKey')}`} className={`px-8 ${className}`}>
+ <XMarkIcon className={`absolute h-6 w-6 cursor-pointer text-text-tertiary ${s.close}`} onClick={onClose} />
+ <p className='mt-1 text-[13px] font-normal leading-5 text-text-tertiary'>{t('appApi.apiKeyModal.generateTips')}</p>
+ <div className='my-4'>
+ <InputCopy className='w-full' value={newKey?.token} />
+ </div>
+ <div className='my-4 flex justify-end'>
+ <Button className={`shrink-0 ${s.w64}`} onClick={onClose}>
+ <span className='text-xs font-medium text-text-secondary'>{t('appApi.actionMsg.ok')}</span>
+ </Button>
+ </div>
+
+ </Modal >
+ )
+}
+
+export default SecretKeyGenerateModal
diff --git a/app/components/develop/secret-key/secret-key-modal.tsx b/app/components/develop/secret-key/secret-key-modal.tsx
new file mode 100644
index 0000000..b61e231
--- /dev/null
+++ b/app/components/develop/secret-key/secret-key-modal.tsx
@@ -0,0 +1,147 @@
+'use client'
+import {
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiDeleteBinLine } from '@remixicon/react'
+import { PlusIcon, XMarkIcon } from '@heroicons/react/20/solid'
+import useSWR, { useSWRConfig } from 'swr'
+import SecretKeyGenerateModal from './secret-key-generate'
+import s from './style.module.css'
+import ActionButton from '@/app/components/base/action-button'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import CopyFeedback from '@/app/components/base/copy-feedback'
+import {
+ createApikey as createAppApikey,
+ delApikey as delAppApikey,
+ fetchApiKeysList as fetchAppApiKeysList,
+} from '@/service/apps'
+import {
+ createApikey as createDatasetApikey,
+ delApikey as delDatasetApikey,
+ fetchApiKeysList as fetchDatasetApiKeysList,
+} from '@/service/datasets'
+import type { CreateApiKeyResponse } from '@/models/app'
+import Loading from '@/app/components/base/loading'
+import Confirm from '@/app/components/base/confirm'
+import useTimestamp from '@/hooks/use-timestamp'
+import { useAppContext } from '@/context/app-context'
+
+type ISecretKeyModalProps = {
+ isShow: boolean
+ appId?: string
+ onClose: () => void
+}
+
+const SecretKeyModal = ({
+ isShow = false,
+ appId,
+ onClose,
+}: ISecretKeyModalProps) => {
+ const { t } = useTranslation()
+ const { formatTime } = useTimestamp()
+ const { currentWorkspace, isCurrentWorkspaceManager, isCurrentWorkspaceEditor } = useAppContext()
+ const [showConfirmDelete, setShowConfirmDelete] = useState(false)
+ const [isVisible, setVisible] = useState(false)
+ const [newKey, setNewKey] = useState<CreateApiKeyResponse | undefined>(undefined)
+ const { mutate } = useSWRConfig()
+ const commonParams = appId
+ ? { url: `/apps/${appId}/api-keys`, params: {} }
+ : { url: '/datasets/api-keys', params: {} }
+ const fetchApiKeysList = appId ? fetchAppApiKeysList : fetchDatasetApiKeysList
+ const { data: apiKeysList } = useSWR(commonParams, fetchApiKeysList)
+
+ const [delKeyID, setDelKeyId] = useState('')
+
+ const onDel = async () => {
+ setShowConfirmDelete(false)
+ if (!delKeyID)
+ return
+
+ const delApikey = appId ? delAppApikey : delDatasetApikey
+ const params = appId
+ ? { url: `/apps/${appId}/api-keys/${delKeyID}`, params: {} }
+ : { url: `/datasets/api-keys/${delKeyID}`, params: {} }
+ await delApikey(params)
+ mutate(commonParams)
+ }
+
+ const onCreate = async () => {
+ const params = appId
+ ? { url: `/apps/${appId}/api-keys`, body: {} }
+ : { url: '/datasets/api-keys', body: {} }
+ const createApikey = appId ? createAppApikey : createDatasetApikey
+ const res = await createApikey(params)
+ setVisible(true)
+ setNewKey(res)
+ mutate(commonParams)
+ }
+
+ const generateToken = (token: string) => {
+ return `${token.slice(0, 3)}...${token.slice(-20)}`
+ }
+
+ return (
+ <Modal isShow={isShow} onClose={onClose} title={`${t('appApi.apiKeyModal.apiSecretKey')}`} className={`${s.customModal} flex flex-col px-8`}>
+ <XMarkIcon className={`absolute h-6 w-6 cursor-pointer text-text-tertiary ${s.close}`} onClick={onClose} />
+ <p className='mt-1 shrink-0 text-[13px] font-normal leading-5 text-text-tertiary'>{t('appApi.apiKeyModal.apiSecretKeyTips')}</p>
+ {!apiKeysList && <div className='mt-4'><Loading /></div>}
+ {
+ !!apiKeysList?.data?.length && (
+ <div className='mt-4 flex grow flex-col overflow-hidden'>
+ <div className='flex h-9 shrink-0 items-center border-b border-divider-regular text-xs font-semibold text-text-tertiary'>
+ <div className='w-64 shrink-0 px-3'>{t('appApi.apiKeyModal.secretKey')}</div>
+ <div className='w-[200px] shrink-0 px-3'>{t('appApi.apiKeyModal.created')}</div>
+ <div className='w-[200px] shrink-0 px-3'>{t('appApi.apiKeyModal.lastUsed')}</div>
+ <div className='grow px-3'></div>
+ </div>
+ <div className='grow overflow-auto'>
+ {apiKeysList.data.map(api => (
+ <div className='flex h-9 items-center border-b border-divider-regular text-sm font-normal text-text-secondary' key={api.id}>
+ <div className='w-64 shrink-0 truncate px-3 font-mono'>{generateToken(api.token)}</div>
+ <div className='w-[200px] shrink-0 truncate px-3'>{formatTime(Number(api.created_at), t('appLog.dateTimeFormat') as string)}</div>
+ <div className='w-[200px] shrink-0 truncate px-3'>{api.last_used_at ? formatTime(Number(api.last_used_at), t('appLog.dateTimeFormat') as string) : t('appApi.never')}</div>
+ <div className='flex grow space-x-2 px-3'>
+ <CopyFeedback content={api.token} />
+ {isCurrentWorkspaceManager && (
+ <ActionButton
+ onClick={() => {
+ setDelKeyId(api.id)
+ setShowConfirmDelete(true)
+ }}
+ >
+ <RiDeleteBinLine className='h-4 w-4' />
+ </ActionButton>
+ )}
+ </div>
+ </div>
+ ))}
+ </div>
+ </div>
+ )
+ }
+ <div className='flex'>
+ <Button className={`mt-4 flex shrink-0 ${s.autoWidth}`} onClick={onCreate} disabled={!currentWorkspace || !isCurrentWorkspaceEditor}>
+ <PlusIcon className='mr-1 flex h-4 w-4 shrink-0' />
+ <div className='text-xs font-medium text-text-secondary'>{t('appApi.apiKeyModal.createNewSecretKey')}</div>
+ </Button>
+ </div>
+ <SecretKeyGenerateModal className='shrink-0' isShow={isVisible} onClose={() => setVisible(false)} newKey={newKey} />
+ {showConfirmDelete && (
+ <Confirm
+ title={`${t('appApi.actionMsg.deleteConfirmTitle')}`}
+ content={`${t('appApi.actionMsg.deleteConfirmTips')}`}
+ isShow={showConfirmDelete}
+ onConfirm={onDel}
+ onCancel={() => {
+ setDelKeyId('')
+ setShowConfirmDelete(false)
+ }}
+ />
+ )}
+ </Modal >
+ )
+}
+
+export default SecretKeyModal
diff --git a/app/components/develop/secret-key/style.module.css b/app/components/develop/secret-key/style.module.css
new file mode 100644
index 0000000..f13161c
--- /dev/null
+++ b/app/components/develop/secret-key/style.module.css
@@ -0,0 +1,57 @@
+.customModal {
+ max-width: 800px !important;
+ max-height: calc(100vh - 80px);
+}
+
+.close {
+ top: 1.5rem;
+ right: 1.5rem;
+}
+
+.trash {
+ color: transparent;
+}
+
+.w64 {
+ width: 4rem;
+}
+
+.customApi {
+ font-size: 11px;
+}
+
+.autoWidth {
+ width: auto;
+}
+
+.trashIcon {
+ background-color: transparent;
+ background-image: url(./assets/trash-gray.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 16px 16px;
+}
+
+.trashIcon:hover {
+ background-color: rgba(254, 228, 226, 1);
+ background-image: url(./assets/trash-red.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 16px 16px;
+}
+
+.copyIcon {
+ background-image: url(./assets/copy.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.copyIcon:hover {
+ background-image: url(./assets/copy-hover.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.copyIcon.copied {
+ background-image: url(./assets/copied.svg);
+}
diff --git a/app/components/develop/tag.tsx b/app/components/develop/tag.tsx
new file mode 100644
index 0000000..0b797f9
--- /dev/null
+++ b/app/components/develop/tag.tsx
@@ -0,0 +1,65 @@
+'use client'
+import classNames from '@/utils/classnames'
+
+const variantStyles = {
+ medium: 'rounded-lg px-1.5 ring-1 ring-inset',
+} as { [key: string]: string }
+
+const colorStyles = {
+ emerald: {
+ small: 'text-emerald-500 dark:text-emerald-400',
+ medium:
+ 'ring-emerald-300 dark:ring-emerald-400/30 bg-emerald-400/10 text-emerald-500 dark:text-emerald-400',
+ },
+ sky: {
+ small: 'text-sky-500',
+ medium:
+ 'ring-sky-300 bg-sky-400/10 text-sky-500 dark:ring-sky-400/30 dark:bg-sky-400/10 dark:text-sky-400',
+ },
+ amber: {
+ small: 'text-amber-500',
+ medium:
+ 'ring-amber-300 bg-amber-400/10 text-amber-500 dark:ring-amber-400/30 dark:bg-amber-400/10 dark:text-amber-400',
+ },
+ rose: {
+ small: 'text-red-500 dark:text-rose-500',
+ medium:
+ 'ring-rose-200 bg-rose-50 text-red-500 dark:ring-rose-500/20 dark:bg-rose-400/10 dark:text-rose-400',
+ },
+ zinc: {
+ small: 'text-zinc-400 dark:text-zinc-500',
+ medium:
+ 'ring-zinc-200 bg-zinc-50 text-zinc-500 dark:ring-zinc-500/20 dark:bg-zinc-400/10 dark:text-zinc-400',
+ },
+} as { [key: string]: { [key: string]: string } }
+
+const valueColorMap = {
+ get: 'emerald',
+ post: 'sky',
+ put: 'amber',
+ delete: 'rose',
+} as { [key: string]: string }
+
+type ITagProps = {
+ children: string
+ color?: string
+ variant?: string
+}
+
+export function Tag({
+ children,
+ variant = 'medium',
+ color = valueColorMap[children.toLowerCase()] ?? 'emerald',
+}: ITagProps) {
+ return (
+ <span
+ className={classNames(
+ 'font-mono text-[0.625rem] font-semibold leading-6',
+ variantStyles[variant],
+ colorStyles[color][variant],
+ )}
+ >
+ {children}
+ </span>
+ )
+}
diff --git a/app/components/develop/template/template.en.mdx b/app/components/develop/template/template.en.mdx
new file mode 100644
index 0000000..8212e80
--- /dev/null
+++ b/app/components/develop/template/template.en.mdx
@@ -0,0 +1,708 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx'
+
+# Completion App API
+
+The text generation application offers non-session support and is ideal for translation, article writing, summarization AI, and more.
+
+<div>
+ ### Base URL
+ <CodeGroup title="Code" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### Authentication
+
+ The Service API uses `API-Key` authentication.
+ <i>**Strongly recommend storing your API Key on the server-side, not shared or stored on the client-side, to avoid possible API-Key leakage that can lead to serious consequences.**</i>
+
+ For all API requests, include your API Key in the `Authorization` HTTP Header, as shown below:
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/completion-messages'
+ method='POST'
+ title='Create Completion Message'
+ name='#Create-Completion-Message'
+/>
+<Row>
+ <Col>
+ Send a request to the text generation application.
+
+ ### Request Body
+
+ <Properties>
+
+ <Property name='inputs' type='object' key='inputs'>
+ Allows the entry of various variable values defined by the App.
+ The `inputs` parameter contains multiple key/value pairs, with each key corresponding to a specific variable and each value being the specific value for that variable.
+ The text generation application requires at least one key/value pair to be inputted.
+ - `query` (string) Required
+ The input text, the content to be processed.
+ </Property>
+ <Property name='response_mode' type='string' key='response_mode'>
+ The mode of response return, supporting:
+ - `streaming` Streaming mode (recommended), implements a typewriter-like output through SSE ([Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)).
+ - `blocking` Blocking mode, returns result after execution is complete. (Requests may be interrupted if the process is long)
+ <i>Due to Cloudflare restrictions, the request will be interrupted without a return after 100 seconds.</i>
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+ </Property>
+ <Property name='files' type='array[object]' key='files'>
+ File list, suitable for inputting files (images) combined with text understanding and answering questions, available only when the model supports Vision capability.
+ - `type` (string) Supported type: `image` (currently only supports image type)
+ - `transfer_method` (string) Transfer method, `remote_url` for image URL / `local_file` for file upload
+ - `url` (string) Image URL (when the transfer method is `remote_url`)
+ - `upload_file_id` (string) Uploaded file ID, which must be obtained by uploading through the File Upload API in advance (when the transfer method is `local_file`)
+ </Property>
+ </Properties>
+
+ ### Response
+ When `response_mode` is `blocking`, return a CompletionResponse object.
+ When `response_mode` is `streaming`, return a ChunkCompletionResponse stream.
+
+ ### ChatCompletionResponse
+ Returns the complete App result, `Content-Type` is `application/json`.
+ - `message_id` (string) Unique message ID
+ - `mode` (string) App mode, fixed as `chat`
+ - `answer` (string) Complete response content
+ - `metadata` (object) Metadata
+ - `usage` (Usage) Model usage information
+ - `retriever_resources` (array[RetrieverResource]) Citation and Attribution List
+ - `created_at` (int) Message creation timestamp, e.g., 1705395332
+
+ ### ChunkChatCompletionResponse
+ Returns the stream chunks outputted by the App, `Content-Type` is `text/event-stream`.
+ Each streaming chunk starts with `data:`, separated by two newline characters `\n\n`, as shown below:
+ <CodeGroup>
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
+ ```
+ </CodeGroup>
+ The structure of the streaming chunks varies depending on the `event`:
+ - `event: message` LLM returns text chunk event, i.e., the complete text is output in a chunked fashion.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `answer` (string) LLM returned text chunk content
+ - `created_at` (int) Creation timestamp, e.g., 1705395332
+ - `event: message_end` Message end event, receiving this event means streaming has ended.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `metadata` (object) Metadata
+ - `usage` (Usage) Model usage information
+ - `retriever_resources` (array[RetrieverResource]) Citation and Attribution List
+ - `event: tts_message` TTS audio stream event, that is, speech synthesis output. The content is an audio block in Mp3 format, encoded as a base64 string. When playing, simply decode the base64 and feed it into the player. (This message is available only when auto-play is enabled)
+ - `task_id` (string) Task ID, used for request tracking and the stop response interface below
+ - `message_id` (string) Unique message ID
+ - `audio` (string) The audio after speech synthesis, encoded in base64 text content, when playing, simply decode the base64 and feed it into the player
+ - `created_at` (int) Creation timestamp, e.g.: 1705395332
+ - `event: tts_message_end` TTS audio stream end event, receiving this event indicates the end of the audio stream.
+ - `task_id` (string) Task ID, used for request tracking and the stop response interface below
+ - `message_id` (string) Unique message ID
+ - `audio` (string) The end event has no audio, so this is an empty string
+ - `created_at` (int) Creation timestamp, e.g.: 1705395332
+ - `event: message_replace` Message content replacement event.
+ When output content moderation is enabled, if the content is flagged, then the message content will be replaced with a preset reply through this event.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `answer` (string) Replacement content (directly replaces all LLM reply text)
+ - `created_at` (int) Creation timestamp, e.g., 1705395332
+ - `event: error`
+ Exceptions that occur during the streaming process will be output in the form of stream events, and reception of an error event will end the stream.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `status` (int) HTTP status code
+ - `code` (string) Error code
+ - `message` (string) Error message
+ - `event: ping` Ping event every 10 seconds to keep the connection alive.
+
+ ### Errors
+ - 404, Conversation does not exists
+ - 400, `invalid_param`, abnormal parameter input
+ - 400, `app_unavailable`, App configuration unavailable
+ - 400, `provider_not_initialize`, no available model credential configuration
+ - 400, `provider_quota_exceeded`, model invocation quota insufficient
+ - 400, `model_currently_not_support`, current model unavailable
+ - 400, `completion_request_error`, text generation failed
+ - 500, internal server error
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/completion-messages" targetCode={`curl -X POST '${props.appDetail.api_base_url}/completion-messages' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": {"query": "Hello, world!"},\n "response_mode": "streaming",\n "user": "abc-123"\n}'\n`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/completion-messages' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {
+ "query": "Hello, world!"
+ },
+ "response_mode": "streaming",
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+ ### Blocking Mode
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "event": "message",
+ "message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "mode": "completion",
+ "answer": "Hello World!...",
+ "metadata": {
+ "usage": {
+ "prompt_tokens": 1033,
+ "prompt_unit_price": "0.001",
+ "prompt_price_unit": "0.001",
+ "prompt_price": "0.0010330",
+ "completion_tokens": 128,
+ "completion_unit_price": "0.002",
+ "completion_price_unit": "0.001",
+ "completion_price": "0.0002560",
+ "total_tokens": 1161,
+ "total_price": "0.0012890",
+ "currency": "USD",
+ "latency": 0.7682376249867957
+ }
+ },
+ "created_at": 1705407629
+ }
+ ```
+ </CodeGroup>
+ ### Streaming Mode
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='File Upload'
+ name='#file-upload'
+/>
+<Row>
+ <Col>
+ Upload a file (currently only images are supported) for use when sending messages, enabling multimodal understanding of images and text.
+ Supports png, jpg, jpeg, webp, gif formats.
+ <i>Uploaded files are for use by the current end-user only.</i>
+
+ ### Request Body
+ This interface requires a `multipart/form-data` request.
+ - `file` (File) Required
+ The file to be uploaded.
+ - `user` (string) Required
+ User identifier, defined by the developer's rules, must be unique within the application.
+
+ ### Response
+ After a successful upload, the server will return the file's ID and related information.
+ - `id` (uuid) ID
+ - `name` (string) File name
+ - `size` (int) File size (bytes)
+ - `extension` (string) File extension
+ - `mime_type` (string) File mime-type
+ - `created_by` (uuid) End-user ID
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+
+ ### Errors
+ - 400, `no_file_uploaded`, a file must be provided
+ - 400, `too_many_files`, currently only one file is accepted
+ - 400, `unsupported_preview`, the file does not support preview
+ - 400, `unsupported_estimate`, the file does not support estimation
+ - 413, `file_too_large`, the file is too large
+ - 415, `unsupported_file_type`, unsupported extension, currently only document files are accepted
+ - 503, `s3_connection_failed`, unable to connect to S3 service
+ - 503, `s3_permission_denied`, no permission to upload files to S3
+ - 503, `s3_file_too_large`, file exceeds S3 size limit
+ - 500, internal server error
+
+
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": "6ad1ab0a-73ff-4ac1-b9e4-cdb312f71f13",
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/completion-messages/:task_id/stop'
+ method='POST'
+ title='Stop Generate'
+ name='#stop-generatebacks'
+/>
+<Row>
+ <Col>
+ Only supported in streaming mode.
+ ### Path
+ - `task_id` (string) Task ID, can be obtained from the streaming chunk return
+ Request Body
+ - `user` (string) Required
+ User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface.
+ ### Response
+ - `result` (string) Always returns "success"
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="POST" label="/completion-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages/:message_id/feedbacks'
+ method='POST'
+ title='Message Feedback'
+ name='#feedbacks'
+/>
+<Row>
+ <Col>
+ End-users can provide feedback messages, facilitating application developers to optimize expected outputs.
+
+ ### Path
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ Message ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+
+ <Properties>
+ <Property name='rating' type='string' key='rating'>
+ Upvote as `like`, downvote as `dislike`, revoke upvote as `null`
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, defined by the developer's rules, must be unique within the application.
+ </Property>
+ <Property name='content' type='string' key='content'>
+ The specific content of message feedback.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) Always returns "success"
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/messages/:message_id/feedbacks" targetCode={`curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks \\\n --header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "rating": "like",\n "user": "abc-123",\n "content": "message feedback information"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "rating": "like",
+ "user": "abc-123",
+ "content": "message feedback information"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/app/feedbacks'
+ method='GET'
+ title='Get feedbacks of application'
+ name='#app-feedbacks'
+/>
+<Row>
+ <Col>
+ Get application's feedbacks.
+
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 锛坥ptional锛塸agination锛宒efault锛�1
+ </Property>
+ </Properties>
+
+ <Properties>
+ <Property name='limit' type='string' key='limit'>
+ 锛坥ptional锛� records per page default锛�20
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (List) return apps feedback list.
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/app/feedbacks" targetCode={`curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "8c0fbed8-e2f9-49ff-9f0e-15a35bdd0e25",
+ "app_id": "f252d396-fe48-450e-94ec-e184218e7346",
+ "conversation_id": "2397604b-9deb-430e-b285-4726e51fd62d",
+ "message_id": "709c0b0f-0a96-4a4e-91a4-ec0889937b11",
+ "rating": "like",
+ "content": "message feedback information-3",
+ "from_source": "user",
+ "from_end_user_id": "74286412-9a1a-42c1-929c-01edb1d381d5",
+ "from_account_id": null,
+ "created_at": "2025-04-24T09:24:38",
+ "updated_at": "2025-04-24T09:24:38"
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/text-to-audio'
+ method='POST'
+ title='Text to Audio'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ Text to speech.
+
+ ### Request Body
+
+ <Properties>
+ <Property name='message_id' type='str' key='message_id'>
+ For text messages generated by Dify, simply pass the generated message-id directly. The backend will use the message-id to look up the corresponding content and synthesize the voice information directly. If both message_id and text are provided simultaneously, the message_id is given priority.
+ </Property>
+ <Property name='text' type='str' key='text'>
+ Speech generated content.
+ </Property>
+ <Property name='user' type='string' key='user'>
+ The user identifier, defined by the developer, must ensure uniqueness within the app.
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "Hello Dify",\n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
+ "text": "Hello Dify",
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="headers">
+ ```json {{ title: 'headers' }}
+ {
+ "Content-Type": "audio/wav"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='Get Application Basic Information'
+ name='#info'
+/>
+<Row>
+ <Col>
+ Used to get basic information about this application
+
+ ### Response
+ - `name` (string) application name
+ - `description` (string) application description
+ - `tags` (array[string]) application tags
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='Get Application Parameters Information'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ Used at the start of entering the page to obtain information such as features, input parameter names, types, and default values.
+
+ ### Response
+ - `opening_statement` (string) Opening statement
+ - `suggested_questions` (array[string]) List of suggested questions for the opening
+ - `suggested_questions_after_answer` (object) Suggest questions after enabling the answer.
+ - `enabled` (bool) Whether it is enabled
+ - `speech_to_text` (object) Speech to text
+ - `enabled` (bool) Whether it is enabled
+ - `retriever_resource` (object) Citation and Attribution
+ - `enabled` (bool) Whether it is enabled
+ - `annotation_reply` (object) Annotation reply
+ - `enabled` (bool) Whether it is enabled
+ - `user_input_form` (array[object]) User input form configuration
+ - `text-input` (object) Text input control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `paragraph` (object) Paragraph text input control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `select` (object) Dropdown control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `options` (array[string]) Option values
+ - `file_upload` (object) File upload configuration
+ - `image` (object) Image settings
+ Currently only supports image types: `png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) Whether it is enabled
+ - `number_limits` (int) Image number limit, default is 3
+ - `transfer_methods` (array[string]) List of transfer methods, remote_url, local_file, must choose one
+ - `system_parameters` (object) System parameters
+ - `file_size_limit` (int) Document upload size limit (MB)
+ - `image_file_size_limit` (int) Image file upload size limit (MB)
+ - `audio_file_size_limit` (int) Audio file upload size limit (MB)
+ - `video_file_size_limit` (int) Video file upload size limit (MB)
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "opening_statement": "Hello!",
+ "suggested_questions_after_answer": {
+ "enabled": true
+ },
+ "speech_to_text": {
+ "enabled": true
+ },
+ "retriever_resource": {
+ "enabled": true
+ },
+ "annotation_reply": {
+ "enabled": true
+ },
+ "user_input_form": [
+ {
+ "paragraph": {
+ "label": "Query",
+ "variable": "query",
+ "required": true,
+ "default": ""
+ }
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": false,
+ "number_limits": 3,
+ "detail": "high",
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='Get Application WebApp Settings'
+ name='#site'
+/>
+<Row>
+ <Col>
+ Used to get the WebApp settings of the application.
+ ### Response
+ - `title` (string) WebApp name
+ - `chat_color_theme` (string) Chat color theme, in hex format
+ - `chat_color_theme_inverted` (bool) Whether the chat color theme is inverted
+ - `icon_type` (string) Icon type, `emoji` - emoji, `image` - picture
+ - `icon` (string) Icon. If it's `emoji` type, it's an emoji symbol; if it's `image` type, it's an image URL.
+ - `icon_background` (string) Background color in hex format
+ - `icon_url` (string) Icon URL
+ - `description` (string) Description
+ - `copyright` (string) Copyright information
+ - `privacy_policy` (string) Privacy policy link
+ - `custom_disclaimer` (string) Custom disclaimer
+ - `default_language` (string) Default language
+ - `show_workflow_steps` (bool) Whether to show workflow details
+ - `use_icon_as_answer_icon` (bool) Whether to replace 馃 in chat with the WebApp icon
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "chat_color_theme": "#ff4a4a",
+ "chat_color_theme_inverted": false,
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ "use_icon_as_answer_icon": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
diff --git a/app/components/develop/template/template.ja.mdx b/app/components/develop/template/template.ja.mdx
new file mode 100644
index 0000000..5061792
--- /dev/null
+++ b/app/components/develop/template/template.ja.mdx
@@ -0,0 +1,706 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx'
+
+# Completion 銈€儣銉� API
+
+銉嗐偔銈广儓鐢熸垚銈€儣銉偙銉笺偡銉с兂銇偦銉冦偡銉с兂銉偣銈掋偟銉濄兗銉堛仐銆佺炕瑷炽�佽浜嬩綔鎴愩�佽绱凙I绛夈伀鏈�閬┿仹銇欍��
+
+<div>
+ ### 銉欍兗銈筓RL
+ <CodeGroup title="Code" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### 瑾嶈
+
+ 銈点兗銉撱偣API銇痐API-Key`瑾嶈銈掍娇鐢ㄣ仐銇俱仚銆�
+ <i>**API銈兗銇紡娲┿伀銈堛倠閲嶅ぇ銇祼鏋溿倰閬裤亼銈嬨仧銈併�丄PI銈兗銇偟銉笺儛銉笺偟銈ゃ儔銇繚瀛樸仐銆併偗銉┿偆銈€兂銉堛偟銈ゃ儔銇с伅鍏辨湁銈勪繚瀛樸仐銇亜銇撱仺銈掑挤銇忔帹濂ㄣ仐銇俱仚銆�**</i>
+
+ 銇欍伖銇︺伄API銉偗銈ㄣ偣銉堛仹銆佷互涓嬨伄銈堛亞銇玚Authorization` HTTP銉樸儍銉�銉笺伀API銈兗銈掑惈銈併仸銇忋仩銇曘亜锛�
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/completion-messages'
+ method='POST'
+ title='瀹屼簡銉°儍銈汇兗銈搞伄浣滄垚'
+ name='#Create-Completion-Message'
+/>
+<Row>
+ <Col>
+ 銉嗐偔銈广儓鐢熸垚銈€儣銉偙銉笺偡銉с兂銇儶銈偍銈广儓銈掗�佷俊銇椼伨銇欍��
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+
+ <Property name='inputs' type='object' key='inputs'>
+ 銈€儣銉仹瀹氱京銇曘倢銇熷悇绋鏁板�ゃ倰鍏ュ姏銇с亶銇俱仚銆�
+ `inputs`銉戙儵銉°兗銈裤伀銇鏁般伄銈兗/鍊ゃ儦銈€亴鍚伨銈屻�佸悇銈兗銇壒瀹氥伄澶夋暟銇蹇溿仐銆佸悇鍊ゃ伅銇濄伄澶夋暟銇叿浣撶殑銇�ゃ仺銇倞銇俱仚銆�
+ 銉嗐偔銈广儓鐢熸垚銈€儣銉偙銉笺偡銉с兂銇с伅銆佸皯銇亸銇ㄣ倐1銇ゃ伄銈兗/鍊ゃ儦銈€伄鍏ュ姏銇屽繀瑕併仹銇欍��
+ - `query` (string) 蹇呴爤
+ 鍏ュ姏銉嗐偔銈广儓銆佸嚘鐞嗐仌銈屻倠鍐呭銆�
+ </Property>
+ <Property name='response_mode' type='string' key='response_mode'>
+ 銉偣銉濄兂銈硅繑鍗淬儮銉笺儔銆佷互涓嬨倰銈点儩銉笺儓锛�
+ - `streaming` 銈广儓銉兗銉熴兂銈般儮銉笺儔锛堟帹濂級銆丼SE锛圼Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)锛夈伀銈堛倠銈裤偆銉椼儵銈ゃ偪銉奸ⅷ銇嚭鍔涖倰瀹熻銆�
+ - `blocking` 銉栥儹銉冦偔銉炽偘銉€兗銉夈�佸疅琛屽畬浜嗗緦銇祼鏋溿倰杩斿嵈銆傦紙鍑︾悊銇岄暦銇勫牬鍚堛伅銉偗銈ㄣ偣銉堛亴涓柇銇曘倢銈嬪彲鑳芥�с亴銇傘倞銇俱仚锛�
+ <i>Cloudflare銇埗闄愩伀銈堛倞銆�100绉掑緦銇繑鍗淬仾銇椼仹涓柇銇曘倢銇俱仚銆�</i>
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇韩鍏冦倰瀹氱京銇椼�佸彇寰椼倓绲辫▓銇娇鐢ㄣ仐銇俱仚銆�
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫亴涓�鎰忋伀瀹氱京銇欍倠蹇呰銇屻亗銈娿伨銇欍��
+ </Property>
+ <Property name='files' type='array[object]' key='files'>
+ 銉曘偂銈ゃ儷銉偣銉堛�併儮銉囥儷銇孷ision姗熻兘銈掋偟銉濄兗銉堛仐銇︺亜銈嬪牬鍚堛伄銇裤�併儐銈偣銉堢悊瑙c仺璩晱蹇滅瓟銈掔祫銇垮悎銈忋仜銇熴儠銈°偆銉紙鐢诲儚锛夈伄鍏ュ姏銇仼銇椼仸銇勩伨銇欍��
+ - `type` (string) 銈点儩銉笺儓銇曘倢銈嬨偪銈ゃ儣锛歚image`锛堢従鍦ㄣ伅鐢诲儚銈裤偆銉椼伄銇裤偟銉濄兗銉堬級
+ - `transfer_method` (string) 杌㈤�佹柟娉曘�佺敾鍍廢RL銇牬鍚堛伅`remote_url` / 銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銇牬鍚堛伅`local_file`
+ - `url` (string) 鐢诲儚URL锛堣虎閫佹柟娉曘亴`remote_url`銇牬鍚堬級
+ - `upload_file_id` (string) 銈€儍銉椼儹銉笺儔銇曘倢銇熴儠銈°偆銉獻D銆佷簨鍓嶃伀銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔API銈掗�氥仒銇︺偄銉冦儣銉兗銉夈仚銈嬪繀瑕併亴銇傘倞銇俱仚锛堣虎閫佹柟娉曘亴`local_file`銇牬鍚堬級
+ </Property>
+ </Properties>
+
+ ### 銉偣銉濄兂銈�
+ `response_mode`銇宍blocking`銇牬鍚堛�丆ompletionResponse銈儢銈搞偋銈儓銈掕繑鍗淬仐銇俱仚銆�
+ `response_mode`銇宍streaming`銇牬鍚堛�丆hunkCompletionResponse銈广儓銉兗銉犮倰杩斿嵈銇椼伨銇欍��
+
+ ### ChatCompletionResponse
+ 銈€儣銉伄瀹屽叏銇祼鏋溿倰杩斿嵈銆乣Content-Type`銇痐application/json`銇с仚銆�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `mode` (string) 銈€儣銉儮銉笺儔銆佸浐瀹氥仹`chat`
+ - `answer` (string) 瀹屽叏銇繙绛斿唴瀹�
+ - `metadata` (object) 銉°偪銉囥兗銈�
+ - `usage` (Usage) 銉€儑銉娇鐢ㄦ儏鍫�
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤銇ㄥ赴灞炪伄銉偣銉�
+ - `created_at` (int) 銉°儍銈汇兗銈镐綔鎴愩偪銈ゃ儬銈广偪銉炽儣銆佷緥锛�1705395332
+
+ ### ChunkChatCompletionResponse
+ 銈€儣銉亴鍑哄姏銇欍倠銈广儓銉兗銉犮儊銉c兂銈倰杩斿嵈銆乣Content-Type`銇痐text/event-stream`銇с仚銆�
+ 鍚勩偣銉堛儶銉笺儫銉炽偘銉併儯銉炽偗銇痐data:`銇у銇俱倞銆�2銇ゃ伄鏀硅鏂囧瓧`\n\n`銇у尯鍒囥倝銈屻伨銇欙細
+ <CodeGroup>
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
+ ```
+ </CodeGroup>
+ 銈广儓銉兗銉熴兂銈般儊銉c兂銈伄妲嬮�犮伅`event`銇倛銇c仸鐣般仾銈娿伨銇欙細
+ - `event: message` LLM銇屻儐銈偣銉堛儊銉c兂銈倰杩斻仚銈ゃ儥銉炽儓銆併仱銇俱倞瀹屽叏銇儐銈偣銉堛亴銉併儯銉炽偗褰㈠紡銇у嚭鍔涖仌銈屻伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓銇拷璺°仺浠ヤ笅銇敓鎴愬仠姝PI銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `answer` (string) LLM銇岃繑銇椼仧銉嗐偔銈广儓銉併儯銉炽偗銇唴瀹�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: message_end` 銉°儍銈汇兗銈哥祩浜嗐偆銉欍兂銉堛�併亾銇偆銉欍兂銉堛倰鍙椾俊銇欍倠銇ㄣ偣銉堛儶銉笺儫銉炽偘銇岀祩浜嗐仐銇熴亾銇ㄣ倰鎰忓懗銇椼伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓銇拷璺°仺浠ヤ笅銇敓鎴愬仠姝PI銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `metadata` (object) 銉°偪銉囥兗銈�
+ - `usage` (Usage) 銉€儑銉娇鐢ㄦ儏鍫�
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤銇ㄥ赴灞炪伄銉偣銉�
+ - `event: tts_message` TTS闊冲0銈广儓銉兗銉犮偆銉欍兂銉堛�併仱銇俱倞闊冲0鍚堟垚鍑哄姏銆傚唴瀹广伅Mp3褰㈠紡銇煶澹般儢銉儍銈仹銆乥ase64鏂囧瓧鍒椼仺銇椼仸銈ㄣ兂銈炽兗銉夈仌銈屻仸銇勩伨銇欍�傚啀鐢熸檪銇崢銇玝ase64銈掋儑銈炽兗銉夈仐銇︺儣銉兗銉ゃ兗銇緵绲︺仚銈嬨仩銇戙仹銇欍�傦紙銇撱伄銉°儍銈汇兗銈搞伅鑷嫊鍐嶇敓銇屾湁鍔广仾鍫村悎銇伩鍒╃敤鍙兘锛�
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓銇拷璺°仺浠ヤ笅銇繙绛斿仠姝€偆銉炽偪銉笺儠銈с兗銈广伀浣跨敤
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `audio` (string) 闊冲0鍚堟垚寰屻伄闊冲0銆乥ase64銉嗐偔銈广儓銈炽兂銉嗐兂銉勩仺銇椼仸銈ㄣ兂銈炽兗銉夈�佸啀鐢熸檪銇崢銇玝ase64銈掋儑銈炽兗銉夈仐銇︺儣銉兗銉ゃ兗銇緵绲�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: tts_message_end` TTS闊冲0銈广儓銉兗銉犵祩浜嗐偆銉欍兂銉堛�併亾銇偆銉欍兂銉堛倰鍙椾俊銇欍倠銇ㄩ煶澹般偣銉堛儶銉笺儬銇岀祩浜嗐仐銇熴亾銇ㄣ倰绀恒仐銇俱仚銆�
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓銇拷璺°仺浠ヤ笅銇繙绛斿仠姝€偆銉炽偪銉笺儠銈с兗銈广伀浣跨敤
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `audio` (string) 绲備簡銈ゃ儥銉炽儓銇伅闊冲0銇屻仾銇勩仧銈併�佺┖鏂囧瓧鍒�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: message_replace` 銉°儍銈汇兗銈稿唴瀹圭疆鎻涖偆銉欍兂銉堛��
+ 鍑哄姏鍐呭銇儮銉囥儸銉笺偡銉с兂銇屾湁鍔广仾鍫村悎銆併偝銉炽儐銉炽儎銇屻儠銉┿偘浠樸亼銇曘倢銈嬨仺銆併亾銇偆銉欍兂銉堛倰閫氥仒銇︺儭銉冦偦銉笺偢鍐呭銇屼簨鍓嶈ō瀹氥仌銈屻仧杩斾俊銇疆銇嶆彌銇堛倝銈屻伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓銇拷璺°仺浠ヤ笅銇敓鎴愬仠姝PI銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `answer` (string) 缃彌鍐呭锛圠LM銇繑淇°儐銈偣銉堛仚銇广仸銈掔洿鎺ョ疆鎻涳級
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: error`
+ 銈广儓銉兗銉熴兂銈板嚘鐞嗕腑銇櫤鐢熴仐銇熶緥澶栥伅銆併偣銉堛儶銉笺儬銈ゃ儥銉炽儓銇舰寮忋仹鍑哄姏銇曘倢銆併偍銉┿兗銈ゃ儥銉炽儓銈掑彈淇°仚銈嬨仺銈广儓銉兗銉犮亴绲備簡銇椼伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓銇拷璺°仺浠ヤ笅銇敓鎴愬仠姝PI銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `status` (int) HTTP銈广儐銉笺偪銈广偝銉笺儔
+ - `code` (string) 銈ㄣ儵銉笺偝銉笺儔
+ - `message` (string) 銈ㄣ儵銉笺儭銉冦偦銉笺偢
+ - `event: ping` 鎺ョ稓銈掔董鎸併仚銈嬨仧銈�10绉掋仈銇ㄣ伄Ping銈ゃ儥銉炽儓銆�
+
+ ### 銈ㄣ儵銉�
+ - 404, 浼氳┍銇屽瓨鍦ㄣ仐銇俱仜銈�
+ - 400, `invalid_param`, 銉戙儵銉°兗銈垮叆鍔涚暟甯�
+ - 400, `app_unavailable`, 銈€儣銉ō瀹氥亴鍒╃敤銇с亶銇俱仜銈�
+ - 400, `provider_not_initialize`, 鍒╃敤鍙兘銇儮銉囥儷瑾嶈鎯呭牨瑷畾銇屻亗銈娿伨銇涖倱
+ - 400, `provider_quota_exceeded`, 銉€儑銉懠銇冲嚭銇椼偗銈┿兗銈夸笉瓒�
+ - 400, `model_currently_not_support`, 鐝惧湪銇儮銉囥儷銇埄鐢ㄣ仹銇嶃伨銇涖倱
+ - 400, `completion_request_error`, 銉嗐偔銈广儓鐢熸垚銇け鏁椼仐銇俱仐銇�
+ - 500, 鍐呴儴銈点兗銉愩兗銈ㄣ儵銉�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/completion-messages" targetCode={`curl -X POST '${props.appDetail.api_base_url}/completion-messages' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": {"query": "Hello, world!"},\n "response_mode": "streaming",\n "user": "abc-123"\n}'\n`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/completion-messages' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {
+ "query": "Hello, world!"
+ },
+ "response_mode": "streaming",
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+ ### 銉栥儹銉冦偔銉炽偘銉€兗銉�
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "event": "message",
+ "message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "mode": "completion",
+ "answer": "Hello World!...",
+ "metadata": {
+ "usage": {
+ "prompt_tokens": 1033,
+ "prompt_unit_price": "0.001",
+ "prompt_price_unit": "0.001",
+ "prompt_price": "0.0010330",
+ "completion_tokens": 128,
+ "completion_unit_price": "0.002",
+ "completion_price_unit": "0.001",
+ "completion_price": "0.0002560",
+ "total_tokens": 1161,
+ "total_price": "0.0012890",
+ "currency": "USD",
+ "latency": 0.7682376249867957
+ }
+ },
+ "created_at": 1705407629
+ }
+ ```
+ </CodeGroup>
+ ### 銈广儓銉兗銉熴兂銈般儮銉笺儔
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔'
+ name='#file-upload'
+/>
+<Row>
+ <Col>
+ 銉°儍銈汇兗銈搁�佷俊鏅傘伀浣跨敤銇欍倠銉曘偂銈ゃ儷锛堢従鍦ㄣ伅鐢诲儚銇伩瀵惧繙锛夈倰銈€儍銉椼儹銉笺儔銇椼�佺敾鍍忋仺銉嗐偔銈广儓銇優銉儊銉€兗銉�銉仾鐞嗚В銈掑彲鑳姐伀銇椼伨銇欍��
+ png銆乯pg銆乯peg銆亀ebp銆乬if褰㈠紡銇蹇溿仐銇︺亜銇俱仚銆�
+ <i>銈€儍銉椼儹銉笺儔銇曘倢銇熴儠銈°偆銉伅銆佺従鍦ㄣ伄銈ㄣ兂銉夈儲銉笺偠銉笺伄銇裤亴浣跨敤銇с亶銇俱仚銆�</i>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ 銇撱伄銈ゃ兂銈裤兗銉曘偋銉笺偣銇痐multipart/form-data`銉偗銈ㄣ偣銉堛亴蹇呰銇с仚銆�
+ - `file` (File) 蹇呴爤
+ 銈€儍銉椼儹銉笺儔銇欍倠銉曘偂銈ゃ儷銆�
+ - `user` (string) 蹇呴爤
+ 闁嬬櫤鑰呫伄銉兗銉仹瀹氱京銇曘倢銇熴儲銉笺偠銉艰瓨鍒ュ瓙銆傘偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇傘倠蹇呰銇屻亗銈娿伨銇欍��
+
+ ### 銉偣銉濄兂銈�
+ 銈€儍銉椼儹銉笺儔銇屾垚鍔熴仚銈嬨仺銆併偟銉笺儛銉笺伅銉曘偂銈ゃ儷銇甀D銇ㄩ枹閫f儏鍫便倰杩斻仐銇俱仚銆�
+ - `id` (uuid) ID
+ - `name` (string) 銉曘偂銈ゃ儷鍚�
+ - `size` (int) 銉曘偂銈ゃ儷銈点偆銈猴紙銉愩偆銉堬級
+ - `extension` (string) 銉曘偂銈ゃ儷鎷″嫉瀛�
+ - `mime_type` (string) 銉曘偂銈ゃ儷銇甅IME銈裤偆銉�
+ - `created_by` (uuid) 銈ㄣ兂銉夈儲銉笺偠銉糏D
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+
+ ### 銈ㄣ儵銉�
+ - 400, `no_file_uploaded`, 銉曘偂銈ゃ儷銈掓彁渚涖仚銈嬪繀瑕併亴銇傘倞銇俱仚
+ - 400, `too_many_files`, 鐝惧湪銇�1銇ゃ伄銉曘偂銈ゃ儷銇伩鍙椼亼浠樸亼銇︺亜銇俱仚
+ - 400, `unsupported_preview`, 銉曘偂銈ゃ儷銇屻儣銉儞銉ャ兗銇蹇溿仐銇︺亜銇俱仜銈�
+ - 400, `unsupported_estimate`, 銉曘偂銈ゃ儷銇屾帹瀹氥伀瀵惧繙銇椼仸銇勩伨銇涖倱
+ - 413, `file_too_large`, 銉曘偂銈ゃ儷銇屽ぇ銇嶃仚銇庛伨銇�
+ - 415, `unsupported_file_type`, 銈点儩銉笺儓銇曘倢銇︺亜銇亜鎷″嫉瀛愩仹銇欍�傜従鍦ㄣ伅銉夈偔銉ャ儭銉炽儓銉曘偂銈ゃ儷銇伩鍙椼亼浠樸亼銇︺亜銇俱仚
+ - 503, `s3_connection_failed`, S3銈点兗銉撱偣銇帴缍氥仹銇嶃伨銇涖倱
+ - 503, `s3_permission_denied`, S3銇搞伄銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔妯╅檺銇屻亗銈娿伨銇涖倱
+ - 503, `s3_file_too_large`, 銉曘偂銈ゃ儷銇孲3銇偟銈ゃ偤鍒堕檺銈掕秴銇堛仸銇勩伨銇�
+ - 500, 鍐呴儴銈点兗銉愩兗銈ㄣ儵銉�
+
+ </Col>
+ <Col sticky>
+ ### 銉偗銈ㄣ偣銉堜緥
+ <CodeGroup title="Request" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+
+ ### 銉偣銉濄兂銈逛緥
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": "6ad1ab0a-73ff-4ac1-b9e4-cdb312f71f13",
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/completion-messages/:task_id/stop'
+ method='POST'
+ title='鐢熸垚銇仠姝�'
+ name='#stop-generatebacks'
+/>
+<Row>
+ <Col>
+ 銈广儓銉兗銉熴兂銈般儮銉笺儔銇с伄銇裤偟銉濄兗銉堛仌銈屻仸銇勩伨銇欍��
+ ### 銉戙偣
+ - `task_id` (string) 銈裤偣銈疘D銆併偣銉堛儶銉笺儫銉炽偘銉併儯銉炽偗銇繑淇°亱銈夊彇寰楀彲鑳�
+ 銉偗銈ㄣ偣銉堛儨銉囥偅
+ - `user` (string) 蹇呴爤
+ 銉︺兗銈躲兗璀樺垾瀛愩�傘偍銉炽儔銉︺兗銈躲兗銇韩鍏冦倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�併儭銉冦偦銉笺偢閫佷俊銈ゃ兂銈裤兗銉曘偋銉笺偣銇ф浮銇曘倢銇熴儲銉笺偠銉笺仺涓�鑷淬仚銈嬪繀瑕併亴銇傘倞銇俱仚銆�
+ ### 銉偣銉濄兂銈�
+ - `result` (string) 甯搞伀"success"銈掕繑銇椼伨銇�
+ </Col>
+ <Col sticky>
+ ### 銉偗銈ㄣ偣銉堜緥
+ <CodeGroup title="Request" tag="POST" label="/completion-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+
+ ### 銉偣銉濄兂銈逛緥
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages/:message_id/feedbacks'
+ method='POST'
+ title='銉°儍銈汇兗銈搞儠銈c兗銉夈儛銉冦偗'
+ name='#feedbacks'
+/>
+<Row>
+ <Col>
+ 銈ㄣ兂銉夈儲銉笺偠銉笺伅銉曘偅銉笺儔銉愩儍銈儭銉冦偦銉笺偢銈掓彁渚涖仹銇嶃�併偄銉椼儶銈便兗銈枫儳銉抽枊鐧鸿�呫亴鏈熷緟銇曘倢銈嬪嚭鍔涖倰鏈�閬╁寲銇欍倠銇伀褰圭珛銇°伨銇欍��
+
+ ### 銉戙偣
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ 銉°儍銈汇兗銈窱D
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='rating' type='string' key='rating'>
+ 楂樿渚°伅`like`銆佷綆瑭曚尽銇痐dislike`銆侀珮瑭曚尽銇彇銈婃秷銇椼伅`null`
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 闁嬬櫤鑰呫伄銉兗銉仹瀹氱京銇曘倢銇熴儲銉笺偠銉艰瓨鍒ュ瓙銆傘偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇傘倠蹇呰銇屻亗銈娿伨銇欍��
+ </Property>
+ <Property name='content' type='string' key='content'>
+ 銉°儍銈汇兗銈搞伄銉曘偅銉笺儔銉愩儍銈仹銇欍��
+ </Property>
+ </Properties>
+
+ ### 銉偣銉濄兂銈�
+ - `result` (string) 甯搞伀"success"銈掕繑銇椼伨銇�
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/messages/:message_id/feedbacks" targetCode={`curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks \\\n --header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "rating": "like",\n "user": "abc-123",\n "content": "message feedback information"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "rating": "like",
+ "user": "abc-123",
+ "content": "message feedback information"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/app/feedbacks'
+ method='GET'
+ title='銈€儣銉伄銉°儍銈汇兗銈搞伄銆屻亜銇勩伃銆嶃仺銉曘偅銉笺儔銉愩儍銈倰鍙栧緱'
+ name='#app-feedbacks'
+/>
+<Row>
+ <Col>
+ 銈€儣銉伄銈ㄣ兂銉夈儲銉笺偠銉笺亱銈夈伄銉曘偅銉笺儔銉愩儍銈倓銆屻亜銇勩伃銆嶃倰鍙栧緱銇椼伨銇欍��
+
+ ### 銈偍銉�
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 锛堜换鎰忥級銉氥兗銈哥暘鍙枫�傘儑銉曘偐銉儓鍊わ細1
+ </Property>
+ </Properties>
+
+ <Properties>
+ <Property name='limit' type='string' key='limit'>
+ 锛堜换鎰忥級1銉氥兗銈搞亗銇熴倞銇欢鏁般�傘儑銉曘偐銉儓鍊わ細20
+ </Property>
+ </Properties>
+
+ ### 銉偣銉濄兂銈�
+ - `data` (銉偣銉�) 銇撱伄銈€儣銉伄銆屻亜銇勩伃銆嶃仺銉曘偅銉笺儔銉愩儍銈伄涓�瑕с倰杩斻仐銇俱仚銆�
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/app/feedbacks" targetCode={`curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "8c0fbed8-e2f9-49ff-9f0e-15a35bdd0e25",
+ "app_id": "f252d396-fe48-450e-94ec-e184218e7346",
+ "conversation_id": "2397604b-9deb-430e-b285-4726e51fd62d",
+ "message_id": "709c0b0f-0a96-4a4e-91a4-ec0889937b11",
+ "rating": "like",
+ "content": "message feedback information-3",
+ "from_source": "user",
+ "from_end_user_id": "74286412-9a1a-42c1-929c-01edb1d381d5",
+ "from_account_id": null,
+ "created_at": "2025-04-24T09:24:38",
+ "updated_at": "2025-04-24T09:24:38"
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/text-to-audio'
+ method='POST'
+ title='銉嗐偔銈广儓銇嬨倝闊冲0'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ 銉嗐偔銈广儓銈掗煶澹般伀澶夋彌銇椼伨銇欍��
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='message_id' type='str' key='message_id'>
+ Dify銇岀敓鎴愩仐銇熴儐銈偣銉堛儭銉冦偦銉笺偢銇牬鍚堛�佺敓鎴愩仌銈屻仧message-id銈掔洿鎺ユ浮銇欍仩銇戙仹銇欍�傘儛銉冦偗銈ㄣ兂銉夈伅message-id銈掍娇鐢ㄣ仐銇﹀蹇溿仚銈嬨偝銉炽儐銉炽儎銈掓绱€仐銆侀煶澹版儏鍫便倰鐩存帴鍚堟垚銇椼伨銇欍�俶essage_id銇╰ext銇浮鏂广亴鍚屾檪銇彁渚涖仌銈屻仧鍫村悎銆乵essage_id銇屽劒鍏堛仌銈屻伨銇欍��
+ </Property>
+ <Property name='text' type='str' key='text'>
+ 闊冲0鐢熸垚銈炽兂銉嗐兂銉勩��
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 闁嬬櫤鑰呫亴瀹氱京銇椼仧銉︺兗銈躲兗璀樺垾瀛愩�傘偄銉椼儶鍐呫仹涓�鎰忔�с倰纰轰繚銇欍倠蹇呰銇屻亗銈娿伨銇欍��
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "Hello Dify",\n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
+ "text": "Hello Dify",
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="headers">
+ ```json {{ title: 'headers' }}
+ {
+ "Content-Type": "audio/wav"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇熀鏈儏鍫便倰鍙栧緱'
+ name='#info'
+/>
+<Row>
+ <Col>
+ 銇撱伄銈€儣銉偙銉笺偡銉с兂銇熀鏈儏鍫便倰鍙栧緱銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻伨銇�
+
+ ### Response
+ - `name` (string) 銈€儣銉偙銉笺偡銉с兂銇悕鍓�
+ - `description` (string) 銈€儣銉偙銉笺偡銉с兂銇鏄�
+ - `tags` (array[string]) 銈€儣銉偙銉笺偡銉с兂銇偪銈�
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇儜銉┿儭銉笺偪鎯呭牨銈掑彇寰�'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ 銉氥兗銈搁枊濮嬫檪銇�佹鑳姐�佸叆鍔涖儜銉┿儭銉笺偪鍚嶃�併偪銈ゃ儣銆併儑銉曘偐銉儓鍊ゃ仾銇┿伄鎯呭牨銈掑彇寰椼仚銈嬨仧銈併伀浣跨敤銇曘倢銇俱仚銆�
+
+ ### 銉偣銉濄兂銈�
+ - `opening_statement` (string) 闁嬪鏂�
+ - `suggested_questions` (array[string]) 闁嬪鏅傘伄鎻愭璩晱銉偣銉�
+ - `suggested_questions_after_answer` (object) 鍥炵瓟寰屻伄鎻愭璩晱銈掓湁鍔广伀銇椼伨銇欍��
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `speech_to_text` (object) 闊冲0銇嬨倝銉嗐偔銈广儓
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `retriever_resource` (object) 寮曠敤銇ㄥ赴灞�
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `annotation_reply` (object) 娉ㄩ噲浠樸亶杩斾俊
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `user_input_form` (array[object]) 銉︺兗銈躲兗鍏ュ姏銉曘偐銉笺儬瑷畾
+ - `text-input` (object) 銉嗐偔銈广儓鍏ュ姏銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `paragraph` (object) 娈佃惤銉嗐偔銈广儓鍏ュ姏銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `select` (object) 銉夈儹銉冦儣銉�銈︺兂銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `options` (array[string]) 銈儣銈枫儳銉冲��
+ - `file_upload` (object) 銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔瑷畾
+ - `image` (object) 鐢诲儚瑷畾
+ 鐝惧湪銇敾鍍忋偪銈ゃ儣銇伩瀵惧繙锛歚png`銆乣jpg`銆乣jpeg`銆乣webp`銆乣gif`
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `number_limits` (int) 鐢诲儚鏁板埗闄愩�併儑銉曘偐銉儓銇�3
+ - `transfer_methods` (array[string]) 杌㈤�佹柟娉曘儶銈广儓銆乺emote_url銆乴ocal_file銆併亜銇氥倢銇嬨倰閬告姙
+ - `system_parameters` (object) 銈枫偣銉嗐儬銉戙儵銉°兗銈�
+ - `file_size_limit` (int) 銉夈偔銉ャ儭銉炽儓銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+ - `image_file_size_limit` (int) 鐢诲儚銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+ - `audio_file_size_limit` (int) 闊冲0銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+ - `video_file_size_limit` (int) 鍕曠敾銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "opening_statement": "Hello!",
+ "suggested_questions_after_answer": {
+ "enabled": true
+ },
+ "speech_to_text": {
+ "enabled": true
+ },
+ "retriever_resource": {
+ "enabled": true
+ },
+ "annotation_reply": {
+ "enabled": true
+ },
+ "user_input_form": [
+ {
+ "paragraph": {
+ "label": "Query",
+ "variable": "query",
+ "required": true,
+ "default": ""
+ }
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": false,
+ "number_limits": 3,
+ "detail": "high",
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='銈€儣銉伄WebApp瑷畾銈掑彇寰�'
+ name='#site'
+/>
+<Row>
+ <Col>
+ 銈€儣銉伄WebApp瑷畾銈掑彇寰椼仚銈嬨仧銈併伀浣跨敤銇椼伨銇欍��
+ ### 銉偣銉濄兂銈�
+ - `title` (string) WebApp鍚�
+ - `chat_color_theme` (string) 銉併儯銉冦儓銇壊銉嗐兗銉炪��16閫叉暟褰㈠紡
+ - `chat_color_theme_inverted` (bool) 銉併儯銉冦儓銇壊銉嗐兗銉炪倰鍙嶈虎銇欍倠銇嬨仼銇嗐亱
+ - `icon_type` (string) 銈€偆銈炽兂銈裤偆銉椼�乣emoji`-绲垫枃瀛椼�乣image`-鐢诲儚
+ - `icon` (string) 銈€偆銈炽兂銆俙emoji`銈裤偆銉椼伄鍫村悎銇档鏂囧瓧銆乣image`銈裤偆銉椼伄鍫村悎銇敾鍍廢RL
+ - `icon_background` (string) 16閫叉暟褰㈠紡銇儗鏅壊
+ - `icon_url` (string) 銈€偆銈炽兂銇甎RL
+ - `description` (string) 瑾槑
+ - `copyright` (string) 钁椾綔妯╂儏鍫�
+ - `privacy_policy` (string) 銉椼儵銈ゃ儛銈枫兗銉濄儶銈枫兗銇儶銉炽偗
+ - `custom_disclaimer` (string) 銈偣銈裤儬鍏嶈铂浜嬮爡
+ - `default_language` (string) 銉囥儠銈┿儷銉堣█瑾�
+ - `show_workflow_steps` (bool) 銉兗銈儠銉兗銇┏绱般倰琛ㄧず銇欍倠銇嬨仼銇嗐亱
+ - `use_icon_as_answer_icon` (bool) WebApp銇偄銈ゃ偝銉炽倰銉併儯銉冦儓鍐呫伄馃銇疆銇嶆彌銇堛倠銇嬨仼銇嗐亱
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "chat_color_theme": "#ff4a4a",
+ "chat_color_theme_inverted": false,
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ "use_icon_as_answer_icon": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
diff --git a/app/components/develop/template/template.zh.mdx b/app/components/develop/template/template.zh.mdx
new file mode 100644
index 0000000..df83684
--- /dev/null
+++ b/app/components/develop/template/template.zh.mdx
@@ -0,0 +1,967 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
+
+# 鏂囨湰鐢熸垚鍨嬪簲鐢� API
+
+鏂囨湰鐢熸垚搴旂敤鏃犱細璇濇敮鎸侊紝閫傚悎鐢ㄤ簬缈昏瘧/鏂囩珷鍐欎綔/鎬荤粨 AI 绛夌瓑銆�
+
+<div>
+ ### 鍩虹 URL
+ <CodeGroup title="Code" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### 閴存潈
+
+
+ Dify Service API 浣跨敤 `API-Key` 杩涜閴存潈銆�
+ <i>**寮虹儓寤鸿寮�鍙戣�呮妸 `API-Key` 鏀惧湪鍚庣瀛樺偍锛岃�岄潪鍒嗕韩鎴栬�呮斁鍦ㄥ鎴风瀛樺偍锛屼互鍏� `API-Key` 娉勯湶锛屽鑷磋储浜ф崯澶便��**</i>
+ 鎵�鏈� API 璇锋眰閮藉簲鍦� **`Authorization`** HTTP Header 涓寘鍚偍鐨� `API-Key`锛屽涓嬫墍绀猴細
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/completion-messages'
+ method='POST'
+ title='鍙戦�佹秷鎭�'
+ name='#Create-Completion-Message'
+/>
+<Row>
+ <Col>
+ 鍙戦�佽姹傜粰鏂囨湰鐢熸垚鍨嬪簲鐢ㄣ��
+
+ ### Request Body
+
+ <Properties>
+ <Property name='inputs' type='object' key='inputs'>
+ (閫夊~)鍏佽浼犲叆 App 瀹氫箟鐨勫悇鍙橀噺鍊笺��
+ inputs 鍙傛暟鍖呭惈浜嗗缁勯敭鍊煎锛圞ey/Value pairs锛夛紝姣忕粍鐨勯敭瀵瑰簲涓�涓壒瀹氬彉閲忥紝姣忕粍鐨勫�煎垯鏄鍙橀噺鐨勫叿浣撳�笺��
+ 鏂囨湰鐢熸垚鍨嬪簲鐢ㄨ姹傝嚦灏戜紶鍏ヤ竴缁勯敭鍊煎銆�
+ - `query` (string) 蹇呭~
+ 鐢ㄦ埛杈撳叆鐨勬枃鏈唴瀹广��
+ </Property>
+ <Property name='response_mode' type='string' key='response_mode'>
+ - `streaming` 娴佸紡妯″紡锛堟帹鑽愶級銆傚熀浜� SSE锛�**[Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)**锛夊疄鐜扮被浼兼墦瀛楁満杈撳嚭鏂瑰紡鐨勬祦寮忚繑鍥炪��
+ - `blocking` 闃诲妯″紡锛岀瓑寰呮墽琛屽畬姣曞悗杩斿洖缁撴灉銆傦紙璇锋眰鑻ユ祦绋嬭緝闀垮彲鑳戒細琚腑鏂級銆�
+ <i>鐢变簬 Cloudflare 闄愬埗锛岃姹備細鍦� 100 绉掕秴鏃舵棤杩斿洖鍚庝腑鏂��</i>
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屾柟渚挎绱€�佺粺璁°��
+ 鐢卞紑鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='files' type='array[object]' key='files'>
+ 涓婁紶鐨勬枃浠躲��
+ - `type` (string) 鏀寔绫诲瀷锛氬浘鐗� `image`锛堢洰鍓嶄粎鏀寔鍥剧墖鏍煎紡锛� 銆�
+ - `transfer_method` (string) 浼犻�掓柟寮�:
+ - `remote_url`: 鍥剧墖鍦板潃銆�
+ - `local_file`: 涓婁紶鏂囦欢銆�
+ - `url` 鍥剧墖鍦板潃銆傦紙浠呭綋浼犻�掓柟寮忎负 `remote_url` 鏃讹級銆�
+ - `upload_file_id` 涓婁紶鏂囦欢 ID銆傦紙浠呭綋浼犻�掓柟寮忎负 `local_file `鏃讹級銆�
+ </Property>
+ </Properties>
+
+ ### Response
+ <Properties>
+ 褰� `response_mode` 涓� `blocking` 鏃讹紝杩斿洖 ChatCompletionResponse object銆�
+ 褰� `response_mode` 涓� `streaming`鏃讹紝杩斿洖 ChunkChatCompletionResponse object 娴佸紡搴忓垪銆�
+
+ ### ChatCompletionResponse
+ 杩斿洖瀹屾暣鐨� App 缁撴灉锛宍Content-Type` 涓� `application/json`銆�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `mode` (string) App 妯″紡锛屽浐瀹氫负 chat
+ - `answer` (string) 瀹屾暣鍥炲鍐呭
+ - `metadata` (object) 鍏冩暟鎹�
+ - `usage` (Usage) 妯″瀷鐢ㄩ噺淇℃伅
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤鍜屽綊灞炲垎娈靛垪琛�
+ - `created_at` (int) 娑堟伅鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+
+ ### ChunkChatCompletionResponse
+ 杩斿洖 App 杈撳嚭鐨勬祦寮忓潡锛宍Content-Type` 涓� `text/event-stream`銆�
+ 姣忎釜娴佸紡鍧楀潎涓� data: 寮�澶达紝鍧椾箣闂翠互 `\n\n` 鍗充袱涓崲琛岀鍒嗛殧锛屽涓嬫墍绀猴細
+ <CodeGroup>
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
+ ```
+ </CodeGroup>
+ 娴佸紡鍧椾腑鏍规嵁 `event` 涓嶅悓锛岀粨鏋勪篃涓嶅悓锛�
+ - `event: message` LLM 杩斿洖鏂囨湰鍧椾簨浠讹紝鍗筹細瀹屾暣鐨勬枃鏈互鍒嗗潡鐨勬柟寮忚緭鍑恒��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `answer` (string) LLM 杩斿洖鏂囨湰鍧楀唴瀹�
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: message_end` 娑堟伅缁撴潫浜嬩欢锛屾敹鍒版浜嬩欢鍒欎唬琛ㄦ枃鏈祦寮忚繑鍥炵粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `metadata` (object) 鍏冩暟鎹�
+ - `usage` (Usage) 妯″瀷鐢ㄩ噺淇℃伅
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤鍜屽綊灞炲垎娈靛垪琛�
+ - `event: tts_message` TTS 闊抽娴佷簨浠讹紝鍗筹細璇煶鍚堟垚杈撳嚭銆傚唴瀹规槸Mp3鏍煎紡鐨勯煶棰戝潡锛屼娇鐢� base64 缂栫爜鍚庣殑瀛楃涓诧紝鎾斁鐨勬椂鍊欑洿鎺ヨВ鐮佸嵆鍙��(寮�鍚嚜鍔ㄦ挱鏀炬墠鏈夋娑堟伅)
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `audio` (string) 璇煶鍚堟垚涔嬪悗鐨勯煶棰戝潡浣跨敤 Base64 缂栫爜涔嬪悗鐨勬枃鏈唴瀹癸紝鎾斁鐨勬椂鍊欑洿鎺� base64 瑙g爜閫佸叆鎾斁鍣ㄥ嵆鍙�
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: tts_message_end` TTS 闊抽娴佺粨鏉熶簨浠讹紝鏀跺埌杩欎釜浜嬩欢琛ㄧず闊抽娴佽繑鍥炵粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `audio` (string) 缁撴潫浜嬩欢鏄病鏈夐煶棰戠殑锛屾墍浠ヨ繖閲屾槸绌哄瓧绗︿覆
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: message_replace` 娑堟伅鍐呭鏇挎崲浜嬩欢銆�
+ 寮�鍚唴瀹瑰鏌ュ拰瀹℃煡杈撳嚭鍐呭鏃讹紝鑻ュ懡涓簡瀹℃煡鏉′欢锛屽垯浼氶�氳繃姝や簨浠舵浛鎹㈡秷鎭唴瀹逛负棰勮鍥炲銆�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `answer` (string) 鏇挎崲鍐呭锛堢洿鎺ユ浛鎹� LLM 鎵�鏈夊洖澶嶆枃鏈級
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: error`
+ 娴佸紡杈撳嚭杩囩▼涓嚭鐜扮殑寮傚父浼氫互 stream event 褰㈠紡杈撳嚭锛屾敹鍒板紓甯镐簨浠跺悗鍗崇粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `status` (int) HTTP 鐘舵�佺爜
+ - `code` (string) 閿欒鐮�
+ - `message` (string) 閿欒娑堟伅
+ - `event: ping` 姣� 10s 涓�娆$殑 ping 浜嬩欢锛屼繚鎸佽繛鎺ュ瓨娲汇��
+
+ ### Errors
+ - 404锛屽璇濅笉瀛樺湪
+ - 400锛宍invalid_param`锛屼紶鍏ュ弬鏁板紓甯�
+ - 400锛宍app_unavailable`锛孉pp 閰嶇疆涓嶅彲鐢�
+ - 400锛宍provider_not_initialize`锛屾棤鍙敤妯″瀷鍑嵁閰嶇疆
+ - 400锛宍provider_quota_exceeded`锛屾ā鍨嬭皟鐢ㄩ搴︿笉瓒�
+ - 400锛宍model_currently_not_support`锛屽綋鍓嶆ā鍨嬩笉鍙敤
+ - 400锛宍completion_request_error`锛屾枃鏈敓鎴愬け璐�
+ - 500锛屾湇鍔″唴閮ㄥ紓甯�
+
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/completion-messages" targetCode={`curl -X POST '${props.appDetail.api_base_url}/completion-messages' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": {"query": "Hello, world!"},\n "response_mode": "streaming",\n "user": "abc-123"\n}'\n`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/completion-messages' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {
+ "query": "Hello, world!"
+ },
+ "response_mode": "streaming",
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+ ### blocking
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "0b089b9a-24d9-48cc-94f8-762677276261",
+ "answer": "how are you?",
+ "created_at": 1679586667
+ }
+ ```
+ </CodeGroup>
+ ### streaming
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " I", "created_at": 1679586595}
+ data: {"id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "answer": " I", "created_at": 1679586595}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='涓婁紶鏂囦欢'
+ name='#files-upload'
+/>
+<Row>
+ <Col>
+ 涓婁紶鏂囦欢锛堢洰鍓嶄粎鏀寔鍥剧墖锛夊苟鍦ㄥ彂閫佹秷鎭椂浣跨敤锛屽彲瀹炵幇鍥炬枃澶氭ā鎬佺悊瑙c��
+ 鏀寔 png, jpg, jpeg, webp, gif 鏍煎紡銆�
+ <i>涓婁紶鐨勬枃浠朵粎渚涘綋鍓嶇粓绔敤鎴蜂娇鐢ㄣ��</i>
+
+ ### Request Body
+ 璇ユ帴鍙i渶浣跨敤 `multipart/form-data` 杩涜璇锋眰銆�
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ 瑕佷笂浼犵殑鏂囦欢銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屽繀椤诲拰鍙戦�佹秷鎭帴鍙d紶鍏� user 淇濇寔涓�鑷淬��
+ </Property>
+ </Properties>
+
+ ### Response
+ 鎴愬姛涓婁紶鍚庯紝鏈嶅姟鍣ㄤ細杩斿洖鏂囦欢鐨� ID 鍜岀浉鍏充俊鎭��
+ - `id` (uuid) ID
+ - `name` (string) 鏂囦欢鍚�
+ - `size` (int) 鏂囦欢澶у皬锛坆yte锛�
+ - `extension` (string) 鏂囦欢鍚庣紑
+ - `mime_type` (string) 鏂囦欢 mime-type
+ - `created_by` (uuid) 涓婁紶浜� ID
+ - `created_at` (timestamp) 涓婁紶鏃堕棿
+
+ ### Errors
+ - 400锛宍no_file_uploaded`锛屽繀椤绘彁渚涙枃浠�
+ - 400锛宍too_many_files`锛岀洰鍓嶅彧鎺ュ彈涓�涓枃浠�
+ - 400锛宍unsupported_preview`锛岃鏂囦欢涓嶆敮鎸侀瑙�
+ - 400锛宍unsupported_estimate`锛岃鏂囦欢涓嶆敮鎸佷及绠�
+ - 413锛宍file_too_large`锛屾枃浠跺お澶�
+ - 415锛宍unsupported_file_type`锛屼笉鏀寔鐨勬墿灞曞悕锛屽綋鍓嶅彧鎺ュ彈鏂囨。绫绘枃浠�
+ - 503锛宍s3_connection_failed`锛屾棤娉曡繛鎺ュ埌 S3 鏈嶅姟
+ - 503锛宍s3_permission_denied`锛屾棤鏉冮檺涓婁紶鏂囦欢鍒� S3
+ - 503锛宍s3_file_too_large`锛屾枃浠惰秴鍑� S3 澶у皬闄愬埗
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": 123,
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+<Heading
+ url='/completion-messages/:task_id/stop'
+ method='POST'
+ title='鍋滄鍝嶅簲'
+ name='#Stop'
+/>
+<Row>
+ <Col>
+ 浠呮敮鎸佹祦寮忔ā寮忋��
+ ### Path
+ - `task_id` (string) 浠诲姟 ID锛屽彲鍦ㄦ祦寮忚繑鍥� Chunk 涓幏鍙�
+
+ ### Request Body
+ - `user` (string) Required
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屽繀椤诲拰鍙戦�佹秷鎭帴鍙d紶鍏� user 淇濇寔涓�鑷淬��
+ ### Response
+ - `result` (string) 鍥哄畾杩斿洖 success
+ </Col>
+ <Col sticky>
+ <CodeGroup title="Request" tag="POST" label="/completion-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/completion-messages/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/messages/:message_id/feedbacks'
+ method='POST'
+ title='娑堟伅鍙嶉锛堢偣璧烇級'
+ name='#feedbacks'
+/>
+<Row>
+ <Col>
+ 娑堟伅缁堢鐢ㄦ埛鍙嶉銆佺偣璧烇紝鏂逛究搴旂敤寮�鍙戣�呬紭鍖栬緭鍑洪鏈熴��
+
+ ### Path Params
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ 娑堟伅 ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+
+ <Properties>
+ <Property name='rating' type='string' key='rating'>
+ 鐐硅禐 like, 鐐硅俯 dislike, 鎾ら攢鐐硅禐 null
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='content' type='string' key='content'>
+ 娑堟伅鍙嶉鐨勫叿浣撲俊鎭��
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) 鍥哄畾杩斿洖 success
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/messages/:message_id/feedbacks" targetCode={`curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "rating": "like",\n "user": "abc-123",\n "content": "message feedback information"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "rating": "like",
+ "user": "abc-123",
+ "content": "message feedback information"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/app/feedbacks'
+ method='GET'
+ title='Get feedbacks of application'
+ name='#app-feedbacks'
+/>
+<Row>
+ <Col>
+ Get application's feedbacks.
+
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 锛坥ptional锛塸agination锛宒efault锛�1
+ </Property>
+ </Properties>
+
+ <Properties>
+ <Property name='limit' type='string' key='limit'>
+ 锛坥ptional锛� records per page default锛�20
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (List) return apps feedback list.
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/app/feedbacks" targetCode={`curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "8c0fbed8-e2f9-49ff-9f0e-15a35bdd0e25",
+ "app_id": "f252d396-fe48-450e-94ec-e184218e7346",
+ "conversation_id": "2397604b-9deb-430e-b285-4726e51fd62d",
+ "message_id": "709c0b0f-0a96-4a4e-91a4-ec0889937b11",
+ "rating": "like",
+ "content": "message feedback information-3",
+ "from_source": "user",
+ "from_end_user_id": "74286412-9a1a-42c1-929c-01edb1d381d5",
+ "from_account_id": null,
+ "created_at": "2025-04-24T09:24:38",
+ "updated_at": "2025-04-24T09:24:38"
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/text-to-audio'
+ method='POST'
+ title='鏂囧瓧杞闊�'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ 鏂囧瓧杞闊炽��
+
+ ### Request Body
+
+ <Properties>
+ <Property name='message_id' type='str' key='message_id'>
+ Dify 鐢熸垚鐨勬枃鏈秷鎭紝閭d箞鐩存帴浼犻�掔敓鎴愮殑message-id 鍗冲彲锛屽悗鍙颁細閫氳繃 message_id 鏌ユ壘鐩稿簲鐨勫唴瀹圭洿鎺ュ悎鎴愯闊充俊鎭�傚鏋滃悓鏃朵紶 message_id 鍜� text锛屼紭鍏堜娇鐢� message_id銆�
+ </Property>
+ <Property name='text' type='str' key='text'>
+ 璇煶鐢熸垚鍐呭銆傚鏋滄病鏈変紶 message-id鐨勮瘽锛屽垯浼氫娇鐢ㄨ繖涓瓧娈电殑鍐呭
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "浣犲ソDify",\n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
+ "text": "浣犲ソDify",
+ "user": "abc-123",
+ "streaming": false
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="headers">
+ ```json {{ title: 'headers' }}
+ {
+ "Content-Type": "audio/wav"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='鑾峰彇搴旂敤鍩烘湰淇℃伅'
+ name='#info'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇搴旂敤鐨勫熀鏈俊鎭�
+ ### Response
+ - `name` (string) 搴旂敤鍚嶇О
+ - `description` (string) 搴旂敤鎻忚堪
+ - `tags` (array[string]) 搴旂敤鏍囩
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='鑾峰彇搴旂敤鍙傛暟'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬杩涘叆椤甸潰涓�寮�濮嬶紝鑾峰彇鍔熻兘寮�鍏炽�佽緭鍏ュ弬鏁板悕绉般�佺被鍨嬪強榛樿鍊肩瓑浣跨敤銆�
+
+ ### Response
+ - `opening_statement` (string) 寮�鍦虹櫧
+ - `suggested_questions` (array[string]) 寮�鍦烘帹鑽愰棶棰樺垪琛�
+ - `suggested_questions_after_answer` (object) 鍚敤鍥炵瓟鍚庣粰鍑烘帹鑽愰棶棰樸��
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `speech_to_text` (object) 璇煶杞枃鏈�
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `retriever_resource` (object) 寮曠敤鍜屽綊灞�
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `annotation_reply` (object) 鏍囪鍥炲
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `user_input_form` (array[object]) 鐢ㄦ埛杈撳叆琛ㄥ崟閰嶇疆
+ - `text-input` (object) 鏂囨湰杈撳叆鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `paragraph` (object) 娈佃惤鏂囨湰杈撳叆鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `select` (object) 涓嬫媺鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `options` (array[string]) 閫夐」鍊�
+ - `file_upload` (object) 鏂囦欢涓婁紶閰嶇疆
+ - `image` (object) 鍥剧墖璁剧疆
+ 褰撳墠浠呮敮鎸佸浘鐗囩被鍨嬶細`png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `number_limits` (int) 鍥剧墖鏁伴噺闄愬埗锛岄粯璁� 3
+ - `transfer_methods` (array[string]) 浼犻�掓柟寮忓垪琛紝remote_url , local_file锛屽繀閫変竴涓�
+ - `system_parameters` (object) 绯荤粺鍙傛暟
+ - `file_size_limit` (int) 鏂囨。涓婁紶澶у皬闄愬埗 (MB)
+ - `image_file_size_limit` (int) 鍥剧墖鏂囦欢涓婁紶澶у皬闄愬埗锛圡B锛�
+ - `audio_file_size_limit` (int) 闊抽鏂囦欢涓婁紶澶у皬闄愬埗 (MB)
+ - `video_file_size_limit` (int) 瑙嗛鏂囦欢涓婁紶澶у皬闄愬埗 (MB)
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'\\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "introduction": "nice to meet you",
+ "user_input_form": [
+ {
+ "text-input": {
+ "label": "a",
+ "variable": "a",
+ "required": true,
+ "max_length": 48,
+ "default": ""
+ }
+ },
+ {
+ // ...
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": true,
+ "number_limits": 3,
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='鑾峰彇搴旂敤 WebApp 璁剧疆'
+ name='#site'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇搴旂敤鐨� WebApp 璁剧疆
+ ### Response
+ - `title` (string) WebApp 鍚嶇О
+ - `chat_color_theme` (string) 鑱婂ぉ棰滆壊涓婚, hex 鏍煎紡
+ - `chat_color_theme_inverted` (bool) 鑱婂ぉ棰滆壊涓婚鏄惁鍙嶈浆
+ - `icon_type` (string) 鍥炬爣绫诲瀷, `emoji`-琛ㄦ儏, `image`-鍥剧墖
+ - `icon` (string) 鍥炬爣, 濡傛灉鏄� `emoji` 绫诲瀷, 鍒欐槸 emoji 琛ㄦ儏绗﹀彿, 濡傛灉鏄� `image` 绫诲瀷, 鍒欐槸鍥剧墖 URL
+ - `icon_background` (string) hex 鏍煎紡鐨勮儗鏅壊
+ - `icon_url` (string) 鍥炬爣 URL
+ - `description` (string) 鎻忚堪
+ - `copyright` (string) 鐗堟潈淇℃伅
+ - `privacy_policy` (string) 闅愮鏀跨瓥閾炬帴
+ - `custom_disclaimer` (string) 鑷畾涔夊厤璐e0鏄�
+ - `default_language` (string) 榛樿璇█
+ - `show_workflow_steps` (bool) 鏄惁鏄剧ず宸ヤ綔娴佽鎯�
+ - `use_icon_as_answer_icon` (bool) 鏄惁浣跨敤 WebApp 鍥炬爣鏇挎崲鑱婂ぉ涓殑 馃
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "chat_color_theme": "#ff4a4a",
+ "chat_color_theme_inverted": false,
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ "use_icon_as_answer_icon": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
+
+<Heading
+ url='/apps/annotations'
+ method='GET'
+ title='鑾峰彇鏍囨敞鍒楄〃'
+ name='#annotation_list'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 椤电爜
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ 姣忛〉鏁伴噺
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/apps/annotations"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/apps/annotations?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/apps/annotations?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ],
+ "has_more": false,
+ "limit": 20,
+ "total": 1,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations'
+ method='POST'
+ title='鍒涘缓鏍囨敞'
+ name='#create_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='question' type='string' key='question'>
+ 闂
+ </Property>
+ <Property name='answer' type='string' key='answer'>
+ 绛旀鍐呭
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/apps/annotations"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/apps/annotations' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"question": "What is your name?","answer": "I am Dify."}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/apps/annotations' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "question": "What is your name?",
+ "answer": "I am Dify."
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations/{annotation_id}'
+ method='PUT'
+ title='鏇存柊鏍囨敞'
+ name='#update_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='annotation_id' type='string' key='annotation_id'>
+ 鏍囨敞 ID
+ </Property>
+ <Property name='question' type='string' key='question'>
+ 闂
+ </Property>
+ <Property name='answer' type='string' key='answer'>
+ 绛旀鍐呭
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PUT"
+ label="/apps/annotations/{annotation_id}"
+ targetCode={`curl --location --request PUT '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"question": "What is your name?","answer": "I am Dify."}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PUT '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "question": "What is your name?",
+ "answer": "I am Dify."
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations/{annotation_id}'
+ method='DELETE'
+ title='鍒犻櫎鏍囨敞'
+ name='#delete_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='annotation_id' type='string' key='annotation_id'>
+ 鏍囨敞 ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PUT"
+ label="/apps/annotations/{annotation_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotation-reply/{action}'
+ method='POST'
+ title='鏍囨敞鍥炲鍒濆璁剧疆'
+ name='#initial_annotation_reply_settings'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='action' type='string' key='action'>
+ 鍔ㄤ綔锛屽彧鑳芥槸 'enable' 鎴� 'disable'
+ </Property>
+ <Property name='embedding_provider_name' type='string' key='embedding_provider_name'>
+ 鎸囧畾鐨勫祵鍏ユā鍨嬫彁渚涘晢, 蹇呴』鍏堝湪绯荤粺鍐呰瀹氬ソ鎺ュ叆鐨勬ā鍨嬶紝瀵瑰簲鐨勬槸provider瀛楁
+ </Property>
+ <Property name='embedding_model_name' type='string' key='embedding_model_name'>
+ 鎸囧畾鐨勫祵鍏ユā鍨嬶紝瀵瑰簲鐨勬槸model瀛楁
+ </Property>
+ <Property name='score_threshold' type='number' key='score_threshold'>
+ 鐩镐技搴﹂槇鍊硷紝褰撶浉浼煎害澶т簬璇ラ槇鍊兼椂锛岀郴缁熶細鑷姩鍥炲锛屽惁鍒欎笉鍥炲
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ 宓屽叆妯″瀷鐨勬彁渚涘晢鍜屾ā鍨嬪悕绉板彲浠ラ�氳繃浠ヤ笅鎺ュ彛鑾峰彇锛歷1/workspaces/current/models/model-types/text-embedding锛� 鍏蜂綋瑙侊細閫氳繃 API 缁存姢鐭ヨ瘑搴撱�� 浣跨敤鐨凙uthorization鏄疍ataset鐨凙PI Token銆�
+ 璇ユ帴鍙f槸寮傛鎵ц锛屾墍浠ヤ細杩斿洖涓�涓猨ob_id锛岄�氳繃鏌ヨjob鐘舵�佹帴鍙e彲浠ヨ幏鍙栧埌鏈�缁堢殑鎵ц缁撴灉銆�
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/apps/annotation-reply/{action}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/apps/annotation-reply/{action}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"score_threshold": 0.9, "embedding_provider_name": "zhipu", "embedding_model_name": "embedding_3"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST 'https://api.dify.ai/v1/apps/annotation-reply/{action}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "score_threshold": 0.9,
+ "embedding_provider_name": "zhipu",
+ "embedding_model_name": "embedding_3"
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
+ "job_status": "waiting"
+ }
+ ```
+
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotation-reply/{action}/status/{job_id}'
+ method='GET'
+ title='鏌ヨ鏍囨敞鍥炲鍒濆璁剧疆浠诲姟鐘舵��'
+ name='#initial_annotation_reply_settings_task_status'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='action' type='string' key='action'>
+ 鍔ㄤ綔锛屽彧鑳芥槸 'enable' 鎴� 'disable'锛屽苟涓斿繀椤诲拰鏍囨敞鍥炲鍒濆璁剧疆鎺ュ彛鐨勫姩浣滀竴鑷�
+ </Property>
+ <Property name='job_id' type='string' key='job_id'>
+ 浠诲姟 ID锛屼粠鏍囨敞鍥炲鍒濆璁剧疆鎺ュ彛杩斿洖鐨� job_id
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/apps/annotations"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/apps/annotation-reply/{action}/status/{job_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/apps/annotation-reply/{action}/status/{job_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
+ "job_status": "waiting",
+ "error_msg": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
diff --git a/app/components/develop/template/template_advanced_chat.en.mdx b/app/components/develop/template/template_advanced_chat.en.mdx
new file mode 100644
index 0000000..f460949
--- /dev/null
+++ b/app/components/develop/template/template_advanced_chat.en.mdx
@@ -0,0 +1,1660 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx'
+
+# Advanced Chat App API
+
+Chat applications support session persistence, allowing previous chat history to be used as context for responses. This can be applicable for chatbot, customer service AI, etc.
+
+<div>
+ ### Base URL
+ <CodeGroup title="Code" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### Authentication
+
+ The Service API uses `API-Key` authentication.
+ <i>**Strongly recommend storing your API Key on the server-side, not shared or stored on the client-side, to avoid possible API-Key leakage that can lead to serious consequences.**</i>
+
+ For all API requests, include your API Key in the `Authorization`HTTP Header, as shown below:
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/chat-messages'
+ method='POST'
+ title='Send Chat Message'
+ name='#Send-Chat-Message'
+/>
+<Row>
+ <Col>
+ Send a request to the chat application.
+
+ ### Request Body
+
+ <Properties>
+ <Property name='query' type='string' key='query'>
+ User Input/Question content
+ </Property>
+ <Property name='inputs' type='object' key='inputs'>
+ Allows the entry of various variable values defined by the App.
+ The `inputs` parameter contains multiple key/value pairs, with each key corresponding to a specific variable and each value being the specific value for that variable.
+ If the variable is of file type, specify an object that has the keys described in `files` below.
+ Default `{}`
+ </Property>
+ <Property name='response_mode' type='string' key='response_mode'>
+ The mode of response return, supporting:
+ - `streaming` Streaming mode (recommended), implements a typewriter-like output through SSE ([Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)).
+ - `blocking` Blocking mode, returns result after execution is complete. (Requests may be interrupted if the process is long)
+ Due to Cloudflare restrictions, the request will be interrupted without a return after 100 seconds.
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+ </Property>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ Conversation ID, to continue the conversation based on previous chat records, it is necessary to pass the previous message's conversation_id.
+ </Property>
+ <Property name='files' type='array[object]' key='files'>
+ File list, suitable for inputting files combined with text understanding and answering questions, available only when the model supports Vision capability.
+ - `type` (string) Supported type:
+ - `document` ('TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB')
+ - `image` ('JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG')
+ - `audio` ('MP3', 'M4A', 'WAV', 'WEBM', 'AMR')
+ - `video` ('MP4', 'MOV', 'MPEG', 'MPGA')
+ - `custom` (Other file types)
+ - `transfer_method` (string) Transfer method, `remote_url` for image URL / `local_file` for file upload
+ - `url` (string) Image URL (when the transfer method is `remote_url`)
+ - `upload_file_id` (string) Uploaded file ID, which must be obtained by uploading through the File Upload API in advance (when the transfer method is `local_file`)
+ </Property>
+ <Property name='auto_generate_name' type='bool' key='auto_generate_name'>
+ Auto-generate title, default is `true`.
+ If set to `false`, can achieve async title generation by calling the conversation rename API and setting `auto_generate` to `true`.
+ </Property>
+ </Properties>
+
+ ### Response
+ When response_mode is blocking, return a CompletionResponse object.
+ When response_mode is streaming, return a ChunkCompletionResponse stream.
+
+ ### ChatCompletionResponse
+ Returns the complete App result, `Content-Type` is `application/json`.
+ - `event` (string) Event type, fixed to `message`
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `id` (string) unique ID
+ - `message_id` (string) Unique message ID
+ - `conversation_id` (string) Conversation ID
+ - `mode` (string) App mode, fixed as `chat`
+ - `answer` (string) Complete response content
+ - `metadata` (object) Metadata
+ - `usage` (Usage) Model usage information
+ - `retriever_resources` (array[RetrieverResource]) Citation and Attribution List
+ - `created_at` (int) Message creation timestamp, e.g., 1705395332
+
+ ### ChunkChatCompletionResponse
+ Returns the stream chunks outputted by the App, `Content-Type` is `text/event-stream`.
+ Each streaming chunk starts with `data:`, separated by two newline characters `\n\n`, as shown below:
+ <CodeGroup>
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
+ ```
+ </CodeGroup>
+ The structure of the streaming chunks varies depending on the `event`:
+ - `event: message` LLM returns text chunk event, i.e., the complete text is output in a chunked fashion.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `conversation_id` (string) Conversation ID
+ - `answer` (string) LLM returned text chunk content
+ - `created_at` (int) Creation timestamp, e.g., 1705395332
+ - `event: message_file` Message file event, a new file has created by tool
+ - `id` (string) File unique ID
+ - `type` (string) File type锛宱nly allow "image" currently
+ - `belongs_to` (string) Belongs to, it will only be an 'assistant' here
+ - `url` (string) Remote url of file
+ - `conversation_id` (string) Conversation ID
+ - `event: message_end` Message end event, receiving this event means streaming has ended.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `conversation_id` (string) Conversation ID
+ - `metadata` (object) Metadata
+ - `usage` (Usage) Model usage information
+ - `retriever_resources` (array[RetrieverResource]) Citation and Attribution List
+ - `event: tts_message` TTS audio stream event, that is, speech synthesis output. The content is an audio block in Mp3 format, encoded as a base64 string. When playing, simply decode the base64 and feed it into the player. (This message is available only when auto-play is enabled)
+ - `task_id` (string) Task ID, used for request tracking and the stop response interface below
+ - `message_id` (string) Unique message ID
+ - `audio` (string) The audio after speech synthesis, encoded in base64 text content, when playing, simply decode the base64 and feed it into the player
+ - `created_at` (int) Creation timestamp, e.g.: 1705395332
+ - `event: tts_message_end` TTS audio stream end event, receiving this event indicates the end of the audio stream.
+ - `task_id` (string) Task ID, used for request tracking and the stop response interface below
+ - `message_id` (string) Unique message ID
+ - `audio` (string) The end event has no audio, so this is an empty string
+ - `created_at` (int) Creation timestamp, e.g.: 1705395332
+ - `event: message_replace` Message content replacement event.
+ When output content moderation is enabled, if the content is flagged, then the message content will be replaced with a preset reply through this event.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `conversation_id` (string) Conversation ID
+ - `answer` (string) Replacement content (directly replaces all LLM reply text)
+ - `created_at` (int) Creation timestamp, e.g., 1705395332
+ - `event: workflow_started` workflow starts execution
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `event` (string) fixed to `workflow_started`
+ - `data` (object) detail
+ - `id` (string) Unique ID of workflow execution
+ - `workflow_id` (string) ID of related workflow
+ - `sequence_number` (int) Self-increasing serial number, self-increasing in the App, starting from 1
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+ - `event: node_started` node execution started
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `event` (string) fixed to `node_started`
+ - `data` (object) detail
+ - `id` (string) Unique ID of workflow execution
+ - `node_id` (string) ID of node
+ - `node_type` (string) type of node
+ - `title` (string) name of node
+ - `index` (int) Execution sequence number, used to display Tracing Node sequence
+ - `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path
+ - `inputs` (object) Contents of all preceding node variables used in the node
+ - `created_at` (timestamp) timestamp of start, e.g., 1705395332
+ - `event: node_finished` node execution ends, success or failure in different states in the same event
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `event` (string) fixed to `node_finished`
+ - `data` (object) detail
+ - `id` (string) Unique ID of workflow execution
+ - `node_id` (string) ID of node
+ - `node_type` (string) type of node
+ - `title` (string) name of node
+ - `index` (int) Execution sequence number, used to display Tracing Node sequence
+ - `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path
+ - `inputs` (object) Contents of all preceding node variables used in the node
+ - `process_data` (json) Optional node process data
+ - `outputs` (json) Optional content of output
+ - `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped`
+ - `error` (string) Optional reason of error
+ - `elapsed_time` (float) Optional total seconds to be used
+ - `execution_metadata` (json) meta data
+ - `total_tokens` (int) optional tokens to be used
+ - `total_price` (decimal) optional Total cost
+ - `currency` (string) optional e.g. `USD` / `RMB`
+ - `created_at` (timestamp) timestamp of start, e.g., 1705395332
+ - `event: workflow_finished` workflow execution ends, success or failure in different states in the same event
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `event` (string) fixed to `workflow_finished`
+ - `data` (object) detail
+ - `id` (string) ID of workflow execution
+ - `workflow_id` (string) ID of related workflow
+ - `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped`
+ - `outputs` (json) Optional content of output
+ - `error` (string) Optional reason of error
+ - `elapsed_time` (float) Optional total seconds to be used
+ - `total_tokens` (int) Optional tokens to be used
+ - `total_steps` (int) default 0
+ - `created_at` (timestamp) start time
+ - `finished_at` (timestamp) end time
+ - `event: error`
+ Exceptions that occur during the streaming process will be output in the form of stream events, and reception of an error event will end the stream.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `status` (int) HTTP status code
+ - `code` (string) Error code
+ - `message` (string) Error message
+ - `event: ping` Ping event every 10 seconds to keep the connection alive.
+
+ ### Errors
+ - 404, Conversation does not exists
+ - 400, `invalid_param`, abnormal parameter input
+ - 400, `app_unavailable`, App configuration unavailable
+ - 400, `provider_not_initialize`, no available model credential configuration
+ - 400, `provider_quota_exceeded`, model invocation quota insufficient
+ - 400, `model_currently_not_support`, current model unavailable
+ - 400, `completion_request_error`, text generation failed
+ - 500, internal server error
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/chat-messages" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": ${JSON.stringify(props.inputs)},\n "query": "What are the specs of the iPhone 13 Pro Max?",\n "response_mode": "streaming",\n "conversation_id": "",\n "user": "abc-123",\n "files": [\n {\n "type": "image",\n "transfer_method": "remote_url",\n "url": "https://cloud.dify.ai/logo/logo-site.png"\n }\n ]\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {},
+ "query": "eh",
+ "response_mode": "streaming",
+ "conversation_id": "1c7e55fb-1ba2-4e10-81b5-30addcea2276",
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+ ### Blocking Mode
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "event": "message",
+ "task_id": "c3800678-a077-43df-a102-53f23ed20b88",
+ "id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
+ "mode": "chat",
+ "answer": "iPhone 13 Pro Max specs are listed here:...",
+ "metadata": {
+ "usage": {
+ "prompt_tokens": 1033,
+ "prompt_unit_price": "0.001",
+ "prompt_price_unit": "0.001",
+ "prompt_price": "0.0010330",
+ "completion_tokens": 128,
+ "completion_unit_price": "0.002",
+ "completion_price_unit": "0.001",
+ "completion_price": "0.0002560",
+ "total_tokens": 1161,
+ "total_price": "0.0012890",
+ "currency": "USD",
+ "latency": 0.7682376249867957
+ },
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ]
+ },
+ "created_at": 1705407629
+ }
+ ```
+ </CodeGroup>
+ ### Streaming Mode
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}
+ data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}
+ data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}
+ data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='File Upload'
+ name='#file-upload'
+/>
+<Row>
+ <Col>
+ Upload a file for use when sending messages, enabling multimodal understanding of images and text.
+ Supports any formats that are supported by your application.
+ Uploaded files are for use by the current end-user only.
+
+ ### Request Body
+ This interface requires a `multipart/form-data` request.
+ - `file` (File) Required
+ The file to be uploaded.
+ - `user` (string) Required
+ User identifier, defined by the developer's rules, must be unique within the application.
+
+ ### Response
+ After a successful upload, the server will return the file's ID and related information.
+ - `id` (uuid) ID
+ - `name` (string) File name
+ - `size` (int) File size (bytes)
+ - `extension` (string) File extension
+ - `mime_type` (string) File mime-type
+ - `created_by` (uuid) End-user ID
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+
+ ### Errors
+ - 400, `no_file_uploaded`, a file must be provided
+ - 400, `too_many_files`, currently only one file is accepted
+ - 400, `unsupported_preview`, the file does not support preview
+ - 400, `unsupported_estimate`, the file does not support estimation
+ - 413, `file_too_large`, the file is too large
+ - 415, `unsupported_file_type`, unsupported extension, currently only document files are accepted
+ - 503, `s3_connection_failed`, unable to connect to S3 service
+ - 503, `s3_permission_denied`, no permission to upload files to S3
+ - 503, `s3_file_too_large`, file exceeds S3 size limit
+ - 500, internal server error
+
+
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": "6ad1ab0a-73ff-4ac1-b9e4-cdb312f71f13",
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/chat-messages/:task_id/stop'
+ method='POST'
+ title='Stop Generate'
+ name='#stop-generatebacks'
+/>
+<Row>
+ <Col>
+ Only supported in streaming mode.
+ ### Path
+ - `task_id` (string) Task ID, can be obtained from the streaming chunk return
+ ### Request Body
+ - `user` (string) Required
+ User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface.
+ ### Response
+ - `result` (string) Always returns "success"
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{"user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages/:message_id/feedbacks'
+ method='POST'
+ title='Message Feedback'
+ name='#feedbacks'
+/>
+<Row>
+ <Col>
+ End-users can provide feedback messages, facilitating application developers to optimize expected outputs.
+
+ ### Path
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ Message ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+
+ <Properties>
+ <Property name='rating' type='string' key='rating'>
+ Upvote as `like`, downvote as `dislike`, revoke upvote as `null`
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, defined by the developer's rules, must be unique within the application.
+ </Property>
+ <Property name='content' type='string' key='content'>
+ The specific content of message feedback.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) Always returns "success"
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/messages/:message_id/feedbacks" targetCode={`curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks \\\n --header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "rating": "like",\n "user": "abc-123",\n "content": "message feedback information"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "rating": "like",
+ "user": "abc-123",
+ "content": "message feedback information"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/app/feedbacks'
+ method='GET'
+ title='Get feedbacks of application'
+ name='#app-feedbacks'
+/>
+<Row>
+ <Col>
+ Get application's feedbacks.
+
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 锛坥ptional锛塸agination锛宒efault锛�1
+ </Property>
+ </Properties>
+
+ <Properties>
+ <Property name='limit' type='string' key='limit'>
+ 锛坥ptional锛� records per page default锛�20
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (List) return apps feedback list.
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/app/feedbacks" targetCode={`curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "8c0fbed8-e2f9-49ff-9f0e-15a35bdd0e25",
+ "app_id": "f252d396-fe48-450e-94ec-e184218e7346",
+ "conversation_id": "2397604b-9deb-430e-b285-4726e51fd62d",
+ "message_id": "709c0b0f-0a96-4a4e-91a4-ec0889937b11",
+ "rating": "like",
+ "content": "message feedback information-3",
+ "from_source": "user",
+ "from_end_user_id": "74286412-9a1a-42c1-929c-01edb1d381d5",
+ "from_account_id": null,
+ "created_at": "2025-04-24T09:24:38",
+ "updated_at": "2025-04-24T09:24:38"
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/messages/{message_id}/suggested'
+ method='GET'
+ title='Next Suggested Questions'
+ name='#suggested'
+/>
+<Row>
+ <Col>
+ Get next questions suggestions for the current message
+
+ ### Path Params
+
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ Message ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/messages/{message_id}/suggested" targetCode={`curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested?user=abc-123& \\\n--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \\\n--header 'Content-Type: application/json'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested?user=abc-123' \
+ --header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
+ --header 'Content-Type: application/json' \
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success",
+ "data": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages'
+ method='GET'
+ title='Get Conversation History Messages'
+ name='#messages'
+/>
+<Row>
+ <Col>
+ Returns historical chat records in a scrolling load format, with the first page returning the latest `{limit}` messages, i.e., in reverse order.
+
+ ### Query
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ Conversation ID
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+ </Property>
+ <Property name='first_id' type='string' key='first_id'>
+ The ID of the first chat record on the current page, default is null.
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ How many chat history messages to return in one request, default is 20.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (array[object]) Message list
+ - `id` (string) Message ID
+ - `conversation_id` (string) Conversation ID
+ - `inputs` (object) User input parameters.
+ - `query` (string) User input / question content.
+ - `message_files` (array[object]) Message files
+ - `id` (string) ID
+ - `type` (string) File type, image for images
+ - `url` (string) Preview image URL
+ - `belongs_to` (string) belongs to锛寀ser orassistant
+ - `answer` (string) Response message content
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+ - `feedback` (object) Feedback information
+ - `rating` (string) Upvote as `like` / Downvote as `dislike`
+ - `retriever_resources` (array[RetrieverResource]) Citation and Attribution List
+ - `has_more` (bool) Whether there is a next page
+ - `limit` (int) Number of returned items, if input exceeds system limit, returns system limit amount
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/messages" targetCode={`curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='\\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "a076a87f-31e5-48dc-b452-0061adbbc922",
+ "conversation_id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "inputs": {
+ "name": "dify"
+ },
+ "query": "iphone 13 pro",
+ "answer": "The iPhone 13 Pro, released on September 24, 2021, features a 6.1-inch display with a resolution of 1170 x 2532. It is equipped with a Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard) processor, 6 GB of RAM, and offers storage options of 128 GB, 256 GB, 512 GB, and 1 TB. The camera is 12 MP, the battery capacity is 3095 mAh, and it runs on iOS 15.",
+ "message_files": [],
+ "feedback": null,
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ],
+ "created_at": 1705569239,
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations'
+ method='GET'
+ title='Get Conversations'
+ name='#conversations'
+/>
+<Row>
+ <Col>
+ Retrieve the conversation list for the current user, defaulting to the most recent 20 entries.
+
+ ### Query
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ (Optional) The ID of the last record on the current page, default is null.
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ (Optional) How many records to return in one request, default is the most recent 20 entries. Maximum 100, minimum 1.
+ </Property>
+ <Property name='sort_by' type='string' key='sort_by'>
+ (Optional) Sorting Field, Default: -updated_at (sorted in descending order by update time)
+ - Available Values: created_at, -created_at, updated_at, -updated_at
+ - The symbol before the field represents the order or reverse, "-" represents reverse order.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (array[object]) List of conversations
+ - `id` (string) Conversation ID
+ - `name` (string) Conversation name, by default, is generated by LLM.
+ - `inputs` (object) User input parameters.
+ - `status` (string) Conversation status
+ - `introduction` (string) Introduction
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+ - `updated_at` (timestamp) Update timestamp, e.g., 1705395332
+ - `has_more` (bool)
+ - `limit` (int) Number of entries returned, if input exceeds system limit, system limit number is returned
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "10799fb8-64f7-4296-bbf7-b42bfbe0ae54",
+ "name": "New chat",
+ "inputs": {
+ "book": "book",
+ "myName": "Lucy"
+ },
+ "status": "normal",
+ "created_at": 1679667915,
+ "updated_at": 1679667915
+ },
+ {
+ "id": "hSIhXBhNe8X1d8Et"
+ // ...
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id'
+ method='DELETE'
+ title='Delete Conversation'
+ name='#delete'
+/>
+<Row>
+ <Col>
+ Delete a conversation.
+
+ ### Path
+ - `conversation_id` (string) Conversation ID
+
+ ### Request Body
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ The user identifier, defined by the developer, must ensure uniqueness within the application.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) Always returns "success"
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="DELETE" label="/conversations/:conversation_id" targetCode={`curl -X DELETE '${props.appDetail.api_base_url}/conversations/:conversation_id' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X DELETE '${props.appDetail.api_base_url}/conversations/{conversation_id}' \
+ --header 'Content-Type: application/json' \
+ --header 'Accept: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data '{
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/conversations/:conversation_id/name'
+ method='POST'
+ title='Conversation Rename'
+ name='#rename'
+/>
+<Row>
+ <Col>
+ ### Request Body
+ Rename the session, the session name is used for display on clients that support multiple sessions.
+
+ ### Path
+ - `conversation_id` (string) Conversation ID
+
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ (Optional) The name of the conversation. This parameter can be omitted if `auto_generate` is set to `true`.
+ </Property>
+ <Property name='auto_generate' type='bool' key='auto_generate'>
+ (Optional) Automatically generate the title, default is `false`
+ </Property>
+ <Property name='user' type='string' key='user'>
+ The user identifier, defined by the developer, must ensure uniqueness within the application.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `id` (string) Conversation ID
+ - `name` (string) Conversation name
+ - `inputs` (object) User input parameters
+ - `status` (string) Conversation status
+ - `introduction` (string) Introduction
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+ - `updated_at` (timestamp) Update timestamp, e.g., 1705395332
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
+ --header 'Content-Type: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data-raw '{
+ "name": "",
+ "auto_generate": true,
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "name": "Chat vs AI",
+ "inputs": {},
+ "status": "normal",
+ "introduction": "",
+ "created_at": 1705569238,
+ "updated_at": 1705569238
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id/variables'
+ method='GET'
+ title='Get Conversation Variables'
+ name='#conversation-variables'
+/>
+<Row>
+ <Col>
+ Retrieve variables from a specific conversation. This endpoint is useful for extracting structured data that was captured during the conversation.
+
+ ### Path Parameters
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ The ID of the conversation to retrieve variables from.
+ </Property>
+ </Properties>
+
+ ### Query Parameters
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ The user identifier, defined by the developer, must ensure uniqueness within the application
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ (Optional) The ID of the last record on the current page, default is null.
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ (Optional) How many records to return in one request, default is the most recent 20 entries. Maximum 100, minimum 1.
+ </Property>
+ </Properties>
+
+ ### Response
+
+ - `limit` (int) Number of items per page
+ - `has_more` (bool) Whether there is a next page
+ - `data` (array[object]) List of variables
+ - `id` (string) Variable ID
+ - `name` (string) Variable name
+ - `value_type` (string) Variable type (string, number, object, etc.)
+ - `value` (string) Variable value
+ - `description` (string) Variable description
+ - `created_at` (int) Creation timestamp
+ - `updated_at` (int) Last update timestamp
+
+ ### Errors
+ - 404, `conversation_not_exists`, Conversation not found
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations/:conversation_id/variables" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Request with variable name filter">
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123&variable_name=customer_name' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 100,
+ "has_more": false,
+ "data": [
+ {
+ "id": "variable-uuid-1",
+ "name": "customer_name",
+ "value_type": "string",
+ "value": "John Doe",
+ "description": "Customer name extracted from the conversation",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ },
+ {
+ "id": "variable-uuid-2",
+ "name": "order_details",
+ "value_type": "json",
+ "value": "{\"product\":\"Widget\",\"quantity\":5,\"price\":19.99}",
+ "description": "Order details from the customer",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/audio-to-text'
+ method='POST'
+ title='Speech to Text'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ This endpoint requires a multipart/form-data request.
+
+ ### Request Body
+
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ Audio file.
+ Supported formats: `['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm']`
+ File size limit: 15MB
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, defined by the developer's rules, must be unique within the application.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `text` (string) Output text
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/audio-to-text" targetCode={`curl -X POST '${props.appDetail.api_base_url}/audio-to-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=audio/[mp3|mp4|mpeg|mpga|m4a|wav|webm]'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/name' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@localfile;type=audio/mp3'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "text": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/text-to-audio'
+ method='POST'
+ title='Text to Audio'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ Text to speech.
+
+ ### Request Body
+
+ <Properties>
+ <Property name='message_id' type='str' key='message_id'>
+ For text messages generated by Dify, simply pass the generated message-id directly. The backend will use the message-id to look up the corresponding content and synthesize the voice information directly. If both message_id and text are provided simultaneously, the message_id is given priority.
+ </Property>
+ <Property name='text' type='str' key='text'>
+ Speech generated content銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ The user identifier, defined by the developer, must ensure uniqueness within the app.
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "Hello Dify",\n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
+ "text": "Hello Dify",
+ "user": "abc-123",
+ "streaming": false
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="headers">
+ ```json {{ title: 'headers' }}
+ {
+ "Content-Type": "audio/wav"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='Get Application Basic Information'
+ name='#info'
+/>
+<Row>
+ <Col>
+ Used to get basic information about this application
+
+ ### Response
+ - `name` (string) application name
+ - `description` (string) application description
+ - `tags` (array[string]) application tags
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='Get Application Parameters Information'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ Used at the start of entering the page to obtain information such as features, input parameter names, types, and default values.
+
+ ### Response
+ - `opening_statement` (string) Opening statement
+ - `suggested_questions` (array[string]) List of suggested questions for the opening
+ - `suggested_questions_after_answer` (object) Suggest questions after enabling the answer.
+ - `enabled` (bool) Whether it is enabled
+ - `speech_to_text` (object) Speech to text
+ - `enabled` (bool) Whether it is enabled
+ - `retriever_resource` (object) Citation and Attribution
+ - `enabled` (bool) Whether it is enabled
+ - `annotation_reply` (object) Annotation reply
+ - `enabled` (bool) Whether it is enabled
+ - `user_input_form` (array[object]) User input form configuration
+ - `text-input` (object) Text input control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `paragraph` (object) Paragraph text input control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `select` (object) Dropdown control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `options` (array[string]) Option values
+ - `file_upload` (object) File upload configuration
+ - `image` (object) Image settings
+ Currently only supports image types: `png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) Whether it is enabled
+ - `number_limits` (int) Image number limit, default is 3
+ - `transfer_methods` (array[string]) List of transfer methods, remote_url, local_file, must choose one
+ - `system_parameters` (object) System parameters
+ - `file_size_limit` (int) Document upload size limit (MB)
+ - `image_file_size_limit` (int) Image file upload size limit (MB)
+ - `audio_file_size_limit` (int) Audio file upload size limit (MB)
+ - `video_file_size_limit` (int) Video file upload size limit (MB)
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "opening_statement": "Hello!",
+ "suggested_questions_after_answer": {
+ "enabled": true
+ },
+ "speech_to_text": {
+ "enabled": true
+ },
+ "retriever_resource": {
+ "enabled": true
+ },
+ "annotation_reply": {
+ "enabled": true
+ },
+ "user_input_form": [
+ {
+ "paragraph": {
+ "label": "Query",
+ "variable": "query",
+ "required": true,
+ "default": ""
+ }
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": false,
+ "number_limits": 3,
+ "detail": "high",
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/meta'
+ method='GET'
+ title='Get Application Meta Information'
+ name='#meta'
+/>
+<Row>
+ <Col>
+ Used to get icons of tools in this application
+
+ ### Response
+ - `tool_icons`(object[string]) tool icons
+ - `tool_name` (string)
+ - `icon` (object|string)
+ - (object) icon object
+ - `background` (string) background color in hex format
+ - `content`(string) emoji
+ - (string) url of icon
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/meta' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/meta' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "tool_icons": {
+ "dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
+ "api_tool": {
+ "background": "#252525",
+ "content": "\ud83d\ude01"
+ }
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='Get Application WebApp Settings'
+ name='#site'
+/>
+<Row>
+ <Col>
+ Used to get the WebApp settings of the application.
+ ### Response
+ - `title` (string) WebApp name
+ - `chat_color_theme` (string) Chat color theme, in hex format
+ - `chat_color_theme_inverted` (bool) Whether the chat color theme is inverted
+ - `icon_type` (string) Icon type, `emoji` - emoji, `image` - picture
+ - `icon` (string) Icon. If it's `emoji` type, it's an emoji symbol; if it's `image` type, it's an image URL
+ - `icon_background` (string) Background color in hex format
+ - `icon_url` (string) Icon URL
+ - `description` (string) Description
+ - `copyright` (string) Copyright information
+ - `privacy_policy` (string) Privacy policy link
+ - `custom_disclaimer` (string) Custom disclaimer
+ - `default_language` (string) Default language
+ - `show_workflow_steps` (bool) Whether to show workflow details
+ - `use_icon_as_answer_icon` (bool) Whether to replace 馃 in chat with the WebApp icon
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "chat_color_theme": "#ff4a4a",
+ "chat_color_theme_inverted": false,
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ "use_icon_as_answer_icon": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
+
+<Heading
+ url='/apps/annotations'
+ method='GET'
+ title='Get Annotation List'
+ name='#annotation_list'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ Page number
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ Number of items returned, default 20, range 1-100
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/apps/annotations"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/apps/annotations?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/apps/annotations?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ],
+ "has_more": false,
+ "limit": 20,
+ "total": 1,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations'
+ method='POST'
+ title='Create Annotation'
+ name='#create_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='question' type='string' key='question'>
+ Question
+ </Property>
+ <Property name='answer' type='string' key='answer'>
+ Answer
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/apps/annotations"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/apps/annotations' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"question": "What is your name?","answer": "I am Dify."}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/apps/annotations' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "question": "What is your name?",
+ "answer": "I am Dify."
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations/{annotation_id}'
+ method='PUT'
+ title='Update Annotation'
+ name='#update_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='annotation_id' type='string' key='annotation_id'>
+ Annotation ID
+ </Property>
+ <Property name='question' type='string' key='question'>
+ Question
+ </Property>
+ <Property name='answer' type='string' key='answer'>
+ Answer
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PUT"
+ label="/apps/annotations/{annotation_id}"
+ targetCode={`curl --location --request PUT '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"question": "What is your name?","answer": "I am Dify."}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PUT '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "question": "What is your name?",
+ "answer": "I am Dify."
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations/{annotation_id}'
+ method='DELETE'
+ title='Delete Annotation'
+ name='#delete_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='annotation_id' type='string' key='annotation_id'>
+ Annotation ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PUT"
+ label="/apps/annotations/{annotation_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotation-reply/{action}'
+ method='POST'
+ title='Initial Annotation Reply Settings'
+ name='#initial_annotation_reply_settings'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='action' type='string' key='action'>
+ Action, can only be 'enable' or 'disable'
+ </Property>
+ <Property name='embedding_provider_name' type='string' key='embedding_provider_name'>
+ Specified embedding model provider, must be set up in the system first, corresponding to the provider field(Optional)
+ </Property>
+ <Property name='embedding_model_name' type='string' key='embedding_model_name'>
+ Specified embedding model, corresponding to the model field(Optional)
+ </Property>
+ <Property name='score_threshold' type='number' key='score_threshold'>
+ The similarity threshold for matching annotated replies. Only annotations with scores above this threshold will be recalled.
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ The provider and model name of the embedding model can be obtained through the following interface: v1/workspaces/current/models/model-types/text-embedding. For specific instructions, see: Maintain Knowledge Base via API. The Authorization used is the Dataset API Token.
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/apps/annotation-reply/{action}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/apps/annotation-reply/{action}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"score_threshold": 0.9, "embedding_provider_name": "zhipu", "embedding_model_name": "embedding_3"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST 'https://api.dify.ai/v1/apps/annotation-reply/{action}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "score_threshold": 0.9,
+ "embedding_provider_name": "zhipu",
+ "embedding_model_name": "embedding_3"
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
+ "job_status": "waiting"
+ }
+ ```
+ </CodeGroup>
+ This interface is executed asynchronously, so it will return a job_id. You can get the final execution result by querying the job status interface.
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotation-reply/{action}/status/{job_id}'
+ method='GET'
+ title='Query Initial Annotation Reply Settings Task Status'
+ name='#initial_annotation_reply_settings_task_status'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='action' type='string' key='action'>
+ Action, can only be 'enable' or 'disable', must be the same as the action in the initial annotation reply settings interface
+ </Property>
+ <Property name='job_id' type='string' key='job_id'>
+ Job ID, obtained from the initial annotation reply settings interface
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/apps/annotations"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/apps/annotation-reply/{action}/status/{job_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/apps/annotation-reply/{action}/status/{job_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
+ "job_status": "waiting",
+ "error_msg": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
diff --git a/app/components/develop/template/template_advanced_chat.ja.mdx b/app/components/develop/template/template_advanced_chat.ja.mdx
new file mode 100644
index 0000000..75c69a4
--- /dev/null
+++ b/app/components/develop/template/template_advanced_chat.ja.mdx
@@ -0,0 +1,1365 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx'
+
+# 楂樺害銇儊銉c儍銉堛偄銉椼儶API
+
+銉併儯銉冦儓銈€儣銉偙銉笺偡銉с兂銇偦銉冦偡銉с兂銇寔缍氭�с倰銈点儩銉笺儓銇椼仸銇娿倞銆佷互鍓嶃伄銉併儯銉冦儓灞ユ銈掑繙绛斻伄銈炽兂銉嗐偔銈广儓銇ㄣ仐銇︿娇鐢ㄣ仹銇嶃伨銇欍�傘亾銈屻伅銆併儊銉c儍銉堛儨銉冦儓銈勩偒銈广偪銉炪兗銈点兗銉撱偣AI銇仼銇仼鐢ㄣ仹銇嶃伨銇欍��
+
+<div>
+ ### 銉欍兗銈筓RL
+ <CodeGroup title="銈炽兗銉�" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### 瑾嶈
+
+ 銈点兗銉撱偣API銇痐API-Key`瑾嶈銈掍娇鐢ㄣ仐銇俱仚銆�
+ <i>**API銈兗銇偟銉笺儛銉煎伌銇繚瀛樸仐銆併偗銉┿偆銈€兂銉堝伌銇у叡鏈夈伨銇熴伅淇濆瓨銇椼仾銇勩亾銇ㄣ倰寮枫亸銇婂嫥銈併仐銇俱仚銆侫PI銈兗銇紡娲┿伅娣卞埢銇祼鏋溿倰鎷涖亸鍙兘鎬с亴銇傘倞銇俱仚銆�**</i>
+
+ 銇欍伖銇︺伄API銉偗銈ㄣ偣銉堛伀銇�佷互涓嬨伄銈堛亞銇玚Authorization`HTTP銉樸儍銉�銉笺伀API銈兗銈掑惈銈併仸銇忋仩銇曘亜锛�
+
+ <CodeGroup title="銈炽兗銉�">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/chat-messages'
+ method='POST'
+ title='銉併儯銉冦儓銉°儍銈汇兗銈搞倰閫佷俊'
+ name='#Send-Chat-Message'
+/>
+<Row>
+ <Col>
+ 銉併儯銉冦儓銈€儣銉偙銉笺偡銉с兂銇儶銈偍銈广儓銈掗�佷俊銇椼伨銇欍��
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='query' type='string' key='query'>
+ 銉︺兗銈躲兗鍏ュ姏/璩晱鍐呭
+ </Property>
+ <Property name='inputs' type='object' key='inputs'>
+ 銈€儣銉伀銈堛仯銇﹀畾缇┿仌銈屻仧銇曘伨銇栥伨銇鏁板�ゃ伄鍏ュ姏銈掕ū鍙仐銇俱仚銆�
+ `inputs`銉戙儵銉°兗銈裤伀銇鏁般伄銈兗/鍊ゃ儦銈€亴鍚伨銈屻�佸悇銈兗銇壒瀹氥伄澶夋暟銇蹇溿仐銆佸悇鍊ゃ伅銇濄伄澶夋暟銇壒瀹氥伄鍊ゃ仹銇欍��
+ 澶夋暟銇屻儠銈°偆銉偪銈ゃ儣銇牬鍚堛�佷互涓嬨伄`files`銇ц鏄庛仌銈屻仸銇勩倠銈兗銈掓寔銇ゃ偑銉栥偢銈с偗銉堛倰鎸囧畾銇椼伨銇欍��
+ 銉囥儠銈┿儷銉坄{}`
+ </Property>
+ <Property name='response_mode' type='string' key='response_mode'>
+ 蹇滅瓟銇繑鍗淬儮銉笺儔銈掓寚瀹氥仐銇俱仚銆傘偟銉濄兗銉堛仌銈屻仸銇勩倠銉€兗銉夛細
+ - `streaming` 銈广儓銉兗銉熴兂銈般儮銉笺儔锛堟帹濂級銆丼SE锛圼銈点兗銉愩兗閫佷俊銈ゃ儥銉炽儓](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)锛夈倰閫氥仒銇︺偪銈ゃ儣銉┿偆銈裤兗銇倛銇嗐仾鍑哄姏銈掑疅瑁呫仐銇俱仚銆�
+ - `blocking` 銉栥儹銉冦偔銉炽偘銉€兗銉夈�佸疅琛屽畬浜嗗緦銇祼鏋溿倰杩斻仐銇俱仚銆傦紙銉椼儹銈汇偣銇岄暦銇勫牬鍚堛�併儶銈偍銈广儓銇屼腑鏂仌銈屻倠鍙兘鎬с亴銇傘倞銇俱仚锛�
+ Cloudflare銇埗闄愩伀銈堛倞銆併儶銈偍銈广儓銇�100绉掑緦銇繑绛斻仾銇椼仹涓柇銇曘倢銇俱仚銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇韩鍏冦倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�佺当瑷堛伄銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍��
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫伀銈堛仯銇︿竴鎰忋伀瀹氱京銇曘倢銈嬨伖銇嶃仹銇欍��
+ </Property>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 浼氳┍ID銆佷互鍓嶃伄銉併儯銉冦儓瑷橀尣銇熀銇ャ亜銇︿細瑭便倰缍氥亼銈嬨伀銇�佷互鍓嶃伄銉°儍銈汇兗銈搞伄conversation_id銈掓浮銇欏繀瑕併亴銇傘倞銇俱仚銆�
+ </Property>
+ <Property name='files' type='array[object]' key='files'>
+ 銉曘偂銈ゃ儷銉偣銉堛�併儐銈偣銉堛伄鐞嗚В銇ㄨ唱鍟忋伕銇洖绛斻倰绲勩伩鍚堛倧銇涖仧銉曘偂銈ゃ儷銇叆鍔涖伀閬┿仐銇︺亰銈娿�併儮銉囥儷銇屻儞銈搞儳銉虫鑳姐倰銈点儩銉笺儓銇椼仸銇勩倠鍫村悎銇伄銇垮埄鐢ㄥ彲鑳姐仹銇欍��
+ - `type` (string) 銈点儩銉笺儓銇曘倢銇︺亜銈嬨偪銈ゃ儣锛�
+ - `document` ('TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB')
+ - `image` ('JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG')
+ - `audio` ('MP3', 'M4A', 'WAV', 'WEBM', 'AMR')
+ - `video` ('MP4', 'MOV', 'MPEG', 'MPGA')
+ - `custom` (浠栥伄銉曘偂銈ゃ儷銈裤偆銉�)
+ - `transfer_method` (string) 杌㈤�佹柟娉曘�佺敾鍍廢RL銇牬鍚堛伅`remote_url` / 銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銇牬鍚堛伅`local_file`
+ - `url` (string) 鐢诲儚URL锛堣虎閫佹柟娉曘亴`remote_url`銇牬鍚堬級
+ - `upload_file_id` (string) 銈€儍銉椼儹銉笺儔銇曘倢銇熴儠銈°偆銉獻D銆佷簨鍓嶃伀銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔API銈掗�氥仒銇﹀彇寰椼仚銈嬪繀瑕併亴銇傘倞銇俱仚锛堣虎閫佹柟娉曘亴`local_file`銇牬鍚堬級
+ </Property>
+ <Property name='auto_generate_name' type='bool' key='auto_generate_name'>
+ 銈裤偆銉堛儷銈掕嚜鍕曠敓鎴愩�併儑銉曘偐銉儓銇痐true`銆�
+ `false`銇ō瀹氥仚銈嬨仺銆佷細瑭便伄銉儘銉笺儬API銈掑懠銇冲嚭銇椼�乣auto_generate`銈抈true`銇ō瀹氥仚銈嬨亾銇ㄣ仹闈炲悓鏈熴偪銈ゃ儓銉敓鎴愩倰瀹熺従銇с亶銇俱仚銆�
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ response_mode銇屻儢銉儍銈兂銈般伄鍫村悎銆丆ompletionResponse銈儢銈搞偋銈儓銈掕繑銇椼伨銇欍��
+ response_mode銇屻偣銉堛儶銉笺儫銉炽偘銇牬鍚堛�丆hunkCompletionResponse銈广儓銉兗銉犮倰杩斻仐銇俱仚銆�
+
+ ### ChatCompletionResponse
+ 瀹屽叏銇偄銉椼儶绲愭灉銈掕繑銇椼伨銇欍�俙Content-Type`銇痐application/json`銇с仚銆�
+ - `event` (string) 銈ゃ儥銉炽儓銈裤偆銉椼�佸浐瀹氥仹 `message`
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `id` (string) 銉︺儖銉笺偗ID
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `mode` (string) 銈€儣銉儮銉笺儔銆乣chat`銇ㄣ仐銇﹀浐瀹�
+ - `answer` (string) 瀹屽叏銇繙绛斿唴瀹�
+ - `metadata` (object) 銉°偪銉囥兗銈�
+ - `usage` (Usage) 銉€儑銉娇鐢ㄦ儏鍫�
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤銇ㄥ赴灞炪儶銈广儓
+ - `created_at` (int) 銉°儍銈汇兗銈镐綔鎴愩偪銈ゃ儬銈广偪銉炽儣銆佷緥锛�1705395332
+
+ ### ChunkChatCompletionResponse
+ 銈€儣銉伀銈堛仯銇﹀嚭鍔涖仌銈屻仧銈广儓銉兗銉犮儊銉c兂銈倰杩斻仐銇俱仚銆俙Content-Type`銇痐text/event-stream`銇с仚銆�
+ 鍚勩偣銉堛儶銉笺儫銉炽偘銉併儯銉炽偗銇痐data:`銇у銇俱倞銆�2銇ゃ伄鏀硅鏂囧瓧`\n\n`銇у尯鍒囥倝銈屻伨銇欍�備互涓嬨伄銈堛亞銇〃绀恒仌銈屻伨銇欙細
+ <CodeGroup>
+ ```streaming {{ title: '蹇滅瓟' }}
+ data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
+ ```
+ </CodeGroup>
+ 銈广儓銉兗銉熴兂銈般儊銉c兂銈伄妲嬮�犮伅`event`銇繙銇樸仸鐣般仾銈娿伨銇欙細
+ - `event: message` LLM銇屻儐銈偣銉堛儊銉c兂銈偆銉欍兂銉堛倰杩斻仐銇俱仚銆傘仱銇俱倞銆佸畬鍏ㄣ仾銉嗐偔銈广儓銇屻儊銉c兂銈舰寮忋仹鍑哄姏銇曘倢銇俱仚銆�
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `answer` (string) LLM銇岃繑銇椼仧銉嗐偔銈广儓銉併儯銉炽偗鍐呭
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: message_file` 銉°儍銈汇兗銈搞儠銈°偆銉偆銉欍兂銉堛�併儎銉笺儷銇倛銇c仸鏂般仐銇勩儠銈°偆銉亴浣滄垚銇曘倢銇俱仐銇�
+ - `id` (string) 銉曘偂銈ゃ儷涓�鎰廔D
+ - `type` (string) 銉曘偂銈ゃ儷銈裤偆銉椼�佺従鍦ㄣ伅"image"銇伩瑷卞彲
+ - `belongs_to` (string) 鎵�灞炪�併亾銇撱仹銇�'assistant'銇伩
+ - `url` (string) 銉曘偂銈ゃ儷銇儶銉€兗銉圲RL
+ - `conversation_id` (string) 浼氳┍ID
+ - `event: message_end` 銉°儍銈汇兗銈哥祩浜嗐偆銉欍兂銉堛�併亾銇偆銉欍兂銉堛倰鍙椾俊銇欍倠銇ㄣ偣銉堛儶銉笺儫銉炽偘銇岀祩浜嗐仐銇熴亾銇ㄣ倰鎰忓懗銇椼伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `metadata` (object) 銉°偪銉囥兗銈�
+ - `usage` (Usage) 銉€儑銉娇鐢ㄦ儏鍫�
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤銇ㄥ赴灞炪儶銈广儓
+ - `event: tts_message` TTS銈兗銉囥偅銈偣銉堛儶銉笺儬銈ゃ儥銉炽儓銆併仱銇俱倞闊冲0鍚堟垚鍑哄姏銆傚唴瀹广伅Mp3褰㈠紡銇偑銉笺儑銈c偑銉栥儹銉冦偗銇с�乥ase64鏂囧瓧鍒椼仺銇椼仸銈ㄣ兂銈炽兗銉夈仌銈屻仸銇勩伨銇欍�傚啀鐢熸檪銇伅銆乥ase64銈掋儑銈炽兗銉夈仐銇︺儣銉兗銉ゃ兗銇叆鍔涖仚銈嬨仩銇戙仹銇欍�傦紙銇撱伄銉°儍銈汇兗銈搞伅鑷嫊鍐嶇敓銇屾湁鍔广仾鍫村悎銇伄銇垮埄鐢ㄥ彲鑳斤級
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄銈广儓銉冦儣蹇滅瓟銈ゃ兂銈裤兗銉曘偋銉笺偣銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `audio` (string) 闊冲0鍚堟垚寰屻伄銈兗銉囥偅銈�乥ase64銉嗐偔銈广儓銈炽兂銉嗐兂銉勩仺銇椼仸銈ㄣ兂銈炽兗銉夈仌銈屻仸銇娿倞銆佸啀鐢熸檪銇伅base64銈掋儑銈炽兗銉夈仐銇︺儣銉兗銉ゃ兗銇叆鍔涖仚銈嬨仩銇戙仹銇�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: tts_message_end` TTS銈兗銉囥偅銈偣銉堛儶銉笺儬绲備簡銈ゃ儥銉炽儓銆併亾銇偆銉欍兂銉堛倰鍙椾俊銇欍倠銇ㄣ偑銉笺儑銈c偑銈广儓銉兗銉犮亴绲備簡銇椼仧銇撱仺銈掔ず銇椼伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄銈广儓銉冦儣蹇滅瓟銈ゃ兂銈裤兗銉曘偋銉笺偣銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `audio` (string) 绲備簡銈ゃ儥銉炽儓銇伅銈兗銉囥偅銈亴銇亜銇熴倎銆併亾銈屻伅绌恒伄鏂囧瓧鍒椼仹銇�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: message_replace` 銉°儍銈汇兗銈稿唴瀹圭疆鎻涖偆銉欍兂銉堛��
+ 鍑哄姏鍐呭銇儮銉囥儸銉笺偡銉с兂銇屾湁鍔广仾鍫村悎銆佸唴瀹广亴銉曘儵銈颁粯銇戙仌銈屻倠銇ㄣ�併亾銇偆銉欍兂銉堛倰閫氥仒銇︺儭銉冦偦銉笺偢鍐呭銇屻儣銉偦銉冦儓銇繑淇°伀缃亶鎻涖亪銈夈倢銇俱仚銆�
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `answer` (string) 缃彌鍐呭锛堛仚銇广仸銇甃LM杩斾俊銉嗐偔銈广儓銈掔洿鎺ョ疆銇嶆彌銇堛伨銇欙級
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: workflow_started` 銉兗銈儠銉兗銇屽疅琛屻倰闁嬪
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰廔D
+ - `event` (string) `workflow_started`銇浐瀹�
+ - `data` (object) 瑭崇窗
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰廔D
+ - `workflow_id` (string) 闁㈤�c儻銉笺偗銉曘儹銉笺伄ID
+ - `sequence_number` (int) 鑷繁澧楀姞銈枫儶銈€儷鐣彿銆併偄銉椼儶鍐呫仹鑷繁澧楀姞銇椼��1銇嬨倝濮嬨伨銈娿伨銇�
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: node_started` 銉庛兗銉夊疅琛屻亴闁嬪
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰廔D
+ - `event` (string) `node_started`銇浐瀹�
+ - `data` (object) 瑭崇窗
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰廔D
+ - `node_id` (string) 銉庛兗銉夈伄ID
+ - `node_type` (string) 銉庛兗銉夈伄銈裤偆銉�
+ - `title` (string) 銉庛兗銉夈伄鍚嶅墠
+ - `index` (int) 瀹熻銈枫兗銈便兂銈圭暘鍙枫�併儓銉兗銈广儙銉笺儔銈枫兗銈便兂銈广倰琛ㄧず銇欍倠銇熴倎銇娇鐢�
+ - `predecessor_node_id` (string) 銈儣銈枫儳銉炽伄銉椼儸銉曘偅銉冦偗銈广儙銉笺儔ID銆併偔銉c兂銉愩偣琛ㄧず瀹熻銉戙偣銇娇鐢�
+ - `inputs` (object) 銉庛兗銉夈仹浣跨敤銇曘倢銈嬨仚銇广仸銇墠銇儙銉笺儔澶夋暟銇唴瀹�
+ - `created_at` (timestamp) 闁嬪銇偪銈ゃ儬銈广偪銉炽儣銆佷緥锛�1705395332
+ - `event: node_finished` 銉庛兗銉夊疅琛屻亴绲備簡銆佹垚鍔熴伨銇熴伅澶辨晽銇悓銇樸偆銉欍兂銉堝唴銇х暟銇倠鐘舵厠銇хず銇曘倢銇俱仚
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰廔D
+ - `event` (string) `node_finished`銇浐瀹�
+ - `data` (object) 瑭崇窗
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰廔D
+ - `node_id` (string) 銉庛兗銉夈伄ID
+ - `node_type` (string) 銉庛兗銉夈伄銈裤偆銉�
+ - `title` (string) 銉庛兗銉夈伄鍚嶅墠
+ - `index` (int) 瀹熻銈枫兗銈便兂銈圭暘鍙枫�併儓銉兗銈广儙銉笺儔銈枫兗銈便兂銈广倰琛ㄧず銇欍倠銇熴倎銇娇鐢�
+ - `predecessor_node_id` (string) 銈儣銈枫儳銉炽伄銉椼儸銉曘偅銉冦偗銈广儙銉笺儔ID銆併偔銉c兂銉愩偣琛ㄧず瀹熻銉戙偣銇娇鐢�
+ - `inputs` (object) 銉庛兗銉夈仹浣跨敤銇曘倢銈嬨仚銇广仸銇墠銇儙銉笺儔澶夋暟銇唴瀹�
+ - `process_data` (json) 銈儣銈枫儳銉炽伄銉庛兗銉夈儣銉偦銈广儑銉笺偪
+ - `outputs` (json) 銈儣銈枫儳銉炽伄鍑哄姏鍐呭
+ - `status` (string) 瀹熻銇姸鎱嬨�乣running` / `succeeded` / `failed` / `stopped`
+ - `error` (string) 銈儣銈枫儳銉炽伄銈ㄣ儵銉肩悊鐢�
+ - `elapsed_time` (float) 銈儣銈枫儳銉炽伄浣跨敤銇曘倢銈嬪悎瑷堢鏁�
+ - `execution_metadata` (json) 銉°偪銉囥兗銈�
+ - `total_tokens` (int) 銈儣銈枫儳銉炽伄浣跨敤銇曘倢銈嬨儓銉笺偗銉虫暟
+ - `total_price` (decimal) 銈儣銈枫儳銉炽伄鍚堣▓銈炽偣銉�
+ - `currency` (string) 銈儣銈枫儳銉炽�佷緥锛歚USD` / `RMB`
+ - `created_at` (timestamp) 闁嬪銇偪銈ゃ儬銈广偪銉炽儣銆佷緥锛�1705395332
+ - `event: workflow_finished` 銉兗銈儠銉兗瀹熻銇岀祩浜嗐�佹垚鍔熴伨銇熴伅澶辨晽銇悓銇樸偆銉欍兂銉堝唴銇х暟銇倠鐘舵厠銇хず銇曘倢銇俱仚
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰廔D
+ - `event` (string) `workflow_finished`銇浐瀹�
+ - `data` (object) 瑭崇窗
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇甀D
+ - `workflow_id` (string) 闁㈤�c儻銉笺偗銉曘儹銉笺伄ID
+ - `status` (string) 瀹熻銇姸鎱嬨�乣running` / `succeeded` / `failed` / `stopped`
+ - `outputs` (json) 銈儣銈枫儳銉炽伄鍑哄姏鍐呭
+ - `error` (string) 銈儣銈枫儳銉炽伄銈ㄣ儵銉肩悊鐢�
+ - `elapsed_time` (float) 銈儣銈枫儳銉炽伄浣跨敤銇曘倢銈嬪悎瑷堢鏁�
+ - `total_tokens` (int) 銈儣銈枫儳銉炽伄浣跨敤銇曘倢銈嬨儓銉笺偗銉虫暟
+ - `total_steps` (int) 銉囥儠銈┿儷銉�0
+ - `created_at` (timestamp) 闁嬪鏅傞枔
+ - `finished_at` (timestamp) 绲備簡鏅傞枔
+ - `event: error`
+ 銈广儓銉兗銉熴兂銈般儣銉偦銈逛腑銇櫤鐢熴仚銈嬩緥澶栥伅銈广儓銉兗銉犮偆銉欍兂銉堛伄褰㈠紡銇у嚭鍔涖仌銈屻�併偍銉┿兗銈ゃ儥銉炽儓銈掑彈淇°仚銈嬨仺銈广儓銉兗銉犮亴绲備簡銇椼伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `status` (int) HTTP銈广儐銉笺偪銈广偝銉笺儔
+ - `code` (string) 銈ㄣ儵銉笺偝銉笺儔
+ - `message` (string) 銈ㄣ儵銉笺儭銉冦偦銉笺偢
+ - `event: ping` 鎺ョ稓銈掔董鎸併仚銈嬨仧銈併伀10绉掋仈銇ㄣ伀ping銈ゃ儥銉炽儓銇岀櫤鐢熴仐銇俱仚銆�
+
+ ### 銈ㄣ儵銉�
+ - 404, 浼氳┍銇屽瓨鍦ㄣ仐銇俱仜銈�
+ - 400, `invalid_param`, 鐣板父銇儜銉┿儭銉笺偪鍏ュ姏
+ - 400, `app_unavailable`, 銈€儣銉鎴愩亴鍒╃敤銇с亶銇俱仜銈�
+ - 400, `provider_not_initialize`, 鍒╃敤鍙兘銇儮銉囥儷璩囨牸鎯呭牨妲嬫垚銇屻亗銈娿伨銇涖倱
+ - 400, `provider_quota_exceeded`, 銉€儑銉懠銇冲嚭銇椼偗銈┿兗銈裤亴涓嶈冻銇椼仸銇勩伨銇�
+ - 400, `model_currently_not_support`, 鐝惧湪銇儮銉囥儷銇屽埄鐢ㄣ仹銇嶃伨銇涖倱
+ - 400, `completion_request_error`, 銉嗐偔銈广儓鐢熸垚銇け鏁椼仐銇俱仐銇�
+ - 500, 鍐呴儴銈点兗銉愩兗銈ㄣ儵銉�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/chat-messages" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": ${JSON.stringify(props.inputs)},\n "query": "iPhone 13 Pro Max銇粫妲樸伅浣曘仹銇欍亱锛�",\n "response_mode": "streaming",\n "conversation_id": "",\n "user": "abc-123",\n "files": [\n {\n "type": "image",\n "transfer_method": "remote_url",\n "url": "https://cloud.dify.ai/logo/logo-site.png"\n }\n ]\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {},
+ "query": "eh",
+ "response_mode": "streaming",
+ "conversation_id": "1c7e55fb-1ba2-4e10-81b5-30addcea2276",
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+ ### 銉栥儹銉冦偔銉炽偘銉€兗銉�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "event": "message",
+ "task_id": "c3800678-a077-43df-a102-53f23ed20b88",
+ "id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
+ "mode": "chat",
+ "answer": "iPhone 13 Pro Max銇粫妲樸伅娆°伄銇ㄣ亰銈娿仹銇�:...",
+ "metadata": {
+ "usage": {
+ "prompt_tokens": 1033,
+ "prompt_unit_price": "0.001",
+ "prompt_price_unit": "0.001",
+ "prompt_price": "0.0010330",
+ "completion_tokens": 128,
+ "completion_unit_price": "0.002",
+ "completion_price_unit": "0.001",
+ "completion_price": "0.0002560",
+ "total_tokens": 1161,
+ "total_price": "0.0012890",
+ "currency": "USD",
+ "latency": 0.7682376249867957
+ },
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ]
+ },
+ "created_at": 1705407629
+ }
+ ```
+ </CodeGroup>
+ ### 銈广儓銉兗銉熴兂銈般儮銉笺儔
+ <CodeGroup title="蹇滅瓟">
+ ```streaming {{ title: '蹇滅瓟' }}
+ data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}
+ data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}
+ data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}
+ data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔'
+ name='#file-upload'
+/>
+<Row>
+ <Col>
+ 銉°儍銈汇兗銈搁�佷俊鏅傘伀浣跨敤銇欍倠銉曘偂銈ゃ儷銈掋偄銉冦儣銉兗銉夈仐銆佺敾鍍忋仺銉嗐偔銈广儓銇優銉儊銉€兗銉�銉悊瑙c倰鍙兘銇仐銇俱仚銆�
+ 銈€儣銉偙銉笺偡銉с兂銇с偟銉濄兗銉堛仌銈屻仸銇勩倠褰㈠紡銈掋偟銉濄兗銉堛仐銇俱仚銆�
+ 銈€儍銉椼儹銉笺儔銇曘倢銇熴儠銈°偆銉伅鐝惧湪銇偍銉炽儔銉︺兗銈躲兗銇伩銇屼娇鐢ㄣ仹銇嶃伨銇欍��
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ 銇撱伄銈ゃ兂銈裤兗銉曘偋銉笺偣銇痐multipart/form-data`銉偗銈ㄣ偣銉堛倰蹇呰銇ㄣ仐銇俱仚銆�
+ - `file` (File) 蹇呴爤
+ 銈€儍銉椼儹銉笺儔銇欍倠銉曘偂銈ゃ儷銆�
+ - `user` (string) 蹇呴爤
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伄銉兗銉伀銈堛仯銇﹀畾缇┿仌銈屻�併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇亼銈屻伆銇倞銇俱仜銈撱��
+
+ ### 蹇滅瓟
+ 銈€儍銉椼儹銉笺儔銇屾垚鍔熴仚銈嬨仺銆併偟銉笺儛銉笺伅銉曘偂銈ゃ儷銇甀D銇ㄩ枹閫f儏鍫便倰杩斻仐銇俱仚銆�
+ - `id` (uuid) ID
+ - `name` (string) 銉曘偂銈ゃ儷鍚�
+ - `size` (int) 銉曘偂銈ゃ儷銈点偆銈猴紙銉愩偆銉堬級
+ - `extension` (string) 銉曘偂銈ゃ儷鎷″嫉瀛�
+ - `mime_type` (string) 銉曘偂銈ゃ儷銇甅IME銈裤偆銉�
+ - `created_by` (uuid) 銈ㄣ兂銉夈儲銉笺偠銉糏D
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+
+ ### 銈ㄣ儵銉�
+ - 400, `no_file_uploaded`, 銉曘偂銈ゃ儷銇屾彁渚涖仌銈屻仾銇戙倢銇般仾銈娿伨銇涖倱
+ - 400, `too_many_files`, 鐝惧湪銇�1銇ゃ伄銉曘偂銈ゃ儷銇伩鍙椼亼浠樸亼銇俱仚
+ - 400, `unsupported_preview`, 銉曘偂銈ゃ儷銇儣銉儞銉ャ兗銈掋偟銉濄兗銉堛仐銇︺亜銇俱仜銈�
+ - 400, `unsupported_estimate`, 銉曘偂銈ゃ儷銇帹瀹氥倰銈点儩銉笺儓銇椼仸銇勩伨銇涖倱
+ - 413, `file_too_large`, 銉曘偂銈ゃ儷銇屽ぇ銇嶃仚銇庛伨銇�
+ - 415, `unsupported_file_type`, 銈点儩銉笺儓銇曘倢銇︺亜銇亜鎷″嫉瀛愩�佺従鍦ㄣ伅銉夈偔銉ャ儭銉炽儓銉曘偂銈ゃ儷銇伩鍙椼亼浠樸亼銇俱仚
+ - 503, `s3_connection_failed`, S3銈点兗銉撱偣銇帴缍氥仹銇嶃伨銇涖倱
+ - 503, `s3_permission_denied`, S3銇儠銈°偆銉倰銈€儍銉椼儹銉笺儔銇欍倠妯╅檺銇屻亗銈娿伨銇涖倱
+ - 503, `s3_file_too_large`, 銉曘偂銈ゃ儷銇孲3銇偟銈ゃ偤鍒堕檺銈掕秴銇堛仸銇勩伨銇�
+ - 500, 鍐呴儴銈点兗銉愩兗銈ㄣ儵銉�
+
+
+ </Col>
+ <Col sticky>
+ ### 銉偗銈ㄣ偣銉堜緥
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+
+ ### 蹇滅瓟渚�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": "6ad1ab0a-73ff-4ac1-b9e4-cdb312f71f13",
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/chat-messages/:task_id/stop'
+ method='POST'
+ title='鐢熸垚銈掑仠姝�'
+ name='#stop-generatebacks'
+/>
+<Row>
+ <Col>
+ 銈广儓銉兗銉熴兂銈般儮銉笺儔銇с伄銇裤偟銉濄兗銉堛仌銈屻仸銇勩伨銇欍��
+ ### 銉戙偣
+ - `task_id` (string) 銈裤偣銈疘D銆併偣銉堛儶銉笺儫銉炽偘銉併儯銉炽偗銇繑銈婂�ゃ亱銈夊彇寰椼仹銇嶃伨銇�
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ - `user` (string) 蹇呴爤
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇韩鍏冦倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�侀�佷俊銉°儍銈汇兗銈搞偆銉炽偪銉笺儠銈с兗銈广仹娓°仌銈屻仧銉︺兗銈躲兗銇ㄤ竴鑷淬仐銇︺亜銈嬪繀瑕併亴銇傘倞銇俱仚銆�
+ ### 蹇滅瓟
+ - `result` (string) 甯搞伀"success"銈掕繑銇椼伨銇�
+ </Col>
+ <Col sticky>
+ ### 銉偗銈ㄣ偣銉堜緥
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{"user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+
+ ### 蹇滅瓟渚�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages/:message_id/feedbacks'
+ method='POST'
+ title='銉°儍銈汇兗銈搞儠銈c兗銉夈儛銉冦偗'
+ name='#feedbacks'
+/>
+<Row>
+ <Col>
+ 銈ㄣ兂銉夈儲銉笺偠銉笺伅銉曘偅銉笺儔銉愩儍銈儭銉冦偦銉笺偢銈掓彁渚涖仹銇嶃�併偄銉椼儶銈便兗銈枫儳銉抽枊鐧鸿�呫亴鏈熷緟銇曘倢銈嬪嚭鍔涖倰鏈�閬╁寲銇欍倠銇倰鏀彺銇椼伨銇欍��
+
+ ### 銉戙偣
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ 銉°儍銈汇兗銈窱D
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='rating' type='string' key='rating'>
+ 銈€儍銉椼儨銉笺儓銇痐like`銆併儉銈︺兂銉溿兗銉堛伅`dislike`銆併偄銉冦儣銉溿兗銉堛伄鍙栥倞娑堛仐銇痐null`
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伄銉兗銉伀銈堛仯銇﹀畾缇┿仌銈屻�併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇亼銈屻伆銇倞銇俱仜銈撱��
+ </Property>
+ <Property name='content' type='string' key='content'>
+ 銉°儍銈汇兗銈搞伄銉曘偅銉笺儔銉愩儍銈仹銇欍��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `result` (string) 甯搞伀"success"銈掕繑銇椼伨銇�
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/messages/:message_id/feedbacks" targetCode={`curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks \\\n --header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "rating": "like",\n "user": "abc-123",\n "content": "message feedback information"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "rating": "like",
+ "user": "abc-123",
+ "content": "message feedback information"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/app/feedbacks'
+ method='GET'
+ title='銈€儣銉伄銉°儍銈汇兗銈搞伄銆屻亜銇勩伃銆嶃仺銉曘偅銉笺儔銉愩儍銈倰鍙栧緱'
+ name='#app-feedbacks'
+/>
+<Row>
+ <Col>
+ 銈€儣銉伄銈ㄣ兂銉夈儲銉笺偠銉笺亱銈夈伄銉曘偅銉笺儔銉愩儍銈倓銆屻亜銇勩伃銆嶃倰鍙栧緱銇椼伨銇欍��
+
+ ### 銈偍銉�
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 锛堜换鎰忥級銉氥兗銈哥暘鍙枫�傘儑銉曘偐銉儓鍊わ細1
+ </Property>
+ </Properties>
+
+ <Properties>
+ <Property name='limit' type='string' key='limit'>
+ 锛堜换鎰忥級1銉氥兗銈搞亗銇熴倞銇欢鏁般�傘儑銉曘偐銉儓鍊わ細20
+ </Property>
+ </Properties>
+
+ ### 銉偣銉濄兂銈�
+ - `data` (銉偣銉�) 銇撱伄銈€儣銉伄銆屻亜銇勩伃銆嶃仺銉曘偅銉笺儔銉愩儍銈伄涓�瑕с倰杩斻仐銇俱仚銆�
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/app/feedbacks" targetCode={`curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "8c0fbed8-e2f9-49ff-9f0e-15a35bdd0e25",
+ "app_id": "f252d396-fe48-450e-94ec-e184218e7346",
+ "conversation_id": "2397604b-9deb-430e-b285-4726e51fd62d",
+ "message_id": "709c0b0f-0a96-4a4e-91a4-ec0889937b11",
+ "rating": "like",
+ "content": "message feedback information-3",
+ "from_source": "user",
+ "from_end_user_id": "74286412-9a1a-42c1-929c-01edb1d381d5",
+ "from_account_id": null,
+ "created_at": "2025-04-24T09:24:38",
+ "updated_at": "2025-04-24T09:24:38"
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+
+<Heading
+ url='/messages/{message_id}/suggested'
+ method='GET'
+ title='娆°伄鎺ㄥエ璩晱'
+ name='#suggested'
+/>
+<Row>
+ <Col>
+ 鐝惧湪銇儭銉冦偦銉笺偢銇銇欍倠娆°伄璩晱銇彁妗堛倰鍙栧緱銇椼伨銇�
+
+ ### 銉戙偣銉戙儵銉°兗銈�
+
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ 銉°儍銈汇兗銈窱D
+ </Property>
+ </Properties>
+
+ ### 銈偍銉�
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇韩鍏冦倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�佺当瑷堛伄銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍��
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫伀銈堛仯銇︿竴鎰忋伀瀹氱京銇曘倢銈嬨伖銇嶃仹銇欍��
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/messages/{message_id}/suggested" targetCode={`curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested?user=abc-123& \\\n--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \\\n--header 'Content-Type: application/json'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested?user=abc-123' \
+ --header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
+ --header 'Content-Type: application/json' \
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "result": "success",
+ "data": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages'
+ method='GET'
+ title='浼氳┍灞ユ銉°儍銈汇兗銈搞倰鍙栧緱'
+ name='#messages'
+/>
+<Row>
+ <Col>
+ 銈广偗銉兗銉儹銉笺儔褰㈠紡銇у饱姝淬儊銉c儍銉堣閷层倰杩斻仐銆佹渶鍒濄伄銉氥兗銈搞伅鏈�鏂般伄`{limit}`銉°儍銈汇兗銈搞倰杩斻仐銇俱仚銆傘仱銇俱倞銆侀�嗛爢銇с仚銆�
+
+ ### 銈偍銉�
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 浼氳┍ID
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇韩鍏冦倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�佺当瑷堛伄銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍��
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫伀銈堛仯銇︿竴鎰忋伀瀹氱京銇曘倢銈嬨伖銇嶃仹銇欍��
+ </Property>
+ <Property name='first_id' type='string' key='first_id'>
+ 鐝惧湪銇儦銉笺偢銇渶鍒濄伄銉併儯銉冦儓瑷橀尣銇甀D銆併儑銉曘偐銉儓銇痭ull銇с仚銆�
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 1鍥炪伄銉偗銈ㄣ偣銉堛仹杩斻仚銉併儯銉冦儓灞ユ銉°儍銈汇兗銈搞伄鏁般�併儑銉曘偐銉儓銇�20銇с仚銆�
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `data` (array[object]) 銉°儍銈汇兗銈搞儶銈广儓
+ - `id` (string) 銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `inputs` (object) 銉︺兗銈躲兗鍏ュ姏銉戙儵銉°兗銈裤��
+ - `query` (string) 銉︺兗銈躲兗鍏ュ姏/璩晱鍐呭銆�
+ - `message_files` (array[object]) 銉°儍銈汇兗銈搞儠銈°偆銉�
+ - `id` (string) ID
+ - `type` (string) 銉曘偂銈ゃ儷銈裤偆銉椼�佺敾鍍忋伄鍫村悎銇痠mage
+ - `url` (string) 銉椼儸銉撱儱銉肩敾鍍廢RL
+ - `belongs_to` (string) 鎵�灞炪�乽ser銇俱仧銇痑ssistant
+ - `answer` (string) 蹇滅瓟銉°儍銈汇兗銈稿唴瀹�
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `feedback` (object) 銉曘偅銉笺儔銉愩儍銈儏鍫�
+ - `rating` (string) 銈€儍銉椼儨銉笺儓銇痐like` / 銉�銈︺兂銉溿兗銉堛伅`dislike`
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤銇ㄥ赴灞炪儶銈广儓
+ - `has_more` (bool) 娆°伄銉氥兗銈搞亴銇傘倠銇嬨仼銇嗐亱
+ - `limit` (int) 杩斻仌銈屻仧闋呯洰鏁般�佸叆鍔涖亴銈枫偣銉嗐儬鍒堕檺銈掕秴銇堛倠鍫村悎銆併偡銈广儐銉犲埗闄愭暟銈掕繑銇椼伨銇�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/messages" targetCode={`curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='\\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+ ### 蹇滅瓟渚�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "a076a87f-31e5-48dc-b452-0061adbbc922",
+ "conversation_id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "inputs": {
+ "name": "dify"
+ },
+ "query": "iphone 13 pro",
+ "answer": "iPhone 13 Pro銇�2021骞�9鏈�24鏃ャ伀鐧哄2銇曘倢銆�6.1銈ゃ兂銉併伄銉囥偅銈广儣銉偆銇�1170 x 2532銇В鍍忓害銈掑倷銇堛仸銇勩伨銇欍�侶exa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)銉椼儹銈汇儍銈点��6 GB銇甊AM銈掓惌杓夈仐銆�128 GB銆�256 GB銆�512 GB銆�1 TB銇偣銉堛儸銉笺偢銈儣銈枫儳銉炽倰鎻愪緵銇椼伨銇欍�傘偒銉°儵銇�12 MP銆併儛銉冦儐銉兗瀹归噺銇�3095 mAh銇с�乮OS 15銈掓惌杓夈仐銇︺亜銇俱仚銆�",
+ "message_files": [],
+ "feedback": null,
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ],
+ "created_at": 1705569239,
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations'
+ method='GET'
+ title='浼氳┍銈掑彇寰�'
+ name='#conversations'
+/>
+<Row>
+ <Col>
+ 鐝惧湪銇儲銉笺偠銉笺伄浼氳┍銉偣銉堛倰鍙栧緱銇椼�併儑銉曘偐銉儓銇ф渶鏂般伄20浠躲倰杩斻仐銇俱仚銆�
+
+ ### 銈偍銉�
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇韩鍏冦倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�佺当瑷堛伄銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍��
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫伀銈堛仯銇︿竴鎰忋伀瀹氱京銇曘倢銈嬨伖銇嶃仹銇欍��
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ (Optional)鐝惧湪銇儦銉笺偢銇渶寰屻伄瑷橀尣銇甀D銆併儑銉曘偐銉儓銇痭ull銇с仚銆�
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ (Optional)1鍥炪伄銉偗銈ㄣ偣銉堛仹杩斻仚瑷橀尣銇暟銆併儑銉曘偐銉儓銇渶鏂般伄20浠躲仹銇欍�傛渶澶�100銆佹渶灏�1銆�
+ </Property>
+ <Property name='sort_by' type='string' key='sort_by'>
+ (Optional)銈姐兗銉堛儠銈c兗銉儔銆併儑銉曘偐銉儓锛�-updated_at锛堟洿鏂版檪闁撱仹闄嶉爢銇偨銉笺儓锛�
+ - 鍒╃敤鍙兘銇�わ細created_at, -created_at, updated_at, -updated_at
+ - 銉曘偅銉笺儷銉夈伄鍓嶃伄瑷樺彿銇爢搴忋伨銇熴伅閫嗛爢銈掕〃銇椼��"-"銇�嗛爢銈掕〃銇椼伨銇欍��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `data` (array[object]) 浼氳┍銇儶銈广儓
+ - `id` (string) 浼氳┍ID
+ - `name` (string) 浼氳┍鍚嶃�併儑銉曘偐銉儓銇с伅LLM銇倛銇c仸鐢熸垚銇曘倢銇俱仚銆�
+ - `inputs` (object) 銉︺兗銈躲兗鍏ュ姏銉戙儵銉°兗銈裤��
+ - `introduction` (string) 绱逛粙
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `updated_at` (timestamp) 鏇存柊銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `has_more` (bool)
+ - `limit` (int) 杩斻仌銈屻仧銈ㄣ兂銉堛儶鏁般�佸叆鍔涖亴銈枫偣銉嗐儬鍒堕檺銈掕秴銇堛倠鍫村悎銆併偡銈广儐銉犲埗闄愭暟銇岃繑銇曘倢銇俱仚
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/conversations" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "10799fb8-64f7-4296-bbf7-b42bfbe0ae54",
+ "name": "鏂般仐銇勩儊銉c儍銉�",
+ "inputs": {
+ "book": "book",
+ "myName": "Lucy"
+ },
+ "status": "normal",
+ "created_at": 1679667915,
+ "updated_at": 1679667915
+ },
+ {
+ "id": "hSIhXBhNe8X1d8Et"
+ // ...
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id'
+ method='DELETE'
+ title='浼氳┍銈掑墛闄�'
+ name='#delete'
+/>
+<Row>
+ <Col>
+ 浼氳┍銈掑墛闄ゃ仐銇俱仚銆�
+
+ ### 銉戙偣
+ - `conversation_id` (string) 浼氳┍ID
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伀銈堛仯銇﹀畾缇┿仌銈屻�併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇傘倠銇撱仺銈掍繚瑷笺仐銇亼銈屻伆銇倞銇俱仜銈撱��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `result` (string) 甯搞伀"success"銈掕繑銇椼伨銇�
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="DELETE" label="/conversations/:conversation_id" targetCode={`curl -X DELETE '${props.appDetail.api_base_url}/conversations/:conversation_id' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X DELETE '${props.appDetail.api_base_url}/conversations/{conversation_id}' \
+ --header 'Content-Type: application/json' \
+ --header 'Accept: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data '{
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```text {{ title: '蹇滅瓟' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/conversations/:conversation_id/name'
+ method='POST'
+ title='浼氳┍銇悕鍓嶃倰澶夋洿'
+ name='#rename'
+/>
+<Row>
+ <Col>
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ 銈汇儍銈枫儳銉炽伄鍚嶅墠銈掑鏇淬仐銇俱仚銆傘偦銉冦偡銉с兂鍚嶃伅銆佽鏁般伄銈汇儍銈枫儳銉炽倰銈点儩銉笺儓銇欍倠銈儵銈ゃ偄銉炽儓銇с伄琛ㄧず銇娇鐢ㄣ仌銈屻伨銇欍��
+
+ ### 銉戙偣
+ - `conversation_id` (string) 浼氳┍ID
+
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ (Optional)浼氳┍銇悕鍓嶃�俙auto_generate`銇宍true`銇ō瀹氥仌銈屻仸銇勩倠鍫村悎銆併亾銇儜銉┿儭銉笺偪銇渷鐣ャ仹銇嶃伨銇欍��
+ </Property>
+ <Property name='auto_generate' type='bool' key='auto_generate'>
+ (Optional)銈裤偆銉堛儷銈掕嚜鍕曠敓鎴愩�併儑銉曘偐銉儓銇痐false`
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伀銈堛仯銇﹀畾缇┿仌銈屻�併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇傘倠銇撱仺銈掍繚瑷笺仐銇亼銈屻伆銇倞銇俱仜銈撱��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `id` (string) 浼氳┍ID
+ - `name` (string) 浼氳┍鍚�
+ - `inputs` (object) 銉︺兗銈躲兗鍏ュ姏銉戙儵銉°兗銈�
+ - `status` (string) 浼氳┍鐘舵厠
+ - `introduction` (string) 绱逛粙
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `updated_at` (timestamp) 鏇存柊銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
+ --header 'Content-Type: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data-raw '{
+ "name": "",
+ "auto_generate": true,
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "name": "銉併儯銉冦儓 vs AI",
+ "inputs": {},
+ "status": "normal",
+ "introduction": "",
+ "created_at": 1705569238,
+ "updated_at": 1705569238
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id/variables'
+ method='GET'
+ title='浼氳┍澶夋暟銇彇寰�'
+ name='#conversation-variables'
+/>
+<Row>
+ <Col>
+ 鐗瑰畾銇細瑭便亱銈夊鏁般倰鍙栧緱銇椼伨銇欍�傘亾銇偍銉炽儔銉濄偆銉炽儓銇�佷細瑭变腑銇彇寰椼仌銈屻仧妲嬮�犲寲銉囥兗銈裤倰鎶藉嚭銇欍倠銇伀褰圭珛銇°伨銇欍��
+
+ ### 銉戙偣銉戙儵銉°兗銈�
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 澶夋暟銈掑彇寰椼仚銈嬩細瑭便伄ID銆�
+ </Property>
+ </Properties>
+
+ ### 銈偍銉儜銉┿儭銉笺偪
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�傞枊鐧鸿�呫伀銈堛仯銇﹀畾缇┿仌銈屻仧銉兗銉伀寰撱亜銆併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇傘倠蹇呰銇屻亗銈娿伨銇欍��
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ (Optional)鐝惧湪銇儦銉笺偢銇渶寰屻伄瑷橀尣銇甀D銆併儑銉曘偐銉儓銇痭ull銇с仚銆�
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ (Optional)1鍥炪伄銉偗銈ㄣ偣銉堛仹杩斻仚瑷橀尣銇暟銆併儑銉曘偐銉儓銇渶鏂般伄20浠躲仹銇欍�傛渶澶�100銆佹渶灏�1銆�
+ </Property>
+ </Properties>
+
+ ### 銉偣銉濄兂銈�
+
+ - `limit` (int) 銉氥兗銈搞仈銇ㄣ伄銈€偆銉嗐儬鏁�
+ - `has_more` (bool) 銇曘倝銇偄銈ゃ儐銉犮亴銇傘倠銇嬨仼銇嗐亱
+ - `data` (array[object]) 澶夋暟銇儶銈广儓
+ - `id` (string) 澶夋暟ID
+ - `name` (string) 澶夋暟鍚�
+ - `value_type` (string) 澶夋暟銈裤偆銉楋紙鏂囧瓧鍒椼�佹暟鍊ゃ�佺湡鍋藉�ゃ仾銇╋級
+ - `value` (string) 澶夋暟鍊�
+ - `description` (string) 澶夋暟銇鏄�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉�
+ - `updated_at` (int) 鏈�绲傛洿鏂般偪銈ゃ儬銈广偪銉炽儣
+
+ ### 銈ㄣ儵銉�
+ - 404, `conversation_not_exists`, 浼氳┍銇岃銇ゃ亱銈娿伨銇涖倱
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations/:conversation_id/variables" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Request with variable name filter">
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123&variable_name=customer_name' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 100,
+ "has_more": false,
+ "data": [
+ {
+ "id": "variable-uuid-1",
+ "name": "customer_name",
+ "value_type": "string",
+ "value": "John Doe",
+ "description": "浼氳┍銇嬨倝鎶藉嚭銇曘倢銇熼¨瀹㈠悕",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ },
+ {
+ "id": "variable-uuid-2",
+ "name": "order_details",
+ "value_type": "json",
+ "value": "{\"product\":\"Widget\",\"quantity\":5,\"price\":19.99}",
+ "description": "椤у銇敞鏂囪┏绱�",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/audio-to-text'
+ method='POST'
+ title='闊冲0銇嬨倝銉嗐偔銈广儓銇�'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ 銇撱伄銈ㄣ兂銉夈儩銈ゃ兂銉堛伅multipart/form-data銉偗銈ㄣ偣銉堛倰蹇呰銇ㄣ仐銇俱仚銆�
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ 銈兗銉囥偅銈儠銈°偆銉��
+ 銈点儩銉笺儓銇曘倢銇︺亜銈嬪舰寮忥細`['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm']`
+ 銉曘偂銈ゃ儷銈点偆銈哄埗闄愶細15MB
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伄銉兗銉伀銈堛仯銇﹀畾缇┿仌銈屻�併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇亼銈屻伆銇倞銇俱仜銈撱��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `text` (string) 鍑哄姏銉嗐偔銈广儓
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/audio-to-text" targetCode={`curl -X POST '${props.appDetail.api_base_url}/audio-to-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=audio/[mp3|mp4|mpeg|mpga|m4a|wav|webm]'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/name' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@localfile;type=audio/mp3'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "text": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/text-to-audio'
+ method='POST'
+ title='銉嗐偔銈广儓銇嬨倝闊冲0銇�'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ 銉嗐偔銈广儓銈掗煶澹般伀澶夋彌銇椼伨銇欍��
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='message_id' type='str' key='message_id'>
+ Dify銇倛銇c仸鐢熸垚銇曘倢銇熴儐銈偣銉堛儭銉冦偦銉笺偢銇牬鍚堛�佺敓鎴愩仌銈屻仧銉°儍銈汇兗銈窱D銈掔洿鎺ユ浮銇椼伨銇欍�傘儛銉冦偗銈ㄣ兂銉夈伅銉°儍銈汇兗銈窱D銈掍娇鐢ㄣ仐銇﹀蹇溿仚銈嬪唴瀹广倰妞滅储銇椼�侀煶澹版儏鍫便倰鐩存帴鍚堟垚銇椼伨銇欍�俶essage_id銇╰ext銇屽悓鏅傘伀鎻愪緵銇曘倢銈嬪牬鍚堛�乵essage_id銇屽劒鍏堛仌銈屻伨銇欍��
+ </Property>
+ <Property name='text' type='str' key='text'>
+ 闊冲0鐢熸垚銈炽兂銉嗐兂銉勩��
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伀銈堛仯銇﹀畾缇┿仌銈屻�併偄銉椼儶鍐呫仹涓�鎰忋仹銇傘倠銇撱仺銈掍繚瑷笺仐銇亼銈屻伆銇倞銇俱仜銈撱��
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "Hello Dify",\n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
+ "text": "Hello Dify",
+ "user": "abc-123",
+ "streaming": false
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="銉樸儍銉�銉�">
+ ```json {{ title: '銉樸儍銉�銉�' }}
+ {
+ "Content-Type": "audio/wav"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇熀鏈儏鍫便倰鍙栧緱'
+ name='#info'
+/>
+<Row>
+ <Col>
+ 銇撱伄銈€儣銉偙銉笺偡銉с兂銇熀鏈儏鍫便倰鍙栧緱銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻伨銇�
+
+ ### Response
+ - `name` (string) 銈€儣銉偙銉笺偡銉с兂銇悕鍓�
+ - `description` (string) 銈€儣銉偙銉笺偡銉с兂銇鏄�
+ - `tags` (array[string]) 銈€儣銉偙銉笺偡銉с兂銇偪銈�
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇儜銉┿儭銉笺偪鎯呭牨銈掑彇寰�'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ 銉氥兗銈搞伀鍏ャ倠闅涖伀銆佹鑳姐�佸叆鍔涖儜銉┿儭銉笺偪鍚嶃�併偪銈ゃ儣銆併儑銉曘偐銉儓鍊ゃ仾銇┿伄鎯呭牨銈掑彇寰椼仚銈嬨仧銈併伀浣跨敤銇曘倢銇俱仚銆�
+
+ ### 蹇滅瓟
+ - `opening_statement` (string) 闁嬪銇尐鎷�
+ - `suggested_questions` (array[string]) 闁嬪鏅傘伄鎺ㄥエ璩晱銇儶銈广儓
+ - `suggested_questions_after_answer` (object) 绛斻亪銈掓湁鍔广伀銇椼仧寰屻伄璩晱銈掓彁妗堛仐銇俱仚銆�
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `speech_to_text` (object) 闊冲0銇嬨倝銉嗐偔銈广儓銇�
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `retriever_resource` (object) 寮曠敤銇ㄥ赴灞�
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `annotation_reply` (object) 娉ㄩ噲杩斾俊
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `user_input_form` (array[object]) 銉︺兗銈躲兗鍏ュ姏銉曘偐銉笺儬銇ō瀹�
+ - `text-input` (object) 銉嗐偔銈广儓鍏ュ姏銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `paragraph` (object) 娈佃惤銉嗐偔銈广儓鍏ュ姏銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `select` (object) 銉夈儹銉冦儣銉�銈︺兂銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `options` (array[string]) 銈儣銈枫儳銉冲��
+ - `file_upload` (object) 銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔瑷畾
+ - `image` (object) 鐢诲儚瑷畾
+ 鐝惧湪銈点儩銉笺儓銇曘倢銇︺亜銈嬬敾鍍忋偪銈ゃ儣锛歚png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `number_limits` (int) 鐢诲儚鏁般伄鍒堕檺銆併儑銉曘偐銉儓銇�3
+ - `transfer_methods` (array[string]) 杌㈤�佹柟娉曘伄銉偣銉堛�乺emote_url, local_file銆併亜銇氥倢銇嬨倰閬告姙銇欍倠蹇呰銇屻亗銈娿伨銇�
+ - `system_parameters` (object) 銈枫偣銉嗐儬銉戙儵銉°兗銈�
+ - `file_size_limit` (int) 銉夈偔銉ャ儭銉炽儓銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+ - `image_file_size_limit` (int) 鐢诲儚銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+ - `audio_file_size_limit` (int) 銈兗銉囥偅銈儠銈°偆銉偄銉冦儣銉兗銉夈偟銈ゃ偤鍒堕檺锛圡B锛�
+ - `video_file_size_limit` (int) 銉撱儑銈儠銈°偆銉偄銉冦儣銉兗銉夈偟銈ゃ偤鍒堕檺锛圡B锛�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "opening_statement": "銇撱倱銇仭銇紒",
+ "suggested_questions_after_answer": {
+ "enabled": true
+ },
+ "speech_to_text": {
+ "enabled": true
+ },
+ "retriever_resource": {
+ "enabled": true
+ },
+ "annotation_reply": {
+ "enabled": true
+ },
+ "user_input_form": [
+ {
+ "paragraph": {
+ "label": "銈偍銉�",
+ "variable": "query",
+ "required": true,
+ "default": ""
+ }
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": false,
+ "number_limits": 3,
+ "detail": "high",
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/meta'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇儭銈挎儏鍫便倰鍙栧緱'
+ name='#meta'
+/>
+<Row>
+ <Col>
+ 銇撱伄銈€儣銉偙銉笺偡銉с兂銇儎銉笺儷銇偄銈ゃ偝銉炽倰鍙栧緱銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻伨銇�
+
+ ### 蹇滅瓟
+ - `tool_icons`(object[string]) 銉勩兗銉偄銈ゃ偝銉�
+ - `tool_name` (string)
+ - `icon` (object|string)
+ - (object) 銈€偆銈炽兂銈儢銈搞偋銈儓
+ - `background` (string) 鑳屾櫙鑹诧紙16閫叉暟褰㈠紡锛�
+ - `content`(string) 绲垫枃瀛�
+ - (string) 銈€偆銈炽兂銇甎RL
+ </Col>
+ <Col>
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/meta' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/meta' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "tool_icons": {
+ "dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
+ "api_tool": {
+ "background": "#252525",
+ "content": "\ud83d\ude01"
+ }
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='銈€儣銉伄WebApp瑷畾銈掑彇寰�'
+ name='#site'
+/>
+<Row>
+ <Col>
+ 銈€儣銉伄WebApp瑷畾銈掑彇寰椼仚銈嬨仧銈併伀浣跨敤銇椼伨銇欍��
+ ### 蹇滅瓟
+ - `title` (string) WebApp鍚�
+ - `chat_color_theme` (string) 銉併儯銉冦儓銇壊銉嗐兗銉炪��16閫叉暟褰㈠紡
+ - `chat_color_theme_inverted` (bool) 銉併儯銉冦儓銇壊銉嗐兗銉炪倰鍙嶈虎銇欍倠銇嬨仼銇嗐亱
+ - `icon_type` (string) 銈€偆銈炽兂銈裤偆銉椼�乣emoji`-绲垫枃瀛椼�乣image`-鐢诲儚
+ - `icon` (string) 銈€偆銈炽兂銆俙emoji`銈裤偆銉椼伄鍫村悎銇档鏂囧瓧銆乣image`銈裤偆銉椼伄鍫村悎銇敾鍍廢RL
+ - `icon_background` (string) 16閫叉暟褰㈠紡銇儗鏅壊
+ - `icon_url` (string) 銈€偆銈炽兂銇甎RL
+ - `description` (string) 瑾槑
+ - `copyright` (string) 钁椾綔妯╂儏鍫�
+ - `privacy_policy` (string) 銉椼儵銈ゃ儛銈枫兗銉濄儶銈枫兗銇儶銉炽偗
+ - `custom_disclaimer` (string) 銈偣銈裤儬鍏嶈铂浜嬮爡
+ - `default_language` (string) 銉囥儠銈┿儷銉堣█瑾�
+ - `show_workflow_steps` (bool) 銉兗銈儠銉兗銇┏绱般倰琛ㄧず銇欍倠銇嬨仼銇嗐亱
+ - `use_icon_as_answer_icon` (bool) WebApp銇偄銈ゃ偝銉炽倰銉併儯銉冦儓鍐呫伄馃銇疆銇嶆彌銇堛倠銇嬨仼銇嗐亱
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "chat_color_theme": "#ff4a4a",
+ "chat_color_theme_inverted": false,
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ "use_icon_as_answer_icon": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
diff --git a/app/components/develop/template/template_advanced_chat.zh.mdx b/app/components/develop/template/template_advanced_chat.zh.mdx
new file mode 100644
index 0000000..9077f54
--- /dev/null
+++ b/app/components/develop/template/template_advanced_chat.zh.mdx
@@ -0,0 +1,1684 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
+
+# 宸ヤ綔娴佺紪鎺掑璇濆瀷搴旂敤 API
+
+瀵硅瘽搴旂敤鏀寔浼氳瘽鎸佷箙鍖栵紝鍙皢涔嬪墠鐨勮亰澶╄褰曚綔涓轰笂涓嬫枃杩涜鍥炵瓟锛屽彲閫傜敤浜庤亰澶�/瀹㈡湇 AI 绛夈��
+
+<div>
+ ### 鍩虹 URL
+ <CodeGroup title="Code" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### 閴存潈
+
+ Service API 浣跨敤 `API-Key` 杩涜閴存潈銆�
+ <i>**寮虹儓寤鸿寮�鍙戣�呮妸 `API-Key` 鏀惧湪鍚庣瀛樺偍锛岃�岄潪鍒嗕韩鎴栬�呮斁鍦ㄥ鎴风瀛樺偍锛屼互鍏� `API-Key` 娉勯湶锛屽鑷磋储浜ф崯澶便��**</i>
+ 鎵�鏈� API 璇锋眰閮藉簲鍦� **`Authorization`** HTTP Header 涓寘鍚偍鐨� `API-Key`锛屽涓嬫墍绀猴細
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/chat-messages'
+ method='POST'
+ title='鍙戦�佸璇濇秷鎭�'
+ name='#Create-Chat-Message'
+/>
+<Row>
+ <Col>
+ 鍒涘缓浼氳瘽娑堟伅銆�
+
+ ### Request Body
+
+ <Properties>
+ <Property name='query' type='string' key='query'>
+ 鐢ㄦ埛杈撳叆/鎻愰棶鍐呭銆�
+ </Property>
+ <Property name='inputs' type='object' key='inputs'>
+ 鍏佽浼犲叆 App 瀹氫箟鐨勫悇鍙橀噺鍊笺��
+ inputs 鍙傛暟鍖呭惈浜嗗缁勯敭鍊煎锛圞ey/Value pairs锛夛紝姣忕粍鐨勯敭瀵瑰簲涓�涓壒瀹氬彉閲忥紝姣忕粍鐨勫�煎垯鏄鍙橀噺鐨勫叿浣撳�笺��
+ 濡傛灉鍙橀噺鏄枃浠剁被鍨嬶紝璇锋寚瀹氫竴涓寘鍚互涓� `files` 涓墍杩伴敭鐨勫璞°��
+ 榛樿 `{}`
+ </Property>
+ <Property name='response_mode' type='string' key='response_mode'>
+ - `streaming` 娴佸紡妯″紡锛堟帹鑽愶級銆傚熀浜� SSE锛�**[Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)**锛夊疄鐜扮被浼兼墦瀛楁満杈撳嚭鏂瑰紡鐨勬祦寮忚繑鍥炪��
+ - `blocking` 闃诲妯″紡锛岀瓑寰呮墽琛屽畬姣曞悗杩斿洖缁撴灉銆傦紙璇锋眰鑻ユ祦绋嬭緝闀垮彲鑳戒細琚腑鏂級銆�
+ <i>鐢变簬 Cloudflare 闄愬埗锛岃姹備細鍦� 100 绉掕秴鏃舵棤杩斿洖鍚庝腑鏂��</i>
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屾柟渚挎绱€�佺粺璁°��
+ 鐢卞紑鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 锛堥�夊~锛変細璇� ID锛岄渶瑕佸熀浜庝箣鍓嶇殑鑱婂ぉ璁板綍缁х画瀵硅瘽锛屽繀椤讳紶涔嬪墠娑堟伅鐨� conversation_id銆�
+ </Property>
+ <Property name='files' type='array[object]' key='files'>
+ 鏂囦欢鍒楄〃锛岄�傜敤浜庝紶鍏ユ枃浠剁粨鍚堟枃鏈悊瑙e苟鍥炵瓟闂锛屼粎褰撴ā鍨嬫敮鎸� Vision 鑳藉姏鏃跺彲鐢ㄣ��
+ - `type` (string) 鏀寔绫诲瀷锛�
+ - `document` 鍏蜂綋绫诲瀷鍖呭惈锛�'TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB'
+ - `image` 鍏蜂綋绫诲瀷鍖呭惈锛�'JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG'
+ - `audio` 鍏蜂綋绫诲瀷鍖呭惈锛�'MP3', 'M4A', 'WAV', 'WEBM', 'AMR'
+ - `video` 鍏蜂綋绫诲瀷鍖呭惈锛�'MP4', 'MOV', 'MPEG', 'MPGA'
+ - `custom` 鍏蜂綋绫诲瀷鍖呭惈锛氬叾浠栨枃浠剁被鍨�
+ - `transfer_method` (string) 浼犻�掓柟寮�:
+ - `remote_url`: 鍥剧墖鍦板潃銆�
+ - `local_file`: 涓婁紶鏂囦欢銆�
+ - `url` 鍥剧墖鍦板潃銆傦紙浠呭綋浼犻�掓柟寮忎负 `remote_url` 鏃讹級銆�
+ - `upload_file_id` 涓婁紶鏂囦欢 ID銆傦紙浠呭綋浼犻�掓柟寮忎负 `local_file `鏃讹級銆�
+ </Property>
+ <Property name='auto_generate_name' type='bool' key='auto_generate_name'>
+ 锛堥�夊~锛夎嚜鍔ㄧ敓鎴愭爣棰橈紝榛樿 `true`銆� 鑻ヨ缃负 `false`锛屽垯鍙�氳繃璋冪敤浼氳瘽閲嶅懡鍚嶆帴鍙e苟璁剧疆 `auto_generate` 涓� `true` 瀹炵幇寮傛鐢熸垚鏍囬銆�
+ </Property>
+ </Properties>
+
+ ### Response
+ <Properties>
+ 褰� `response_mode` 涓� `blocking` 鏃讹紝杩斿洖 ChatCompletionResponse object銆�
+ 褰� `response_mode` 涓� `streaming`鏃讹紝杩斿洖 ChunkChatCompletionResponse object 娴佸紡搴忓垪銆�
+
+ ### ChatCompletionResponse
+
+ 杩斿洖瀹屾暣鐨� App 缁撴灉锛宍Content-Type` 涓� `application/json`銆�
+ - `event` (string) 浜嬩欢绫诲瀷锛屽浐瀹氫负 `message`
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `id` (string) 鍞竴ID
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `mode` (string) App 妯″紡锛屽浐瀹氫负 chat
+ - `answer` (string) 瀹屾暣鍥炲鍐呭
+ - `metadata` (object) 鍏冩暟鎹�
+ - `usage` (Usage) 妯″瀷鐢ㄩ噺淇℃伅
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤鍜屽綊灞炲垎娈靛垪琛�
+ - `created_at` (int) 娑堟伅鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+
+ ### ChunkChatCompletionResponse
+ 杩斿洖 App 杈撳嚭鐨勬祦寮忓潡锛宍Content-Type` 涓� `text/event-stream`銆�
+ 姣忎釜娴佸紡鍧楀潎涓� data: 寮�澶达紝鍧椾箣闂翠互 \n\n 鍗充袱涓崲琛岀鍒嗛殧锛屽涓嬫墍绀猴細
+ <CodeGroup>
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
+ ```
+ </CodeGroup>
+
+ 娴佸紡鍧椾腑鏍规嵁 event 涓嶅悓锛岀粨鏋勪篃涓嶅悓锛�
+ - `event: message` LLM 杩斿洖鏂囨湰鍧椾簨浠讹紝鍗筹細瀹屾暣鐨勬枃鏈互鍒嗗潡鐨勬柟寮忚緭鍑恒��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `answer` (string) LLM 杩斿洖鏂囨湰鍧楀唴瀹�
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: message_file` 鏂囦欢浜嬩欢锛岃〃绀烘湁鏂版枃浠堕渶瑕佸睍绀�
+ - `id` (string) 鏂囦欢鍞竴ID
+ - `type` (string) 鏂囦欢绫诲瀷锛岀洰鍓嶄粎涓篿mage
+ - `belongs_to` (string) 鏂囦欢褰掑睘锛寀ser鎴朼ssistant锛岃鎺ュ彛杩斿洖浠呬负 `assistant`
+ - `url` (string) 鏂囦欢璁块棶鍦板潃
+ - `conversation_id` (string) 浼氳瘽ID
+ - `event: message_end` 娑堟伅缁撴潫浜嬩欢锛屾敹鍒版浜嬩欢鍒欎唬琛ㄦ祦寮忚繑鍥炵粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `metadata` (object) 鍏冩暟鎹�
+ - `usage` (Usage) 妯″瀷鐢ㄩ噺淇℃伅
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤鍜屽綊灞炲垎娈靛垪琛�
+ - `event: tts_message` TTS 闊抽娴佷簨浠讹紝鍗筹細璇煶鍚堟垚杈撳嚭銆傚唴瀹规槸Mp3鏍煎紡鐨勯煶棰戝潡锛屼娇鐢� base64 缂栫爜鍚庣殑瀛楃涓诧紝鎾斁鐨勬椂鍊欑洿鎺ヨВ鐮佸嵆鍙��(寮�鍚嚜鍔ㄦ挱鏀炬墠鏈夋娑堟伅)
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `audio` (string) 璇煶鍚堟垚涔嬪悗鐨勯煶棰戝潡浣跨敤 Base64 缂栫爜涔嬪悗鐨勬枃鏈唴瀹癸紝鎾斁鐨勬椂鍊欑洿鎺� base64 瑙g爜閫佸叆鎾斁鍣ㄥ嵆鍙�
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: tts_message_end` TTS 闊抽娴佺粨鏉熶簨浠讹紝鏀跺埌杩欎釜浜嬩欢琛ㄧず闊抽娴佽繑鍥炵粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `audio` (string) 缁撴潫浜嬩欢鏄病鏈夐煶棰戠殑锛屾墍浠ヨ繖閲屾槸绌哄瓧绗︿覆
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: message_replace` 娑堟伅鍐呭鏇挎崲浜嬩欢銆�
+ 寮�鍚唴瀹瑰鏌ュ拰瀹℃煡杈撳嚭鍐呭鏃讹紝鑻ュ懡涓簡瀹℃煡鏉′欢锛屽垯浼氶�氳繃姝や簨浠舵浛鎹㈡秷鎭唴瀹逛负棰勮鍥炲銆�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `answer` (string) 鏇挎崲鍐呭锛堢洿鎺ユ浛鎹� LLM 鎵�鏈夊洖澶嶆枃鏈級
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: workflow_started` workflow 寮�濮嬫墽琛�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `event` (string) 鍥哄畾涓� `workflow_started`
+ - `data` (object) 璇︾粏鍐呭
+ - `id` (string) workflow 鎵ц ID
+ - `workflow_id` (string) 鍏宠仈 Workflow ID
+ - `sequence_number` (int) 鑷搴忓彿锛孉pp 鍐呰嚜澧烇紝浠� 1 寮�濮�
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `event: node_started` node 寮�濮嬫墽琛�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `event` (string) 鍥哄畾涓� `node_started`
+ - `data` (object) 璇︾粏鍐呭
+ - `id` (string) workflow 鎵ц ID
+ - `node_id` (string) 鑺傜偣 ID
+ - `node_type` (string) 鑺傜偣绫诲瀷
+ - `title` (string) 鑺傜偣鍚嶇О
+ - `index` (int) 鎵ц搴忓彿锛岀敤浜庡睍绀� Tracing Node 椤哄簭
+ - `predecessor_node_id` (string) 鍓嶇疆鑺傜偣 ID锛岀敤浜庣敾甯冨睍绀烘墽琛岃矾寰�
+ - `inputs` (object) 鑺傜偣涓墍鏈変娇鐢ㄥ埌鐨勫墠缃妭鐐瑰彉閲忓唴瀹�
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `event: node_finished` node 鎵ц缁撴潫锛屾垚鍔熷け璐ュ悓涓�浜嬩欢涓笉鍚岀姸鎬�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `event` (string) 鍥哄畾涓� `node_finished`
+ - `data` (object) 璇︾粏鍐呭
+ - `id` (string) node 鎵ц ID
+ - `node_id` (string) 鑺傜偣 ID
+ - `index` (int) 鎵ц搴忓彿锛岀敤浜庡睍绀� Tracing Node 椤哄簭
+ - `predecessor_node_id` (string) optional 鍓嶇疆鑺傜偣 ID锛岀敤浜庣敾甯冨睍绀烘墽琛岃矾寰�
+ - `inputs` (object) 鑺傜偣涓墍鏈変娇鐢ㄥ埌鐨勫墠缃妭鐐瑰彉閲忓唴瀹�
+ - `process_data` (json) Optional 鑺傜偣杩囩▼鏁版嵁
+ - `outputs` (json) Optional 杈撳嚭鍐呭
+ - `status` (string) 鎵ц鐘舵�� `running` / `succeeded` / `failed` / `stopped`
+ - `error` (string) Optional 閿欒鍘熷洜
+ - `elapsed_time` (float) Optional 鑰楁椂(s)
+ - `execution_metadata` (json) 鍏冩暟鎹�
+ - `total_tokens` (int) optional 鎬讳娇鐢� tokens
+ - `total_price` (decimal) optional 鎬昏垂鐢�
+ - `currency` (string) optional 璐у竵锛屽 `USD` / `RMB`
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `event: workflow_finished` workflow 鎵ц缁撴潫锛屾垚鍔熷け璐ュ悓涓�浜嬩欢涓笉鍚岀姸鎬�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `event` (string) 鍥哄畾涓� `workflow_finished`
+ - `data` (object) 璇︾粏鍐呭
+ - `id` (string) workflow 鎵ц ID
+ - `workflow_id` (string) 鍏宠仈 Workflow ID
+ - `status` (string) 鎵ц鐘舵�� `running` / `succeeded` / `failed` / `stopped`
+ - `outputs` (json) Optional 杈撳嚭鍐呭
+ - `error` (string) Optional 閿欒鍘熷洜
+ - `elapsed_time` (float) Optional 鑰楁椂(s)
+ - `total_tokens` (int) Optional 鎬讳娇鐢� tokens
+ - `total_steps` (int) 鎬绘鏁帮紙鍐椾綑锛夛紝榛樿 0
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `finished_at` (timestamp) 缁撴潫鏃堕棿
+ - `event: error`
+ 娴佸紡杈撳嚭杩囩▼涓嚭鐜扮殑寮傚父浼氫互 stream event 褰㈠紡杈撳嚭锛屾敹鍒板紓甯镐簨浠跺悗鍗崇粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `status` (int) HTTP 鐘舵�佺爜
+ - `code` (string) 閿欒鐮�
+ - `message` (string) 閿欒娑堟伅
+ - `event: ping` 姣� 10s 涓�娆$殑 ping 浜嬩欢锛屼繚鎸佽繛鎺ュ瓨娲汇��
+
+ ### Errors
+ - 404锛屽璇濅笉瀛樺湪
+ - 400锛宍invalid_param`锛屼紶鍏ュ弬鏁板紓甯�
+ - 400锛宍app_unavailable`锛孉pp 閰嶇疆涓嶅彲鐢�
+ - 400锛宍provider_not_initialize`锛屾棤鍙敤妯″瀷鍑嵁閰嶇疆
+ - 400锛宍provider_quota_exceeded`锛屾ā鍨嬭皟鐢ㄩ搴︿笉瓒�
+ - 400锛宍model_currently_not_support`锛屽綋鍓嶆ā鍨嬩笉鍙敤
+ - 400锛宍completion_request_error`锛屾枃鏈敓鎴愬け璐�
+ - 500锛屾湇鍔″唴閮ㄥ紓甯�
+
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/chat-messages" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": ${JSON.stringify(props.inputs)},\n "query": "What are the specs of the iPhone 13 Pro Max?",\n "response_mode": "streaming",\n "conversation_id": "",\n "user": "abc-123",\n "files": [\n {\n "type": "image",\n "transfer_method": "remote_url",\n "url": "https://cloud.dify.ai/logo/logo-site.png"\n }\n ]\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {
+ "name": "dify"
+ },
+ "query": "What are the specs of the iPhone 13 Pro Max?",
+ "conversation_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "response_mode": "streaming",
+ "user": "abc-123",
+ "files": [
+ {
+ "type": "image",
+ "transfer_method": "remote_url",
+ "url": "https://cloud.dify.ai/logo/logo-site.png"
+ }
+ ]
+ }'
+ ```
+
+ </CodeGroup>
+ ### 闃诲妯″紡
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "event": "message",
+ "task_id": "c3800678-a077-43df-a102-53f23ed20b88",
+ "id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
+ "mode": "chat",
+ "answer": "iPhone 13 Pro Max specs are listed here:...",
+ "metadata": {
+ "usage": {
+ "prompt_tokens": 1033,
+ "prompt_unit_price": "0.001",
+ "prompt_price_unit": "0.001",
+ "prompt_price": "0.0010330",
+ "completion_tokens": 128,
+ "completion_unit_price": "0.002",
+ "completion_price_unit": "0.001",
+ "completion_price": "0.0002560",
+ "total_tokens": 1161,
+ "total_price": "0.0012890",
+ "currency": "USD",
+ "latency": 0.7682376249867957
+ },
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ]
+ },
+ "created_at": 1705407629
+ }
+ ```
+ </CodeGroup>
+ ### 娴佸紡妯″紡
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}
+ data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}
+ data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}
+ data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='涓婁紶鏂囦欢'
+ name='#files-upload'
+/>
+<Row>
+ <Col>
+ 涓婁紶鏂囦欢骞跺湪鍙戦�佹秷鎭椂浣跨敤锛屽彲瀹炵幇鍥炬枃澶氭ā鎬佺悊瑙c��
+ 鏀寔鎮ㄧ殑搴旂敤绋嬪簭鎵�鏀寔鐨勬墍鏈夋牸寮忋��
+ <i>涓婁紶鐨勬枃浠朵粎渚涘綋鍓嶇粓绔敤鎴蜂娇鐢ㄣ��</i>
+
+ ### Request Body
+ 璇ユ帴鍙i渶浣跨敤 `multipart/form-data` 杩涜璇锋眰銆�
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ 瑕佷笂浼犵殑鏂囦欢銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屽繀椤诲拰鍙戦�佹秷鎭帴鍙d紶鍏� user 淇濇寔涓�鑷淬��
+ </Property>
+ </Properties>
+
+ ### Response
+ 鎴愬姛涓婁紶鍚庯紝鏈嶅姟鍣ㄤ細杩斿洖鏂囦欢鐨� ID 鍜岀浉鍏充俊鎭��
+ - `id` (uuid) ID
+ - `name` (string) 鏂囦欢鍚�
+ - `size` (int) 鏂囦欢澶у皬锛坆yte锛�
+ - `extension` (string) 鏂囦欢鍚庣紑
+ - `mime_type` (string) 鏂囦欢 mime-type
+ - `created_by` (uuid) 涓婁紶浜� ID
+ - `created_at` (timestamp) 涓婁紶鏃堕棿
+
+ ### Errors
+ - 400锛宍no_file_uploaded`锛屽繀椤绘彁渚涙枃浠�
+ - 400锛宍too_many_files`锛岀洰鍓嶅彧鎺ュ彈涓�涓枃浠�
+ - 400锛宍unsupported_preview`锛岃鏂囦欢涓嶆敮鎸侀瑙�
+ - 400锛宍unsupported_estimate`锛岃鏂囦欢涓嶆敮鎸佷及绠�
+ - 413锛宍file_too_large`锛屾枃浠跺お澶�
+ - 415锛宍unsupported_file_type`锛屼笉鏀寔鐨勬墿灞曞悕锛屽綋鍓嶅彧鎺ュ彈鏂囨。绫绘枃浠�
+ - 503锛宍s3_connection_failed`锛屾棤娉曡繛鎺ュ埌 S3 鏈嶅姟
+ - 503锛宍s3_permission_denied`锛屾棤鏉冮檺涓婁紶鏂囦欢鍒� S3
+ - 503锛宍s3_file_too_large`锛屾枃浠惰秴鍑� S3 澶у皬闄愬埗
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": 123,
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+<Heading
+ url='/chat-messages/:task_id/stop'
+ method='POST'
+ title='鍋滄鍝嶅簲'
+ name='#Stop'
+/>
+<Row>
+ <Col>
+ 浠呮敮鎸佹祦寮忔ā寮忋��
+ ### Path
+ - `task_id` (string) 浠诲姟 ID锛屽彲鍦ㄦ祦寮忚繑鍥� Chunk 涓幏鍙�
+
+ ### Request Body
+ - `user` (string) Required
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屽繀椤诲拰鍙戦�佹秷鎭帴鍙d紶鍏� user 淇濇寔涓�鑷淬��
+ ### Response
+ - `result` (string) 鍥哄畾杩斿洖 success
+ </Col>
+ <Col sticky>
+ <CodeGroup title="Request" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/messages/:message_id/feedbacks'
+ method='POST'
+ title='娑堟伅鍙嶉锛堢偣璧烇級'
+ name='#feedbacks'
+/>
+<Row>
+ <Col>
+ 娑堟伅缁堢鐢ㄦ埛鍙嶉銆佺偣璧烇紝鏂逛究搴旂敤寮�鍙戣�呬紭鍖栬緭鍑洪鏈熴��
+
+ ### Path Params
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ 娑堟伅 ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+
+ <Properties>
+ <Property name='rating' type='string' key='rating'>
+ 鐐硅禐 like, 鐐硅俯 dislike, 鎾ら攢鐐硅禐 null
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='content' type='string' key='content'>
+ 娑堟伅鍙嶉鐨勫叿浣撲俊鎭��
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) 鍥哄畾杩斿洖 success
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/messages/:message_id/feedbacks" targetCode={`curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "rating": "like",\n "user": "abc-123",\n "content": "message feedback information"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "rating": "like",
+ "user": "abc-123",
+ "content": "message feedback information"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/app/feedbacks'
+ method='GET'
+ title='鑾峰彇APP鐨勬秷鎭偣璧炲拰鍙嶉'
+ name='#app-feedbacks'
+/>
+<Row>
+ <Col>
+ 鑾峰彇搴旂敤鐨勭粓绔敤鎴峰弽棣堛�佺偣璧炪��
+
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 锛堥�夊~锛夊垎椤碉紝榛樿鍊硷細1
+ </Property>
+ </Properties>
+
+ <Properties>
+ <Property name='limit' type='string' key='limit'>
+ 锛堥�夊~锛夋瘡椤垫暟閲忥紝榛樿鍊硷細20
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (List) 杩斿洖璇PP鐨勭偣璧炪�佸弽棣堝垪琛ㄣ��
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/app/feedbacks" targetCode={`curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "8c0fbed8-e2f9-49ff-9f0e-15a35bdd0e25",
+ "app_id": "f252d396-fe48-450e-94ec-e184218e7346",
+ "conversation_id": "2397604b-9deb-430e-b285-4726e51fd62d",
+ "message_id": "709c0b0f-0a96-4a4e-91a4-ec0889937b11",
+ "rating": "like",
+ "content": "message feedback information-3",
+ "from_source": "user",
+ "from_end_user_id": "74286412-9a1a-42c1-929c-01edb1d381d5",
+ "from_account_id": null,
+ "created_at": "2025-04-24T09:24:38",
+ "updated_at": "2025-04-24T09:24:38"
+ }
+ ]
+ }
+
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages/{message_id}/suggested'
+ method='GET'
+ title='鑾峰彇涓嬩竴杞缓璁棶棰樺垪琛�'
+ name='#suggested'
+/>
+<Row>
+ <Col>
+ 鑾峰彇涓嬩竴杞缓璁棶棰樺垪琛ㄣ��
+
+ ### Path Params
+
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ Message ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/messages/{message_id}/suggested" targetCode={`curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested?user=abc-123 \\\n--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \\\n--header 'Content-Type: application/json'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested?user=abc-123' \
+ --header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
+ --header 'Content-Type: application/json' \
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success",
+ "data": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+---
+
+<Heading
+ url='/messages'
+ method='GET'
+ title='鑾峰彇浼氳瘽鍘嗗彶娑堟伅'
+ name='#messages'
+/>
+<Row>
+ <Col>
+ 婊氬姩鍔犺浇褰㈠紡杩斿洖鍘嗗彶鑱婂ぉ璁板綍锛岀涓�椤佃繑鍥炴渶鏂� `limit` 鏉★紝鍗筹細鍊掑簭杩斿洖銆�
+
+ ### Query
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 浼氳瘽 ID
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='first_id' type='string' key='first_id'>
+ 褰撳墠椤电涓�鏉¤亰澶╄褰曠殑 ID锛岄粯璁� null
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 涓�娆¤姹傝繑鍥炲灏戞潯鑱婂ぉ璁板綍锛岄粯璁� 20 鏉°��
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (array[object]) 娑堟伅鍒楄〃
+ - `id` (string) 娑堟伅 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `inputs` (object) 鐢ㄦ埛杈撳叆鍙傛暟銆�
+ - `query` (string) 鐢ㄦ埛杈撳叆 / 鎻愰棶鍐呭銆�
+ - `message_files` (array[object]) 娑堟伅鏂囦欢
+ - `id` (string) ID
+ - `type` (string) 鏂囦欢绫诲瀷锛宨mage 鍥剧墖
+ - `url` (string) 棰勮鍥剧墖鍦板潃
+ - `belongs_to` (string) 鏂囦欢褰掑睘鏂癸紝user 鎴� assistant
+ - `answer` (string) 鍥炵瓟娑堟伅鍐呭
+ - `created_at` (timestamp) 鍒涘缓鏃堕棿
+ - `feedback` (object) 鍙嶉淇℃伅
+ - `rating` (string) 鐐硅禐 like / 鐐硅俯 dislike
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤鍜屽綊灞炲垎娈靛垪琛�
+ - `has_more` (bool) 鏄惁瀛樺湪涓嬩竴椤�
+ - `limit` (int) 杩斿洖鏉℃暟锛岃嫢浼犲叆瓒呰繃绯荤粺闄愬埗锛岃繑鍥炵郴缁熼檺鍒舵暟閲�
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="GET" label="/messages" targetCode={`curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id=' \\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "a076a87f-31e5-48dc-b452-0061adbbc922",
+ "conversation_id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "inputs": {
+ "name": "dify"
+ },
+ "query": "iphone 13 pro",
+ "answer": "The iPhone 13 Pro, released on September 24, 2021, features a 6.1-inch display with a resolution of 1170 x 2532. It is equipped with a Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard) processor, 6 GB of RAM, and offers storage options of 128 GB, 256 GB, 512 GB, and 1 TB. The camera is 12 MP, the battery capacity is 3095 mAh, and it runs on iOS 15.",
+ "message_files": [],
+ "feedback": null,
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ],
+ "created_at": 1705569239
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+
+ ### Response Example(鏅鸿兘鍔╂墜)
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "conversation_id": "957c068b-f258-4f89-ba10-6e8a0361c457",
+ "inputs": {},
+ "query": "draw a cat",
+ "answer": "I have generated an image of a cat for you. Please check your messages to view the image.",
+ "message_files": [
+ {
+ "id": "976990d2-5294-47e6-8f14-7356ba9d2d76",
+ "type": "image",
+ "url": "http://127.0.0.1:5001/files/tools/976990d2-5294-47e6-8f14-7356ba9d2d76.png?timestamp=1705988524&nonce=55df3f9f7311a9acd91bf074cd524092&sign=z43nMSO1L2HBvoqADLkRxr7Biz0fkjeDstnJiCK1zh8=",
+ "belongs_to": "assistant"
+ }
+ ],
+ "feedback": null,
+ "retriever_resources": [],
+ "created_at": 1705988187
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations'
+ method='GET'
+ title='鑾峰彇浼氳瘽鍒楄〃'
+ name='#conversations'
+/>
+<Row>
+ <Col>
+ 鑾峰彇褰撳墠鐢ㄦ埛鐨勪細璇濆垪琛紝榛樿杩斿洖鏈�杩戠殑 20 鏉°��
+
+ ### Query
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ 锛堥�夊~锛夊綋鍓嶉〉鏈�鍚庨潰涓�鏉¤褰曠殑 ID锛岄粯璁� null
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 锛堥�夊~锛変竴娆¤姹傝繑鍥炲灏戞潯璁板綍锛岄粯璁� 20 鏉★紝鏈�澶� 100 鏉★紝鏈�灏� 1 鏉°��
+ </Property>
+ <Property name='sort_by' type='string' key='sort_by'>
+ 锛堥�夊~锛夋帓搴忓瓧娈碉紝榛樿 -updated_at(鎸夋洿鏂版椂闂村�掑簭鎺掑垪)
+ - 鍙�夊�硷細created_at, -created_at, updated_at, -updated_at
+ - 瀛楁鍓嶉潰鐨勭鍙蜂唬琛ㄩ『搴忔垨鍊掑簭锛�-浠h〃鍊掑簭
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (array[object]) 浼氳瘽鍒楄〃
+ - `id` (string) 浼氳瘽 ID
+ - `name` (string) 浼氳瘽鍚嶇О锛岄粯璁ょ敱澶ц瑷�妯″瀷鐢熸垚銆�
+ - `inputs` (object) 鐢ㄦ埛杈撳叆鍙傛暟銆�
+ - `status` (string) 浼氳瘽鐘舵��
+ - `introduction` (string) 寮�鍦虹櫧
+ - `created_at` (timestamp) 鍒涘缓鏃堕棿
+ - `updated_at` (timestamp) 鏇存柊鏃堕棿
+ - `has_more` (bool)
+ - `limit` (int) 杩斿洖鏉℃暟锛岃嫢浼犲叆瓒呰繃绯荤粺闄愬埗锛岃繑鍥炵郴缁熼檺鍒舵暟閲�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20'\\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "10799fb8-64f7-4296-bbf7-b42bfbe0ae54",
+ "name": "New chat",
+ "inputs": {
+ "book": "book",
+ "myName": "Lucy"
+ },
+ "status": "normal",
+ "created_at": 1679667915,
+ "updated_at": 1679667915
+ },
+ {
+ "id": "hSIhXBhNe8X1d8Et"
+ // ...
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/conversations/:conversation_id'
+ method='DELETE'
+ title='鍒犻櫎浼氳瘽'
+ name='#delete'
+/>
+<Row>
+ <Col>
+ 鍒犻櫎浼氳瘽銆�
+
+ ### Path
+ - `conversation_id` (string) 浼氳瘽 ID
+
+ ### Request Body
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) 鍥哄畾杩斿洖 success
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="DELETE" label="/conversations/:conversation_id" targetCode={`curl -X DELETE '${props.appDetail.api_base_url}/conversations/:conversation_id' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X DELETE '${props.appDetail.api_base_url}/conversations/{conversation_id}' \
+ --header 'Content-Type: application/json' \
+ --header 'Accept: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data '{
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id/name'
+ method='POST'
+ title='浼氳瘽閲嶅懡鍚�'
+ name='#rename'
+/>
+<Row>
+ <Col>
+ 瀵逛細璇濊繘琛岄噸鍛藉悕锛屼細璇濆悕绉扮敤浜庢樉绀哄湪鏀寔澶氫細璇濈殑瀹㈡埛绔笂銆�
+
+ ### Path
+ - `conversation_id` (string) 浼氳瘽 ID
+
+ ### Request Body
+
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 锛堥�夊~锛夊悕绉帮紝鑻� `auto_generate` 涓� `true` 鏃讹紝璇ュ弬鏁板彲涓嶄紶銆�
+ </Property>
+ <Property name='auto_generate' type='bool' key='auto_generate'>
+ 锛堥�夊~锛夎嚜鍔ㄧ敓鎴愭爣棰橈紝榛樿 false銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+
+ ### Response
+ - `id` (string) 浼氳瘽 ID
+ - `name` (string) 浼氳瘽鍚嶇О
+ - `inputs` (object) 鐢ㄦ埛杈撳叆鍙傛暟
+ - `status` (string) 浼氳瘽鐘舵��
+ - `introduction` (string) 寮�鍦虹櫧
+ - `created_at` (timestamp) 鍒涘缓鏃堕棿
+ - `updated_at` (timestamp) 鏇存柊鏃堕棿
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "",
+ "auto_generate": true,
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "34d511d5-56de-4f16-a997-57b379508443",
+ "name": "hello",
+ "inputs": {},
+ "status": "normal",
+ "introduction": "",
+ "created_at": 1732731141,
+ "updated_at": 1732734510
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id/variables'
+ method='GET'
+ title='鑾峰彇瀵硅瘽鍙橀噺'
+ name='#conversation-variables'
+/>
+<Row>
+ <Col>
+ 浠庣壒瀹氬璇濅腑妫�绱㈠彉閲忋�傛绔偣瀵逛簬鎻愬彇瀵硅瘽杩囩▼涓崟鑾风殑缁撴瀯鍖栨暟鎹潪甯告湁鐢ㄣ��
+
+ ### 璺緞鍙傛暟
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 瑕佷粠涓绱㈠彉閲忕殑瀵硅瘽ID銆�
+ </Property>
+ </Properties>
+
+ ### 鏌ヨ鍙傛暟
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑绗︼紝鐢卞紑鍙戜汉鍛樺畾涔夌殑瑙勫垯锛屽湪搴旂敤绋嬪簭鍐呭繀椤诲敮涓�銆�
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ 锛堥�夊~锛夊綋鍓嶉〉鏈�鍚庨潰涓�鏉¤褰曠殑 ID锛岄粯璁� null
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 锛堥�夊~锛変竴娆¤姹傝繑鍥炲灏戞潯璁板綍锛岄粯璁� 20 鏉★紝鏈�澶� 100 鏉★紝鏈�灏� 1 鏉°��
+ </Property>
+ </Properties>
+
+ ### 鍝嶅簲
+
+ - `limit` (int) 姣忛〉椤圭洰鏁�
+ - `has_more` (bool) 鏄惁鏈夋洿澶氶」鐩�
+ - `data` (array[object]) 鍙橀噺鍒楄〃
+ - `id` (string) 鍙橀噺ID
+ - `name` (string) 鍙橀噺鍚嶇О
+ - `value_type` (string) 鍙橀噺绫诲瀷锛堝瓧绗︿覆銆佹暟瀛椼�佸竷灏旂瓑锛�
+ - `value` (string) 鍙橀噺鍊�
+ - `description` (string) 鍙橀噺鎻忚堪
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴�
+ - `updated_at` (int) 鏈�鍚庢洿鏂版椂闂存埑
+
+ ### 閿欒
+ - 404, `conversation_not_exists`, 瀵硅瘽涓嶅瓨鍦�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations/:conversation_id/variables" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Request with variable name filter">
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123&variable_name=customer_name' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 100,
+ "has_more": false,
+ "data": [
+ {
+ "id": "variable-uuid-1",
+ "name": "customer_name",
+ "value_type": "string",
+ "value": "John Doe",
+ "description": "瀹㈡埛鍚嶇О锛堜粠瀵硅瘽涓彁鍙栵級",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ },
+ {
+ "id": "variable-uuid-2",
+ "name": "order_details",
+ "value_type": "json",
+ "value": "{\"product\":\"Widget\",\"quantity\":5,\"price\":19.99}",
+ "description": "瀹㈡埛鐨勮鍗曡鎯�",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/audio-to-text'
+ method='POST'
+ title='璇煶杞枃瀛�'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ ### Request Body
+ 璇ユ帴鍙i渶浣跨敤 `multipart/form-data` 杩涜璇锋眰銆�
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ 璇煶鏂囦欢銆�
+ 鏀寔鏍煎紡锛歚['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm']`
+ 鏂囦欢澶у皬闄愬埗锛�15MB
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+
+ ### Response
+ - `text` (string) 杈撳嚭鏂囧瓧
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/audio-to-text" targetCode={`curl -X POST '${props.appDetail.api_base_url}/audio-to-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=audio/[mp3|mp4|mpeg|mpga|m4a|wav|webm]`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/name' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@localfile;type=audio/mp3'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "text": "hello"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/text-to-audio'
+ method='POST'
+ title='鏂囧瓧杞闊�'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ 鏂囧瓧杞闊炽��
+
+ ### Request Body
+
+ <Properties>
+ <Property name='message_id' type='str' key='message_id'>
+ Dify 鐢熸垚鐨勬枃鏈秷鎭紝閭d箞鐩存帴浼犻�掔敓鎴愮殑message-id 鍗冲彲锛屽悗鍙颁細閫氳繃 message_id 鏌ユ壘鐩稿簲鐨勫唴瀹圭洿鎺ュ悎鎴愯闊充俊鎭�傚鏋滃悓鏃朵紶 message_id 鍜� text锛屼紭鍏堜娇鐢� message_id銆�
+ </Property>
+ <Property name='text' type='str' key='text'>
+ 璇煶鐢熸垚鍐呭銆傚鏋滄病鏈変紶 message-id鐨勮瘽锛屽垯浼氫娇鐢ㄨ繖涓瓧娈电殑鍐呭
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "浣犲ソDify",\n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
+ "text": "浣犲ソDify",
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="headers">
+ ```json {{ title: 'headers' }}
+ {
+ "Content-Type": "audio/wav"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='鑾峰彇搴旂敤鍩烘湰淇℃伅'
+ name='#info'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇搴旂敤鐨勫熀鏈俊鎭�
+ ### Response
+ - `name` (string) 搴旂敤鍚嶇О
+ - `description` (string) 搴旂敤鎻忚堪
+ - `tags` (array[string]) 搴旂敤鏍囩
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='鑾峰彇搴旂敤鍙傛暟'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬杩涘叆椤甸潰涓�寮�濮嬶紝鑾峰彇鍔熻兘寮�鍏炽�佽緭鍏ュ弬鏁板悕绉般�佺被鍨嬪強榛樿鍊肩瓑浣跨敤銆�
+
+ ### Response
+ - `opening_statement` (string) 寮�鍦虹櫧
+ - `suggested_questions` (array[string]) 寮�鍦烘帹鑽愰棶棰樺垪琛�
+ - `suggested_questions_after_answer` (object) 鍚敤鍥炵瓟鍚庣粰鍑烘帹鑽愰棶棰樸��
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `speech_to_text` (object) 璇煶杞枃鏈�
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `retriever_resource` (object) 寮曠敤鍜屽綊灞�
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `annotation_reply` (object) 鏍囪鍥炲
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `user_input_form` (array[object]) 鐢ㄦ埛杈撳叆琛ㄥ崟閰嶇疆
+ - `text-input` (object) 鏂囨湰杈撳叆鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `paragraph` (object) 娈佃惤鏂囨湰杈撳叆鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `select` (object) 涓嬫媺鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `options` (array[string]) 閫夐」鍊�
+ - `file_upload` (object) 鏂囦欢涓婁紶閰嶇疆
+ - `image` (object) 鍥剧墖璁剧疆
+ 褰撳墠浠呮敮鎸佸浘鐗囩被鍨嬶細`png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `number_limits` (int) 鍥剧墖鏁伴噺闄愬埗锛岄粯璁� 3
+ - `transfer_methods` (array[string]) 浼犻�掓柟寮忓垪琛紝remote_url , local_file锛屽繀閫変竴涓�
+ - `system_parameters` (object) 绯荤粺鍙傛暟
+ - `file_size_limit` (int) Document upload size limit (MB)
+ - `image_file_size_limit` (int) Image file upload size limit (MB)
+ - `audio_file_size_limit` (int) Audio file upload size limit (MB)
+ - `video_file_size_limit` (int) Video file upload size limit (MB)
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'\\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "introduction": "nice to meet you",
+ "user_input_form": [
+ {
+ "text-input": {
+ "label": "a",
+ "variable": "a",
+ "required": true,
+ "max_length": 48,
+ "default": ""
+ }
+ },
+ {
+ // ...
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": true,
+ "number_limits": 3,
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/meta'
+ method='GET'
+ title='鑾峰彇搴旂敤Meta淇℃伅'
+ name='#meta'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇宸ュ叿icon
+ ### Response
+ - `tool_icons`(object[string]) 宸ュ叿鍥炬爣
+ - `宸ュ叿鍚嶇О` (string)
+ - `icon` (object|string)
+ - (object) 鍥炬爣
+ - `background` (string) hex鏍煎紡鐨勮儗鏅壊
+ - `content`(string) emoji
+ - (string) 鍥炬爣URL
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/meta' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/meta' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "tool_icons": {
+ "dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
+ "api_tool": {
+ "background": "#252525",
+ "content": "\ud83d\ude01"
+ }
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='鑾峰彇搴旂敤 WebApp 璁剧疆'
+ name='#site'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇搴旂敤鐨� WebApp 璁剧疆
+ ### Response
+ - `title` (string) WebApp 鍚嶇О
+ - `chat_color_theme` (string) 鑱婂ぉ棰滆壊涓婚, hex 鏍煎紡
+ - `chat_color_theme_inverted` (bool) 鑱婂ぉ棰滆壊涓婚鏄惁鍙嶈浆
+ - `icon_type` (string) 鍥炬爣绫诲瀷, `emoji`-琛ㄦ儏, `image`-鍥剧墖
+ - `icon` (string) 鍥炬爣, 濡傛灉鏄� `emoji` 绫诲瀷, 鍒欐槸 emoji 琛ㄦ儏绗﹀彿, 濡傛灉鏄� `image` 绫诲瀷, 鍒欐槸鍥剧墖 URL
+ - `icon_background` (string) hex 鏍煎紡鐨勮儗鏅壊
+ - `icon_url` (string) 鍥炬爣 URL
+ - `description` (string) 鎻忚堪
+ - `copyright` (string) 鐗堟潈淇℃伅
+ - `privacy_policy` (string) 闅愮鏀跨瓥閾炬帴
+ - `custom_disclaimer` (string) 鑷畾涔夊厤璐e0鏄�
+ - `default_language` (string) 榛樿璇█
+ - `show_workflow_steps` (bool) 鏄惁鏄剧ず宸ヤ綔娴佽鎯�
+ - `use_icon_as_answer_icon` (bool) 鏄惁浣跨敤 WebApp 鍥炬爣鏇挎崲鑱婂ぉ涓殑 馃
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "chat_color_theme": "#ff4a4a",
+ "chat_color_theme_inverted": false,
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ "use_icon_as_answer_icon": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
+
+<Heading
+ url='/apps/annotations'
+ method='GET'
+ title='鑾峰彇鏍囨敞鍒楄〃'
+ name='#annotation_list'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 椤电爜
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ 姣忛〉鏁伴噺
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/apps/annotations"
+ targetCode={`curl --location --request GET '${props.appDetail.api_base_url}/apps/annotations?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.appDetail.api_base_url}/apps/annotations?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ],
+ "has_more": false,
+ "limit": 20,
+ "total": 1,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations'
+ method='POST'
+ title='鍒涘缓鏍囨敞'
+ name='#create_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='question' type='string' key='question'>
+ 闂
+ </Property>
+ <Property name='answer' type='string' key='answer'>
+ 绛旀鍐呭
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/apps/annotations"
+ targetCode={`curl --location --request POST '${props.appDetail.api_base_url}/apps/annotations' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"question": "What is your name?","answer": "I am Dify."}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.appDetail.api_base_url}/apps/annotations' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "question": "What is your name?",
+ "answer": "I am Dify."
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations/{annotation_id}'
+ method='PUT'
+ title='鏇存柊鏍囨敞'
+ name='#update_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='annotation_id' type='string' key='annotation_id'>
+ 鏍囨敞 ID
+ </Property>
+ <Property name='question' type='string' key='question'>
+ 闂
+ </Property>
+ <Property name='answer' type='string' key='answer'>
+ 绛旀鍐呭
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PUT"
+ label="/apps/annotations/{annotation_id}"
+ targetCode={`curl --location --request PUT '${props.appDetail.api_base_url}/apps/annotations/{annotation_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"question": "What is your name?","answer": "I am Dify."}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PUT '${props.appDetail.api_base_url}/apps/annotations/{annotation_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "question": "What is your name?",
+ "answer": "I am Dify."
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations/{annotation_id}'
+ method='DELETE'
+ title='鍒犻櫎鏍囨敞'
+ name='#delete_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='annotation_id' type='string' key='annotation_id'>
+ 鏍囨敞 ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PUT"
+ label="/apps/annotations/{annotation_id}"
+ targetCode={`curl --location --request DELETE '${props.appDetail.api_base_url}/apps/annotations/{annotation_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.appDetail.api_base_url}/apps/annotations/{annotation_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotation-reply/{action}'
+ method='POST'
+ title='鏍囨敞鍥炲鍒濆璁剧疆'
+ name='#initial_annotation_reply_settings'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='action' type='string' key='action'>
+ 鍔ㄤ綔锛屽彧鑳芥槸 'enable' 鎴� 'disable'
+ </Property>
+ <Property name='embedding_provider_name' type='string' key='embedding_provider_name'>
+ 鎸囧畾鐨勫祵鍏ユā鍨嬫彁渚涘晢, 蹇呴』鍏堝湪绯荤粺鍐呰瀹氬ソ鎺ュ叆鐨勬ā鍨嬶紝瀵瑰簲鐨勬槸provider瀛楁
+ </Property>
+ <Property name='embedding_model_name' type='string' key='embedding_model_name'>
+ 鎸囧畾鐨勫祵鍏ユā鍨嬶紝瀵瑰簲鐨勬槸model瀛楁
+ </Property>
+ <Property name='score_threshold' type='number' key='score_threshold'>
+ 鐩镐技搴﹂槇鍊硷紝褰撶浉浼煎害澶т簬璇ラ槇鍊兼椂锛岀郴缁熶細鑷姩鍥炲锛屽惁鍒欎笉鍥炲
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ 宓屽叆妯″瀷鐨勬彁渚涘晢鍜屾ā鍨嬪悕绉板彲浠ラ�氳繃浠ヤ笅鎺ュ彛鑾峰彇锛歷1/workspaces/current/models/model-types/text-embedding锛� 鍏蜂綋瑙侊細閫氳繃 API 缁存姢鐭ヨ瘑搴撱�� 浣跨敤鐨凙uthorization鏄疍ataset鐨凙PI Token銆�
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/apps/annotation-reply/{action}"
+ targetCode={`curl --location --request POST '${props.appDetail.api_base_url}/apps/annotation-reply/{action}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"score_threshold": 0.9, "embedding_provider_name": "zhipu", "embedding_model_name": "embedding_3"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST 'https://api.dify.ai/v1/apps/annotation-reply/{action}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "score_threshold": 0.9,
+ "embedding_provider_name": "zhipu",
+ "embedding_model_name": "embedding_3"
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
+ "job_status": "waiting"
+ }
+ ```
+ </CodeGroup>
+ 璇ユ帴鍙f槸寮傛鎵ц锛屾墍浠ヤ細杩斿洖涓�涓猨ob_id锛岄�氳繃鏌ヨjob鐘舵�佹帴鍙e彲浠ヨ幏鍙栧埌鏈�缁堢殑鎵ц缁撴灉銆�
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotation-reply/{action}/status/{job_id}'
+ method='GET'
+ title='鏌ヨ鏍囨敞鍥炲鍒濆璁剧疆浠诲姟鐘舵��'
+ name='#initial_annotation_reply_settings_task_status'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='action' type='string' key='action'>
+ 鍔ㄤ綔锛屽彧鑳芥槸 'enable' 鎴� 'disable'锛屽苟涓斿繀椤诲拰鏍囨敞鍥炲鍒濆璁剧疆鎺ュ彛鐨勫姩浣滀竴鑷�
+ </Property>
+ <Property name='job_id' type='string' key='job_id'>
+ 浠诲姟 ID锛屼粠鏍囨敞鍥炲鍒濆璁剧疆鎺ュ彛杩斿洖鐨� job_id
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/apps/annotations"
+ targetCode={`curl --location --request GET '${props.appDetail.api_base_url}/apps/annotation-reply/{action}/status/{job_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.appDetail.api_base_url}/apps/annotation-reply/{action}/status/{job_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
+ "job_status": "waiting",
+ "error_msg": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
diff --git a/app/components/develop/template/template_chat.en.mdx b/app/components/develop/template/template_chat.en.mdx
new file mode 100644
index 0000000..c45a803
--- /dev/null
+++ b/app/components/develop/template/template_chat.en.mdx
@@ -0,0 +1,1700 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx'
+
+# Chat App API
+
+Chat applications support session persistence, allowing previous chat history to be used as context for responses. This can be applicable for chatbot, customer service AI, etc.
+
+<div>
+ ### Base URL
+ <CodeGroup title="Code" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### Authentication
+
+ The Service API uses `API-Key` authentication.
+ <i>**Strongly recommend storing your API Key on the server-side, not shared or stored on the client-side, to avoid possible API-Key leakage that can lead to serious consequences.**</i>
+
+ For all API requests, include your API Key in the `Authorization`HTTP Header, as shown below:
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/chat-messages'
+ method='POST'
+ title='Send Chat Message'
+ name='#Send-Chat-Message'
+/>
+<Row>
+ <Col>
+ Send a request to the chat application.
+
+ ### Request Body
+
+ <Properties>
+ <Property name='query' type='string' key='query'>
+ User Input/Question content
+ </Property>
+ <Property name='inputs' type='object' key='inputs'>
+ Allows the entry of various variable values defined by the App.
+ The `inputs` parameter contains multiple key/value pairs, with each key corresponding to a specific variable and each value being the specific value for that variable. Default `{}`
+ </Property>
+ <Property name='response_mode' type='string' key='response_mode'>
+ The mode of response return, supporting:
+ - `streaming` Streaming mode (recommended), implements a typewriter-like output through SSE ([Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)).
+ - `blocking` Blocking mode, returns result after execution is complete. (Requests may be interrupted if the process is long)
+ Due to Cloudflare restrictions, the request will be interrupted without a return after 100 seconds.
+ <i>Note: blocking mode is not supported in Agent Assistant mode</i>
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+ </Property>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ Conversation ID, to continue the conversation based on previous chat records, it is necessary to pass the previous message's conversation_id.
+ </Property>
+ <Property name='files' type='array[object]' key='files'>
+ File list, suitable for inputting files (images) combined with text understanding and answering questions, available only when the model supports Vision capability.
+ - `type` (string) Supported type: `image` (currently only supports image type)
+ - `transfer_method` (string) Transfer method, `remote_url` for image URL / `local_file` for file upload
+ - `url` (string) Image URL (when the transfer method is `remote_url`)
+ - `upload_file_id` (string) Uploaded file ID, which must be obtained by uploading through the File Upload API in advance (when the transfer method is `local_file`)
+ </Property>
+ <Property name='auto_generate_name' type='bool' key='auto_generate_name'>
+ Auto-generate title, default is `true`.
+ If set to `false`, can achieve async title generation by calling the conversation rename API and setting `auto_generate` to `true`.
+ </Property>
+ </Properties>
+
+ ### Response
+ When response_mode is blocking, return a CompletionResponse object.
+ When response_mode is streaming, return a ChunkCompletionResponse stream.
+
+ ### ChatCompletionResponse
+ Returns the complete App result, `Content-Type` is `application/json`.
+ - `event` (string) 浜嬩欢绫诲瀷锛屽浐瀹氫负 `message`
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `id` (string) 鍞竴ID
+ - `message_id` (string) Unique message ID
+ - `conversation_id` (string) Conversation ID
+ - `mode` (string) App mode, fixed as `chat`
+ - `answer` (string) Complete response content
+ - `metadata` (object) Metadata
+ - `usage` (Usage) Model usage information
+ - `retriever_resources` (array[RetrieverResource]) Citation and Attribution List
+ - `created_at` (int) Message creation timestamp, e.g., 1705395332
+
+ ### ChunkChatCompletionResponse
+ Returns the stream chunks outputted by the App, `Content-Type` is `text/event-stream`.
+ Each streaming chunk starts with `data:`, separated by two newline characters `\n\n`, as shown below:
+ <CodeGroup>
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
+ ```
+ </CodeGroup>
+ The structure of the streaming chunks varies depending on the `event`:
+ - `event: message` LLM returns text chunk event, i.e., the complete text is output in a chunked fashion.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `conversation_id` (string) Conversation ID
+ - `answer` (string) LLM returned text chunk content
+ - `created_at` (int) Creation timestamp, e.g., 1705395332
+ - `event: agent_message` LLM returns text chunk event, i.e., with Agent Assistant enabled, the complete text is output in a chunked fashion (Only supported in Agent mode)
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `conversation_id` (string) Conversation ID
+ - `answer` (string) LLM returned text chunk content
+ - `created_at` (int) Creation timestamp, e.g., 1705395332
+ - `event: tts_message` TTS audio stream event, that is, speech synthesis output. The content is an audio block in Mp3 format, encoded as a base64 string. When playing, simply decode the base64 and feed it into the player. (This message is available only when auto-play is enabled)
+ - `task_id` (string) Task ID, used for request tracking and the stop response interface below
+ - `message_id` (string) Unique message ID
+ - `audio` (string) The audio after speech synthesis, encoded in base64 text content, when playing, simply decode the base64 and feed it into the player
+ - `created_at` (int) Creation timestamp, e.g.: 1705395332
+ - `event: tts_message_end` TTS audio stream end event, receiving this event indicates the end of the audio stream.
+ - `task_id` (string) Task ID, used for request tracking and the stop response interface below
+ - `message_id` (string) Unique message ID
+ - `audio` (string) The end event has no audio, so this is an empty string
+ - `created_at` (int) Creation timestamp, e.g.: 1705395332
+ - `event: agent_thought` thought of Agent, contains the thought of LLM, input and output of tool calls (Only supported in Agent mode)
+ - `id` (string) Agent thought ID, every iteration has a unique agent thought ID
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `position` (int) Position of current agent thought, each message may have multiple thoughts in order.
+ - `thought` (string) What LLM is thinking about
+ - `observation` (string) Response from tool calls
+ - `tool` (string) A list of tools represents which tools are called锛宻plit by ;
+ - `tool_input` (string) Input of tools in JSON format. Like: `{"dalle3": {"prompt": "a cute cat"}}`.
+ - `created_at` (int) Creation timestamp, e.g., 1705395332
+ - `message_files` (array[string]) Refer to message_file event
+ - `file_id` (string) File ID
+ - `conversation_id` (string) Conversation ID
+ - `event: message_file` Message file event, a new file has created by tool
+ - `id` (string) File unique ID
+ - `type` (string) File type锛宱nly allow "image" currently
+ - `belongs_to` (string) Belongs to, it will only be an 'assistant' here
+ - `url` (string) Remote url of file
+ - `conversation_id` (string) Conversation ID
+ - `event: message_end` Message end event, receiving this event means streaming has ended.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `conversation_id` (string) Conversation ID
+ - `metadata` (object) Metadata
+ - `usage` (Usage) Model usage information
+ - `retriever_resources` (array[RetrieverResource]) Citation and Attribution List
+ - `event: message_replace` Message content replacement event.
+ When output content moderation is enabled, if the content is flagged, then the message content will be replaced with a preset reply through this event.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `conversation_id` (string) Conversation ID
+ - `answer` (string) Replacement content (directly replaces all LLM reply text)
+ - `created_at` (int) Creation timestamp, e.g., 1705395332
+ - `event: error`
+ Exceptions that occur during the streaming process will be output in the form of stream events, and reception of an error event will end the stream.
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `message_id` (string) Unique message ID
+ - `status` (int) HTTP status code
+ - `code` (string) Error code
+ - `message` (string) Error message
+ - `event: ping` Ping event every 10 seconds to keep the connection alive.
+
+ ### Errors
+ - 404, Conversation does not exists
+ - 400, `invalid_param`, abnormal parameter input
+ - 400, `app_unavailable`, App configuration unavailable
+ - 400, `provider_not_initialize`, no available model credential configuration
+ - 400, `provider_quota_exceeded`, model invocation quota insufficient
+ - 400, `model_currently_not_support`, current model unavailable
+ - 400, `completion_request_error`, text generation failed
+ - 500, internal server error
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/chat-messages" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": ${JSON.stringify(props.inputs)},\n "query": "What are the specs of the iPhone 13 Pro Max?",\n "response_mode": "streaming",\n "conversation_id": "",\n "user": "abc-123",\n "files": [\n {\n "type": "image",\n "transfer_method": "remote_url",\n "url": "https://cloud.dify.ai/logo/logo-site.png"\n }\n ]\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {},
+ "query": "eh",
+ "response_mode": "streaming",
+ "conversation_id": "1c7e55fb-1ba2-4e10-81b5-30addcea2276",
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+ ### Blocking Mode
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "event": "message",
+ "task_id": "c3800678-a077-43df-a102-53f23ed20b88",
+ "id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
+ "mode": "chat",
+ "answer": "iPhone 13 Pro Max specs are listed here:...",
+ "metadata": {
+ "usage": {
+ "prompt_tokens": 1033,
+ "prompt_unit_price": "0.001",
+ "prompt_price_unit": "0.001",
+ "prompt_price": "0.0010330",
+ "completion_tokens": 128,
+ "completion_unit_price": "0.002",
+ "completion_price_unit": "0.001",
+ "completion_price": "0.0002560",
+ "total_tokens": 1161,
+ "total_price": "0.0012890",
+ "currency": "USD",
+ "latency": 0.7682376249867957
+ },
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ]
+ },
+ "created_at": 1705407629
+ }
+ ```
+ </CodeGroup>
+ ### Streaming Mode ( Basic Assistant )
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ ### Response Example(Agent Assistant)
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='File Upload'
+ name='#file-upload'
+/>
+<Row>
+ <Col>
+ Upload a file (currently only images are supported) for use when sending messages, enabling multimodal understanding of images and text.
+ Supports png, jpg, jpeg, webp, gif formats.
+ Uploaded files are for use by the current end-user only.
+
+ ### Request Body
+ This interface requires a `multipart/form-data` request.
+ - `file` (File) Required
+ The file to be uploaded.
+ - `user` (string) Required
+ User identifier, defined by the developer's rules, must be unique within the application.
+
+ ### Response
+ After a successful upload, the server will return the file's ID and related information.
+ - `id` (uuid) ID
+ - `name` (string) File name
+ - `size` (int) File size (bytes)
+ - `extension` (string) File extension
+ - `mime_type` (string) File mime-type
+ - `created_by` (uuid) End-user ID
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+
+ ### Errors
+ - 400, `no_file_uploaded`, a file must be provided
+ - 400, `too_many_files`, currently only one file is accepted
+ - 400, `unsupported_preview`, the file does not support preview
+ - 400, `unsupported_estimate`, the file does not support estimation
+ - 413, `file_too_large`, the file is too large
+ - 415, `unsupported_file_type`, unsupported extension, currently only document files are accepted
+ - 503, `s3_connection_failed`, unable to connect to S3 service
+ - 503, `s3_permission_denied`, no permission to upload files to S3
+ - 503, `s3_file_too_large`, file exceeds S3 size limit
+ - 500, internal server error
+
+
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": "6ad1ab0a-73ff-4ac1-b9e4-cdb312f71f13",
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/chat-messages/:task_id/stop'
+ method='POST'
+ title='Stop Generate'
+ name='#stop-generatebacks'
+/>
+<Row>
+ <Col>
+ Only supported in streaming mode.
+ ### Path
+ - `task_id` (string) Task ID, can be obtained from the streaming chunk return
+ ### Request Body
+ - `user` (string) Required
+ User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface.
+ ### Response
+ - `result` (string) Always returns "success"
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{"user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages/:message_id/feedbacks'
+ method='POST'
+ title='Message Feedback'
+ name='#feedbacks'
+/>
+<Row>
+ <Col>
+ End-users can provide feedback messages, facilitating application developers to optimize expected outputs.
+
+ ### Path
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ Message ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+
+ <Properties>
+ <Property name='rating' type='string' key='rating'>
+ Upvote as `like`, downvote as `dislike`, revoke upvote as `null`
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, defined by the developer's rules, must be unique within the application.
+ </Property>
+ <Property name='content' type='string' key='content'>
+ The specific content of message feedback.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) Always returns "success"
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/messages/:message_id/feedbacks" targetCode={`curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks \\\n --header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "rating": "like",\n "user": "abc-123",\n "content": "message feedback information"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "rating": "like",
+ "user": "abc-123",
+ "content": "message feedback information"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/app/feedbacks'
+ method='GET'
+ title='Get feedbacks of application'
+ name='#app-feedbacks'
+/>
+<Row>
+ <Col>
+ Get application's feedbacks.
+
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 锛坥ptional锛塸agination锛宒efault锛�1
+ </Property>
+ </Properties>
+
+ <Properties>
+ <Property name='limit' type='string' key='limit'>
+ 锛坥ptional锛� records per page default锛�20
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (List) return apps feedback list.
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/app/feedbacks" targetCode={`curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "8c0fbed8-e2f9-49ff-9f0e-15a35bdd0e25",
+ "app_id": "f252d396-fe48-450e-94ec-e184218e7346",
+ "conversation_id": "2397604b-9deb-430e-b285-4726e51fd62d",
+ "message_id": "709c0b0f-0a96-4a4e-91a4-ec0889937b11",
+ "rating": "like",
+ "content": "message feedback information-3",
+ "from_source": "user",
+ "from_end_user_id": "74286412-9a1a-42c1-929c-01edb1d381d5",
+ "from_account_id": null,
+ "created_at": "2025-04-24T09:24:38",
+ "updated_at": "2025-04-24T09:24:38"
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/messages/{message_id}/suggested'
+ method='GET'
+ title='Next Suggested Questions'
+ name='#suggested'
+/>
+<Row>
+ <Col>
+ Get next questions suggestions for the current message
+
+ ### Path Params
+
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ Message ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/messages/{message_id}/suggested" targetCode={`curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested?user=abc-123& \\\n--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \\\n--header 'Content-Type: application/json'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested' \
+ --header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
+ --header 'Content-Type: application/json' \
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success",
+ "data": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages'
+ method='GET'
+ title='Get Conversation History Messages'
+ name='#messages'
+/>
+<Row>
+ <Col>
+ Returns historical chat records in a scrolling load format, with the first page returning the latest `{limit}` messages, i.e., in reverse order.
+
+ ### Query
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ Conversation ID
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+ </Property>
+ <Property name='first_id' type='string' key='first_id'>
+ The ID of the first chat record on the current page, default is null.
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ How many chat history messages to return in one request, default is 20.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (array[object]) Message list
+ - `id` (string) Message ID
+ - `conversation_id` (string) Conversation ID
+ - `inputs` (object) User input parameters.
+ - `query` (string) User input / question content.
+ - `message_files` (array[object]) Message files
+ - `id` (string) ID
+ - `type` (string) File type, image for images
+ - `url` (string) Preview image URL
+ - `belongs_to` (string) belongs to锛寀ser or assistant
+ - `agent_thoughts` (array[object]) Agent thought锛圗mpty if it's a Basic Assistant锛�
+ - `id` (string) Agent thought ID, every iteration has a unique agent thought ID
+ - `message_id` (string) Unique message ID
+ - `position` (int) Position of current agent thought, each message may have multiple thoughts in order.
+ - `thought` (string) What LLM is thinking about
+ - `observation` (string) Response from tool calls
+ - `tool` (string) A list of tools represents which tools are called锛宻plit by ;
+ - `tool_input` (string) Input of tools in JSON format. Like: `{"dalle3": {"prompt": "a cute cat"}}`.
+ - `created_at` (int) Creation timestamp, e.g., 1705395332
+ - `message_files` (array[string]) Refer to message_file event
+ - `file_id` (string) File ID
+ - `answer` (string) Response message content
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+ - `feedback` (object) Feedback information
+ - `rating` (string) Upvote as `like` / Downvote as `dislike`
+ - `retriever_resources` (array[RetrieverResource]) Citation and Attribution List
+ - `has_more` (bool) Whether there is a next page
+ - `limit` (int) Number of returned items, if input exceeds system limit, returns system limit amount
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/messages" targetCode={`curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='\\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+ ### Response Example (Basic Assistant)
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "a076a87f-31e5-48dc-b452-0061adbbc922",
+ "conversation_id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "inputs": {
+ "name": "dify"
+ },
+ "query": "iphone 13 pro",
+ "answer": "The iPhone 13 Pro, released on September 24, 2021, features a 6.1-inch display with a resolution of 1170 x 2532. It is equipped with a Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard) processor, 6 GB of RAM, and offers storage options of 128 GB, 256 GB, 512 GB, and 1 TB. The camera is 12 MP, the battery capacity is 3095 mAh, and it runs on iOS 15.",
+ "message_files": [],
+ "feedback": null,
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ],
+ "agent_thoughts": [],
+ "created_at": 1705569239,
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+
+ ### Response Example (Agent Assistant)
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "conversation_id": "957c068b-f258-4f89-ba10-6e8a0361c457",
+ "inputs": {},
+ "query": "draw a cat",
+ "answer": "I have generated an image of a cat for you. Please check your messages to view the image.",
+ "message_files": [
+ {
+ "id": "976990d2-5294-47e6-8f14-7356ba9d2d76",
+ "type": "image",
+ "url": "http://127.0.0.1:5001/files/tools/976990d2-5294-47e6-8f14-7356ba9d2d76.png?timestamp=1705988524&nonce=55df3f9f7311a9acd91bf074cd524092&sign=z43nMSO1L2HBvoqADLkRxr7Biz0fkjeDstnJiCK1zh8=",
+ "belongs_to": "assistant"
+ }
+ ],
+ "feedback": null,
+ "retriever_resources": [],
+ "created_at": 1705988187,
+ "agent_thoughts": [
+ {
+ "id": "592c84cf-07ee-441c-9dcc-ffc66c033469",
+ "chain_id": null,
+ "message_id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "position": 1,
+ "thought": "",
+ "tool": "dalle2",
+ "tool_input": "{\"dalle2\": {\"prompt\": \"cat\"}}",
+ "created_at": 1705988186,
+ "observation": "image has been created and sent to user already, you should tell user to check it now.",
+ "files": [
+ "976990d2-5294-47e6-8f14-7356ba9d2d76"
+ ]
+ },
+ {
+ "id": "73ead60d-2370-4780-b5ed-532d2762b0e5",
+ "chain_id": null,
+ "message_id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "position": 2,
+ "thought": "I have generated an image of a cat for you. Please check your messages to view the image.",
+ "tool": "",
+ "tool_input": "",
+ "created_at": 1705988199,
+ "observation": "",
+ "files": []
+ }
+ ]
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations'
+ method='GET'
+ title='Get Conversations'
+ name='#conversations'
+/>
+<Row>
+ <Col>
+ Retrieve the conversation list for the current user, defaulting to the most recent 20 entries.
+
+ ### Query
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ (Optional) The ID of the last record on the current page, default is null.
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ (Optional) How many records to return in one request, default is the most recent 20 entries. Maximum 100, minimum 1.
+ </Property>
+ <Property name='sort_by' type='string' key='sort_by'>
+ (Optional) Sorting Field, Default: -updated_at (sorted in descending order by update time)
+ - Available Values: created_at, -created_at, updated_at, -updated_at
+ - The symbol before the field represents the order or reverse, "-" represents reverse order.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (array[object]) List of conversations
+ - `id` (string) Conversation ID
+ - `name` (string) Conversation name, by default, is a snippet of the first question asked by the user in the conversation.
+ - `inputs` (object) User input parameters.
+ - `status` (string) Conversation status
+ - `introduction` (string) Introduction
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+ - `updated_at` (timestamp) Update timestamp, e.g., 1705395332
+ - `has_more` (bool)
+ - `limit` (int) Number of entries returned, if input exceeds system limit, system limit number is returned
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "10799fb8-64f7-4296-bbf7-b42bfbe0ae54",
+ "name": "New chat",
+ "inputs": {
+ "book": "book",
+ "myName": "Lucy"
+ },
+ "status": "normal",
+ "created_at": 1679667915,
+ "updated_at": 1679667915
+ },
+ {
+ "id": "hSIhXBhNe8X1d8Et"
+ // ...
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id'
+ method='DELETE'
+ title='Delete Conversation'
+ name='#delete'
+/>
+<Row>
+ <Col>
+ Delete a conversation.
+
+ ### Path
+ - `conversation_id` (string) Conversation ID
+
+ ### Request Body
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ The user identifier, defined by the developer, must ensure uniqueness within the application.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) Always returns "success"
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="DELETE" label="/conversations/:conversation_id" targetCode={`curl -X DELETE '${props.appDetail.api_base_url}/conversations/:conversation_id' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X DELETE '${props.appDetail.api_base_url}/conversations/{conversation_id}' \
+ --header 'Content-Type: application/json' \
+ --header 'Accept: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data '{
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/conversations/:conversation_id/name'
+ method='POST'
+ title='Conversation Rename'
+ name='#rename'
+/>
+<Row>
+ <Col>
+ ### Request Body
+ Rename the session, the session name is used for display on clients that support multiple sessions.
+
+ ### Path
+ - `conversation_id` (string) Conversation ID
+
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ (Optional) The name of the conversation. This parameter can be omitted if `auto_generate` is set to `true`.
+ </Property>
+ <Property name='auto_generate' type='bool' key='auto_generate'>
+ (Optional) Automatically generate the title, default is `false`
+ </Property>
+ <Property name='user' type='string' key='user'>
+ The user identifier, defined by the developer, must ensure uniqueness within the application.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `id` (string) Conversation ID
+ - `name` (string) Conversation name
+ - `inputs` (object) User input parameters
+ - `status` (string) Conversation status
+ - `introduction` (string) Introduction
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+ - `updated_at` (timestamp) Update timestamp, e.g., 1705395332
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
+ --header 'Content-Type: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data-raw '{
+ "name": "",
+ "auto_generate": true,
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "name": "Chat vs AI",
+ "inputs": {},
+ "status": "normal",
+ "introduction": "",
+ "created_at": 1705569238,
+ "updated_at": 1705569238
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id/variables'
+ method='GET'
+ title='Get Conversation Variables'
+ name='#conversation-variables'
+/>
+<Row>
+ <Col>
+ Retrieve variables from a specific conversation. This endpoint is useful for extracting structured data that was captured during the conversation.
+
+ ### Path Parameters
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ The ID of the conversation to retrieve variables from.
+ </Property>
+ </Properties>
+
+ ### Query Parameters
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ The user identifier, defined by the developer, must ensure uniqueness within the application
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ (Optional) The ID of the last record on the current page, default is null.
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ (Optional) How many records to return in one request, default is the most recent 20 entries. Maximum 100, minimum 1.
+ </Property>
+ </Properties>
+
+ ### Response
+
+ - `limit` (int) Number of items per page
+ - `has_more` (bool) Whether there is a next page
+ - `data` (array[object]) List of variables
+ - `id` (string) Variable ID
+ - `name` (string) Variable name
+ - `value_type` (string) Variable type (string, number, object, etc.)
+ - `value` (string) Variable value
+ - `description` (string) Variable description
+ - `created_at` (int) Creation timestamp
+ - `updated_at` (int) Last update timestamp
+
+ ### Errors
+ - 404, `conversation_not_exists`, Conversation not found
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations/:conversation_id/variables" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Request with variable name filter">
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123&variable_name=customer_name' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 100,
+ "has_more": false,
+ "data": [
+ {
+ "id": "variable-uuid-1",
+ "name": "customer_name",
+ "value_type": "string",
+ "value": "John Doe",
+ "description": "Customer name extracted from the conversation",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ },
+ {
+ "id": "variable-uuid-2",
+ "name": "order_details",
+ "value_type": "json",
+ "value": "{\"product\":\"Widget\",\"quantity\":5,\"price\":19.99}",
+ "description": "Order details from the customer",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/audio-to-text'
+ method='POST'
+ title='Speech to Text'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ This endpoint requires a multipart/form-data request.
+
+ ### Request Body
+
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ Audio file.
+ Supported formats: `['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm']`
+ File size limit: 15MB
+ </Property>
+ <Property name='user' type='string' key='user'>
+ User identifier, defined by the developer's rules, must be unique within the application.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `text` (string) Output text
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/audio-to-text" targetCode={`curl -X POST '${props.appDetail.api_base_url}/audio-to-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=audio/[mp3|mp4|mpeg|mpga|m4a|wav|webm]'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/name' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@localfile;type=audio/mp3'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "text": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/text-to-audio'
+ method='POST'
+ title='Text to Audio'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ Text to speech.
+
+ ### Request Body
+
+ <Properties>
+ <Property name='message_id' type='str' key='message_id'>
+ For text messages generated by Dify, simply pass the generated message-id directly. The backend will use the message-id to look up the corresponding content and synthesize the voice information directly. If both message_id and text are provided simultaneously, the message_id is given priority.
+ </Property>
+ <Property name='text' type='str' key='text'>
+ Speech generated content銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ The user identifier, defined by the developer, must ensure uniqueness within the app.
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl --location --request POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \\\n--form 'text=Hello Dify;user=abc-123;message_id=5ad4cb98-f0c7-4085-b384-88c403be6290`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.appDetail.api_base_url}/text-to-audio' \
+ --header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
+ --form 'file=Hello Dify;user=abc-123;message_id=5ad4cb98-f0c7-4085-b384-88c403be6290'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="headers">
+ ```json {{ title: 'headers' }}
+ {
+ "Content-Type": "audio/wav"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='Get Application Basic Information'
+ name='#info'
+/>
+<Row>
+ <Col>
+ Used to get basic information about this application
+
+ ### Response
+ - `name` (string) application name
+ - `description` (string) application description
+ - `tags` (array[string]) application tags
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='Get Application Parameters Information'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ Used at the start of entering the page to obtain information such as features, input parameter names, types, and default values.
+
+ ### Query
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ User identifier, defined by the developer's rules, must be unique within the application.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `opening_statement` (string) Opening statement
+ - `suggested_questions` (array[string]) List of suggested questions for the opening
+ - `suggested_questions_after_answer` (object) Suggest questions after enabling the answer.
+ - `enabled` (bool) Whether it is enabled
+ - `speech_to_text` (object) Speech to text
+ - `enabled` (bool) Whether it is enabled
+ - `retriever_resource` (object) Citation and Attribution
+ - `enabled` (bool) Whether it is enabled
+ - `annotation_reply` (object) Annotation reply
+ - `enabled` (bool) Whether it is enabled
+ - `user_input_form` (array[object]) User input form configuration
+ - `text-input` (object) Text input control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `paragraph` (object) Paragraph text input control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `select` (object) Dropdown control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `options` (array[string]) Option values
+ - `file_upload` (object) File upload configuration
+ - `image` (object) Image settings
+ Currently only supports image types: `png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) Whether it is enabled
+ - `number_limits` (int) Image number limit, default is 3
+ - `transfer_methods` (array[string]) List of transfer methods, remote_url, local_file, must choose one
+ - `system_parameters` (object) System parameters
+ - `file_size_limit` (int) Document upload size limit (MB)
+ - `image_file_size_limit` (int) Image file upload size limit (MB)
+ - `audio_file_size_limit` (int) Audio file upload size limit (MB)
+ - `video_file_size_limit` (int) Video file upload size limit (MB)
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "opening_statement": "Hello!",
+ "suggested_questions_after_answer": {
+ "enabled": true
+ },
+ "speech_to_text": {
+ "enabled": true
+ },
+ "retriever_resource": {
+ "enabled": true
+ },
+ "annotation_reply": {
+ "enabled": true
+ },
+ "user_input_form": [
+ {
+ "paragraph": {
+ "label": "Query",
+ "variable": "query",
+ "required": true,
+ "default": ""
+ }
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": false,
+ "number_limits": 3,
+ "detail": "high",
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/meta'
+ method='GET'
+ title='Get Application Meta Information'
+ name='#meta'
+/>
+<Row>
+ <Col>
+ Used to get icons of tools in this application
+
+ ### Response
+ - `tool_icons`(object[string]) tool icons
+ - `tool_name` (string)
+ - `icon` (object|string)
+ - (object) icon object
+ - `background` (string) background color in hex format
+ - `content`(string) emoji
+ - (string) url of icon
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/meta' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/meta' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "tool_icons": {
+ "dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
+ "api_tool": {
+ "background": "#252525",
+ "content": "\ud83d\ude01"
+ }
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='Get Application WebApp Settings'
+ name='#site'
+/>
+<Row>
+ <Col>
+ Used to get the WebApp settings of the application.
+ ### Response
+ - `title` (string) WebApp name
+ - `chat_color_theme` (string) Chat color theme, in hex format
+ - `chat_color_theme_inverted` (bool) Whether the chat color theme is inverted
+ - `icon_type` (string) Icon type, `emoji` - emoji, `image` - picture
+ - `icon` (string) Icon. If it's `emoji` type, it's an emoji symbol; if it's `image` type, it's an image URL
+ - `icon_background` (string) Background color in hex format
+ - `icon_url` (string) Icon URL
+ - `description` (string) Description
+ - `copyright` (string) Copyright information
+ - `privacy_policy` (string) Privacy policy link
+ - `custom_disclaimer` (string) Custom disclaimer
+ - `default_language` (string) Default language
+ - `show_workflow_steps` (bool) Whether to show workflow details
+ - `use_icon_as_answer_icon` (bool) Whether to replace 馃 in chat with the WebApp icon
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "chat_color_theme": "#ff4a4a",
+ "chat_color_theme_inverted": false,
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ "use_icon_as_answer_icon": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
+
+<Heading
+ url='/apps/annotations'
+ method='GET'
+ title='Get Annotation List'
+ name='#annotation_list'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ Page number
+ </Property>
+ <Property name='limit' type='string' key='limit'>
+ Number of items returned, default 20, range 1-100
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/apps/annotations"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/apps/annotations?page=1&limit=20' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/apps/annotations?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ ],
+ "has_more": false,
+ "limit": 20,
+ "total": 1,
+ "page": 1
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations'
+ method='POST'
+ title='Create Annotation'
+ name='#create_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='question' type='string' key='question'>
+ Question
+ </Property>
+ <Property name='answer' type='string' key='answer'>
+ Answer
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/apps/annotations"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/apps/annotations' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"question": "What is your name?","answer": "I am Dify."}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/apps/annotations' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "question": "What is your name?",
+ "answer": "I am Dify."
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations/{annotation_id}'
+ method='PUT'
+ title='Update Annotation'
+ name='#update_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='annotation_id' type='string' key='annotation_id'>
+ Annotation ID
+ </Property>
+ <Property name='question' type='string' key='question'>
+ Question
+ </Property>
+ <Property name='answer' type='string' key='answer'>
+ Answer
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PUT"
+ label="/apps/annotations/{annotation_id}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"question": "What is your name?","answer": "I am Dify."}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "question": "What is your name?",
+ "answer": "I am Dify."
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ {
+ "id": "69d48372-ad81-4c75-9c46-2ce197b4d402",
+ "question": "What is your name?",
+ "answer": "I am Dify.",
+ "hit_count": 0,
+ "created_at": 1735625869
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotations/{annotation_id}'
+ method='DELETE'
+ title='Delete Annotation'
+ name='#delete_annotation'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='annotation_id' type='string' key='annotation_id'>
+ Annotation ID
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="PUT"
+ label="/apps/annotations/{annotation_id}"
+ targetCode={`curl --location --request DELETE '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/apps/annotations/{annotation_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotation-reply/{action}'
+ method='POST'
+ title='Initial Annotation Reply Settings'
+ name='#initial_annotation_reply_settings'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='action' type='string' key='action'>
+ Action, can only be 'enable' or 'disable'
+ </Property>
+ <Property name='embedding_model_provider' type='string' key='embedding_model_provider'>
+ Specified embedding model provider, must be set up in the system first, corresponding to the provider field(Optional)
+ </Property>
+ <Property name='embedding_model' type='string' key='embedding_model'>
+ Specified embedding model, corresponding to the model field(Optional)
+ </Property>
+ <Property name='score_threshold' type='number' key='score_threshold'>
+ The similarity threshold for matching annotated replies. Only annotations with scores above this threshold will be recalled.
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ The provider and model name of the embedding model can be obtained through the following interface: v1/workspaces/current/models/model-types/text-embedding. For specific instructions, see: Maintain Knowledge Base via API. The Authorization used is the Dataset API Token.
+ <CodeGroup
+ title="Request"
+ tag="POST"
+ label="/apps/annotation-reply/{action}"
+ targetCode={`curl --location --request POST '${props.apiBaseUrl}/apps/annotation-reply/{action}' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{"score_threshold": 0.9, "embedding_provider_name": "zhipu", "embedding_model_name": "embedding_3"}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST 'https://api.dify.ai/v1/apps/annotation-reply/{action}' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "score_threshold": 0.9,
+ "embedding_provider_name": "zhipu",
+ "embedding_model_name": "embedding_3"
+ }'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
+ "job_status": "waiting"
+ }
+ ```
+ </CodeGroup>
+ This interface is executed asynchronously, so it will return a job_id. You can get the final execution result by querying the job status interface.
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/apps/annotation-reply/{action}/status/{job_id}'
+ method='GET'
+ title='Query Initial Annotation Reply Settings Task Status'
+ name='#initial_annotation_reply_settings_task_status'
+/>
+<Row>
+ <Col>
+ ### Query
+ <Properties>
+ <Property name='action' type='string' key='action'>
+ Action, can only be 'enable' or 'disable', must be the same as the action in the initial annotation reply settings interface
+ </Property>
+ <Property name='job_id' type='string' key='job_id'>
+ Job ID,
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+ <CodeGroup
+ title="Request"
+ tag="GET"
+ label="/apps/annotations"
+ targetCode={`curl --location --request GET '${props.apiBaseUrl}/apps/annotation-reply/{action}/status/{job_id}' \\\n--header 'Authorization: Bearer {api_key}'`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/apps/annotation-reply/{action}/status/{job_id}' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "job_id": "b15c8f68-1cf4-4877-bf21-ed7cf2011802",
+ "job_status": "waiting",
+ "error_msg": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
diff --git a/app/components/develop/template/template_chat.ja.mdx b/app/components/develop/template/template_chat.ja.mdx
new file mode 100644
index 0000000..81385ed
--- /dev/null
+++ b/app/components/develop/template/template_chat.ja.mdx
@@ -0,0 +1,1392 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx'
+
+# 銉併儯銉冦儓銈€儣銉狝PI
+
+銉併儯銉冦儓銈€儣銉偙銉笺偡銉с兂銇偦銉冦偡銉с兂銇寔缍氭�с倰銈点儩銉笺儓銇椼仸銇娿倞銆佷互鍓嶃伄銉併儯銉冦儓灞ユ銈掑繙绛斻伄銈炽兂銉嗐偔銈广儓銇ㄣ仐銇︿娇鐢ㄣ仹銇嶃伨銇欍�傘亾銈屻伅銆併儊銉c儍銉堛儨銉冦儓銈勩偒銈广偪銉炪兗銈点兗銉撱偣AI銇仼銇仼鐢ㄣ仹銇嶃伨銇欍��
+
+<div>
+ ### 銉欍兗銈筓RL
+ <CodeGroup title="銈炽兗銉�" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### 瑾嶈
+
+ 銈点兗銉撱偣API銇痐API-Key`瑾嶈銈掍娇鐢ㄣ仐銇俱仚銆�
+ <i>**API銈兗銇紡娲┿倰闃层亹銇熴倎銆丄PI銈兗銇偗銉┿偆銈€兂銉堝伌銇у叡鏈夈伨銇熴伅淇濆瓨銇涖仛銆併偟銉笺儛銉煎伌銇т繚瀛樸仚銈嬨亾銇ㄣ倰寮枫亸銇婂嫥銈併仐銇俱仚銆�**</i>
+
+ 銇欍伖銇︺伄API銉偗銈ㄣ偣銉堛伀銇娿亜銇︺�佷互涓嬨伄銈堛亞銇玚Authorization`HTTP銉樸儍銉�銉笺伀API銈兗銈掑惈銈併仸銇忋仩銇曘亜锛�
+
+ <CodeGroup title="銈炽兗銉�">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/chat-messages'
+ method='POST'
+ title='銉併儯銉冦儓銉°儍銈汇兗銈搞倰閫佷俊'
+ name='#Send-Chat-Message'
+/>
+<Row>
+ <Col>
+ 銉併儯銉冦儓銈€儣銉偙銉笺偡銉с兂銇儶銈偍銈广儓銈掗�佷俊銇椼伨銇欍��
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='query' type='string' key='query'>
+ 銉︺兗銈躲兗鍏ュ姏/璩晱鍐呭
+ </Property>
+ <Property name='inputs' type='object' key='inputs'>
+ 銈€儣銉仹瀹氱京銇曘倢銇熴仌銇俱仏銇俱仾澶夋暟鍊ゃ伄鍏ュ姏銈掕ū鍙仐銇俱仚銆�
+ `inputs`銉戙儵銉°兗銈裤伀銇鏁般伄銈兗/鍊ゃ儦銈€亴鍚伨銈屻�佸悇銈兗銇壒瀹氥伄澶夋暟銇蹇溿仐銆佸悇鍊ゃ伅銇濄伄澶夋暟銇壒瀹氥伄鍊ゃ仹銇欍�傘儑銉曘偐銉儓銇痐{}`
+ </Property>
+ <Property name='response_mode' type='string' key='response_mode'>
+ 蹇滅瓟銇繑鍗淬儮銉笺儔銈掓寚瀹氥仐銇俱仚銆傘偟銉濄兗銉堛仌銈屻仸銇勩倠銉€兗銉夛細
+ - `streaming` 銈广儓銉兗銉熴兂銈般儮銉笺儔锛堟帹濂級銆丼SE锛圼Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)锛夈倰閫氥仒銇︺偪銈ゃ儣銉┿偆銈裤兗銇倛銇嗐仾鍑哄姏銈掑疅瑁呫仐銇俱仚銆�
+ - `blocking` 銉栥儹銉冦偔銉炽偘銉€兗銉夈�佸疅琛屽畬浜嗗緦銇祼鏋溿倰杩斻仐銇俱仚銆傦紙銉椼儹銈汇偣銇岄暦銇勫牬鍚堛�併儶銈偍銈广儓銇屼腑鏂仌銈屻倠鍙兘鎬с亴銇傘倞銇俱仚锛�
+ Cloudflare銇埗闄愩伀銈堛倞銆�100绉掑緦銇繙绛斻亴銇亜鍫村悎銆併儶銈偍銈广儓銇腑鏂仌銈屻伨銇欍��
+ <i>娉細銈ㄣ兗銈搞偋銉炽儓銈€偡銈广偪銉炽儓銉€兗銉夈仹銇儢銉儍銈兂銈般儮銉笺儔銇偟銉濄兗銉堛仌銈屻仸銇勩伨銇涖倱</i>
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇偄銈ゃ儑銉炽儐銈c儐銈c倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍��
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫伀銈堛仯銇︿竴鎰忋伀瀹氱京銇曘倢銈嬪繀瑕併亴銇傘倞銇俱仚銆�
+ </Property>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 浼氳┍ID銆佷互鍓嶃伄銉併儯銉冦儓瑷橀尣銇熀銇ャ亜銇︿細瑭便倰缍氥亼銈嬨伀銇�佸墠銇儭銉冦偦銉笺偢銇甤onversation_id銈掓浮銇欏繀瑕併亴銇傘倞銇俱仚銆�
+ </Property>
+ <Property name='files' type='array[object]' key='files'>
+ 銉曘偂銈ゃ儷銉偣銉堛�併儐銈偣銉堛伄鐞嗚В銇ㄨ唱鍟忋伕銇洖绛斻倰绲勩伩鍚堛倧銇涖仧銉曘偂銈ゃ儷锛堢敾鍍忥級銇叆鍔涖伀閬┿仐銇︺亰銈娿�併儮銉囥儷銇屻儞銈搞儳銉虫鑳姐倰銈点儩銉笺儓銇椼仸銇勩倠鍫村悎銇伄銇垮埄鐢ㄥ彲鑳姐仹銇欍��
+ - `type` (string) 銈点儩銉笺儓銇曘倢銇︺亜銈嬨偪銈ゃ儣锛歚image`锛堢従鍦ㄣ伅鐢诲儚銈裤偆銉椼伄銇裤偟銉濄兗銉堬級
+ - `transfer_method` (string) 杌㈤�佹柟娉曘�佺敾鍍廢RL銇牬鍚堛伅`remote_url` / 銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銇牬鍚堛伅`local_file`
+ - `url` (string) 鐢诲儚URL锛堣虎閫佹柟娉曘亴`remote_url`銇牬鍚堬級
+ - `upload_file_id` (string) 銈€儍銉椼儹銉笺儔銇曘倢銇熴儠銈°偆銉獻D銆佷簨鍓嶃伀銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔API銈掗�氥仒銇﹀彇寰椼仚銈嬪繀瑕併亴銇傘倞銇俱仚锛堣虎閫佹柟娉曘亴`local_file`銇牬鍚堬級
+ </Property>
+ <Property name='auto_generate_name' type='bool' key='auto_generate_name'>
+ 銈裤偆銉堛儷銈掕嚜鍕曠敓鎴愩仐銇俱仚銆傘儑銉曘偐銉儓銇痐true`銇с仚銆�
+ `false`銇ō瀹氥仚銈嬨仺銆佷細瑭便伄銉儘銉笺儬API銈掑懠銇冲嚭銇椼�乣auto_generate`銈抈true`銇ō瀹氥仚銈嬨亾銇ㄣ仹闈炲悓鏈熴偪銈ゃ儓銉敓鎴愩倰瀹熺従銇с亶銇俱仚銆�
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ response_mode銇屻儢銉儍銈兂銈般伄鍫村悎銆丆ompletionResponse銈儢銈搞偋銈儓銈掕繑銇椼伨銇欍��
+ response_mode銇屻偣銉堛儶銉笺儫銉炽偘銇牬鍚堛�丆hunkCompletionResponse銈广儓銉兗銉犮倰杩斻仐銇俱仚銆�
+
+ ### ChatCompletionResponse
+ 瀹屽叏銇偄銉椼儶绲愭灉銈掕繑銇椼伨銇欍�俙Content-Type`銇痐application/json`銇с仚銆�
+ - `event` (string) 銈ゃ儥銉炽儓銈裤偆銉椼�佸浐瀹氥仹 `message`
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `id` (string) 銉︺儖銉笺偗ID
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `mode` (string) 銈€儣銉儮銉笺儔銆乣chat`銇ㄣ仐銇﹀浐瀹�
+ - `answer` (string) 瀹屽叏銇繙绛斿唴瀹�
+ - `metadata` (object) 銉°偪銉囥兗銈�
+ - `usage` (Usage) 銉€儑銉娇鐢ㄦ儏鍫�
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤銇ㄥ赴灞炪儶銈广儓
+ - `created_at` (int) 銉°儍銈汇兗銈镐綔鎴愩偪銈ゃ儬銈广偪銉炽儣銆佷緥锛�1705395332
+
+ ### ChunkChatCompletionResponse
+ 銈€儣銉伀銈堛仯銇﹀嚭鍔涖仌銈屻仧銈广儓銉兗銉犮儊銉c兂銈倰杩斻仐銇俱仚銆俙Content-Type`銇痐text/event-stream`銇с仚銆�
+ 鍚勩偣銉堛儶銉笺儫銉炽偘銉併儯銉炽偗銇痐data:`銇у銇俱倞銆�2銇ゃ伄鏀硅鏂囧瓧`\n\n`銇у尯鍒囥倝銈屻伨銇欍�備互涓嬨伄銈堛亞銇〃绀恒仌銈屻伨銇欙細
+ <CodeGroup>
+ ```streaming {{ title: '蹇滅瓟' }}
+ data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
+ ```
+ </CodeGroup>
+ 銈广儓銉兗銉熴兂銈般儊銉c兂銈伄妲嬮�犮伅`event`銇繙銇樸仸鐣般仾銈娿伨銇欙細
+ - `event: message` LLM銇儐銈偣銉堛儊銉c兂銈偆銉欍兂銉堛倰杩斻仐銇俱仚銆傘仱銇俱倞銆佸畬鍏ㄣ仾銉嗐偔銈广儓銇屻儊銉c兂銈舰寮忋仹鍑哄姏銇曘倢銇俱仚銆�
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `answer` (string) LLM銇岃繑銇椼仧銉嗐偔銈广儓銉併儯銉炽偗鍐呭
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: agent_message` LLM銇儐銈偣銉堛儊銉c兂銈偆銉欍兂銉堛倰杩斻仐銇俱仚銆傘仱銇俱倞銆併偍銉笺偢銈с兂銉堛偄銈枫偣銈裤兂銉堛亴鏈夊姽銇牬鍚堛�佸畬鍏ㄣ仾銉嗐偔銈广儓銇屻儊銉c兂銈舰寮忋仹鍑哄姏銇曘倢銇俱仚锛堛偍銉笺偢銈с兂銉堛儮銉笺儔銇с伄銇裤偟銉濄兗銉堬級
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `answer` (string) LLM銇岃繑銇椼仧銉嗐偔銈广儓銉併儯銉炽偗鍐呭
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: tts_message` TTS銈兗銉囥偅銈偣銉堛儶銉笺儬銈ゃ儥銉炽儓銆併仱銇俱倞闊冲0鍚堟垚鍑哄姏銆傚唴瀹广伅Mp3褰㈠紡銇偑銉笺儑銈c偑銉栥儹銉冦偗銇с�乥ase64鏂囧瓧鍒椼仺銇椼仸銈ㄣ兂銈炽兗銉夈仌銈屻仸銇勩伨銇欍�傚啀鐢熸檪銇伅銆乥ase64銈掋儑銈炽兗銉夈仐銇︺儣銉兗銉ゃ兗銇叆鍔涖仚銈嬨仩銇戙仹銇欍�傦紙銇撱伄銉°儍銈汇兗銈搞伅鑷嫊鍐嶇敓銇屾湁鍔广仾鍫村悎銇伄銇垮埄鐢ㄥ彲鑳斤級
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄鍋滄蹇滅瓟銈ゃ兂銈裤兗銉曘偋銉笺偣銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `audio` (string) 闊冲0鍚堟垚寰屻伄銈兗銉囥偅銈�乥ase64銉嗐偔銈广儓銈炽兂銉嗐兂銉勩仺銇椼仸銈ㄣ兂銈炽兗銉夈仌銈屻仸銇娿倞銆佸啀鐢熸檪銇伅base64銈掋儑銈炽兗銉夈仐銇︺儣銉兗銉ゃ兗銇叆鍔涖仚銈嬨仩銇戙仹銇�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: tts_message_end` TTS銈兗銉囥偅銈偣銉堛儶銉笺儬绲備簡銈ゃ儥銉炽儓銆傘亾銇偆銉欍兂銉堛倰鍙椾俊銇欍倠銇ㄣ�併偑銉笺儑銈c偑銈广儓銉兗銉犮伄绲備簡銈掔ず銇椼伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄鍋滄蹇滅瓟銈ゃ兂銈裤兗銉曘偋銉笺偣銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `audio` (string) 绲備簡銈ゃ儥銉炽儓銇伅銈兗銉囥偅銈亴銇亜銇熴倎銆併亾銈屻伅绌恒伄鏂囧瓧鍒椼仹銇�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: agent_thought` 銈ㄣ兗銈搞偋銉炽儓銇�濊�冦�丩LM銇�濊�冦�併儎銉笺儷鍛笺伋鍑恒仐銇叆鍔涖仺鍑哄姏銈掑惈銇裤伨銇欙紙銈ㄣ兗銈搞偋銉炽儓銉€兗銉夈仹銇伩銈点儩銉笺儓锛�
+ - `id` (string) 銈ㄣ兗銈搞偋銉炽儓鎬濊�僆D銆佸悇鍙嶅京銇伅涓�鎰忋伄銈ㄣ兗銈搞偋銉炽儓鎬濊�僆D銇屻亗銈娿伨銇�
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `position` (int) 鐝惧湪銇偍銉笺偢銈с兂銉堟�濊�冦伄浣嶇疆銆佸悇銉°儍銈汇兗銈搞伀銇爢鐣伀瑜囨暟銇�濊�冦亴鍚伨銈屻倠鍫村悎銇屻亗銈娿伨銇欍��
+ - `thought` (string) LLM銇岃�冦亪銇︺亜銈嬨亾銇�
+ - `observation` (string) 銉勩兗銉懠銇冲嚭銇椼亱銈夈伄蹇滅瓟
+ - `tool` (string) 鍛笺伋鍑恒仌銈屻仧銉勩兗銉伄銉偣銉堛��;銇у尯鍒囥倝銈屻伨銇�
+ - `tool_input` (string) 銉勩兗銉伄鍏ュ姏銆丣SON褰㈠紡銆備緥锛歚{"dalle3": {"prompt": "a cute cat"}}`銆�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `message_files` (array[string]) message_file銈ゃ儥銉炽儓銈掑弬鐓�
+ - `file_id` (string) 銉曘偂銈ゃ儷ID
+ - `conversation_id` (string) 浼氳┍ID
+ - `event: message_file` 銉°儍銈汇兗銈搞儠銈°偆銉偆銉欍兂銉堛�併儎銉笺儷銇倛銇c仸鏂般仐銇勩儠銈°偆銉亴浣滄垚銇曘倢銇俱仐銇�
+ - `id` (string) 銉曘偂銈ゃ儷涓�鎰廔D
+ - `type` (string) 銉曘偂銈ゃ儷銈裤偆銉椼�佺従鍦ㄣ伅"image"銇伩瑷卞彲
+ - `belongs_to` (string) 鎵�灞炪�併亾銇撱仹銇�'assistant'銇伩
+ - `url` (string) 銉曘偂銈ゃ儷銇儶銉€兗銉圲RL
+ - `conversation_id` (string) 浼氳┍ID
+ - `event: message_end` 銉°儍銈汇兗銈哥祩浜嗐偆銉欍兂銉堛�併亾銇偆銉欍兂銉堛倰鍙椾俊銇欍倠銇ㄣ偣銉堛儶銉笺儫銉炽偘銇岀祩浜嗐仐銇熴亾銇ㄣ倰鎰忓懗銇椼伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `metadata` (object) 銉°偪銉囥兗銈�
+ - `usage` (Usage) 銉€儑銉娇鐢ㄦ儏鍫�
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤銇ㄥ赴灞炪儶銈广儓
+ - `event: message_replace` 銉°儍銈汇兗銈稿唴瀹圭疆鎻涖偆銉欍兂銉堛��
+ 鍑哄姏鍐呭銇儮銉囥儸銉笺偡銉с兂銇屾湁鍔广仾鍫村悎銆佸唴瀹广亴銉曘儵銈般仌銈屻倠銇ㄣ�併亾銇偆銉欍兂銉堛倰閫氥仒銇︺儭銉冦偦銉笺偢鍐呭銇屼簨鍓嶈ō瀹氥仌銈屻仧杩斾俊銇疆銇嶆彌銇堛倝銈屻伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `answer` (string) 缃彌鍐呭锛堛仚銇广仸銇甃LM杩斾俊銉嗐偔銈广儓銈掔洿鎺ョ疆鎻涳級
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: error`
+ 銈广儓銉兗銉熴兂銈般儣銉偦銈逛腑銇櫤鐢熴仐銇熶緥澶栥伅銈广儓銉兗銉犮偆銉欍兂銉堛伄褰㈠紡銇у嚭鍔涖仌銈屻�併偍銉┿兗銈ゃ儥銉炽儓銈掑彈淇°仚銈嬨仺銈广儓銉兗銉犮亴绲備簡銇椼伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `status` (int) HTTP銈广儐銉笺偪銈广偝銉笺儔
+ - `code` (string) 銈ㄣ儵銉笺偝銉笺儔
+ - `message` (string) 銈ㄣ儵銉笺儭銉冦偦銉笺偢
+ - `event: ping` 鎺ョ稓銈掔董鎸併仚銈嬨仧銈併伀10绉掋仈銇ㄣ伀ping銈ゃ儥銉炽儓銇岀櫤鐢熴仐銇俱仚銆�
+
+ ### 銈ㄣ儵銉�
+ - 404, 浼氳┍銇屽瓨鍦ㄣ仐銇俱仜銈�
+ - 400, `invalid_param`, 鐣板父銇儜銉┿儭銉笺偪鍏ュ姏
+ - 400, `app_unavailable`, 銈€儣銉鎴愩亴鍒╃敤銇с亶銇俱仜銈�
+ - 400, `provider_not_initialize`, 鍒╃敤鍙兘銇儮銉囥儷璩囨牸鎯呭牨妲嬫垚銇屻亗銈娿伨銇涖倱
+ - 400, `provider_quota_exceeded`, 銉€儑銉懠銇冲嚭銇椼偗銈┿兗銈裤亴涓嶈冻銇椼仸銇勩伨銇�
+ - 400, `model_currently_not_support`, 鐝惧湪銇儮銉囥儷銇埄鐢ㄣ仹銇嶃伨銇涖倱
+ - 400, `completion_request_error`, 銉嗐偔銈广儓鐢熸垚銇け鏁椼仐銇俱仐銇�
+ - 500, 鍐呴儴銈点兗銉愩兗銈ㄣ儵銉�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/chat-messages" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": ${JSON.stringify(props.inputs)},\n "query": "What are the specs of the iPhone 13 Pro Max?",\n "response_mode": "streaming",\n "conversation_id": "",\n "user": "abc-123",\n "files": [\n {\n "type": "image",\n "transfer_method": "remote_url",\n "url": "https://cloud.dify.ai/logo/logo-site.png"\n }\n ]\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {},
+ "query": "eh",
+ "response_mode": "streaming",
+ "conversation_id": "1c7e55fb-1ba2-4e10-81b5-30addcea2276",
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+ ### 銉栥儹銉冦偔銉炽偘銉€兗銉�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "event": "message",
+ "task_id": "c3800678-a077-43df-a102-53f23ed20b88",
+ "id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
+ "mode": "chat",
+ "answer": "iPhone 13 Pro Max銇粫妲樸伅娆°伄銇ㄣ亰銈娿仹銇�:...",
+ "metadata": {
+ "usage": {
+ "prompt_tokens": 1033,
+ "prompt_unit_price": "0.001",
+ "prompt_price_unit": "0.001",
+ "prompt_price": "0.0010330",
+ "completion_tokens": 128,
+ "completion_unit_price": "0.002",
+ "completion_price_unit": "0.001",
+ "completion_price": "0.0002560",
+ "total_tokens": 1161,
+ "total_price": "0.0012890",
+ "currency": "USD",
+ "latency": 0.7682376249867957
+ },
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ]
+ },
+ "created_at": 1705407629
+ }
+ ```
+ </CodeGroup>
+ ### 銈广儓銉兗銉熴兂銈般儮銉笺儔锛堝熀鏈偄銈枫偣銈裤兂銉堬級
+ <CodeGroup title="蹇滅瓟">
+ ```streaming {{ title: '蹇滅瓟' }}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ ### 蹇滅瓟渚嬶紙銈ㄣ兗銈搞偋銉炽儓銈€偡銈广偪銉炽儓锛�
+ <CodeGroup title="蹇滅瓟">
+ ```streaming {{ title: '蹇滅瓟' }}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔'
+ name='#file-upload'
+/>
+<Row>
+ <Col>
+ 銉°儍銈汇兗銈搁�佷俊鏅傘伀浣跨敤銇欍倠銇熴倎銇儠銈°偆銉倰銈€儍銉椼儹銉笺儔銇椼伨銇欙紙鐝惧湪銇敾鍍忋伄銇裤偟銉濄兗銉堬級銆傜敾鍍忋仺銉嗐偔銈广儓銇優銉儊銉€兗銉�銉悊瑙c倰鍙兘銇仐銇俱仚銆�
+ png銆乯pg銆乯peg銆亀ebp銆乬if褰㈠紡銈掋偟銉濄兗銉堛仐銇︺亜銇俱仚銆�
+ 銈€儍銉椼儹銉笺儔銇曘倢銇熴儠銈°偆銉伅鐝惧湪銇偍銉炽儔銉︺兗銈躲兗銇伩銇屼娇鐢ㄣ仹銇嶃伨銇欍��
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ 銇撱伄銈ゃ兂銈裤兗銉曘偋銉笺偣銇痐multipart/form-data`銉偗銈ㄣ偣銉堛倰蹇呰銇ㄣ仐銇俱仚銆�
+ - `file` (File) 蹇呴爤
+ 銈€儍銉椼儹銉笺儔銇欍倠銉曘偂銈ゃ儷銆�
+ - `user` (string) 蹇呴爤
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伄銉兗銉仹瀹氱京銇曘倢銆併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇亼銈屻伆銇倞銇俱仜銈撱��
+
+ ### 蹇滅瓟
+ 銈€儍銉椼儹銉笺儔銇屾垚鍔熴仚銈嬨仺銆併偟銉笺儛銉笺伅銉曘偂銈ゃ儷銇甀D銇ㄩ枹閫f儏鍫便倰杩斻仐銇俱仚銆�
+ - `id` (uuid) ID
+ - `name` (string) 銉曘偂銈ゃ儷鍚�
+ - `size` (int) 銉曘偂銈ゃ儷銈点偆銈猴紙銉愩偆銉堬級
+ - `extension` (string) 銉曘偂銈ゃ儷鎷″嫉瀛�
+ - `mime_type` (string) 銉曘偂銈ゃ儷銇甅IME銈裤偆銉�
+ - `created_by` (uuid) 銈ㄣ兂銉夈儲銉笺偠銉糏D
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+
+ ### 銈ㄣ儵銉�
+ - 400, `no_file_uploaded`, 銉曘偂銈ゃ儷銇屾彁渚涖仌銈屻仾銇戙倢銇般仾銈娿伨銇涖倱
+ - 400, `too_many_files`, 鐝惧湪銇�1銇ゃ伄銉曘偂銈ゃ儷銇伩鍙椼亼浠樸亼銇俱仚
+ - 400, `unsupported_preview`, 銉曘偂銈ゃ儷銇儣銉儞銉ャ兗銈掋偟銉濄兗銉堛仐銇︺亜銇俱仜銈�
+ - 400, `unsupported_estimate`, 銉曘偂銈ゃ儷銇帹瀹氥倰銈点儩銉笺儓銇椼仸銇勩伨銇涖倱
+ - 413, `file_too_large`, 銉曘偂銈ゃ儷銇屽ぇ銇嶃仚銇庛伨銇�
+ - 415, `unsupported_file_type`, 銈点儩銉笺儓銇曘倢銇︺亜銇亜鎷″嫉瀛愩�佺従鍦ㄣ伅銉夈偔銉ャ儭銉炽儓銉曘偂銈ゃ儷銇伩鍙椼亼浠樸亼銇俱仚
+ - 503, `s3_connection_failed`, S3銈点兗銉撱偣銇帴缍氥仹銇嶃伨銇涖倱
+ - 503, `s3_permission_denied`, S3銇儠銈°偆銉倰銈€儍銉椼儹銉笺儔銇欍倠妯╅檺銇屻亗銈娿伨銇涖倱
+ - 503, `s3_file_too_large`, 銉曘偂銈ゃ儷銇孲3銇偟銈ゃ偤鍒堕檺銈掕秴銇堛仸銇勩伨銇�
+ - 500, 鍐呴儴銈点兗銉愩兗銈ㄣ儵銉�
+
+
+ </Col>
+ <Col sticky>
+ ### 銉偗銈ㄣ偣銉堜緥
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+
+ ### 蹇滅瓟渚�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": "6ad1ab0a-73ff-4ac1-b9e4-cdb312f71f13",
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/chat-messages/:task_id/stop'
+ method='POST'
+ title='鐢熸垚鍋滄'
+ name='#stop-generatebacks'
+/>
+<Row>
+ <Col>
+ 銈广儓銉兗銉熴兂銈般儮銉笺儔銇с伄銇裤偟銉濄兗銉堛仌銈屻仸銇勩伨銇欍��
+ ### 銉戙偣
+ - `task_id` (string) 銈裤偣銈疘D銆併偣銉堛儶銉笺儫銉炽偘銉併儯銉炽偗銇繑銈婂�ゃ亱銈夊彇寰椼仹銇嶃伨銇�
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ - `user` (string) 蹇呴爤
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇偄銈ゃ儑銉炽儐銈c儐銈c倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�併儭銉冦偦銉笺偢閫佷俊銈ゃ兂銈裤兗銉曘偋銉笺偣銇ф浮銇曘倢銇熴儲銉笺偠銉笺仺涓�鑷淬仐銇︺亜銈嬪繀瑕併亴銇傘倞銇俱仚銆�
+ ### 蹇滅瓟
+ - `result` (string) 甯搞伀"success"銈掕繑銇椼伨銇�
+ </Col>
+ <Col sticky>
+ ### 銉偗銈ㄣ偣銉堜緥
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{"user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+
+ ### 蹇滅瓟渚�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages/:message_id/feedbacks'
+ method='POST'
+ title='銉°儍銈汇兗銈搞儠銈c兗銉夈儛銉冦偗'
+ name='#feedbacks'
+/>
+<Row>
+ <Col>
+ 銈ㄣ兂銉夈儲銉笺偠銉笺伅銉曘偅銉笺儔銉愩儍銈儭銉冦偦銉笺偢銈掓彁渚涖仹銇嶃�併偄銉椼儶銈便兗銈枫儳銉抽枊鐧鸿�呫亴鏈熷緟銇曘倢銈嬪嚭鍔涖倰鏈�閬╁寲銇欍倠銇伀褰圭珛銇°伨銇欍��
+
+ ### 銉戙偣
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ 銉°儍銈汇兗銈窱D
+ </Property>
+ </Properties>
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='rating' type='string' key='rating'>
+ 銈€儍銉椼儨銉笺儓銇痐like`銆併儉銈︺兂銉溿兗銉堛伅`dislike`銆併偄銉冦儣銉溿兗銉堛伄鍙栥倞娑堛仐銇痐null`
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伄銉兗銉仹瀹氱京銇曘倢銆併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇亼銈屻伆銇倞銇俱仜銈撱��
+ </Property>
+ <Property name='content' type='string' key='content'>
+ 銉°儍銈汇兗銈搞伄銉曘偅銉笺儔銉愩儍銈仹銇欍��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `result` (string) 甯搞伀"success"銈掕繑銇椼伨銇�
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/messages/:message_id/feedbacks" targetCode={`curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks \\\n --header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "rating": "like",\n "user": "abc-123",\n "content": "message feedback information"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "rating": "like",
+ "user": "abc-123",
+ "content": "message feedback information"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/app/feedbacks'
+ method='GET'
+ title='銈€儣銉伄銉°儍銈汇兗銈搞伄銆屻亜銇勩伃銆嶃仺銉曘偅銉笺儔銉愩儍銈倰鍙栧緱'
+ name='#app-feedbacks'
+/>
+<Row>
+ <Col>
+ 銈€儣銉伄銈ㄣ兂銉夈儲銉笺偠銉笺亱銈夈伄銉曘偅銉笺儔銉愩儍銈倓銆屻亜銇勩伃銆嶃倰鍙栧緱銇椼伨銇欍��
+
+ ### 銈偍銉�
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 锛堜换鎰忥級銉氥兗銈哥暘鍙枫�傘儑銉曘偐銉儓鍊わ細1
+ </Property>
+ </Properties>
+
+ <Properties>
+ <Property name='limit' type='string' key='limit'>
+ 锛堜换鎰忥級1銉氥兗銈搞亗銇熴倞銇欢鏁般�傘儑銉曘偐銉儓鍊わ細20
+ </Property>
+ </Properties>
+
+ ### 銉偣銉濄兂銈�
+ - `data` (銉偣銉�) 銇撱伄銈€儣銉伄銆屻亜銇勩伃銆嶃仺銉曘偅銉笺儔銉愩儍銈伄涓�瑕с倰杩斻仐銇俱仚銆�
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/app/feedbacks" targetCode={`curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "8c0fbed8-e2f9-49ff-9f0e-15a35bdd0e25",
+ "app_id": "f252d396-fe48-450e-94ec-e184218e7346",
+ "conversation_id": "2397604b-9deb-430e-b285-4726e51fd62d",
+ "message_id": "709c0b0f-0a96-4a4e-91a4-ec0889937b11",
+ "rating": "like",
+ "content": "message feedback information-3",
+ "from_source": "user",
+ "from_end_user_id": "74286412-9a1a-42c1-929c-01edb1d381d5",
+ "from_account_id": null,
+ "created_at": "2025-04-24T09:24:38",
+ "updated_at": "2025-04-24T09:24:38"
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+
+<Heading
+ url='/messages/{message_id}/suggested'
+ method='GET'
+ title='娆°伄鎺ㄥエ璩晱'
+ name='#suggested'
+/>
+<Row>
+ <Col>
+ 鐝惧湪銇儭銉冦偦銉笺偢銇銇欍倠娆°伄璩晱銇彁妗堛倰鍙栧緱銇椼伨銇�
+
+ ### 銉戙偣銉戙儵銉°兗銈�
+
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ 銉°儍銈汇兗銈窱D
+ </Property>
+ </Properties>
+
+ ### 銈偍銉�
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇偄銈ゃ儑銉炽儐銈c儐銈c倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�佺当瑷堛伄銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍��
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫伀銈堛仯銇︿竴鎰忋伀瀹氱京銇曘倢銈嬪繀瑕併亴銇傘倞銇俱仚銆�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/messages/{message_id}/suggested" targetCode={`curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested?user=abc-123& \\\n--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \\\n--header 'Content-Type: application/json'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested' \
+ --header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
+ --header 'Content-Type: application/json' \
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "result": "success",
+ "data": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/messages'
+ method='GET'
+ title='浼氳┍灞ユ銉°儍銈汇兗銈搞倰鍙栧緱'
+ name='#messages'
+/>
+<Row>
+ <Col>
+ 銈广偗銉兗銉儹銉笺儔褰㈠紡銇ч亷鍘汇伄銉併儯銉冦儓瑷橀尣銈掕繑銇椼�佹渶鍒濄伄銉氥兗銈搞伅鏈�鏂般伄`{limit}`銉°儍銈汇兗銈搞倰杩斻仐銇俱仚銆傘仱銇俱倞銆侀�嗛爢銇с仚銆�
+
+ ### 銈偍銉�
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 浼氳┍ID
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇偄銈ゃ儑銉炽儐銈c儐銈c倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�佺当瑷堛伄銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍��
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫伀銈堛仯銇︿竴鎰忋伀瀹氱京銇曘倢銈嬪繀瑕併亴銇傘倞銇俱仚銆�
+ </Property>
+ <Property name='first_id' type='string' key='first_id'>
+ 鐝惧湪銇儦銉笺偢銇渶鍒濄伄銉併儯銉冦儓瑷橀尣銇甀D銆併儑銉曘偐銉儓銇痭ull銇с仚銆�
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 1鍥炪伄銉偗銈ㄣ偣銉堛仹杩斻仚銉併儯銉冦儓灞ユ銉°儍銈汇兗銈搞伄鏁般�併儑銉曘偐銉儓銇�20銇с仚銆�
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `data` (array[object]) 銉°儍銈汇兗銈搞儶銈广儓
+ - `id` (string) 銉°儍銈汇兗銈窱D
+ - `conversation_id` (string) 浼氳┍ID
+ - `inputs` (object) 銉︺兗銈躲兗鍏ュ姏銉戙儵銉°兗銈裤��
+ - `query` (string) 銉︺兗銈躲兗鍏ュ姏/璩晱鍐呭銆�
+ - `message_files` (array[object]) 銉°儍銈汇兗銈搞儠銈°偆銉�
+ - `id` (string) ID
+ - `type` (string) 銉曘偂銈ゃ儷銈裤偆銉椼�佺敾鍍忋伄鍫村悎銇痠mage
+ - `url` (string) 銉椼儸銉撱儱銉肩敾鍍廢RL
+ - `belongs_to` (string) 鎵�灞炪�併儲銉笺偠銉笺伨銇熴伅銈€偡銈广偪銉炽儓
+ - `agent_thoughts` (array[object]) 銈ㄣ兗銈搞偋銉炽儓銇�濊�冿紙鍩烘湰銈€偡銈广偪銉炽儓銇牬鍚堛伅绌猴級
+ - `id` (string) 銈ㄣ兗銈搞偋銉炽儓鎬濊�僆D銆佸悇鍙嶅京銇伅涓�鎰忋伄銈ㄣ兗銈搞偋銉炽儓鎬濊�僆D銇屻亗銈娿伨銇�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `position` (int) 鐝惧湪銇偍銉笺偢銈с兂銉堟�濊�冦伄浣嶇疆銆佸悇銉°儍銈汇兗銈搞伀銇爢鐣伀瑜囨暟銇�濊�冦亴鍚伨銈屻倠鍫村悎銇屻亗銈娿伨銇欍��
+ - `thought` (string) LLM銇岃�冦亪銇︺亜銈嬨亾銇�
+ - `observation` (string) 銉勩兗銉懠銇冲嚭銇椼亱銈夈伄蹇滅瓟
+ - `tool` (string) 鍛笺伋鍑恒仌銈屻仧銉勩兗銉伄銉偣銉堛��;銇у尯鍒囥倝銈屻伨銇�
+ - `tool_input` (string) 銉勩兗銉伄鍏ュ姏銆丣SON褰㈠紡銆備緥锛歚{"dalle3": {"prompt": "a cute cat"}}`銆�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `message_files` (array[string]) message_file銈ゃ儥銉炽儓銈掑弬鐓�
+ - `file_id` (string) 銉曘偂銈ゃ儷ID
+ - `answer` (string) 蹇滅瓟銉°儍銈汇兗銈稿唴瀹�
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `feedback` (object) 銉曘偅銉笺儔銉愩儍銈儏鍫�
+ - `rating` (string) 銈€儍銉椼儨銉笺儓銇痐like` / 銉�銈︺兂銉溿兗銉堛伅`dislike`
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤銇ㄥ赴灞炪儶銈广儓
+ - `has_more` (bool) 娆°伄銉氥兗銈搞亴銇傘倠銇嬨仼銇嗐亱
+ - `limit` (int) 杩斻仌銈屻仧銈€偆銉嗐儬銇暟銆佸叆鍔涖亴銈枫偣銉嗐儬鍒堕檺銈掕秴銇堛倠鍫村悎銆併偡銈广儐銉犲埗闄愩伄鏁般倰杩斻仐銇俱仚
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/messages" targetCode={`curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='\\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+ ### 蹇滅瓟渚嬶紙鍩烘湰銈€偡銈广偪銉炽儓锛�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "a076a87f-31e5-48dc-b452-0061adbbc922",
+ "conversation_id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "inputs": {
+ "name": "dify"
+ },
+ "query": "iphone 13 pro",
+ "answer": "iPhone 13 Pro銇�2021骞�9鏈�24鏃ャ伀鐧哄2銇曘倢銆�6.1銈ゃ兂銉併伄銉囥偅銈广儣銉偆銇�1170 x 2532銇В鍍忓害銈掑倷銇堛仸銇勩伨銇欍�侶exa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)銉椼儹銈汇儍銈点��6 GB銇甊AM銈掓惌杓夈仐銆�128 GB銆�256 GB銆�512 GB銆�1 TB銇偣銉堛儸銉笺偢銈儣銈枫儳銉炽倰鎻愪緵銇椼伨銇欍�傘偒銉°儵銇�12 MP銆併儛銉冦儐銉兗瀹归噺銇�3095 mAh銇с�乮OS 15銈掓惌杓夈仐銇︺亜銇俱仚銆�",
+ "message_files": [],
+ "feedback": null,
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ],
+ "agent_thoughts": [],
+ "created_at": 1705569239,
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+
+ ### 蹇滅瓟渚嬶紙銈ㄣ兗銈搞偋銉炽儓銈€偡銈广偪銉炽儓锛�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "conversation_id": "957c068b-f258-4f89-ba10-6e8a0361c457",
+ "inputs": {},
+ "query": "draw a cat",
+ "answer": "鐚伄鐢诲儚銈掔敓鎴愩仐銇俱仐銇熴�傘儭銉冦偦銉笺偢銈掔⒑瑾嶃仐銇︾敾鍍忋倰琛ㄧず銇椼仸銇忋仩銇曘亜銆�",
+ "message_files": [
+ {
+ "id": "976990d2-5294-47e6-8f14-7356ba9d2d76",
+ "type": "image",
+ "url": "http://127.0.0.1:5001/files/tools/976990d2-5294-47e6-8f14-7356ba9d2d76.png?timestamp=1705988524&nonce=55df3f9f7311a9acd91bf074cd524092&sign=z43nMSO1L2HBvoqADLkRxr7Biz0fkjeDstnJiCK1zh8=",
+ "belongs_to": "assistant"
+ }
+ ],
+ "feedback": null,
+ "retriever_resources": [],
+ "created_at": 1705988187,
+ "agent_thoughts": [
+ {
+ "id": "592c84cf-07ee-441c-9dcc-ffc66c033469",
+ "chain_id": null,
+ "message_id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "position": 1,
+ "thought": "",
+ "tool": "dalle2",
+ "tool_input": "{\"dalle2\": {\"prompt\": \"cat\"}}",
+ "created_at": 1705988186,
+ "observation": "鐢诲儚銇仚銇с伀浣滄垚銇曘倢銆併儲銉笺偠銉笺伀閫佷俊銇曘倢銇俱仐銇熴�備粖銇欍亹銉︺兗銈躲兗銇⒑瑾嶃仚銈嬨倛銇嗐伀浼濄亪銇︺亸銇犮仌銇勩��",
+ "files": [
+ "976990d2-5294-47e6-8f14-7356ba9d2d76"
+ ]
+ },
+ {
+ "id": "73ead60d-2370-4780-b5ed-532d2762b0e5",
+ "chain_id": null,
+ "message_id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "position": 2,
+ "thought": "鐚伄鐢诲儚銈掔敓鎴愩仐銇俱仐銇熴�傘儭銉冦偦銉笺偢銈掔⒑瑾嶃仐銇︾敾鍍忋倰琛ㄧず銇椼仸銇忋仩銇曘亜銆�",
+ "tool": "",
+ "tool_input": "",
+ "created_at": 1705988199,
+ "observation": "",
+ "files": []
+ }
+ ]
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations'
+ method='GET'
+ title='浼氳┍銈掑彇寰�'
+ name='#conversations'
+/>
+<Row>
+ <Col>
+ 鐝惧湪銇儲銉笺偠銉笺伄浼氳┍銉偣銉堛倰鍙栧緱銇椼�併儑銉曘偐銉儓銇ф渶鏂般伄20浠躲倰杩斻仐銇俱仚銆�
+
+ ### 銈偍銉�
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇偄銈ゃ儑銉炽儐銈c儐銈c倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�佺当瑷堛伄銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍��
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫伀銈堛仯銇︿竴鎰忋伀瀹氱京銇曘倢銈嬪繀瑕併亴銇傘倞銇俱仚銆�
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ (Optional)鐝惧湪銇儦銉笺偢銇渶寰屻伄銉偝銉笺儔銇甀D銆併儑銉曘偐銉儓銇痭ull銇с仚銆�
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ (Optional)1鍥炪伄銉偗銈ㄣ偣銉堛仹杩斻仚銉偝銉笺儔銇暟銆併儑銉曘偐銉儓銇渶鏂般伄20浠躲仹銇欍�傛渶澶�100銆佹渶灏�1銆�
+ </Property>
+ <Property name='sort_by' type='string' key='sort_by'>
+ (Optional)銈姐兗銉堛儠銈c兗銉儔銆併儑銉曘偐銉儓锛�-updated_at锛堟洿鏂版檪闁撱仹闄嶉爢銇偨銉笺儓锛�
+ - 鍒╃敤鍙兘銇�わ細created_at, -created_at, updated_at, -updated_at
+ - 銉曘偅銉笺儷銉夈伄鍓嶃伄瑷樺彿銇爢搴忋伨銇熴伅閫嗛爢銈掕〃銇椼��"-"銇�嗛爢銈掕〃銇椼伨銇欍��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `data` (array[object]) 浼氳┍銇儶銈广儓
+ - `id` (string) 浼氳┍ID
+ - `name` (string) 浼氳┍鍚嶃�併儑銉曘偐銉儓銇с伅銆併儲銉笺偠銉笺亴浼氳┍銇ф渶鍒濄伀灏嬨伃銇熻唱鍟忋伄銈广儖銉氥儍銉堛仹銇欍��
+ - `inputs` (object) 銉︺兗銈躲兗鍏ュ姏銉戙儵銉°兗銈裤��
+ - `introduction` (string) 绱逛粙
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `updated_at` (timestamp) 鏇存柊銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `has_more` (bool)
+ - `limit` (int) 杩斻仌銈屻仧銈ㄣ兂銉堛儶銇暟銆佸叆鍔涖亴銈枫偣銉嗐儬鍒堕檺銈掕秴銇堛倠鍫村悎銆併偡銈广儐銉犲埗闄愩伄鏁般倰杩斻仐銇俱仚
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/conversations" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "10799fb8-64f7-4296-bbf7-b42bfbe0ae54",
+ "name": "鏂般仐銇勩儊銉c儍銉�",
+ "inputs": {
+ "book": "book",
+ "myName": "Lucy"
+ },
+ "status": "normal",
+ "created_at": 1679667915,
+ "updated_at": 1679667915
+ },
+ {
+ "id": "hSIhXBhNe8X1d8Et"
+ // ...
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id'
+ method='DELETE'
+ title='浼氳┍銈掑墛闄�'
+ name='#delete'
+/>
+<Row>
+ <Col>
+ 浼氳┍銈掑墛闄ゃ仐銇俱仚銆�
+
+ ### 銉戙偣
+ - `conversation_id` (string) 浼氳┍ID
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伀銈堛仯銇﹀畾缇┿仌銈屻�併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇傘倠蹇呰銇屻亗銈娿伨銇欍��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `result` (string) 甯搞伀"success"銈掕繑銇椼伨銇�
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="DELETE" label="/conversations/:conversation_id" targetCode={`curl -X DELETE '${props.appDetail.api_base_url}/conversations/:conversation_id' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X DELETE '${props.appDetail.api_base_url}/conversations/{conversation_id}' \
+ --header 'Content-Type: application/json' \
+ --header 'Accept: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data '{
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```text {{ title: '蹇滅瓟' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/conversations/:conversation_id/name'
+ method='POST'
+ title='浼氳┍銇悕鍓嶃倰澶夋洿'
+ name='#rename'
+/>
+<Row>
+ <Col>
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ 銈汇儍銈枫儳銉炽伄鍚嶅墠銈掑鏇淬仐銇俱仚銆傘偦銉冦偡銉с兂鍚嶃伅銆佽鏁般伄銈汇儍銈枫儳銉炽倰銈点儩銉笺儓銇欍倠銈儵銈ゃ偄銉炽儓銇с伄琛ㄧず銇娇鐢ㄣ仌銈屻伨銇欍��
+
+ ### 銉戙偣
+ - `conversation_id` (string) 浼氳┍ID
+
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ (Optional)浼氳┍銇悕鍓嶃�傘亾銇儜銉┿儭銉笺偪銇�乣auto_generate`銇宍true`銇ō瀹氥仌銈屻仸銇勩倠鍫村悎銆佺渷鐣ャ仹銇嶃伨銇欍��
+ </Property>
+ <Property name='auto_generate' type='bool' key='auto_generate'>
+ (Optional)銈裤偆銉堛儷銈掕嚜鍕曠敓鎴愩仐銇俱仚銆傘儑銉曘偐銉儓銇痐false`銇с仚銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伀銈堛仯銇﹀畾缇┿仌銈屻�併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇傘倠蹇呰銇屻亗銈娿伨銇欍��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `id` (string) 浼氳┍ID
+ - `name` (string) 浼氳┍鍚�
+ - `inputs` (object) 銉︺兗銈躲兗鍏ュ姏銉戙儵銉°兗銈�
+ - `status` (string) 浼氳┍鐘舵厠
+ - `introduction` (string) 绱逛粙
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `updated_at` (timestamp) 鏇存柊銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
+ --header 'Content-Type: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data-raw '{
+ "name": "",
+ "auto_generate": true,
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "name": "Chat vs AI",
+ "inputs": {},
+ "introduction": "",
+ "created_at": 1705569238,
+ "updated_at": 1705569238
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id/variables'
+ method='GET'
+ title='浼氳┍澶夋暟銇彇寰�'
+ name='#conversation-variables'
+/>
+<Row>
+ <Col>
+ 鐗瑰畾銇細瑭便亱銈夊鏁般倰鍙栧緱銇椼伨銇欍�傘亾銇偍銉炽儔銉濄偆銉炽儓銇�佷細瑭变腑銇彇寰椼仌銈屻仧妲嬮�犲寲銉囥兗銈裤倰鎶藉嚭銇欍倠銇伀褰圭珛銇°伨銇欍��
+
+ ### 銉戙偣銉戙儵銉°兗銈�
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 澶夋暟銈掑彇寰椼仚銈嬩細瑭便伄ID銆�
+ </Property>
+ </Properties>
+
+ ### 銈偍銉儜銉┿儭銉笺偪
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�傞枊鐧鸿�呫伀銈堛仯銇﹀畾缇┿仌銈屻仧銉兗銉伀寰撱亜銆併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇傘倠蹇呰銇屻亗銈娿伨銇欍��
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ (Optional)鐝惧湪銇儦銉笺偢銇渶寰屻伄銉偝銉笺儔銇甀D銆併儑銉曘偐銉儓銇痭ull銇с仚銆�
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ (Optional)1鍥炪伄銉偗銈ㄣ偣銉堛仹杩斻仚銉偝銉笺儔銇暟銆併儑銉曘偐銉儓銇渶鏂般伄20浠躲仹銇欍�傛渶澶�100銆佹渶灏�1銆�
+ </Property>
+ </Properties>
+
+ ### 銉偣銉濄兂銈�
+
+ - `limit` (int) 銉氥兗銈搞仈銇ㄣ伄銈€偆銉嗐儬鏁�
+ - `has_more` (bool) 銇曘倝銇偄銈ゃ儐銉犮亴銇傘倠銇嬨仼銇嗐亱
+ - `data` (array[object]) 澶夋暟銇儶銈广儓
+ - `id` (string) 澶夋暟ID
+ - `name` (string) 澶夋暟鍚�
+ - `value_type` (string) 澶夋暟銈裤偆銉楋紙鏂囧瓧鍒椼�佹暟鍊ゃ�佺湡鍋藉�ゃ仾銇╋級
+ - `value` (string) 澶夋暟鍊�
+ - `description` (string) 澶夋暟銇鏄�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉�
+ - `updated_at` (int) 鏈�绲傛洿鏂般偪銈ゃ儬銈广偪銉炽儣
+
+ ### 銈ㄣ儵銉�
+ - 404, `conversation_not_exists`, 浼氳┍銇岃銇ゃ亱銈娿伨銇涖倱
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations/:conversation_id/variables" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Request with variable name filter">
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123&variable_name=customer_name' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 100,
+ "has_more": false,
+ "data": [
+ {
+ "id": "variable-uuid-1",
+ "name": "customer_name",
+ "value_type": "string",
+ "value": "John Doe",
+ "description": "浼氳┍銇嬨倝鎶藉嚭銇曘倢銇熼¨瀹㈠悕",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ },
+ {
+ "id": "variable-uuid-2",
+ "name": "order_details",
+ "value_type": "json",
+ "value": "{\"product\":\"Widget\",\"quantity\":5,\"price\":19.99}",
+ "description": "椤у銇敞鏂囪┏绱�",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/audio-to-text'
+ method='POST'
+ title='闊冲0銇嬨倝銉嗐偔銈广儓銇�'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ 銇撱伄銈ㄣ兂銉夈儩銈ゃ兂銉堛伅multipart/form-data銉偗銈ㄣ偣銉堛倰蹇呰銇ㄣ仐銇俱仚銆�
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ 銈兗銉囥偅銈儠銈°偆銉��
+ 銈点儩銉笺儓銇曘倢銇︺亜銈嬪舰寮忥細`['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm']`
+ 銉曘偂銈ゃ儷銈点偆銈哄埗闄愶細15MB
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伄銉兗銉仹瀹氱京銇曘倢銆併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇亼銈屻伆銇倞銇俱仜銈撱��
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `text` (string) 鍑哄姏銉嗐偔銈广儓
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/audio-to-text" targetCode={`curl -X POST '${props.appDetail.api_base_url}/audio-to-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=audio/[mp3|mp4|mpeg|mpga|m4a|wav|webm]'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/name' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@localfile;type=audio/mp3'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "text": ""
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/text-to-audio'
+ method='POST'
+ title='銉嗐偔銈广儓銇嬨倝闊冲0銇�'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ 銉嗐偔銈广儓銈掗煶澹般伀澶夋彌銇椼伨銇欍��
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+
+ <Properties>
+ <Property name='message_id' type='str' key='message_id'>
+ Dify銇倛銇c仸鐢熸垚銇曘倢銇熴儐銈偣銉堛儭銉冦偦銉笺偢銇牬鍚堛�佺敓鎴愩仌銈屻仧銉°儍銈汇兗銈窱D銈掔洿鎺ユ浮銇椼伨銇欍�傘儛銉冦偗銈ㄣ兂銉夈伅銉°儍銈汇兗銈窱D銈掍娇鐢ㄣ仐銇﹀蹇溿仚銈嬨偝銉炽儐銉炽儎銈掓绱€仐銆侀煶澹版儏鍫便倰鐩存帴鍚堟垚銇椼伨銇欍�俶essage_id銇╰ext銇屽悓鏅傘伀鎻愪緵銇曘倢銈嬪牬鍚堛�乵essage_id銇屽劒鍏堛仌銈屻伨銇欍��
+ </Property>
+ <Property name='text' type='str' key='text'>
+ 闊冲0鐢熸垚銈炽兂銉嗐兂銉勩��
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伀銈堛仯銇﹀畾缇┿仌銈屻�併偄銉椼儶鍐呫仹涓�鎰忋仹銇傘倠蹇呰銇屻亗銈娿伨銇欍��
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/text-to-audio" targetCode={`curl --location --request POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \\\n--form 'text=Hello Dify;user=abc-123;message_id=5ad4cb98-f0c7-4085-b384-88c403be6290`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.appDetail.api_base_url}/text-to-audio' \
+ --header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
+ --form 'file=Hello Dify;user=abc-123;message_id=5ad4cb98-f0c7-4085-b384-88c403be6290'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="銉樸儍銉�銉�">
+ ```json {{ title: '銉樸儍銉�銉�' }}
+ {
+ "Content-Type": "audio/wav"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇熀鏈儏鍫便倰鍙栧緱'
+ name='#info'
+/>
+<Row>
+ <Col>
+ 銇撱伄銈€儣銉偙銉笺偡銉с兂銇熀鏈儏鍫便倰鍙栧緱銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻伨銇�
+
+ ### Response
+ - `name` (string) 銈€儣銉偙銉笺偡銉с兂銇悕鍓�
+ - `description` (string) 銈€儣銉偙銉笺偡銉с兂銇鏄�
+ - `tags` (array[string]) 銈€儣銉偙銉笺偡銉с兂銇偪銈�
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇儜銉┿儭銉笺偪鎯呭牨銈掑彇寰�'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ 銉氥兗銈搞伀鍏ャ倠闅涖伀銆佹鑳姐�佸叆鍔涖儜銉┿儭銉笺偪鍚嶃�併偪銈ゃ儣銆併儑銉曘偐銉儓鍊ゃ仾銇┿伄鎯呭牨銈掑彇寰椼仚銈嬨仧銈併伀浣跨敤銇曘倢銇俱仚銆�
+
+ ### 蹇滅瓟
+ - `opening_statement` (string) 闁嬪鏂�
+ - `suggested_questions` (array[string]) 闁嬪鏅傘伄鎺ㄥエ璩晱銇儶銈广儓
+ - `suggested_questions_after_answer` (object) 绛斻亪銈掓湁鍔广伀銇椼仧寰屻伄璩晱銈掓彁妗堛仐銇俱仚銆�
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `speech_to_text` (object) 闊冲0銇嬨倝銉嗐偔銈广儓銇�
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `retriever_resource` (object) 寮曠敤銇ㄥ赴灞�
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `annotation_reply` (object) 娉ㄩ噲杩斾俊
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `user_input_form` (array[object]) 銉︺兗銈躲兗鍏ュ姏銉曘偐銉笺儬銇鎴�
+ - `text-input` (object) 銉嗐偔銈广儓鍏ュ姏銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `paragraph` (object) 娈佃惤銉嗐偔銈广儓鍏ュ姏銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `select` (object) 銉夈儹銉冦儣銉�銈︺兂銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `options` (array[string]) 銈儣銈枫儳銉冲��
+ - `file_upload` (object) 銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔妲嬫垚
+ - `image` (object) 鐢诲儚瑷畾
+ 鐝惧湪銈点儩銉笺儓銇曘倢銇︺亜銈嬬敾鍍忋偪銈ゃ儣锛歚png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `number_limits` (int) 鐢诲儚鏁般伄鍒堕檺銆併儑銉曘偐銉儓銇�3
+ - `transfer_methods` (array[string]) 杌㈤�佹柟娉曘伄銉偣銉堛�乺emote_url, local_file銆併亜銇氥倢銇嬨倰閬告姙銇欍倠蹇呰銇屻亗銈娿伨銇�
+ - `system_parameters` (object) 銈枫偣銉嗐儬銉戙儵銉°兗銈�
+ - `file_size_limit` (int) 銉夈偔銉ャ儭銉炽儓銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+ - `image_file_size_limit` (int) 鐢诲儚銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+ - `audio_file_size_limit` (int) 銈兗銉囥偅銈儠銈°偆銉偄銉冦儣銉兗銉夈偟銈ゃ偤鍒堕檺锛圡B锛�
+ - `video_file_size_limit` (int) 銉撱儑銈儠銈°偆銉偄銉冦儣銉兗銉夈偟銈ゃ偤鍒堕檺锛圡B锛�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "opening_statement": "銇撱倱銇仭銇紒",
+ "suggested_questions_after_answer": {
+ "enabled": true
+ },
+ "speech_to_text": {
+ "enabled": true
+ },
+ "retriever_resource": {
+ "enabled": true
+ },
+ "annotation_reply": {
+ "enabled": true
+ },
+ "user_input_form": [
+ {
+ "paragraph": {
+ "label": "銈偍銉�",
+ "variable": "query",
+ "required": true,
+ "default": ""
+ }
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": false,
+ "number_limits": 3,
+ "detail": "high",
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/meta'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇儭銈挎儏鍫便倰鍙栧緱'
+ name='#meta'
+/>
+<Row>
+ <Col>
+ 銇撱伄銈€儣銉偙銉笺偡銉с兂銇儎銉笺儷銇偄銈ゃ偝銉炽倰鍙栧緱銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻伨銇�
+
+ ### 蹇滅瓟
+ - `tool_icons`(object[string]) 銉勩兗銉偄銈ゃ偝銉�
+ - `tool_name` (string)
+ - `icon` (object|string)
+ - (object) 銈€偆銈炽兂銈儢銈搞偋銈儓
+ - `background` (string) 鑳屾櫙鑹诧紙16閫叉暟褰㈠紡锛�
+ - `content`(string) 绲垫枃瀛�
+ - (string) 銈€偆銈炽兂銇甎RL
+ </Col>
+ <Col>
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/meta' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/meta' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "tool_icons": {
+ "dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
+ "api_tool": {
+ "background": "#252525",
+ "content": "\ud83d\ude01"
+ }
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='銈€儣銉伄WebApp瑷畾銈掑彇寰�'
+ name='#site'
+/>
+<Row>
+ <Col>
+ 銈€儣銉伄WebApp瑷畾銈掑彇寰椼仚銈嬨仧銈併伀浣跨敤銇椼伨銇欍��
+ ### 蹇滅瓟
+ - `title` (string) WebApp鍚�
+ - `chat_color_theme` (string) 銉併儯銉冦儓銇壊銉嗐兗銉炪��16閫叉暟褰㈠紡
+ - `chat_color_theme_inverted` (bool) 銉併儯銉冦儓銇壊銉嗐兗銉炪倰鍙嶈虎銇欍倠銇嬨仼銇嗐亱
+ - `icon_type` (string) 銈€偆銈炽兂銈裤偆銉椼�乣emoji`-绲垫枃瀛椼�乣image`-鐢诲儚
+ - `icon` (string) 銈€偆銈炽兂銆俙emoji`銈裤偆銉椼伄鍫村悎銇档鏂囧瓧銆乣image`銈裤偆銉椼伄鍫村悎銇敾鍍廢RL
+ - `icon_background` (string) 16閫叉暟褰㈠紡銇儗鏅壊
+ - `icon_url` (string) 銈€偆銈炽兂銇甎RL
+ - `description` (string) 瑾槑
+ - `copyright` (string) 钁椾綔妯╂儏鍫�
+ - `privacy_policy` (string) 銉椼儵銈ゃ儛銈枫兗銉濄儶銈枫兗銇儶銉炽偗
+ - `custom_disclaimer` (string) 銈偣銈裤儬鍏嶈铂浜嬮爡
+ - `default_language` (string) 銉囥儠銈┿儷銉堣█瑾�
+ - `show_workflow_steps` (bool) 銉兗銈儠銉兗銇┏绱般倰琛ㄧず銇欍倠銇嬨仼銇嗐亱
+ - `use_icon_as_answer_icon` (bool) WebApp銇偄銈ゃ偝銉炽倰銉併儯銉冦儓鍐呫伄馃銇疆銇嶆彌銇堛倠銇嬨仼銇嗐亱
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "chat_color_theme": "#ff4a4a",
+ "chat_color_theme_inverted": false,
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ "use_icon_as_answer_icon": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
diff --git a/app/components/develop/template/template_chat.zh.mdx b/app/components/develop/template/template_chat.zh.mdx
new file mode 100644
index 0000000..8661700
--- /dev/null
+++ b/app/components/develop/template/template_chat.zh.mdx
@@ -0,0 +1,1394 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
+
+# 瀵硅瘽鍨嬪簲鐢� API
+
+瀵硅瘽搴旂敤鏀寔浼氳瘽鎸佷箙鍖栵紝鍙皢涔嬪墠鐨勮亰澶╄褰曚綔涓轰笂涓嬫枃杩涜鍥炵瓟锛屽彲閫傜敤浜庤亰澶�/瀹㈡湇 AI 绛夈��
+
+<div>
+ ### 鍩虹 URL
+ <CodeGroup title="Code" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### 閴存潈
+
+ Service API 浣跨敤 `API-Key` 杩涜閴存潈銆�
+ <i>**寮虹儓寤鸿寮�鍙戣�呮妸 `API-Key` 鏀惧湪鍚庣瀛樺偍锛岃�岄潪鍒嗕韩鎴栬�呮斁鍦ㄥ鎴风瀛樺偍锛屼互鍏� `API-Key` 娉勯湶锛屽鑷磋储浜ф崯澶便��**</i>
+ 鎵�鏈� API 璇锋眰閮藉簲鍦� **`Authorization`** HTTP Header 涓寘鍚偍鐨� `API-Key`锛屽涓嬫墍绀猴細
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/chat-messages'
+ method='POST'
+ title='鍙戦�佸璇濇秷鎭�'
+ name='#Create-Chat-Message'
+/>
+<Row>
+ <Col>
+ 鍒涘缓浼氳瘽娑堟伅銆�
+
+ ### Request Body
+
+ <Properties>
+ <Property name='query' type='string' key='query'>
+ 鐢ㄦ埛杈撳叆/鎻愰棶鍐呭銆�
+ </Property>
+ <Property name='inputs' type='object' key='inputs'>
+ 鍏佽浼犲叆 App 瀹氫箟鐨勫悇鍙橀噺鍊笺��
+ inputs 鍙傛暟鍖呭惈浜嗗缁勯敭鍊煎锛圞ey/Value pairs锛夛紝姣忕粍鐨勯敭瀵瑰簲涓�涓壒瀹氬彉閲忥紝姣忕粍鐨勫�煎垯鏄鍙橀噺鐨勫叿浣撳�笺��
+ 榛樿 `{}`
+ </Property>
+ <Property name='response_mode' type='string' key='response_mode'>
+ - `streaming` 娴佸紡妯″紡锛堟帹鑽愶級銆傚熀浜� SSE锛�**[Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)**锛夊疄鐜扮被浼兼墦瀛楁満杈撳嚭鏂瑰紡鐨勬祦寮忚繑鍥炪��
+ - `blocking` 闃诲妯″紡锛岀瓑寰呮墽琛屽畬姣曞悗杩斿洖缁撴灉銆傦紙璇锋眰鑻ユ祦绋嬭緝闀垮彲鑳戒細琚腑鏂級銆�
+ <i>鐢变簬 Cloudflare 闄愬埗锛岃姹備細鍦� 100 绉掕秴鏃舵棤杩斿洖鍚庝腑鏂��</i>
+ 娉細Agent妯″紡涓嬩笉鍏佽blocking銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屾柟渚挎绱€�佺粺璁°��
+ 鐢卞紑鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 锛堥�夊~锛変細璇� ID锛岄渶瑕佸熀浜庝箣鍓嶇殑鑱婂ぉ璁板綍缁х画瀵硅瘽锛屽繀椤讳紶涔嬪墠娑堟伅鐨� conversation_id銆�
+ </Property>
+ <Property name='files' type='array[object]' key='files'>
+ 涓婁紶鐨勬枃浠躲��
+ - `type` (string) 鏀寔绫诲瀷锛氬浘鐗� `image`锛堢洰鍓嶄粎鏀寔鍥剧墖鏍煎紡锛� 銆�
+ - `transfer_method` (string) 浼犻�掓柟寮�:
+ - `remote_url`: 鍥剧墖鍦板潃銆�
+ - `local_file`: 涓婁紶鏂囦欢銆�
+ - `url` 鍥剧墖鍦板潃銆傦紙浠呭綋浼犻�掓柟寮忎负 `remote_url` 鏃讹級銆�
+ - `upload_file_id` 涓婁紶鏂囦欢 ID銆傦紙浠呭綋浼犻�掓柟寮忎负 `local_file `鏃讹級銆�
+ </Property>
+ <Property name='auto_generate_name' type='bool' key='auto_generate_name'>
+ 锛堥�夊~锛夎嚜鍔ㄧ敓鎴愭爣棰橈紝榛樿 `true`銆� 鑻ヨ缃负 `false`锛屽垯鍙�氳繃璋冪敤浼氳瘽閲嶅懡鍚嶆帴鍙e苟璁剧疆 `auto_generate` 涓� `true` 瀹炵幇寮傛鐢熸垚鏍囬銆�
+ </Property>
+ </Properties>
+
+ ### Response
+ <Properties>
+ 褰� `response_mode` 涓� `blocking` 鏃讹紝杩斿洖 ChatCompletionResponse object銆�
+ 褰� `response_mode` 涓� `streaming`鏃讹紝杩斿洖 ChunkChatCompletionResponse object 娴佸紡搴忓垪銆�
+
+ ### ChatCompletionResponse
+
+ 杩斿洖瀹屾暣鐨� App 缁撴灉锛宍Content-Type` 涓� `application/json`銆�
+ - `event` (string) 浜嬩欢绫诲瀷锛屽浐瀹氫负 `message`
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `id` (string) 鍞竴ID
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `mode` (string) App 妯″紡锛屽浐瀹氫负 chat
+ - `answer` (string) 瀹屾暣鍥炲鍐呭
+ - `metadata` (object) 鍏冩暟鎹�
+ - `usage` (Usage) 妯″瀷鐢ㄩ噺淇℃伅
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤鍜屽綊灞炲垎娈靛垪琛�
+ - `created_at` (int) 娑堟伅鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ ### ChunkChatCompletionResponse
+ 杩斿洖 App 杈撳嚭鐨勬祦寮忓潡锛宍Content-Type` 涓� `text/event-stream`銆�
+ 姣忎釜娴佸紡鍧楀潎涓� data: 寮�澶达紝鍧椾箣闂翠互 \n\n 鍗充袱涓崲琛岀鍒嗛殧锛屽涓嬫墍绀猴細
+ <CodeGroup>
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
+ ```
+ </CodeGroup>
+
+ 娴佸紡鍧椾腑鏍规嵁 event 涓嶅悓锛岀粨鏋勪篃涓嶅悓锛�
+ - `event: message` LLM 杩斿洖鏂囨湰鍧椾簨浠讹紝鍗筹細瀹屾暣鐨勬枃鏈互鍒嗗潡鐨勬柟寮忚緭鍑恒��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `answer` (string) LLM 杩斿洖鏂囨湰鍧楀唴瀹�
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: agent_message` Agent妯″紡涓嬭繑鍥炴枃鏈潡浜嬩欢锛屽嵆锛氬湪Agent妯″紡涓嬶紝鏂囩珷鐨勬枃鏈互鍒嗗潡鐨勬柟寮忚緭鍑猴紙浠匒gent妯″紡涓嬩娇鐢級
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `answer` (string) LLM 杩斿洖鏂囨湰鍧楀唴瀹�
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: agent_thought` Agent妯″紡涓嬫湁鍏矨gent鎬濊�冩楠ょ殑鐩稿叧鍐呭锛屾秹鍙婂埌宸ュ叿璋冪敤锛堜粎Agent妯″紡涓嬩娇鐢級
+ - `id` (string) agent_thought ID锛屾瘡涓�杞瓵gent杩唬閮戒細鏈変竴涓敮涓�鐨刬d
+ - `task_id` (string) 浠诲姟ID锛岀敤浜庤姹傝窡韪笅鏂圭殑鍋滄鍝嶅簲鎺ュ彛
+ - `message_id` (string) 娑堟伅鍞竴ID
+ - `position` (int) agent_thought鍦ㄦ秷鎭腑鐨勪綅缃紝濡傜涓�杞凯浠osition涓�1
+ - `thought` (string) agent鐨勬�濊�冨唴瀹�
+ - `observation` (string) 宸ュ叿璋冪敤鐨勮繑鍥炵粨鏋�
+ - `tool` (string) 浣跨敤鐨勫伐鍏峰垪琛紝浠� ; 鍒嗗壊澶氫釜宸ュ叿
+ - `tool_input` (string) 宸ュ叿鐨勮緭鍏ワ紝JSON鏍煎紡鐨勫瓧绗︿覆(object)銆傚锛歚{"dalle3": {"prompt": "a cute cat"}}`
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `message_files` (array[string]) 褰撳墠 `agent_thought` 鍏宠仈鐨勬枃浠禝D
+ - `file_id` (string) 鏂囦欢ID
+ - `conversation_id` (string) 浼氳瘽ID
+ - `event: message_file` 鏂囦欢浜嬩欢锛岃〃绀烘湁鏂版枃浠堕渶瑕佸睍绀�
+ - `id` (string) 鏂囦欢鍞竴ID
+ - `type` (string) 鏂囦欢绫诲瀷锛岀洰鍓嶄粎涓篿mage
+ - `belongs_to` (string) 鏂囦欢褰掑睘锛寀ser鎴朼ssistant锛岃鎺ュ彛杩斿洖浠呬负 `assistant`
+ - `url` (string) 鏂囦欢璁块棶鍦板潃
+ - `conversation_id` (string) 浼氳瘽ID
+ - `event: message_end` 娑堟伅缁撴潫浜嬩欢锛屾敹鍒版浜嬩欢鍒欎唬琛ㄦ祦寮忚繑鍥炵粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `metadata` (object) 鍏冩暟鎹�
+ - `usage` (Usage) 妯″瀷鐢ㄩ噺淇℃伅
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤鍜屽綊灞炲垎娈靛垪琛�
+ - `event: tts_message` TTS 闊抽娴佷簨浠讹紝鍗筹細璇煶鍚堟垚杈撳嚭銆傚唴瀹规槸Mp3鏍煎紡鐨勯煶棰戝潡锛屼娇鐢� base64 缂栫爜鍚庣殑瀛楃涓诧紝鎾斁鐨勬椂鍊欑洿鎺ヨВ鐮佸嵆鍙��(寮�鍚嚜鍔ㄦ挱鏀炬墠鏈夋娑堟伅)
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `audio` (string) 璇煶鍚堟垚涔嬪悗鐨勯煶棰戝潡浣跨敤 Base64 缂栫爜涔嬪悗鐨勬枃鏈唴瀹癸紝鎾斁鐨勬椂鍊欑洿鎺� base64 瑙g爜閫佸叆鎾斁鍣ㄥ嵆鍙�
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: tts_message_end` TTS 闊抽娴佺粨鏉熶簨浠讹紝鏀跺埌杩欎釜浜嬩欢琛ㄧず闊抽娴佽繑鍥炵粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `audio` (string) 缁撴潫浜嬩欢鏄病鏈夐煶棰戠殑锛屾墍浠ヨ繖閲屾槸绌哄瓧绗︿覆
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: message_replace` 娑堟伅鍐呭鏇挎崲浜嬩欢銆�
+ 寮�鍚唴瀹瑰鏌ュ拰瀹℃煡杈撳嚭鍐呭鏃讹紝鑻ュ懡涓簡瀹℃煡鏉′欢锛屽垯浼氶�氳繃姝や簨浠舵浛鎹㈡秷鎭唴瀹逛负棰勮鍥炲銆�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `answer` (string) 鏇挎崲鍐呭锛堢洿鎺ユ浛鎹� LLM 鎵�鏈夊洖澶嶆枃鏈級
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: error`
+ 娴佸紡杈撳嚭杩囩▼涓嚭鐜扮殑寮傚父浼氫互 stream event 褰㈠紡杈撳嚭锛屾敹鍒板紓甯镐簨浠跺悗鍗崇粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `status` (int) HTTP 鐘舵�佺爜
+ - `code` (string) 閿欒鐮�
+ - `message` (string) 閿欒娑堟伅
+ - `event: ping` 姣� 10s 涓�娆$殑 ping 浜嬩欢锛屼繚鎸佽繛鎺ュ瓨娲汇��
+
+ ### Errors
+ - 404锛屽璇濅笉瀛樺湪
+ - 400锛宍invalid_param`锛屼紶鍏ュ弬鏁板紓甯�
+ - 400锛宍app_unavailable`锛孉pp 閰嶇疆涓嶅彲鐢�
+ - 400锛宍provider_not_initialize`锛屾棤鍙敤妯″瀷鍑嵁閰嶇疆
+ - 400锛宍provider_quota_exceeded`锛屾ā鍨嬭皟鐢ㄩ搴︿笉瓒�
+ - 400锛宍model_currently_not_support`锛屽綋鍓嶆ā鍨嬩笉鍙敤
+ - 400锛宍completion_request_error`锛屾枃鏈敓鎴愬け璐�
+ - 500锛屾湇鍔″唴閮ㄥ紓甯�
+
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/chat-messages" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": ${JSON.stringify(props.inputs)},\n "query": "What are the specs of the iPhone 13 Pro Max?",\n "response_mode": "streaming",\n "conversation_id": "",\n "user": "abc-123",\n "files": [\n {\n "type": "image",\n "transfer_method": "remote_url",\n "url": "https://cloud.dify.ai/logo/logo-site.png"\n }\n ]\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {
+ "name": "dify"
+ },
+ "query": "What are the specs of the iPhone 13 Pro Max?",
+ "conversation_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "response_mode": "streaming",
+ "user": "abc-123",
+ "files": [
+ {
+ "type": "image",
+ "transfer_method": "remote_url",
+ "url": "https://cloud.dify.ai/logo/logo-site.png"
+ }
+ ]
+ }'
+ ```
+
+ </CodeGroup>
+ ### 闃诲妯″紡
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "event": "message",
+ "task_id": "c3800678-a077-43df-a102-53f23ed20b88",
+ "id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "message_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2",
+ "mode": "chat",
+ "answer": "iPhone 13 Pro Max specs are listed here:...",
+ "metadata": {
+ "usage": {
+ "prompt_tokens": 1033,
+ "prompt_unit_price": "0.001",
+ "prompt_price_unit": "0.001",
+ "prompt_price": "0.0010330",
+ "completion_tokens": 128,
+ "completion_unit_price": "0.002",
+ "completion_price_unit": "0.001",
+ "completion_price": "0.0002560",
+ "total_tokens": 1161,
+ "total_price": "0.0012890",
+ "currency": "USD",
+ "latency": 0.7682376249867957
+ },
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ]
+ },
+ "created_at": 1705407629
+ }
+ ```
+ </CodeGroup>
+ ### 娴佸紡妯″紡锛堝熀纭�鍔╂墜锛�
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " I", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": "'m", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " glad", "created_at": 1679586595}
+ data: {"event": "message", "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " to", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " meet", "created_at": 1679586595}
+ data: {"event": "message", "message_id" : "5ad4cb98-f0c7-4085-b384-88c403be6290", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "answer": " you", "created_at": 1679586595}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+
+ ### 娴佸紡妯″紡锛堟櫤鑳藉姪鎵嬶級
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "agent_thought", "id": "8dcf3648-fbad-407a-85dd-73a6f43aeb9f", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 1, "thought": "", "observation": "", "tool": "", "tool_input": "", "created_at": 1705639511, "message_files": [], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "agent_thought", "id": "8dcf3648-fbad-407a-85dd-73a6f43aeb9f", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 1, "thought": "", "observation": "", "tool": "dalle3", "tool_input": "{\"dalle3\": {\"prompt\": \"cute Japanese anime girl with white hair, blue eyes, bunny girl suit\"}}", "created_at": 1705639511, "message_files": [], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "message_file", "id": "d75b7a5c-ce5e-442e-ab1b-d6a5e5b557b0", "type": "image", "belongs_to": "assistant", "url": "http://127.0.0.1:5001/files/tools/d75b7a5c-ce5e-442e-ab1b-d6a5e5b557b0.png?timestamp=1705639526&nonce=70423256c60da73a9c96d1385ff78487&sign=7B5fKV9890YJuqchQvrABvW4AIupDvDvxGdu1EOJT94=", "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "agent_thought", "id": "8dcf3648-fbad-407a-85dd-73a6f43aeb9f", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 1, "thought": "", "observation": "image has been created and sent to user already, you should tell user to check it now.", "tool": "dalle3", "tool_input": "{\"dalle3\": {\"prompt\": \"cute Japanese anime girl with white hair, blue eyes, bunny girl suit\"}}", "created_at": 1705639511, "message_files": ["d75b7a5c-ce5e-442e-ab1b-d6a5e5b557b0"], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "agent_thought", "id": "67a99dc1-4f82-42d3-b354-18d4594840c8", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 2, "thought": "", "observation": "", "tool": "", "tool_input": "", "created_at": 1705639511, "message_files": [], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "agent_message", "id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "answer": "I have created an image of a cute Japanese", "created_at": 1705639511, "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "agent_message", "id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "answer": " anime girl with white hair and blue", "created_at": 1705639511, "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "agent_message", "id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "answer": " eyes wearing a bunny girl" ,"created_at": 1705639511, "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "agent_message", "id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "answer": " suit .", "created_at": 1705639511, "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "agent_thought", "id": "67a99dc1-4f82-42d3-b354-18d4594840c8", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 2, "thought": "I have created an image of a cute Japanese anime girl with white hair and blue eyes wearing a bunny girl suit.", "observation": "", "tool": "", "tool_input": "", "created_at": 1705639511, "message_files": [], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
+ data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='涓婁紶鏂囦欢'
+ name='#files-upload'
+/>
+<Row>
+ <Col>
+ 涓婁紶鏂囦欢锛堢洰鍓嶄粎鏀寔鍥剧墖锛夊苟鍦ㄥ彂閫佹秷鎭椂浣跨敤锛屽彲瀹炵幇鍥炬枃澶氭ā鎬佺悊瑙c��
+ 鏀寔 png, jpg, jpeg, webp, gif 鏍煎紡銆�
+ <i>涓婁紶鐨勬枃浠朵粎渚涘綋鍓嶇粓绔敤鎴蜂娇鐢ㄣ��</i>
+
+ ### Request Body
+ 璇ユ帴鍙i渶浣跨敤 `multipart/form-data` 杩涜璇锋眰銆�
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ 瑕佷笂浼犵殑鏂囦欢銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屽繀椤诲拰鍙戦�佹秷鎭帴鍙d紶鍏� user 淇濇寔涓�鑷淬��
+ </Property>
+ </Properties>
+
+ ### Response
+ 鎴愬姛涓婁紶鍚庯紝鏈嶅姟鍣ㄤ細杩斿洖鏂囦欢鐨� ID 鍜岀浉鍏充俊鎭��
+ - `id` (uuid) ID
+ - `name` (string) 鏂囦欢鍚�
+ - `size` (int) 鏂囦欢澶у皬锛坆yte锛�
+ - `extension` (string) 鏂囦欢鍚庣紑
+ - `mime_type` (string) 鏂囦欢 mime-type
+ - `created_by` (uuid) 涓婁紶浜� ID
+ - `created_at` (timestamp) 涓婁紶鏃堕棿
+
+ ### Errors
+ - 400锛宍no_file_uploaded`锛屽繀椤绘彁渚涙枃浠�
+ - 400锛宍too_many_files`锛岀洰鍓嶅彧鎺ュ彈涓�涓枃浠�
+ - 400锛宍unsupported_preview`锛岃鏂囦欢涓嶆敮鎸侀瑙�
+ - 400锛宍unsupported_estimate`锛岃鏂囦欢涓嶆敮鎸佷及绠�
+ - 413锛宍file_too_large`锛屾枃浠跺お澶�
+ - 415锛宍unsupported_file_type`锛屼笉鏀寔鐨勬墿灞曞悕锛屽綋鍓嶅彧鎺ュ彈鏂囨。绫绘枃浠�
+ - 503锛宍s3_connection_failed`锛屾棤娉曡繛鎺ュ埌 S3 鏈嶅姟
+ - 503锛宍s3_permission_denied`锛屾棤鏉冮檺涓婁紶鏂囦欢鍒� S3
+ - 503锛宍s3_file_too_large`锛屾枃浠惰秴鍑� S3 澶у皬闄愬埗
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": 123,
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+<Heading
+ url='/chat-messages/:task_id/stop'
+ method='POST'
+ title='鍋滄鍝嶅簲'
+ name='#Stop'
+/>
+<Row>
+ <Col>
+ 浠呮敮鎸佹祦寮忔ā寮忋��
+ ### Path
+ - `task_id` (string) 浠诲姟 ID锛屽彲鍦ㄦ祦寮忚繑鍥� Chunk 涓幏鍙�
+
+ ### Request Body
+ - `user` (string) Required
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屽繀椤诲拰鍙戦�佹秷鎭帴鍙d紶鍏� user 淇濇寔涓�鑷淬��
+ ### Response
+ - `result` (string) 鍥哄畾杩斿洖 success
+ </Col>
+ <Col sticky>
+ <CodeGroup title="Request" tag="POST" label="/chat-messages/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{ "user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/chat-messages/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/messages/:message_id/feedbacks'
+ method='POST'
+ title='娑堟伅鍙嶉锛堢偣璧烇級'
+ name='#feedbacks'
+/>
+<Row>
+ <Col>
+ 娑堟伅缁堢鐢ㄦ埛鍙嶉銆佺偣璧烇紝鏂逛究搴旂敤寮�鍙戣�呬紭鍖栬緭鍑洪鏈熴��
+
+ ### Path Params
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ 娑堟伅 ID
+ </Property>
+ </Properties>
+
+ ### Request Body
+
+ <Properties>
+ <Property name='rating' type='string' key='rating'>
+ 鐐硅禐 like, 鐐硅俯 dislike, 鎾ら攢鐐硅禐 null
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='content' type='string' key='content'>
+ 娑堟伅鍙嶉鐨勫叿浣撲俊鎭��
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) 鍥哄畾杩斿洖 success
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/messages/:message_id/feedbacks" targetCode={`curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "rating": "like",\n "user": "abc-123",\n "content": "message feedback information"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/messages/:message_id/feedbacks' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "rating": "like",
+ "user": "abc-123",
+ "content": "message feedback information"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/app/feedbacks'
+ method='GET'
+ title='鑾峰彇APP鐨勬秷鎭偣璧炲拰鍙嶉'
+ name='#app-feedbacks'
+/>
+<Row>
+ <Col>
+ 鑾峰彇搴旂敤鐨勭粓绔敤鎴峰弽棣堛�佺偣璧炪��
+
+ ### Query
+ <Properties>
+ <Property name='page' type='string' key='page'>
+ 锛堥�夊~锛夊垎椤碉紝榛樿鍊硷細1
+ </Property>
+ </Properties>
+
+ <Properties>
+ <Property name='limit' type='string' key='limit'>
+ 锛堥�夊~锛夋瘡椤垫暟閲忥紝榛樿鍊硷細20
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (List) 杩斿洖璇PP鐨勭偣璧炪�佸弽棣堝垪琛ㄣ��
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/app/feedbacks" targetCode={`curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/app/feedbacks?page=1&limit=20' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "data": [
+ {
+ "id": "8c0fbed8-e2f9-49ff-9f0e-15a35bdd0e25",
+ "app_id": "f252d396-fe48-450e-94ec-e184218e7346",
+ "conversation_id": "2397604b-9deb-430e-b285-4726e51fd62d",
+ "message_id": "709c0b0f-0a96-4a4e-91a4-ec0889937b11",
+ "rating": "like",
+ "content": "message feedback information-3",
+ "from_source": "user",
+ "from_end_user_id": "74286412-9a1a-42c1-929c-01edb1d381d5",
+ "from_account_id": null,
+ "created_at": "2025-04-24T09:24:38",
+ "updated_at": "2025-04-24T09:24:38"
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/messages/{message_id}/suggested'
+ method='GET'
+ title='鑾峰彇涓嬩竴杞缓璁棶棰樺垪琛�'
+ name='#suggested'
+/>
+<Row>
+ <Col>
+ 鑾峰彇涓嬩竴杞缓璁棶棰樺垪琛ㄣ��
+
+ ### Path Params
+
+ <Properties>
+ <Property name='message_id' type='string' key='message_id'>
+ Message ID
+ </Property>
+ </Properties>
+
+ ### Query
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/messages/{message_id}/suggested" targetCode={`curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested?user=abc-123 \\\n--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \\\n--header 'Content-Type: application/json'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.appDetail.api_base_url}/messages/{message_id}/suggested' \
+ --header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
+ --header 'Content-Type: application/json' \
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success",
+ "data": [
+ "a",
+ "b",
+ "c"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+---
+
+<Heading
+ url='/messages'
+ method='GET'
+ title='鑾峰彇浼氳瘽鍘嗗彶娑堟伅'
+ name='#messages'
+/>
+<Row>
+ <Col>
+ 婊氬姩鍔犺浇褰㈠紡杩斿洖鍘嗗彶鑱婂ぉ璁板綍锛岀涓�椤佃繑鍥炴渶鏂� `limit` 鏉★紝鍗筹細鍊掑簭杩斿洖銆�
+
+ ### Query
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 浼氳瘽 ID
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='first_id' type='string' key='first_id'>
+ 褰撳墠椤电涓�鏉¤亰澶╄褰曠殑 ID锛岄粯璁� null
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 涓�娆¤姹傝繑鍥炲灏戞潯鑱婂ぉ璁板綍锛岄粯璁� 20 鏉°��
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (array[object]) 娑堟伅鍒楄〃
+ - `id` (string) 娑堟伅 ID
+ - `conversation_id` (string) 浼氳瘽 ID
+ - `inputs` (object) 鐢ㄦ埛杈撳叆鍙傛暟銆�
+ - `query` (string) 鐢ㄦ埛杈撳叆 / 鎻愰棶鍐呭銆�
+ - `message_files` (array[object]) 娑堟伅鏂囦欢
+ - `id` (string) ID
+ - `type` (string) 鏂囦欢绫诲瀷锛宨mage 鍥剧墖
+ - `url` (string) 棰勮鍥剧墖鍦板潃
+ - `belongs_to` (string) 鏂囦欢褰掑睘鏂癸紝user 鎴� assistant
+ - `agent_thoughts` (array[object]) Agent鎬濊�冨唴瀹癸紙浠匒gent妯″紡涓嬩笉涓虹┖锛�
+ - `id` (string) agent_thought ID锛屾瘡涓�杞瓵gent杩唬閮戒細鏈変竴涓敮涓�鐨刬d
+ - `message_id` (string) 娑堟伅鍞竴ID
+ - `position` (int) agent_thought鍦ㄦ秷鎭腑鐨勪綅缃紝濡傜涓�杞凯浠osition涓�1
+ - `thought` (string) agent鐨勬�濊�冨唴瀹�
+ - `observation` (string) 宸ュ叿璋冪敤鐨勮繑鍥炵粨鏋�
+ - `tool` (string) 浣跨敤鐨勫伐鍏峰垪琛紝浠� ; 鍒嗗壊澶氫釜宸ュ叿
+ - `tool_input` (string) 宸ュ叿鐨勮緭鍏ワ紝JSON鏍煎紡鐨勫瓧绗︿覆(object)銆傚锛歚{"dalle3": {"prompt": "a cute cat"}}`
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `message_files` (array[string]) 褰撳墠agent_thought 鍏宠仈鐨勬枃浠禝D
+ - `file_id` (string) 鏂囦欢ID
+ - `conversation_id` (string) 浼氳瘽ID
+ - `answer` (string) 鍥炵瓟娑堟伅鍐呭
+ - `created_at` (timestamp) 鍒涘缓鏃堕棿
+ - `feedback` (object) 鍙嶉淇℃伅
+ - `rating` (string) 鐐硅禐 like / 鐐硅俯 dislike
+ - `retriever_resources` (array[RetrieverResource]) 寮曠敤鍜屽綊灞炲垎娈靛垪琛�
+ - `has_more` (bool) 鏄惁瀛樺湪涓嬩竴椤�
+ - `limit` (int) 杩斿洖鏉℃暟锛岃嫢浼犲叆瓒呰繃绯荤粺闄愬埗锛岃繑鍥炵郴缁熼檺鍒舵暟閲�
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="GET" label="/messages" targetCode={`curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id=' \\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/messages?user=abc-123&conversation_id='
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ ### Response Example(鍩虹鍔╂墜)
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "a076a87f-31e5-48dc-b452-0061adbbc922",
+ "conversation_id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
+ "inputs": {
+ "name": "dify"
+ },
+ "query": "iphone 13 pro",
+ "answer": "The iPhone 13 Pro, released on September 24, 2021, features a 6.1-inch display with a resolution of 1170 x 2532. It is equipped with a Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard) processor, 6 GB of RAM, and offers storage options of 128 GB, 256 GB, 512 GB, and 1 TB. The camera is 12 MP, the battery capacity is 3095 mAh, and it runs on iOS 15.",
+ "message_files": [],
+ "feedback": null,
+ "retriever_resources": [
+ {
+ "position": 1,
+ "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb",
+ "dataset_name": "iPhone",
+ "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00",
+ "document_name": "iPhone List",
+ "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a",
+ "score": 0.98457545,
+ "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""
+ }
+ ],
+ "agent_thoughts": [],
+ "created_at": 1705569239
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+
+ ### Response Example(鏅鸿兘鍔╂墜)
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "conversation_id": "957c068b-f258-4f89-ba10-6e8a0361c457",
+ "inputs": {},
+ "query": "draw a cat",
+ "answer": "I have generated an image of a cat for you. Please check your messages to view the image.",
+ "message_files": [
+ {
+ "id": "976990d2-5294-47e6-8f14-7356ba9d2d76",
+ "type": "image",
+ "url": "http://127.0.0.1:5001/files/tools/976990d2-5294-47e6-8f14-7356ba9d2d76.png?timestamp=1705988524&nonce=55df3f9f7311a9acd91bf074cd524092&sign=z43nMSO1L2HBvoqADLkRxr7Biz0fkjeDstnJiCK1zh8=",
+ "belongs_to": "assistant"
+ }
+ ],
+ "feedback": null,
+ "retriever_resources": [],
+ "created_at": 1705988187,
+ "agent_thoughts": [
+ {
+ "id": "592c84cf-07ee-441c-9dcc-ffc66c033469",
+ "chain_id": null,
+ "message_id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "position": 1,
+ "thought": "",
+ "tool": "dalle2",
+ "tool_input": "{\"dalle2\": {\"prompt\": \"cat\"}}",
+ "created_at": 1705988186,
+ "observation": "image has been created and sent to user already, you should tell user to check it now.",
+ "files": [
+ "976990d2-5294-47e6-8f14-7356ba9d2d76"
+ ]
+ },
+ {
+ "id": "73ead60d-2370-4780-b5ed-532d2762b0e5",
+ "chain_id": null,
+ "message_id": "d35e006c-7c4d-458f-9142-be4930abdf94",
+ "position": 2,
+ "thought": "I have generated an image of a cat for you. Please check your messages to view the image.",
+ "tool": "",
+ "tool_input": "",
+ "created_at": 1705988199,
+ "observation": "",
+ "files": []
+ }
+ ]
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations'
+ method='GET'
+ title='鑾峰彇浼氳瘽鍒楄〃'
+ name='#conversations'
+/>
+<Row>
+ <Col>
+ 鑾峰彇褰撳墠鐢ㄦ埛鐨勪細璇濆垪琛紝榛樿杩斿洖鏈�杩戠殑 20 鏉°��
+
+ ### Query
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ 锛堥�夊~锛夊綋鍓嶉〉鏈�鍚庨潰涓�鏉¤褰曠殑 ID锛岄粯璁� null
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 锛堥�夊~锛変竴娆¤姹傝繑鍥炲灏戞潯璁板綍锛岄粯璁� 20 鏉★紝鏈�澶� 100 鏉★紝鏈�灏� 1 鏉°��
+ </Property>
+ <Property name='sort_by' type='string' key='sort_by'>
+ 锛堥�夊~锛夋帓搴忓瓧娈碉紝榛樿 -updated_at(鎸夋洿鏂版椂闂村�掑簭鎺掑垪)
+ - 鍙�夊�硷細created_at, -created_at, updated_at, -updated_at
+ - 瀛楁鍓嶉潰鐨勭鍙蜂唬琛ㄩ『搴忔垨鍊掑簭锛�-浠h〃鍊掑簭
+ </Property>
+ </Properties>
+
+ ### Response
+ - `data` (array[object]) 浼氳瘽鍒楄〃
+ - `id` (string) 浼氳瘽 ID
+ - `name` (string) 浼氳瘽鍚嶇О锛岄粯璁や负浼氳瘽涓敤鎴锋渶寮�濮嬮棶棰樼殑鎴彇銆�
+ - `inputs` (object) 鐢ㄦ埛杈撳叆鍙傛暟銆�
+ - `status` (string) 浼氳瘽鐘舵��
+ - `introduction` (string) 寮�鍦虹櫧
+ - `created_at` (timestamp) 鍒涘缓鏃堕棿
+ - `updated_at` (timestamp) 鏇存柊鏃堕棿
+ - `has_more` (bool)
+ - `limit` (int) 杩斿洖鏉℃暟锛岃嫢浼犲叆瓒呰繃绯荤粺闄愬埗锛岃繑鍥炵郴缁熼檺鍒舵暟閲�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20'\\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations?user=abc-123&last_id=&limit=20' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 20,
+ "has_more": false,
+ "data": [
+ {
+ "id": "10799fb8-64f7-4296-bbf7-b42bfbe0ae54",
+ "name": "New chat",
+ "inputs": {
+ "book": "book",
+ "myName": "Lucy"
+ },
+ "status": "normal",
+ "created_at": 1679667915,
+ "updated_at": 1679667915
+ },
+ {
+ "id": "hSIhXBhNe8X1d8Et"
+ // ...
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+<Heading
+ url='/conversations/:conversation_id'
+ method='DELETE'
+ title='鍒犻櫎浼氳瘽'
+ name='#delete'
+/>
+<Row>
+ <Col>
+ 鍒犻櫎浼氳瘽銆�
+
+ ### Path
+ - `conversation_id` (string) 浼氳瘽 ID
+
+ ### Request Body
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+
+ ### Response
+ - `result` (string) 鍥哄畾杩斿洖 success
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="DELETE" label="/conversations/:conversation_id" targetCode={`curl -X DELETE '${props.appDetail.api_base_url}/conversations/:conversation_id' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X DELETE '${props.appDetail.api_base_url}/conversations/{conversation_id}' \
+ --header 'Content-Type: application/json' \
+ --header 'Accept: application/json' \
+ --header 'Authorization: Bearer {api_key}' \
+ --data '{
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```text {{ title: 'Response' }}
+ 204 No Content
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id/name'
+ method='POST'
+ title='浼氳瘽閲嶅懡鍚�'
+ name='#rename'
+/>
+<Row>
+ <Col>
+ 瀵逛細璇濊繘琛岄噸鍛藉悕锛屼細璇濆悕绉扮敤浜庢樉绀哄湪鏀寔澶氫細璇濈殑瀹㈡埛绔笂銆�
+
+ ### Path
+ - `conversation_id` (string) 浼氳瘽 ID
+
+ ### Request Body
+
+ <Properties>
+ <Property name='name' type='string' key='name'>
+ 锛堥�夊~锛夊悕绉帮紝鑻� `auto_generate` 涓� `true` 鏃讹紝璇ュ弬鏁板彲涓嶄紶銆�
+ </Property>
+ <Property name='auto_generate' type='bool' key='auto_generate'>
+ 锛堥�夊~锛夎嚜鍔ㄧ敓鎴愭爣棰橈紝榛樿 false銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+
+ ### Response
+ - `id` (string) 浼氳瘽 ID
+ - `name` (string) 浼氳瘽鍚嶇О
+ - `inputs` (object) 鐢ㄦ埛杈撳叆鍙傛暟
+ - `status` (string) 浼氳瘽鐘舵��
+ - `introduction` (string) 寮�鍦虹櫧
+ - `created_at` (timestamp) 鍒涘缓鏃堕棿
+ - `updated_at` (timestamp) 鏇存柊鏃堕棿
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "name": "",
+ "auto_generate": true,
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "34d511d5-56de-4f16-a997-57b379508443",
+ "name": "hello",
+ "inputs": {},
+ "status": "normal",
+ "introduction": "",
+ "created_at": 1732731141,
+ "updated_at": 1732734510
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/conversations/:conversation_id/variables'
+ method='GET'
+ title='鑾峰彇瀵硅瘽鍙橀噺'
+ name='#conversation-variables'
+/>
+<Row>
+ <Col>
+ 浠庣壒瀹氬璇濅腑妫�绱㈠彉閲忋�傛绔偣瀵逛簬鎻愬彇瀵硅瘽杩囩▼涓崟鑾风殑缁撴瀯鍖栨暟鎹潪甯告湁鐢ㄣ��
+
+ ### 璺緞鍙傛暟
+
+ <Properties>
+ <Property name='conversation_id' type='string' key='conversation_id'>
+ 瑕佷粠涓绱㈠彉閲忕殑瀵硅瘽ID銆�
+ </Property>
+ </Properties>
+
+ ### 鏌ヨ鍙傛暟
+
+ <Properties>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑绗︼紝鐢卞紑鍙戜汉鍛樺畾涔夌殑瑙勫垯锛屽湪搴旂敤绋嬪簭鍐呭繀椤诲敮涓�銆�
+ </Property>
+ <Property name='last_id' type='string' key='last_id'>
+ 锛堥�夊~锛夊綋鍓嶉〉鏈�鍚庨潰涓�鏉¤褰曠殑 ID锛岄粯璁� null
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 锛堥�夊~锛変竴娆¤姹傝繑鍥炲灏戞潯璁板綍锛岄粯璁� 20 鏉★紝鏈�澶� 100 鏉★紝鏈�灏� 1 鏉°��
+ </Property>
+ </Properties>
+
+ ### 鍝嶅簲
+
+ - `limit` (int) 姣忛〉椤圭洰鏁�
+ - `has_more` (bool) 鏄惁鏈夋洿澶氶」鐩�
+ - `data` (array[object]) 鍙橀噺鍒楄〃
+ - `id` (string) 鍙橀噺ID
+ - `name` (string) 鍙橀噺鍚嶇О
+ - `value_type` (string) 鍙橀噺绫诲瀷锛堝瓧绗︿覆銆佹暟瀛椼�佸竷灏旂瓑锛�
+ - `value` (string) 鍙橀噺鍊�
+ - `description` (string) 鍙橀噺鎻忚堪
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴�
+ - `updated_at` (int) 鏈�鍚庢洿鏂版椂闂存埑
+
+ ### 閿欒
+ - 404, `conversation_not_exists`, 瀵硅瘽涓嶅瓨鍦�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/conversations/:conversation_id/variables" targetCode={`curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Request with variable name filter">
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/conversations/{conversation_id}/variables?user=abc-123&variable_name=customer_name' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "limit": 100,
+ "has_more": false,
+ "data": [
+ {
+ "id": "variable-uuid-1",
+ "name": "customer_name",
+ "value_type": "string",
+ "value": "John Doe",
+ "description": "瀹㈡埛鍚嶇О锛堜粠瀵硅瘽涓彁鍙栵級",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ },
+ {
+ "id": "variable-uuid-2",
+ "name": "order_details",
+ "value_type": "json",
+ "value": "{\"product\":\"Widget\",\"quantity\":5,\"price\":19.99}",
+ "description": "瀹㈡埛鐨勮鍗曡鎯�",
+ "created_at": 1650000000000,
+ "updated_at": 1650000000000
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/audio-to-text'
+ method='POST'
+ title='璇煶杞枃瀛�'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ ### Request Body
+ 璇ユ帴鍙i渶浣跨敤 `multipart/form-data` 杩涜璇锋眰銆�
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ 璇煶鏂囦欢銆�
+ 鏀寔鏍煎紡锛歚['mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm']`
+ 鏂囦欢澶у皬闄愬埗锛�15MB
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+
+ ### Response
+ - `text` (string) 杈撳嚭鏂囧瓧
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/audio-to-text" targetCode={`curl -X POST '${props.appDetail.api_base_url}/audio-to-text' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=audio/[mp3|mp4|mpeg|mpga|m4a|wav|webm]`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/conversations/name' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@localfile;type=audio/mp3'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "text": "hello"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/text-to-audio'
+ method='POST'
+ title='鏂囧瓧杞闊�'
+ name='#audio'
+/>
+<Row>
+ <Col>
+ 鏂囧瓧杞闊炽��
+
+ ### Request Body
+
+ <Properties>
+ <Property name='message_id' type='str' key='message_id'>
+ Dify 鐢熸垚鐨勬枃鏈秷鎭紝閭d箞鐩存帴浼犻�掔敓鎴愮殑message-id 鍗冲彲锛屽悗鍙颁細閫氳繃 message_id 鏌ユ壘鐩稿簲鐨勫唴瀹圭洿鎺ュ悎鎴愯闊充俊鎭�傚鏋滃悓鏃朵紶 message_id 鍜� text锛屼紭鍏堜娇鐢� message_id銆�
+ </Property>
+ <Property name='text' type='str' key='text'>
+ 璇煶鐢熸垚鍐呭銆傚鏋滄病鏈変紶 message-id鐨勮瘽锛屽垯浼氫娇鐢ㄨ繖涓瓧娈电殑鍐呭
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敱寮�鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+ </Property>
+ </Properties>
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl --location --request POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \\\n--form 'text=浣犲ソDify;user=abc-123;message_id=5ad4cb98-f0c7-4085-b384-88c403be6290`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.appDetail.api_base_url}/text-to-audio' \
+ --header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
+ --form 'file=浣犲ソDify;user=abc-123;message_id=5ad4cb98-f0c7-4085-b384-88c403be6290'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="headers">
+ ```json {{ title: 'headers' }}
+ {
+ "Content-Type": "audio/wav"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='鑾峰彇搴旂敤鍩烘湰淇℃伅'
+ name='#info'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇搴旂敤鐨勫熀鏈俊鎭�
+ ### Response
+ - `name` (string) 搴旂敤鍚嶇О
+ - `description` (string) 搴旂敤鎻忚堪
+ - `tags` (array[string]) 搴旂敤鏍囩
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='鑾峰彇搴旂敤鍙傛暟'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬杩涘叆椤甸潰涓�寮�濮嬶紝鑾峰彇鍔熻兘寮�鍏炽�佽緭鍏ュ弬鏁板悕绉般�佺被鍨嬪強榛樿鍊肩瓑浣跨敤銆�
+
+ ### Response
+ - `opening_statement` (string) 寮�鍦虹櫧
+ - `suggested_questions` (array[string]) 寮�鍦烘帹鑽愰棶棰樺垪琛�
+ - `suggested_questions_after_answer` (object) 鍚敤鍥炵瓟鍚庣粰鍑烘帹鑽愰棶棰樸��
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `speech_to_text` (object) 璇煶杞枃鏈�
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `retriever_resource` (object) 寮曠敤鍜屽綊灞�
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `annotation_reply` (object) 鏍囪鍥炲
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `user_input_form` (array[object]) 鐢ㄦ埛杈撳叆琛ㄥ崟閰嶇疆
+ - `text-input` (object) 鏂囨湰杈撳叆鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `paragraph` (object) 娈佃惤鏂囨湰杈撳叆鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `select` (object) 涓嬫媺鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `options` (array[string]) 閫夐」鍊�
+ - `file_upload` (object) 鏂囦欢涓婁紶閰嶇疆
+ - `image` (object) 鍥剧墖璁剧疆
+ 褰撳墠浠呮敮鎸佸浘鐗囩被鍨嬶細`png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `number_limits` (int) 鍥剧墖鏁伴噺闄愬埗锛岄粯璁� 3
+ - `transfer_methods` (array[string]) 浼犻�掓柟寮忓垪琛紝remote_url , local_file锛屽繀閫変竴涓�
+ - `system_parameters` (object) 绯荤粺鍙傛暟
+ - `file_size_limit` (int) 鏂囨。涓婁紶澶у皬闄愬埗 (MB)
+ - `image_file_size_limit` (int) 鍥剧墖鏂囦欢涓婁紶澶у皬闄愬埗锛圡B锛�
+ - `audio_file_size_limit` (int) 闊抽鏂囦欢涓婁紶澶у皬闄愬埗 (MB)
+ - `video_file_size_limit` (int) 瑙嗛鏂囦欢涓婁紶澶у皬闄愬埗 (MB)
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'\\\n--header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "introduction": "nice to meet you",
+ "user_input_form": [
+ {
+ "text-input": {
+ "label": "a",
+ "variable": "a",
+ "required": true,
+ "max_length": 48,
+ "default": ""
+ }
+ },
+ {
+ // ...
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": true,
+ "number_limits": 3,
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/meta'
+ method='GET'
+ title='鑾峰彇搴旂敤Meta淇℃伅'
+ name='#meta'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇宸ュ叿icon
+ ### Response
+ - `tool_icons`(object[string]) 宸ュ叿鍥炬爣
+ - `宸ュ叿鍚嶇О` (string)
+ - `icon` (object|string)
+ - (object) 鍥炬爣
+ - `background` (string) hex鏍煎紡鐨勮儗鏅壊
+ - `content`(string) emoji
+ - (string) 鍥炬爣URL
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/meta' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/meta' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "tool_icons": {
+ "dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
+ "api_tool": {
+ "background": "#252525",
+ "content": "\ud83d\ude01"
+ }
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='鑾峰彇搴旂敤 WebApp 璁剧疆'
+ name='#site'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇搴旂敤鐨� WebApp 璁剧疆
+ ### Response
+ - `title` (string) WebApp 鍚嶇О
+ - `chat_color_theme` (string) 鑱婂ぉ棰滆壊涓婚, hex 鏍煎紡
+ - `chat_color_theme_inverted` (bool) 鑱婂ぉ棰滆壊涓婚鏄惁鍙嶈浆
+ - `icon_type` (string) 鍥炬爣绫诲瀷, `emoji`-琛ㄦ儏, `image`-鍥剧墖
+ - `icon` (string) 鍥炬爣, 濡傛灉鏄� `emoji` 绫诲瀷, 鍒欐槸 emoji 琛ㄦ儏绗﹀彿, 濡傛灉鏄� `image` 绫诲瀷, 鍒欐槸鍥剧墖 URL
+ - `icon_background` (string) hex 鏍煎紡鐨勮儗鏅壊
+ - `icon_url` (string) 鍥炬爣 URL
+ - `description` (string) 鎻忚堪
+ - `copyright` (string) 鐗堟潈淇℃伅
+ - `privacy_policy` (string) 闅愮鏀跨瓥閾炬帴
+ - `custom_disclaimer` (string) 鑷畾涔夊厤璐e0鏄�
+ - `default_language` (string) 榛樿璇█
+ - `show_workflow_steps` (bool) 鏄惁鏄剧ず宸ヤ綔娴佽鎯�
+ - `use_icon_as_answer_icon` (bool) 鏄惁浣跨敤 WebApp 鍥炬爣鏇挎崲鑱婂ぉ涓殑 馃
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "chat_color_theme": "#ff4a4a",
+ "chat_color_theme_inverted": false,
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ "use_icon_as_answer_icon": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
diff --git a/app/components/develop/template/template_workflow.en.mdx b/app/components/develop/template/template_workflow.en.mdx
new file mode 100644
index 0000000..2afcedc
--- /dev/null
+++ b/app/components/develop/template/template_workflow.en.mdx
@@ -0,0 +1,792 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx'
+
+# Workflow App API
+
+Workflow applications offers non-session support and is ideal for translation, article writing, summarization AI, and more.
+
+<div>
+ ### Base URL
+ <CodeGroup title="Code" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### Authentication
+
+ The Service API uses `API-Key` authentication.
+ <i>**Strongly recommend storing your API Key on the server-side, not shared or stored on the client-side, to avoid possible API-Key leakage that can lead to serious consequences.**</i>
+
+ For all API requests, include your API Key in the `Authorization` HTTP Header, as shown below:
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/workflows/run'
+ method='POST'
+ title='Execute Workflow'
+ name='#Execute-Workflow'
+/>
+<Row>
+ <Col>
+ Execute workflow, cannot be executed without a published workflow.
+
+ ### Request Body
+ - `inputs` (object) Required
+ Allows the entry of various variable values defined by the App.
+ The `inputs` parameter contains multiple key/value pairs, with each key corresponding to a specific variable and each value being the specific value for that variable.
+ The workflow application requires at least one key/value pair to be inputted. The variable can be of File Array type.
+ File Array type variable is suitable for inputting files combined with text understanding and answering questions, available only when the model supports file parsing and understanding capability.
+ If the variable is of File Array type, the corresponding value should be a list whose elements contain following attributions:
+ - `type` (string) Supported type:
+ - `document` ('TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB')
+ - `image` ('JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG')
+ - `audio` ('MP3', 'M4A', 'WAV', 'WEBM', 'AMR')
+ - `video` ('MP4', 'MOV', 'MPEG', 'MPGA')
+ - `custom` (Other file types)
+ - `transfer_method` (string) Transfer method, `remote_url` for image URL / `local_file` for file upload
+ - `url` (string) Image URL (when the transfer method is `remote_url`)
+ - `upload_file_id` (string) Uploaded file ID, which must be obtained by uploading through the File Upload API in advance (when the transfer method is `local_file`)
+
+ - `response_mode` (string) Required
+ The mode of response return, supporting:
+ - `streaming` Streaming mode (recommended), implements a typewriter-like output through SSE ([Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)).
+ - `blocking` Blocking mode, returns result after execution is complete. (Requests may be interrupted if the process is long)
+ <i>Due to Cloudflare restrictions, the request will be interrupted without a return after 100 seconds.</i>
+ - `user` (string) Required
+ User identifier, used to define the identity of the end-user for retrieval and statistics.
+ Should be uniquely defined by the developer within the application.
+
+ ### Response
+ When `response_mode` is `blocking`, return a CompletionResponse object.
+ When `response_mode` is `streaming`, return a ChunkCompletionResponse stream.
+
+ ### CompletionResponse
+ Returns the App result, `Content-Type` is `application/json`.
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `data` (object) detail of result
+ - `id` (string) ID of workflow execution
+ - `workflow_id` (string) ID of related workflow
+ - `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped`
+ - `outputs` (json) Optional content of output
+ - `error` (string) Optional reason of error
+ - `elapsed_time` (float) Optional total seconds to be used
+ - `total_tokens` (int) Optional tokens to be used
+ - `total_steps` (int) default 0
+ - `created_at` (timestamp) start time
+ - `finished_at` (timestamp) end time
+
+ ### ChunkCompletionResponse
+ Returns the stream chunks outputted by the App, `Content-Type` is `text/event-stream`.
+ Each streaming chunk starts with `data:`, separated by two newline characters `\n\n`, as shown below:
+ <CodeGroup>
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "text_chunk", "workflow_run_id": "b85e5fc5-751b-454d-b14e-dc5f240b0a31", "task_id": "bd029338-b068-4d34-a331-fc85478922c2", "data": {"text": "\u4e3a\u4e86", "from_variable_selector": ["1745912968134", "text"]}}\n\n
+ ```
+ </CodeGroup>
+ The structure of the streaming chunks varies depending on the `event`:
+ - `event: workflow_started` workflow starts execution
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `event` (string) fixed to `workflow_started`
+ - `data` (object) detail
+ - `id` (string) Unique ID of workflow execution
+ - `workflow_id` (string) ID of related workflow
+ - `sequence_number` (int) Self-increasing serial number, self-increasing in the App, starting from 1
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+ - `event: node_started` node execution started
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `event` (string) fixed to `node_started`
+ - `data` (object) detail
+ - `id` (string) Unique ID of workflow execution
+ - `node_id` (string) ID of node
+ - `node_type` (string) type of node
+ - `title` (string) name of node
+ - `index` (int) Execution sequence number, used to display Tracing Node sequence
+ - `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path
+ - `inputs` (object) Contents of all preceding node variables used in the node
+ - `created_at` (timestamp) timestamp of start, e.g., 1705395332
+ - `event: text_chunk` Text fragment
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `event` (string) fixed to `text_chunk`
+ - `data` (object) detail
+ - `text` (string) Text content
+ - `from_variable_selector` (array) Text source path, helping developers understand which node and variable generated the text
+ - `event: node_finished` node execution ends, success or failure in different states in the same event
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `event` (string) fixed to `node_finished`
+ - `data` (object) detail
+ - `id` (string) Unique ID of workflow execution
+ - `node_id` (string) ID of node
+ - `node_type` (string) type of node
+ - `title` (string) name of node
+ - `index` (int) Execution sequence number, used to display Tracing Node sequence
+ - `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path
+ - `inputs` (object) Contents of all preceding node variables used in the node
+ - `process_data` (json) Optional node process data
+ - `outputs` (json) Optional content of output
+ - `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped`
+ - `error` (string) Optional reason of error
+ - `elapsed_time` (float) Optional total seconds to be used
+ - `execution_metadata` (json) meta data
+ - `total_tokens` (int) optional tokens to be used
+ - `total_price` (decimal) optional Total cost
+ - `currency` (string) optional e.g. `USD` / `RMB`
+ - `created_at` (timestamp) timestamp of start, e.g., 1705395332
+ - `event: workflow_finished` workflow execution ends, success or failure in different states in the same event
+ - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
+ - `workflow_run_id` (string) Unique ID of workflow execution
+ - `event` (string) fixed to `workflow_finished`
+ - `data` (object) detail
+ - `id` (string) ID of workflow execution
+ - `workflow_id` (string) ID of related workflow
+ - `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped`
+ - `outputs` (json) Optional content of output
+ - `error` (string) Optional reason of error
+ - `elapsed_time` (float) Optional total seconds to be used
+ - `total_tokens` (int) Optional tokens to be used
+ - `total_steps` (int) default 0
+ - `created_at` (timestamp) start time
+ - `finished_at` (timestamp) end time
+ - `event: tts_message` TTS audio stream event, that is, speech synthesis output. The content is an audio block in Mp3 format, encoded as a base64 string. When playing, simply decode the base64 and feed it into the player. (This message is available only when auto-play is enabled)
+ - `task_id` (string) Task ID, used for request tracking and the stop response interface below
+ - `message_id` (string) Unique message ID
+ - `audio` (string) The audio after speech synthesis, encoded in base64 text content, when playing, simply decode the base64 and feed it into the player
+ - `created_at` (int) Creation timestamp, e.g.: 1705395332
+ - `event: tts_message_end` TTS audio stream end event, receiving this event indicates the end of the audio stream.
+ - `task_id` (string) Task ID, used for request tracking and the stop response interface below
+ - `message_id` (string) Unique message ID
+ - `audio` (string) The end event has no audio, so this is an empty string
+ - `created_at` (int) Creation timestamp, e.g.: 1705395332
+ - `event: ping` Ping event every 10 seconds to keep the connection alive.
+
+ ### Errors
+ - 400, `invalid_param`, abnormal parameter input
+ - 400, `app_unavailable`, App configuration unavailable
+ - 400, `provider_not_initialize`, no available model credential configuration
+ - 400, `provider_quota_exceeded`, model invocation quota insufficient
+ - 400, `model_currently_not_support`, current model unavailable
+ - 400, `workflow_request_error`, workflow execution failed
+ - 500, internal server error
+
+ </Col>
+ <Col sticky>
+ <CodeGroup title="Request" tag="POST" label="/workflows/run" targetCode={`curl -X POST '${props.appDetail.api_base_url}/workflows/run' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": ${JSON.stringify(props.inputs)},\n "response_mode": "streaming",\n "user": "abc-123"\n}'\n`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/workflows/run' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {},
+ "response_mode": "streaming",
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+ <CodeGroup title="Example: file array as an input variable">
+ ```json {{ title: 'File variable example' }}
+ {
+ "inputs": {
+ "{variable_name}":
+ [
+ {
+ "transfer_method": "local_file",
+ "upload_file_id": "{upload_file_id}",
+ "type": "{document_type}"
+ }
+ ]
+ }
+ }
+ ```
+ </CodeGroup>
+ ### Blocking Mode
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "workflow_run_id": "djflajgkldjgd",
+ "task_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "data": {
+ "id": "fdlsjfjejkghjda",
+ "workflow_id": "fldjaslkfjlsda",
+ "status": "succeeded",
+ "outputs": {
+ "text": "Nice to meet you."
+ },
+ "error": null,
+ "elapsed_time": 0.875,
+ "total_tokens": 3562,
+ "total_steps": 8,
+ "created_at": 1705407629,
+ "finished_at": 1727807631
+ }
+ }
+ ```
+ </CodeGroup>
+ ### Streaming Mode
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}
+ data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}
+ data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}
+ data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ <CodeGroup title="File upload sample code">
+ ```json {{ title: 'File upload sample code' }}
+ import requests
+ import json
+
+ def upload_file(file_path, user):
+ upload_url = "https://api.dify.ai/v1/files/upload"
+ headers = {
+ "Authorization": "Bearer app-xxxxxxxx",
+ }
+
+ try:
+ print("Upload file...")
+ with open(file_path, 'rb') as file:
+ files = {
+ 'file': (file_path, file, 'text/plain') # Make sure the file is uploaded with the appropriate MIME type
+ }
+ data = {
+ "user": user,
+ "type": "TXT" # Set the file type to TXT
+ }
+
+ response = requests.post(upload_url, headers=headers, files=files, data=data)
+ if response.status_code == 201: # 201 means creation is successful
+ print("File uploaded successfully")
+ return response.json().get("id") # Get the uploaded file ID
+ else:
+ print(f"File upload failed, status code: {response.status_code}")
+ return None
+ except Exception as e:
+ print(f"Error occurred: {str(e)}")
+ return None
+
+ def run_workflow(file_id, user, response_mode="blocking"):
+ workflow_url = "https://api.dify.ai/v1/workflows/run"
+ headers = {
+ "Authorization": "Bearer app-xxxxxxxxx",
+ "Content-Type": "application/json"
+ }
+
+ data = {
+ "inputs": {
+ "orig_mail": [{
+ "transfer_method": "local_file",
+ "upload_file_id": file_id,
+ "type": "document"
+ }]
+ },
+ "response_mode": response_mode,
+ "user": user
+ }
+
+ try:
+ print("Run Workflow...")
+ response = requests.post(workflow_url, headers=headers, json=data)
+ if response.status_code == 200:
+ print("Workflow execution successful")
+ return response.json()
+ else:
+ print(f"Workflow execution failed, status code: {response.status_code}")
+ return {"status": "error", "message": f"Failed to execute workflow, status code: {response.status_code}"}
+ except Exception as e:
+ print(f"Error occurred: {str(e)}")
+ return {"status": "error", "message": str(e)}
+
+ # Usage Examples
+ file_path = "{your_file_path}"
+ user = "difyuser"
+
+ # Upload files
+ file_id = upload_file(file_path, user)
+ if file_id:
+ # The file was uploaded successfully, and the workflow continues to run
+ result = run_workflow(file_id, user)
+ print(result)
+ else:
+ print("File upload failed and workflow cannot be executed")
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/workflows/run/:workflow_id'
+ method='GET'
+ title='Get Workflow Run Detail'
+ name='#get-workflow-run-detail'
+/>
+<Row>
+ <Col>
+ Retrieve the current execution results of a workflow task based on the workflow execution ID.
+ ### Path
+ - `workflow_id` (string) Workflow ID, can be obtained from the streaming chunk return
+ ### Response
+ - `id` (string) ID of workflow execution
+ - `workflow_id` (string) ID of related workflow
+ - `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped`
+ - `inputs` (json) content of input
+ - `outputs` (json) content of output
+ - `error` (string) reason of error
+ - `total_steps` (int) total steps of task
+ - `total_tokens` (int) total tokens to be used
+ - `created_at` (timestamp) start time
+ - `finished_at` (timestamp) end time
+ - `elapsed_time` (float) total seconds to be used
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="GET" label="/workflows/run/:workflow_id" targetCode={`curl -X GET '${props.appDetail.api_base_url}/workflows/run/:workflow_id' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/workflows/run/:workflow_id' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "b1ad3277-089e-42c6-9dff-6820d94fbc76",
+ "workflow_id": "19eff89f-ec03-4f75-b0fc-897e7effea02",
+ "status": "succeeded",
+ "inputs": "{\"sys.files\": [], \"sys.user_id\": \"abc-123\"}",
+ "outputs": null,
+ "error": null,
+ "total_steps": 3,
+ "total_tokens": 0,
+ "created_at": 1705407629,
+ "finished_at": 1727807631,
+ "elapsed_time": 30.098514399956912
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/workflows/tasks/:task_id/stop'
+ method='POST'
+ title='Stop Generate'
+ name='#stop-generatebacks'
+/>
+<Row>
+ <Col>
+ Only supported in streaming mode.
+ ### Path
+ - `task_id` (string) Task ID, can be obtained from the streaming chunk return
+ ### Request Body
+ - `user` (string) Required
+ User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface.
+ ### Response
+ - `result` (string) Always returns "success"
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="POST" label="/workflows/tasks/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/workflows/tasks/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{"user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/workflows/tasks/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='File Upload'
+ name='#file-upload'
+/>
+<Row>
+ <Col>
+ Upload a file for use when sending messages, enabling multimodal understanding of images and text.
+ Supports any formats that are supported by your workflow.
+ Uploaded files are for use by the current end-user only.
+
+ ### Request Body
+ This interface requires a `multipart/form-data` request.
+ - `file` (File) Required
+ The file to be uploaded.
+ - `user` (string) Required
+ User identifier, defined by the developer's rules, must be unique within the application.
+
+ ### Response
+ After a successful upload, the server will return the file's ID and related information.
+ - `id` (uuid) ID
+ - `name` (string) File name
+ - `size` (int) File size (bytes)
+ - `extension` (string) File extension
+ - `mime_type` (string) File mime-type
+ - `created_by` (uuid) End-user ID
+ - `created_at` (timestamp) Creation timestamp, e.g., 1705395332
+
+ ### Errors
+ - 400, `no_file_uploaded`, a file must be provided
+ - 400, `too_many_files`, currently only one file is accepted
+ - 400, `unsupported_preview`, the file does not support preview
+ - 400, `unsupported_estimate`, the file does not support estimation
+ - 413, `file_too_large`, the file is too large
+ - 415, `unsupported_file_type`, unsupported extension, currently only document files are accepted
+ - 503, `s3_connection_failed`, unable to connect to S3 service
+ - 503, `s3_permission_denied`, no permission to upload files to S3
+ - 503, `s3_file_too_large`, file exceeds S3 size limit
+ - 500, internal server error
+
+
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": "6ad1ab0a-73ff-4ac1-b9e4-cdb312f71f13",
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/workflows/logs'
+ method='GET'
+ title='Get Workflow Logs'
+ name='#Get-Workflow-Logs'
+/>
+<Row>
+ <Col>
+ Returns workflow logs, with the first page returning the latest `{limit}` messages, i.e., in reverse order.
+
+ ### Query
+
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ Keyword to search
+ </Property>
+ <Property name='status' type='string' key='status'>
+ succeeded/failed/stopped
+ </Property>
+ <Property name='page' type='int' key='page'>
+ current page, default is 1.
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ How many chat history messages to return in one request, default is 20.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `page` (int) Current page
+ - `limit` (int) Number of returned items, if input exceeds system limit, returns system limit amount
+ - `total` (int) Number of total items
+ - `has_more` (bool) Whether there is a next page
+ - `data` (array[object]) Log list
+ - `id` (string) ID
+ - `workflow_run` (object) Workflow run
+ - `id` (string) ID
+ - `version` (string) Version
+ - `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped`
+ - `error` (string) Optional reason of error
+ - `elapsed_time` (float) total seconds to be used
+ - `total_tokens` (int) tokens to be used
+ - `total_steps` (int) default 0
+ - `created_at` (timestamp) start time
+ - `finished_at` (timestamp) end time
+ - `created_from` (string) Created from
+ - `created_by_role` (string) Created by role
+ - `created_by_account` (string) Optional Created by account
+ - `created_by_end_user` (object) Created by end user
+ - `id` (string) ID
+ - `type` (string) Type
+ - `is_anonymous` (bool) Is anonymous
+ - `session_id` (string) Session ID
+ - `created_at` (timestamp) create time
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/workflows/logs" targetCode={`curl -X GET '${props.appDetail.api_base_url}/workflows/logs'\\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/workflows/logs?limit=1'
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "page": 1,
+ "limit": 1,
+ "total": 7,
+ "has_more": true,
+ "data": [
+ {
+ "id": "e41b93f1-7ca2-40fd-b3a8-999aeb499cc0",
+ "workflow_run": {
+ "id": "c0640fc8-03ef-4481-a96c-8a13b732a36e",
+ "version": "2024-08-01 12:17:09.771832",
+ "status": "succeeded",
+ "error": null,
+ "elapsed_time": 1.3588523610014818,
+ "total_tokens": 0,
+ "total_steps": 3,
+ "created_at": 1726139643,
+ "finished_at": 1726139644
+ },
+ "created_from": "service-api",
+ "created_by_role": "end_user",
+ "created_by_account": null,
+ "created_by_end_user": {
+ "id": "7f7d9117-dd9d-441d-8970-87e5e7e687a3",
+ "type": "service_api",
+ "is_anonymous": false,
+ "session_id": "abc-123"
+ },
+ "created_at": 1726139644
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='Get Application Basic Information'
+ name='#info'
+/>
+<Row>
+ <Col>
+ Used to get basic information about this application
+
+ ### Response
+ - `name` (string) application name
+ - `description` (string) application description
+ - `tags` (array[string]) application tags
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='Get Application Parameters Information'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ Used at the start of entering the page to obtain information such as features, input parameter names, types, and default values.
+
+ ### Response
+ - `user_input_form` (array[object]) User input form configuration
+ - `text-input` (object) Text input control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `paragraph` (object) Paragraph text input control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `select` (object) Dropdown control
+ - `label` (string) Variable display label name
+ - `variable` (string) Variable ID
+ - `required` (bool) Whether it is required
+ - `default` (string) Default value
+ - `options` (array[string]) Option values
+ - `file_upload` (object) File upload configuration
+ - `image` (object) Image settings
+ Currently only supports image types: `png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) Whether it is enabled
+ - `number_limits` (int) Image number limit, default is 3
+ - `transfer_methods` (array[string]) List of transfer methods, remote_url, local_file, must choose one
+ - `system_parameters` (object) System parameters
+ - `file_size_limit` (int) Document upload size limit (MB)
+ - `image_file_size_limit` (int) Image file upload size limit (MB)
+ - `audio_file_size_limit` (int) Audio file upload size limit (MB)
+ - `video_file_size_limit` (int) Video file upload size limit (MB)
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "user_input_form": [
+ {
+ "paragraph": {
+ "label": "Query",
+ "variable": "query",
+ "required": true,
+ "default": ""
+ }
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": false,
+ "number_limits": 3,
+ "detail": "high",
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='Get Application WebApp Settings'
+ name='#site'
+/>
+<Row>
+ <Col>
+ Used to get the WebApp settings of the application.
+ ### Response
+ - `title` (string) WebApp name
+ - `icon_type` (string) Icon type, `emoji` - emoji, `image` - picture
+ - `icon` (string) Icon. If it's `emoji` type, it's an emoji symbol; if it's `image` type, it's an image URL.
+ - `icon_background` (string) Background color in hex format
+ - `icon_url` (string) Icon URL
+ - `description` (string) Description
+ - `copyright` (string) Copyright information
+ - `privacy_policy` (string) Privacy policy link
+ - `custom_disclaimer` (string) Custom disclaimer
+ - `default_language` (string) Default language
+ - `show_workflow_steps` (bool) Whether to show workflow details
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
diff --git a/app/components/develop/template/template_workflow.ja.mdx b/app/components/develop/template/template_workflow.ja.mdx
new file mode 100644
index 0000000..b6afea9
--- /dev/null
+++ b/app/components/develop/template/template_workflow.ja.mdx
@@ -0,0 +1,796 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx'
+
+# 銉兗銈儠銉兗銈€儣銉狝PI
+
+銉兗銈儠銉兗銈€儣銉偙銉笺偡銉с兂銇�併偦銉冦偡銉с兂銈掋偟銉濄兗銉堛仜銇氥�佺炕瑷炽�佽浜嬩綔鎴愩�佽绱凙I銇仼銇渶閬┿仹銇欍��
+
+<div>
+ ### 銉欍兗銈筓RL
+ <CodeGroup title="銈炽兗銉�" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### 瑾嶈
+
+ 銈点兗銉撱偣API銇痐API-Key`瑾嶈銈掍娇鐢ㄣ仐銇俱仚銆�
+ <i>**API銈兗銇紡娲┿倰闃层亹銇熴倎銆丄PI銈兗銇偗銉┿偆銈€兂銉堝伌銇у叡鏈夈伨銇熴伅淇濆瓨銇涖仛銆併偟銉笺儛銉煎伌銇т繚瀛樸仚銈嬨亾銇ㄣ倰寮枫亸銇婂嫥銈併仐銇俱仚銆�**</i>
+
+ 銇欍伖銇︺伄API銉偗銈ㄣ偣銉堛伀銇娿亜銇︺�佷互涓嬨伄銈堛亞銇玚Authorization`HTTP銉樸儍銉�銉笺伀API銈兗銈掑惈銈併仸銇忋仩銇曘亜锛�
+
+ <CodeGroup title="銈炽兗銉�">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/workflows/run'
+ method='POST'
+ title='銉兗銈儠銉兗銈掑疅琛�'
+ name='#Execute-Workflow'
+/>
+<Row>
+ <Col>
+ 銉兗銈儠銉兗銈掑疅琛屻仐銇俱仚銆傚叕闁嬨仌銈屻仧銉兗銈儠銉兗銇屻仾銇勩仺瀹熻銇с亶銇俱仜銈撱��
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ - `inputs` (object) 蹇呴爤
+ 銈€儣銉仹瀹氱京銇曘倢銇熴仌銇俱仏銇俱仾澶夋暟鍊ゃ伄鍏ュ姏銈掕ū鍙仐銇俱仚銆�
+ `inputs`銉戙儵銉°兗銈裤伀銇鏁般伄銈兗/鍊ゃ儦銈€亴鍚伨銈屻�佸悇銈兗銇壒瀹氥伄澶夋暟銇蹇溿仐銆佸悇鍊ゃ伅銇濄伄澶夋暟銇壒瀹氥伄鍊ゃ仹銇欍��
+ 銉兗銈儠銉兗銈€儣銉偙銉笺偡銉с兂銇皯銇亸銇ㄣ倐1銇ゃ伄銈兗/鍊ゃ儦銈€伄鍏ュ姏銈掑繀瑕併仺銇椼伨銇欍�傚�ゃ伅銉曘偂銈ゃ儷銉偣銉堛仹銇傘倠鍫村悎銈傘亗銈娿伨銇欍��
+ 銉曘偂銈ゃ儷銉偣銉堛伅銆併儐銈偣銉堢悊瑙c仺璩晱銇搞伄鍥炵瓟銈掔祫銇垮悎銈忋仜銇熴儠銈°偆銉伄鍏ュ姏銇仼銇椼仸銇勩伨銇欍�傘儮銉囥儷銇屻儠銈°偆銉伄瑙f瀽銇ㄧ悊瑙f鑳姐倰銈点儩銉笺儓銇椼仸銇勩倠鍫村悎銇伄銇夸娇鐢ㄣ仹銇嶃伨銇欍��
+
+ 澶夋暟銇屻儠銈°偆銉儶銈广儓銇牬鍚堛�併儶銈广儓銇悇瑕佺礌銇互涓嬨伄灞炴�с倰鎸併仱蹇呰銇屻亗銈娿伨銇欍��
+ - `type` (string) 銈点儩銉笺儓銇曘倢銇︺亜銈嬨偪銈ゃ儣:
+ - `document` ('TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB')
+ - `image` ('JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG')
+ - `audio` ('MP3', 'M4A', 'WAV', 'WEBM', 'AMR')
+ - `video` ('MP4', 'MOV', 'MPEG', 'MPGA')
+ - `custom` (浠栥伄銉曘偂銈ゃ儷銈裤偆銉�)
+ - `transfer_method` (string) 杌㈤�佹柟娉曘�佺敾鍍廢RL銇牬鍚堛伅`remote_url` / 銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銇牬鍚堛伅`local_file`
+ - `url` (string) 鐢诲儚URL锛堣虎閫佹柟娉曘亴`remote_url`銇牬鍚堬級
+ - `upload_file_id` (string) 銈€儍銉椼儹銉笺儔銇曘倢銇熴儠銈°偆銉獻D銆佷簨鍓嶃伀銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔API銈掗�氥仒銇﹀彇寰椼仚銈嬪繀瑕併亴銇傘倞銇俱仚锛堣虎閫佹柟娉曘亴`local_file`銇牬鍚堬級
+
+ - `response_mode` (string) 蹇呴爤
+ 蹇滅瓟銇繑鍗淬儮銉笺儔銈掓寚瀹氥仐銇俱仚銆傘偟銉濄兗銉堛仌銈屻仸銇勩倠銉€兗銉夛細
+ - `streaming` 銈广儓銉兗銉熴兂銈般儮銉笺儔锛堟帹濂級銆丼SE锛圼Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)锛夈倰閫氥仒銇︺偪銈ゃ儣銉┿偆銈裤兗銇倛銇嗐仾鍑哄姏銈掑疅瑁呫仐銇俱仚銆�
+ - `blocking` 銉栥儹銉冦偔銉炽偘銉€兗銉夈�佸疅琛屽畬浜嗗緦銇祼鏋溿倰杩斻仐銇俱仚銆傦紙銉椼儹銈汇偣銇岄暦銇勫牬鍚堛�併儶銈偍銈广儓銇屼腑鏂仌銈屻倠鍙兘鎬с亴銇傘倞銇俱仚锛�
+ <i>Cloudflare銇埗闄愩伀銈堛倞銆�100绉掑緦銇繙绛斻亴銇亜鍫村悎銆併儶銈偍銈广儓銇腑鏂仌銈屻伨銇欍��</i>
+ - `user` (string) 蹇呴爤
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇偄銈ゃ儑銉炽儐銈c儐銈c倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻伨銇欍��
+ 銈€儣銉偙銉笺偡銉с兂鍐呫仹闁嬬櫤鑰呫伀銈堛仯銇︿竴鎰忋伀瀹氱京銇曘倢銈嬪繀瑕併亴銇傘倞銇俱仚銆�
+ - `files` (array[object]) 銈儣銈枫儳銉�
+
+
+ ### 蹇滅瓟
+ `response_mode`銇宍blocking`銇牬鍚堛�丆ompletionResponse銈儢銈搞偋銈儓銈掕繑銇椼伨銇欍��
+ `response_mode`銇宍streaming`銇牬鍚堛�丆hunkCompletionResponse銈广儓銉兗銉犮倰杩斻仐銇俱仚銆�
+
+ ### CompletionResponse
+ 銈€儣銉伄绲愭灉銈掕繑銇椼伨銇欍�俙Content-Type`銇痐application/json`銇с仚銆�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰忋伄ID
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `data` (object) 绲愭灉銇┏绱�
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇甀D
+ - `workflow_id` (string) 闁㈤�c仚銈嬨儻銉笺偗銉曘儹銉笺伄ID
+ - `status` (string) 瀹熻銇偣銉嗐兗銈裤偣銆乣running` / `succeeded` / `failed` / `stopped`
+ - `outputs` (json) 銈儣銈枫儳銉炽伄鍑哄姏鍐呭
+ - `error` (string) 銈儣銈枫儳銉炽伄銈ㄣ儵銉肩悊鐢�
+ - `elapsed_time` (float) 銈儣銈枫儳銉炽伄浣跨敤鏅傞枔锛堢锛�
+ - `total_tokens` (int) 銈儣銈枫儳銉炽伄浣跨敤銉堛兗銈兂鏁�
+ - `total_steps` (int) 銉囥儠銈┿儷銉�0
+ - `created_at` (timestamp) 闁嬪鏅傞枔
+ - `finished_at` (timestamp) 绲備簡鏅傞枔
+
+ ### ChunkCompletionResponse
+ 銈€儣銉伀銈堛仯銇﹀嚭鍔涖仌銈屻仧銈广儓銉兗銉犮儊銉c兂銈倰杩斻仐銇俱仚銆俙Content-Type`銇痐text/event-stream`銇с仚銆�
+ 鍚勩偣銉堛儶銉笺儫銉炽偘銉併儯銉炽偗銇痐data:`銇у銇俱倞銆�2銇ゃ伄鏀硅鏂囧瓧`\n\n`銇у尯鍒囥倝銈屻伨銇欍�備互涓嬨伄銈堛亞銇〃绀恒仌銈屻伨銇欙細
+ <CodeGroup>
+ ```streaming {{ title: '蹇滅瓟' }}
+ data: {"event": "text_chunk", "workflow_run_id": "b85e5fc5-751b-454d-b14e-dc5f240b0a31", "task_id": "bd029338-b068-4d34-a331-fc85478922c2", "data": {"text": "\u4e3a\u4e86", "from_variable_selector": ["1745912968134", "text"]}}\n\n
+ ```
+ </CodeGroup>
+ 銈广儓銉兗銉熴兂銈般儊銉c兂銈伄妲嬮�犮伅`event`銇繙銇樸仸鐣般仾銈娿伨銇欙細
+ - `event: workflow_started` 銉兗銈儠銉兗銇屽疅琛屻倰闁嬪
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰忋伄ID
+ - `event` (string) `workflow_started`銇浐瀹�
+ - `data` (object) 瑭崇窗
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰忋伄ID
+ - `workflow_id` (string) 闁㈤�c仚銈嬨儻銉笺偗銉曘儹銉笺伄ID
+ - `sequence_number` (int) 鑷繁澧楀姞銈枫儶銈€儷鐣彿銆併偄銉椼儶鍐呫仹鑷繁澧楀姞銇椼��1銇嬨倝濮嬨伨銈娿伨銇�
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: node_started` 銉庛兗銉夊疅琛岄枊濮�
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰忋伄ID
+ - `event` (string) `node_started`銇浐瀹�
+ - `data` (object) 瑭崇窗
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰忋伄ID
+ - `node_id` (string) 銉庛兗銉夈伄ID
+ - `node_type` (string) 銉庛兗銉夈伄銈裤偆銉�
+ - `title` (string) 銉庛兗銉夈伄鍚嶅墠
+ - `index` (int) 瀹熻銈枫兗銈便兂銈圭暘鍙枫�併儓銉兗銈广儙銉笺儔銈枫兗銈便兂銈广倰琛ㄧず銇欍倠銇熴倎銇娇鐢�
+ - `predecessor_node_id` (string) 銈儣銈枫儳銉炽伄銉椼儸銉曘偅銉冦偗銈广儙銉笺儔ID銆併偔銉c兂銉愩偣琛ㄧず瀹熻銉戙偣銇娇鐢�
+ - `inputs` (object) 銉庛兗銉夈仹浣跨敤銇曘倢銈嬨仚銇广仸銇墠銇儙銉笺儔澶夋暟銇唴瀹�
+ - `created_at` (timestamp) 闁嬪銇偪銈ゃ儬銈广偪銉炽儣銆佷緥锛�1705395332
+ - `event: text_chunk` 銉嗐偔銈广儓銉曘儵銈般儭銉炽儓
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰忋伄ID
+ - `event` (string) `text_chunk`銇浐瀹�
+ - `data` (object) 瑭崇窗
+ - `text` (string) 銉嗐偔銈广儓鍐呭
+ - `from_variable_selector` (array) 銉嗐偔銈广儓鐢熸垚鍏冦儜銈癸紙闁嬬櫤鑰呫亴銇┿伄銉庛兗銉夈伄銇┿伄澶夋暟銇嬨倝鐢熸垚銇曘倢銇熴亱銈掔悊瑙c仚銈嬨仧銈併伄鎯呭牨锛�
+ - `event: node_finished` 銉庛兗銉夊疅琛岀祩浜嗐�佸悓銇樸偆銉欍兂銉堛仹鐣般仾銈嬬姸鎱嬨仹鎴愬姛銇俱仧銇け鏁�
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰忋伄ID
+ - `event` (string) `node_finished`銇浐瀹�
+ - `data` (object) 瑭崇窗
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰忋伄ID
+ - `node_id` (string) 銉庛兗銉夈伄ID
+ - `node_type` (string) 銉庛兗銉夈伄銈裤偆銉�
+ - `title` (string) 銉庛兗銉夈伄鍚嶅墠
+ - `index` (int) 瀹熻銈枫兗銈便兂銈圭暘鍙枫�併儓銉兗銈广儙銉笺儔銈枫兗銈便兂銈广倰琛ㄧず銇欍倠銇熴倎銇娇鐢�
+ - `predecessor_node_id` (string) 銈儣銈枫儳銉炽伄銉椼儸銉曘偅銉冦偗銈广儙銉笺儔ID銆併偔銉c兂銉愩偣琛ㄧず瀹熻銉戙偣銇娇鐢�
+ - `inputs` (object) 銉庛兗銉夈仹浣跨敤銇曘倢銈嬨仚銇广仸銇墠銇儙銉笺儔澶夋暟銇唴瀹�
+ - `process_data` (json) 銈儣銈枫儳銉炽伄銉庛兗銉夈儣銉偦銈广儑銉笺偪
+ - `outputs` (json) 銈儣銈枫儳銉炽伄鍑哄姏鍐呭
+ - `status` (string) 瀹熻銇偣銉嗐兗銈裤偣銆乣running` / `succeeded` / `failed` / `stopped`
+ - `error` (string) 銈儣銈枫儳銉炽伄銈ㄣ儵銉肩悊鐢�
+ - `elapsed_time` (float) 銈儣銈枫儳銉炽伄浣跨敤鏅傞枔锛堢锛�
+ - `execution_metadata` (json) 銉°偪銉囥兗銈�
+ - `total_tokens` (int) 銈儣銈枫儳銉炽伄浣跨敤銉堛兗銈兂鏁�
+ - `total_price` (decimal) 銈儣銈枫儳銉炽伄绶忋偝銈广儓
+ - `currency` (string) 銈儣銈枫儳銉� 渚嬶細`USD` / `RMB`
+ - `created_at` (timestamp) 闁嬪銇偪銈ゃ儬銈广偪銉炽儣銆佷緥锛�1705395332
+ - `event: workflow_finished` 銉兗銈儠銉兗瀹熻绲備簡銆佸悓銇樸偆銉欍兂銉堛仹鐣般仾銈嬬姸鎱嬨仹鎴愬姛銇俱仧銇け鏁�
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄Stop Generate API銇娇鐢�
+ - `workflow_run_id` (string) 銉兗銈儠銉兗瀹熻銇竴鎰忋伄ID
+ - `event` (string) `workflow_finished`銇浐瀹�
+ - `data` (object) 瑭崇窗
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇甀D
+ - `workflow_id` (string) 闁㈤�c仚銈嬨儻銉笺偗銉曘儹銉笺伄ID
+ - `status` (string) 瀹熻銇偣銉嗐兗銈裤偣銆乣running` / `succeeded` / `failed` / `stopped`
+ - `outputs` (json) 銈儣銈枫儳銉炽伄鍑哄姏鍐呭
+ - `error` (string) 銈儣銈枫儳銉炽伄銈ㄣ儵銉肩悊鐢�
+ - `elapsed_time` (float) 銈儣銈枫儳銉炽伄浣跨敤鏅傞枔锛堢锛�
+ - `total_tokens` (int) 銈儣銈枫儳銉炽伄浣跨敤銉堛兗銈兂鏁�
+ - `total_steps` (int) 銉囥儠銈┿儷銉�0
+ - `created_at` (timestamp) 闁嬪鏅傞枔
+ - `finished_at` (timestamp) 绲備簡鏅傞枔
+ - `event: tts_message` TTS銈兗銉囥偅銈偣銉堛儶銉笺儬銈ゃ儥銉炽儓銆併仱銇俱倞闊冲0鍚堟垚鍑哄姏銆傚唴瀹广伅Mp3褰㈠紡銇偑銉笺儑銈c偑銉栥儹銉冦偗銇с�乥ase64鏂囧瓧鍒椼仺銇椼仸銈ㄣ兂銈炽兗銉夈仌銈屻仸銇勩伨銇欍�傚啀鐢熸檪銇伅銆乥ase64銈掋儑銈炽兗銉夈仐銇︺儣銉兗銉ゃ兗銇叆鍔涖仚銈嬨仩銇戙仹銇欍�傦紙銇撱伄銉°儍銈汇兗銈搞伅鑷嫊鍐嶇敓銇屾湁鍔广仾鍫村悎銇伄銇垮埄鐢ㄥ彲鑳斤級
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄鍋滄蹇滅瓟銈ゃ兂銈裤兗銉曘偋銉笺偣銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `audio` (string) 闊冲0鍚堟垚寰屻伄銈兗銉囥偅銈�乥ase64銉嗐偔銈广儓銈炽兂銉嗐兂銉勩仺銇椼仸銈ㄣ兂銈炽兗銉夈仌銈屻仸銇娿倞銆佸啀鐢熸檪銇伅base64銈掋儑銈炽兗銉夈仐銇︺儣銉兗銉ゃ兗銇叆鍔涖仚銈嬨仩銇戙仹銇�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: tts_message_end` TTS銈兗銉囥偅銈偣銉堛儶銉笺儬绲備簡銈ゃ儥銉炽儓銆傘亾銇偆銉欍兂銉堛倰鍙椾俊銇欍倠銇ㄣ�併偑銉笺儑銈c偑銈广儓銉兗銉犮伄绲備簡銈掔ず銇椼伨銇欍��
+ - `task_id` (string) 銈裤偣銈疘D銆併儶銈偍銈广儓杩借贰銇ㄤ互涓嬨伄鍋滄蹇滅瓟銈ゃ兂銈裤兗銉曘偋銉笺偣銇娇鐢�
+ - `message_id` (string) 涓�鎰忋伄銉°儍銈汇兗銈窱D
+ - `audio` (string) 绲備簡銈ゃ儥銉炽儓銇伅銈兗銉囥偅銈亴銇亜銇熴倎銆併亾銈屻伅绌恒伄鏂囧瓧鍒椼仹銇�
+ - `created_at` (int) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+ - `event: ping` 鎺ョ稓銈掔董鎸併仚銈嬨仧銈併伀10绉掋仈銇ㄣ伀閫佷俊銇曘倢銈婸ing銈ゃ儥銉炽儓銆�
+
+ ### 銈ㄣ儵銉�
+ - 400, `invalid_param`, 鐣板父銇儜銉┿儭銉笺偪鍏ュ姏
+ - 400, `app_unavailable`, 銈€儣銉伄瑷畾銇屽埄鐢ㄣ仹銇嶃伨銇涖倱
+ - 400, `provider_not_initialize`, 鍒╃敤鍙兘銇儮銉囥儷璩囨牸鎯呭牨銇ō瀹氥亴銇傘倞銇俱仜銈�
+ - 400, `provider_quota_exceeded`, 銉€儑銉懠銇冲嚭銇椼伄銈偐銉笺偪銇屼笉瓒炽仐銇︺亜銇俱仚
+ - 400, `model_currently_not_support`, 鐝惧湪銇儮銉囥儷銇埄鐢ㄣ仹銇嶃伨銇涖倱
+ - 400, `workflow_request_error`, 銉兗銈儠銉兗瀹熻銇け鏁椼仐銇俱仐銇�
+ - 500, 鍐呴儴銈点兗銉愩兗銈ㄣ儵銉�
+
+ </Col>
+ <Col sticky>
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/workflows/run" targetCode={`curl -X POST '${props.appDetail.api_base_url}/workflows/run' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": ${JSON.stringify(props.inputs)},\n "response_mode": "streaming",\n "user": "abc-123"\n}'\n`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/workflows/run' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {},
+ "response_mode": "streaming",
+ "user": "abc-123"
+ }'
+ ```
+
+ </CodeGroup>
+ <CodeGroup title="銉曘偂銈ゃ儷澶夋暟銇緥">
+ ```json {{ title: '銉曘偂銈ゃ儷澶夋暟銇緥' }}
+ {
+ "inputs": {
+ "{variable_name}":
+ [
+ {
+ "transfer_method": "local_file",
+ "upload_file_id": "{upload_file_id}",
+ "type": "{document_type}"
+ }
+ ]
+ }
+ }
+ ```
+ </CodeGroup>
+ ### 銉栥儹銉冦偔銉炽偘銉€兗銉�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "workflow_run_id": "djflajgkldjgd",
+ "task_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "data": {
+ "id": "fdlsjfjejkghjda",
+ "workflow_id": "fldjaslkfjlsda",
+ "status": "succeeded",
+ "outputs": {
+ "text": "Nice to meet you."
+ },
+ "error": null,
+ "elapsed_time": 0.875,
+ "total_tokens": 3562,
+ "total_steps": 8,
+ "created_at": 1705407629,
+ "finished_at": 1727807631
+ }
+ }
+ ```
+ </CodeGroup>
+ ### 銈广儓銉兗銉熴兂銈般儮銉笺儔
+ <CodeGroup title="蹇滅瓟">
+ ```streaming {{ title: '蹇滅瓟' }}
+ data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}
+ data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}
+ data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}
+ data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ <CodeGroup title="銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銇偟銉炽儣銉偝銉笺儔">
+ ```json {{ title: '銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銇偟銉炽儣銉偝銉笺儔' }}
+ import requests
+ import json
+
+ def upload_file(file_path, user):
+ upload_url = "https://api.dify.ai/v1/files/upload"
+ headers = {
+ "Authorization": "Bearer app-xxxxxxxx",
+ }
+
+ try:
+ print("銉曘偂銈ゃ儷銈掋偄銉冦儣銉兗銉夈仐銇︺亜銇俱仚...")
+ with open(file_path, 'rb') as file:
+ files = {
+ 'file': (file_path, file, 'text/plain') # 銉曘偂銈ゃ儷銇岄仼鍒囥仾 MIME 銈裤偆銉椼仹銈€儍銉椼儹銉笺儔銇曘倢銇︺亜銈嬨亾銇ㄣ倰纰鸿獚銇椼仸銇忋仩銇曘亜
+ }
+ data = {
+ "user": user,
+ "type": "TXT" # 銉曘偂銈ゃ儷銈裤偆銉椼倰TXT銇ō瀹氥仐銇俱仚
+ }
+
+ response = requests.post(upload_url, headers=headers, files=files, data=data)
+ if response.status_code == 201: # 201 銇綔鎴愩亴鎴愬姛銇椼仧銇撱仺銈掓剰鍛炽仐銇俱仚
+ print("銉曘偂銈ゃ儷銇屾甯搞伀銈€儍銉椼儹銉笺儔銇曘倢銇俱仐銇�")
+ return response.json().get("id") # 銈€儍銉椼儹銉笺儔銇曘倢銇熴儠銈°偆銉獻D銈掑彇寰椼仚銈�
+ else:
+ print(f"銉曘偂銈ゃ儷銇偄銉冦儣銉兗銉夈伀澶辨晽銇椼伨銇椼仧銆傘偣銉嗐兗銈裤偣 銈炽兗銉�: {response.status_code}")
+ return None
+ except Exception as e:
+ print(f"銈ㄣ儵銉笺亴鐧虹敓銇椼伨銇椼仧: {str(e)}")
+ return None
+
+ def run_workflow(file_id, user, response_mode="blocking"):
+ workflow_url = "https://api.dify.ai/v1/workflows/run"
+ headers = {
+ "Authorization": "Bearer app-xxxxxxxxx",
+ "Content-Type": "application/json"
+ }
+
+ data = {
+ "inputs": {
+ "orig_mail": [{
+ "transfer_method": "local_file",
+ "upload_file_id": file_id,
+ "type": "document"
+ }]
+ },
+ "response_mode": response_mode,
+ "user": user
+ }
+
+ try:
+ print("銉兗銈儠銉兗銈掑疅琛�...")
+ response = requests.post(workflow_url, headers=headers, json=data)
+ if response.status_code == 200:
+ print("銉兗銈儠銉兗銇屾甯搞伀瀹熻銇曘倢銇俱仐銇�")
+ return response.json()
+ else:
+ print(f"銉兗銈儠銉兗銇疅琛屻亴銈广儐銉笺偪銈� 銈炽兗銉夈仹澶辨晽銇椼伨銇椼仧: {response.status_code}")
+ return {"status": "error", "message": f"Failed to execute workflow, status code: {response.status_code}"}
+ except Exception as e:
+ print(f"銈ㄣ儵銉笺亴鐧虹敓銇椼伨銇椼仧: {str(e)}")
+ return {"status": "error", "message": str(e)}
+
+ # 浣跨敤渚�
+ file_path = "{your_file_path}"
+ user = "difyuser"
+
+ # 銉曘偂銈ゃ儷銈掋偄銉冦儣銉兗銉夈仚銈�
+ file_id = upload_file(file_path, user)
+ if file_id:
+ # 銉曘偂銈ゃ儷銇甯搞伀銈€儍銉椼儹銉笺儔銇曘倢銇俱仐銇熴�傘儻銉笺偗銉曘儹銉笺伄瀹熻銈掔稓琛屻仐銇俱仚
+ result = run_workflow(file_id, user)
+ print(result)
+ else:
+ print("銉曘偂銈ゃ儷銇偄銉冦儣銉兗銉夈伀澶辨晽銇椼�併儻銉笺偗銉曘儹銉笺倰瀹熻銇с亶銇俱仜銈�")
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/workflows/run/:workflow_id'
+ method='GET'
+ title='銉兗銈儠銉兗瀹熻瑭崇窗銈掑彇寰�'
+ name='#get-workflow-run-detail'
+/>
+<Row>
+ <Col>
+ 銉兗銈儠銉兗瀹熻ID銇熀銇ャ亜銇︺�併儻銉笺偗銉曘儹銉笺偪銈广偗銇従鍦ㄣ伄瀹熻绲愭灉銈掑彇寰椼仐銇俱仚銆�
+ ### 銉戙偣
+ - `workflow_id` (string) 銉兗銈儠銉兗ID銆併偣銉堛儶銉笺儫銉炽偘銉併儯銉炽偗銇繑銈婂�ゃ亱銈夊彇寰楀彲鑳�
+ ### 蹇滅瓟
+ - `id` (string) 銉兗銈儠銉兗瀹熻銇甀D
+ - `workflow_id` (string) 闁㈤�c仚銈嬨儻銉笺偗銉曘儹銉笺伄ID
+ - `status` (string) 瀹熻銇偣銉嗐兗銈裤偣銆乣running` / `succeeded` / `failed` / `stopped`
+ - `inputs` (json) 鍏ュ姏鍐呭
+ - `outputs` (json) 鍑哄姏鍐呭
+ - `error` (string) 銈ㄣ儵銉肩悊鐢�
+ - `total_steps` (int) 銈裤偣銈伄绶忋偣銉嗐儍銉楁暟
+ - `total_tokens` (int) 浣跨敤銇曘倢銈嬨儓銉笺偗銉炽伄绶忔暟
+ - `created_at` (timestamp) 闁嬪鏅傞枔
+ - `finished_at` (timestamp) 绲備簡鏅傞枔
+ - `elapsed_time` (float) 浣跨敤銇曘倢銈嬬窂绉掓暟
+ </Col>
+ <Col sticky>
+ ### 銉偗銈ㄣ偣銉堜緥
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/workflows/run/:workflow_id" targetCode={`curl -X GET '${props.appDetail.api_base_url}/workflows/run/:workflow_id' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/workflows/run/:workflow_id' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+
+ ### 蹇滅瓟渚�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "id": "b1ad3277-089e-42c6-9dff-6820d94fbc76",
+ "workflow_id": "19eff89f-ec03-4f75-b0fc-897e7effea02",
+ "status": "succeeded",
+ "inputs": "{\"sys.files\": [], \"sys.user_id\": \"abc-123\"}",
+ "outputs": null,
+ "error": null,
+ "total_steps": 3,
+ "total_tokens": 0,
+ "created_at": 1705407629,
+ "finished_at": 1727807631,
+ "elapsed_time": 30.098514399956912
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/workflows/tasks/:task_id/stop'
+ method='POST'
+ title='鐢熸垚銈掑仠姝�'
+ name='#stop-generatebacks'
+/>
+<Row>
+ <Col>
+ 銈广儓銉兗銉熴兂銈般儮銉笺儔銇с伄銇裤偟銉濄兗銉堛仌銈屻仸銇勩伨銇欍��
+ ### 銉戙偣
+ - `task_id` (string) 銈裤偣銈疘D銆併偣銉堛儶銉笺儫銉炽偘銉併儯銉炽偗銇繑銈婂�ゃ亱銈夊彇寰楀彲鑳�
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ - `user` (string) 蹇呴爤
+ 銉︺兗銈躲兗璀樺垾瀛愩�併偍銉炽儔銉︺兗銈躲兗銇偄銈ゃ儑銉炽儐銈c儐銈c倰瀹氱京銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻�侀�佷俊銉°儍銈汇兗銈搞偆銉炽偪銉笺儠銈с兗銈广仹娓°仌銈屻仧銉︺兗銈躲兗銇ㄤ竴鑷淬仐銇︺亜銈嬪繀瑕併亴銇傘倞銇俱仚銆�
+ ### 蹇滅瓟
+ - `result` (string) 甯搞伀"success"銈掕繑銇椼伨銇�
+ </Col>
+ <Col sticky>
+ ### 銉偗銈ㄣ偣銉堜緥
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/workflows/tasks/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/workflows/tasks/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{"user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/workflows/tasks/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+
+ ### 蹇滅瓟渚�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔'
+ name='#file-upload'
+/>
+<Row>
+ <Col>
+ 銉°儍銈汇兗銈搁�佷俊鏅傘伀浣跨敤銇欍倠銇熴倎銇儠銈°偆銉倰銈€儍銉椼儹銉笺儔銇椼�佺敾鍍忋仺銉嗐偔銈广儓銇優銉儊銉€兗銉�銉悊瑙c倰鍙兘銇仐銇俱仚銆�
+ 銉兗銈儠銉兗銇с偟銉濄兗銉堛仌銈屻仸銇勩倠浠绘剰銇舰寮忋倰銈点儩銉笺儓銇椼伨銇欍��
+ 銈€儍銉椼儹銉笺儔銇曘倢銇熴儠銈°偆銉伅銆佺従鍦ㄣ伄銈ㄣ兂銉夈儲銉笺偠銉笺伄銇裤亴浣跨敤銇с亶銇俱仚銆�
+
+ ### 銉偗銈ㄣ偣銉堛儨銉囥偅
+ 銇撱伄銈ゃ兂銈裤兗銉曘偋銉笺偣銇痐multipart/form-data`銉偗銈ㄣ偣銉堛倰蹇呰銇ㄣ仐銇俱仚銆�
+ - `file` (File) 蹇呴爤
+ 銈€儍銉椼儹銉笺儔銇欍倠銉曘偂銈ゃ儷銆�
+ - `user` (string) 蹇呴爤
+ 銉︺兗銈躲兗璀樺垾瀛愩�侀枊鐧鸿�呫伄銉兗銉仹瀹氱京銇曘倢銆併偄銉椼儶銈便兗銈枫儳銉冲唴銇т竴鎰忋仹銇亼銈屻伆銇倞銇俱仜銈撱��
+
+ ### 蹇滅瓟
+ 銈€儍銉椼儹銉笺儔銇屾垚鍔熴仚銈嬨仺銆併偟銉笺儛銉笺伅銉曘偂銈ゃ儷銇甀D銇ㄩ枹閫f儏鍫便倰杩斻仐銇俱仚銆�
+ - `id` (uuid) ID
+ - `name` (string) 銉曘偂銈ゃ儷鍚�
+ - `size` (int) 銉曘偂銈ゃ儷銈点偆銈猴紙銉愩偆銉堬級
+ - `extension` (string) 銉曘偂銈ゃ儷鎷″嫉瀛�
+ - `mime_type` (string) 銉曘偂銈ゃ儷銇甅IME銈裤偆銉�
+ - `created_by` (uuid) 銈ㄣ兂銉夈儲銉笺偠銉糏D
+ - `created_at` (timestamp) 浣滄垚銈裤偆銉犮偣銈裤兂銉椼�佷緥锛�1705395332
+
+ ### 銈ㄣ儵銉�
+ - 400, `no_file_uploaded`, 銉曘偂銈ゃ儷銇屾彁渚涖仌銈屻仸銇勩伨銇涖倱
+ - 400, `too_many_files`, 鐝惧湪銇�1銇ゃ伄銉曘偂銈ゃ儷銇伩鍙椼亼浠樸亼銇︺亜銇俱仚
+ - 400, `unsupported_preview`, 銉曘偂銈ゃ儷銇儣銉儞銉ャ兗銈掋偟銉濄兗銉堛仐銇︺亜銇俱仜銈�
+ - 400, `unsupported_estimate`, 銉曘偂銈ゃ儷銇帹瀹氥倰銈点儩銉笺儓銇椼仸銇勩伨銇涖倱
+ - 413, `file_too_large`, 銉曘偂銈ゃ儷銇屽ぇ銇嶃仚銇庛伨銇�
+ - 415, `unsupported_file_type`, 銈点儩銉笺儓銇曘倢銇︺亜銇亜鎷″嫉瀛愩�佺従鍦ㄣ伅銉夈偔銉ャ儭銉炽儓銉曘偂銈ゃ儷銇伩鍙椼亼浠樸亼銇︺亜銇俱仚
+ - 503, `s3_connection_failed`, S3銈点兗銉撱偣銇帴缍氥仹銇嶃伨銇涖倱
+ - 503, `s3_permission_denied`, S3銇儠銈°偆銉倰銈€儍銉椼儹銉笺儔銇欍倠妯╅檺銇屻亗銈娿伨銇涖倱
+ - 503, `s3_file_too_large`, 銉曘偂銈ゃ儷銇孲3銇偟銈ゃ偤鍒堕檺銈掕秴銇堛仸銇勩伨銇�
+ - 500, 鍐呴儴銈点兗銉愩兗銈ㄣ儵銉�
+
+
+ </Col>
+ <Col sticky>
+ ### 銉偗銈ㄣ偣銉堜緥
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+
+ ### 蹇滅瓟渚�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": "6ad1ab0a-73ff-4ac1-b9e4-cdb312f71f13",
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/workflows/logs'
+ method='GET'
+ title='銉兗銈儠銉兗銉偘銈掑彇寰�'
+ name='#Get-Workflow-Logs'
+/>
+<Row>
+ <Col>
+ 銉兗銈儠銉兗銉偘銈掕繑銇椼伨銇欍�傛渶鍒濄伄銉氥兗銈搞伅鏈�鏂般伄`{limit}`銉°儍銈汇兗銈搞倰杩斻仐銇俱仚銆傘仱銇俱倞銆侀�嗛爢銇с仚銆�
+
+ ### 銈偍銉�
+
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 妞滅储銇欍倠銈兗銉兗銉�
+ </Property>
+ <Property name='status' type='string' key='status'>
+ succeeded/failed/stopped
+ </Property>
+ <Property name='page' type='int' key='page'>
+ 鐝惧湪銇儦銉笺偢銆併儑銉曘偐銉儓銇�1銆�
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 1鍥炪伄銉偗銈ㄣ偣銉堛仹杩斻仚銉併儯銉冦儓灞ユ銉°儍銈汇兗銈搞伄鏁般�併儑銉曘偐銉儓銇�20銆�
+ </Property>
+ </Properties>
+
+ ### 蹇滅瓟
+ - `page` (int) 鐝惧湪銇儦銉笺偢
+ - `limit` (int) 杩斻仌銈屻仧銈€偆銉嗐儬銇暟銆佸叆鍔涖亴銈枫偣銉嗐儬鍒堕檺銈掕秴銇堛倠鍫村悎銆併偡銈广儐銉犲埗闄愰噺銈掕繑銇椼伨銇�
+ - `total` (int) 鍚堣▓銈€偆銉嗐儬鏁�
+ - `has_more` (bool) 娆°伄銉氥兗銈搞亴銇傘倠銇嬨仼銇嗐亱
+ - `data` (array[object]) 銉偘銉偣銉�
+ - `id` (string) ID
+ - `workflow_run` (object) 銉兗銈儠銉兗瀹熻
+ - `id` (string) ID
+ - `version` (string) 銉愩兗銈搞儳銉�
+ - `status` (string) 瀹熻銇偣銉嗐兗銈裤偣銆乣running` / `succeeded` / `failed` / `stopped`
+ - `error` (string) 銈儣銈枫儳銉炽伄銈ㄣ儵銉肩悊鐢�
+ - `elapsed_time` (float) 浣跨敤銇曘倢銈嬬窂绉掓暟
+ - `total_tokens` (int) 浣跨敤銇曘倢銈嬨儓銉笺偗銉虫暟
+ - `total_steps` (int) 銉囥儠銈┿儷銉�0
+ - `created_at` (timestamp) 闁嬪鏅傞枔
+ - `finished_at` (timestamp) 绲備簡鏅傞枔
+ - `created_from` (string) 浣滄垚鍏�
+ - `created_by_role` (string) 浣滄垚鑰呫伄褰瑰壊
+ - `created_by_account` (string) 銈儣銈枫儳銉炽伄浣滄垚鑰呫偄銈偊銉炽儓
+ - `created_by_end_user` (object) 銈ㄣ兂銉夈儲銉笺偠銉笺伀銈堛仯銇︿綔鎴�
+ - `id` (string) ID
+ - `type` (string) 銈裤偆銉�
+ - `is_anonymous` (bool) 鍖垮悕銇嬨仼銇嗐亱
+ - `session_id` (string) 銈汇儍銈枫儳銉矷D
+ - `created_at` (timestamp) 浣滄垚鏅傞枔
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/workflows/logs" targetCode={`curl -X GET '${props.appDetail.api_base_url}/workflows/logs'\\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/workflows/logs?limit=1'
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+ ### 蹇滅瓟渚�
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "page": 1,
+ "limit": 1,
+ "total": 7,
+ "has_more": true,
+ "data": [
+ {
+ "id": "e41b93f1-7ca2-40fd-b3a8-999aeb499cc0",
+ "workflow_run": {
+ "id": "c0640fc8-03ef-4481-a96c-8a13b732a36e",
+ "version": "2024-08-01 12:17:09.771832",
+ "status": "succeeded",
+ "error": null,
+ "elapsed_time": 1.3588523610014818,
+ "total_tokens": 0,
+ "total_steps": 3,
+ "created_at": 1726139643,
+ "finished_at": 1726139644
+ },
+ "created_from": "service-api",
+ "created_by_role": "end_user",
+ "created_by_account": null,
+ "created_by_end_user": {
+ "id": "7f7d9117-dd9d-441d-8970-87e5e7e687a3",
+ "type": "service_api",
+ "is_anonymous": false,
+ "session_id": "abc-123"
+ },
+ "created_at": 1726139644
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇熀鏈儏鍫便倰鍙栧緱'
+ name='#info'
+/>
+<Row>
+ <Col>
+ 銇撱伄銈€儣銉偙銉笺偡銉с兂銇熀鏈儏鍫便倰鍙栧緱銇欍倠銇熴倎銇娇鐢ㄣ仌銈屻伨銇�
+
+ ### Response
+ - `name` (string) 銈€儣銉偙銉笺偡銉с兂銇悕鍓�
+ - `description` (string) 銈€儣銉偙銉笺偡銉с兂銇鏄�
+ - `tags` (array[string]) 銈€儣銉偙銉笺偡銉с兂銇偪銈�
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='銈€儣銉偙銉笺偡銉с兂銇儜銉┿儭銉笺偪鎯呭牨銈掑彇寰�'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ 銉氥兗銈搞伀鍏ャ倠闅涖伀銆佹鑳姐�佸叆鍔涖儜銉┿儭銉笺偪鍚嶃�併偪銈ゃ儣銆併儑銉曘偐銉儓鍊ゃ仾銇┿伄鎯呭牨銈掑彇寰椼仚銈嬨仧銈併伀浣跨敤銇曘倢銇俱仚銆�
+
+ ### 蹇滅瓟
+ - `user_input_form` (array[object]) 銉︺兗銈躲兗鍏ュ姏銉曘偐銉笺儬銇ō瀹�
+ - `text-input` (object) 銉嗐偔銈广儓鍏ュ姏銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `paragraph` (object) 娈佃惤銉嗐偔銈广儓鍏ュ姏銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `select` (object) 銉夈儹銉冦儣銉�銈︺兂銈炽兂銉堛儹銉笺儷
+ - `label` (string) 澶夋暟琛ㄧず銉┿儥銉悕
+ - `variable` (string) 澶夋暟ID
+ - `required` (bool) 蹇呴爤銇嬨仼銇嗐亱
+ - `default` (string) 銉囥儠銈┿儷銉堝��
+ - `options` (array[string]) 銈儣銈枫儳銉冲��
+ - `file_upload` (object) 銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔瑷畾
+ - `image` (object) 鐢诲儚瑷畾
+ 鐝惧湪銈点儩銉笺儓銇曘倢銇︺亜銈嬬敾鍍忋偪銈ゃ儣銇伩锛歚png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) 鏈夊姽銇嬨仼銇嗐亱
+ - `number_limits` (int) 鐢诲儚鏁般伄鍒堕檺銆併儑銉曘偐銉儓銇�3
+ - `transfer_methods` (array[string]) 杌㈤�佹柟娉曘伄銉偣銉堛�乺emote_url, local_file銆併亜銇氥倢銇嬨倰閬告姙銇欍倠蹇呰銇屻亗銈娿伨銇�
+ - `system_parameters` (object) 銈枫偣銉嗐儬銉戙儵銉°兗銈�
+ - `file_size_limit` (int) 銉夈偔銉ャ儭銉炽儓銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+ - `image_file_size_limit` (int) 鐢诲儚銉曘偂銈ゃ儷銈€儍銉椼儹銉笺儔銈点偆銈哄埗闄愶紙MB锛�
+ - `audio_file_size_limit` (int) 銈兗銉囥偅銈儠銈°偆銉偄銉冦儣銉兗銉夈偟銈ゃ偤鍒堕檺锛圡B锛�
+ - `video_file_size_limit` (int) 銉撱儑銈儠銈°偆銉偄銉冦儣銉兗銉夈偟銈ゃ偤鍒堕檺锛圡B锛�
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="銉偗銈ㄣ偣銉�" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="蹇滅瓟">
+ ```json {{ title: '蹇滅瓟' }}
+ {
+ "user_input_form": [
+ {
+ "paragraph": {
+ "label": "Query",
+ "variable": "query",
+ "required": true,
+ "default": ""
+ }
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": false,
+ "number_limits": 3,
+ "detail": "high",
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+鈥斺�斺��
+
+<Heading
+ url='/site'
+ method='GET'
+ title='銈€儣銉伄WebApp瑷畾銈掑彇寰�'
+ name='#site'
+/>
+<Row>
+ <Col>
+ 銈€儣銉伄WebApp瑷畾銈掑彇寰椼仚銈嬨仧銈併伀浣跨敤銇椼伨銇欍��
+ ### 蹇滅瓟
+ - `title` (string) WebApp鍚�
+ - `icon_type` (string) 銈€偆銈炽兂銈裤偆銉椼�乣emoji`-绲垫枃瀛椼�乣image`-鐢诲儚
+ - `icon` (string) 銈€偆銈炽兂銆俙emoji`銈裤偆銉椼伄鍫村悎銇档鏂囧瓧銆乣image`銈裤偆銉椼伄鍫村悎銇敾鍍廢RL
+ - `icon_background` (string) 16閫叉暟褰㈠紡銇儗鏅壊
+ - `icon_url` (string) 銈€偆銈炽兂銇甎RL
+ - `description` (string) 瑾槑
+ - `copyright` (string) 钁椾綔妯╂儏鍫�
+ - `privacy_policy` (string) 銉椼儵銈ゃ儛銈枫兗銉濄儶銈枫兗銇儶銉炽偗
+ - `custom_disclaimer` (string) 銈偣銈裤儬鍏嶈铂浜嬮爡
+ - `default_language` (string) 銉囥儠銈┿儷銉堣█瑾�
+ - `show_workflow_steps` (bool) 銉兗銈儠銉兗銇┏绱般倰琛ㄧず銇欍倠銇嬨仼銇嗐亱
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
+
diff --git a/app/components/develop/template/template_workflow.zh.mdx b/app/components/develop/template/template_workflow.zh.mdx
new file mode 100644
index 0000000..e78b309
--- /dev/null
+++ b/app/components/develop/template/template_workflow.zh.mdx
@@ -0,0 +1,783 @@
+import { CodeGroup } from '../code.tsx'
+import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx'
+
+# Workflow 搴旂敤 API
+
+Workflow 搴旂敤鏃犱細璇濇敮鎸侊紝閫傚悎鐢ㄤ簬缈昏瘧/鏂囩珷鍐欎綔/鎬荤粨 AI 绛夌瓑銆�
+
+<div>
+ ### Base URL
+ <CodeGroup title="Code" targetCode={props.appDetail.api_base_url}>
+ ```javascript
+ ```
+ </CodeGroup>
+
+ ### Authentication
+
+ Dify Service API 浣跨敤 `API-Key` 杩涜閴存潈銆�
+ <i>**寮虹儓寤鸿寮�鍙戣�呮妸 `API-Key` 鏀惧湪鍚庣瀛樺偍锛岃�岄潪鍒嗕韩鎴栬�呮斁鍦ㄥ鎴风瀛樺偍锛屼互鍏� `API-Key` 娉勯湶锛屽鑷磋储浜ф崯澶便��**</i>
+ 鎵�鏈� API 璇锋眰閮藉簲鍦� **`Authorization`** HTTP Header 涓寘鍚偍鐨� `API-Key`锛屽涓嬫墍绀猴細
+
+ <CodeGroup title="Code">
+ ```javascript
+ Authorization: Bearer {API_KEY}
+
+ ```
+ </CodeGroup>
+</div>
+
+---
+
+<Heading
+ url='/workflows/run'
+ method='POST'
+ title='鎵ц workflow'
+ name='#Execute-Workflow'
+/>
+<Row>
+ <Col>
+ 鎵ц workflow锛屾病鏈夊凡鍙戝竷鐨� workflow锛屼笉鍙墽琛屻��
+
+ ### Request Body
+ - `inputs` (object) Required
+ 鍏佽浼犲叆 App 瀹氫箟鐨勫悇鍙橀噺鍊笺��
+ inputs 鍙傛暟鍖呭惈浜嗗缁勯敭鍊煎锛圞ey/Value pairs锛夛紝姣忕粍鐨勯敭瀵瑰簲涓�涓壒瀹氬彉閲忥紝姣忕粍鐨勫�煎垯鏄鍙橀噺鐨勫叿浣撳�笺�傚彉閲忓彲浠ユ槸鏂囦欢鍒楄〃绫诲瀷銆�
+ 鏂囦欢鍒楄〃绫诲瀷鍙橀噺閫傜敤浜庝紶鍏ユ枃浠剁粨鍚堟枃鏈悊瑙e苟鍥炵瓟闂锛屼粎褰撴ā鍨嬫敮鎸佽绫诲瀷鏂囦欢瑙f瀽鑳藉姏鏃跺彲鐢ㄣ�傚鏋滆鍙橀噺鏄枃浠跺垪琛ㄧ被鍨嬶紝璇ュ彉閲忓搴旂殑鍊煎簲鏄垪琛ㄦ牸寮忥紝鍏朵腑姣忎釜鍏冪礌搴斿寘鍚互涓嬪唴瀹癸細
+ - `type` (string) 鏀寔绫诲瀷锛�
+ - `document` 鍏蜂綋绫诲瀷鍖呭惈锛�'TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB'
+ - `image` 鍏蜂綋绫诲瀷鍖呭惈锛�'JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG'
+ - `audio` 鍏蜂綋绫诲瀷鍖呭惈锛�'MP3', 'M4A', 'WAV', 'WEBM', 'AMR'
+ - `video` 鍏蜂綋绫诲瀷鍖呭惈锛�'MP4', 'MOV', 'MPEG', 'MPGA'
+ - `custom` 鍏蜂綋绫诲瀷鍖呭惈锛氬叾浠栨枃浠剁被鍨�
+ - `transfer_method` (string) 浼犻�掓柟寮忥紝`remote_url` 鍥剧墖鍦板潃 / `local_file` 涓婁紶鏂囦欢
+ - `url` (string) 鍥剧墖鍦板潃锛堜粎褰撲紶閫掓柟寮忎负 `remote_url` 鏃讹級
+ - `upload_file_id` (string) 涓婁紶鏂囦欢 ID锛堜粎褰撲紶閫掓柟寮忎负 `local_file` 鏃讹級
+ - `response_mode` (string) Required
+ 杩斿洖鍝嶅簲妯″紡锛屾敮鎸侊細
+ - `streaming` 娴佸紡妯″紡锛堟帹鑽愶級銆傚熀浜� SSE锛�**[Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)**锛夊疄鐜扮被浼兼墦瀛楁満杈撳嚭鏂瑰紡鐨勬祦寮忚繑鍥炪��
+ - `blocking` 闃诲妯″紡锛岀瓑寰呮墽琛屽畬姣曞悗杩斿洖缁撴灉銆傦紙璇锋眰鑻ユ祦绋嬭緝闀垮彲鑳戒細琚腑鏂級銆�
+ <i>鐢变簬 Cloudflare 闄愬埗锛岃姹備細鍦� 100 绉掕秴鏃舵棤杩斿洖鍚庝腑鏂��</i>
+ - `user` (string) Required
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屾柟渚挎绱€�佺粺璁°��
+ 鐢卞紑鍙戣�呭畾涔夎鍒欙紝闇�淇濊瘉鐢ㄦ埛鏍囪瘑鍦ㄥ簲鐢ㄥ唴鍞竴銆�
+
+
+ ### Response
+ 褰� `response_mode` 涓� `blocking` 鏃讹紝杩斿洖 CompletionResponse object銆�
+ 褰� `response_mode` 涓� `streaming`鏃讹紝杩斿洖 ChunkCompletionResponse object 娴佸紡搴忓垪銆�
+
+ ### CompletionResponse
+ 杩斿洖瀹屾暣鐨� App 缁撴灉锛宍Content-Type` 涓� `application/json` 銆�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `data` (object) 璇︾粏鍐呭
+ - `id` (string) workflow 鎵ц ID
+ - `workflow_id` (string) 鍏宠仈 Workflow ID
+ - `status` (string) 鎵ц鐘舵��, `running` / `succeeded` / `failed` / `stopped`
+ - `outputs` (json) Optional 杈撳嚭鍐呭
+ - `error` (string) Optional 閿欒鍘熷洜
+ - `elapsed_time` (float) Optional 鑰楁椂(s)
+ - `total_tokens` (int) Optional 鎬讳娇鐢� tokens
+ - `total_steps` (int) 鎬绘鏁帮紙鍐椾綑锛夛紝榛樿 0
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `finished_at` (timestamp) 缁撴潫鏃堕棿
+
+ ### ChunkCompletionResponse
+ 杩斿洖 App 杈撳嚭鐨勬祦寮忓潡锛宍Content-Type` 涓� `text/event-stream`銆�
+ 姣忎釜娴佸紡鍧楀潎涓� data: 寮�澶达紝鍧椾箣闂翠互 `\n\n` 鍗充袱涓崲琛岀鍒嗛殧锛屽涓嬫墍绀猴細
+ <CodeGroup>
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "text_chunk", "workflow_run_id": "b85e5fc5-751b-454d-b14e-dc5f240b0a31", "task_id": "bd029338-b068-4d34-a331-fc85478922c2", "data": {"text": "\u4e3a\u4e86", "from_variable_selector": ["1745912968134", "text"]}}\n\n
+ ```
+ </CodeGroup>
+ 娴佸紡鍧椾腑鏍规嵁 `event` 涓嶅悓锛岀粨鏋勪篃涓嶅悓锛屽寘鍚互涓嬬被鍨嬶細
+ - `event: workflow_started` workflow 寮�濮嬫墽琛�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `event` (string) 鍥哄畾涓� `workflow_started`
+ - `data` (object) 璇︾粏鍐呭
+ - `id` (string) workflow 鎵ц ID
+ - `workflow_id` (string) 鍏宠仈 Workflow ID
+ - `sequence_number` (int) 鑷搴忓彿锛孉pp 鍐呰嚜澧烇紝浠� 1 寮�濮�
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `event: node_started` node 寮�濮嬫墽琛�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `event` (string) 鍥哄畾涓� `node_started`
+ - `data` (object) 璇︾粏鍐呭
+ - `id` (string) workflow 鎵ц ID
+ - `node_id` (string) 鑺傜偣 ID
+ - `node_type` (string) 鑺傜偣绫诲瀷
+ - `title` (string) 鑺傜偣鍚嶇О
+ - `index` (int) 鎵ц搴忓彿锛岀敤浜庡睍绀� Tracing Node 椤哄簭
+ - `predecessor_node_id` (string) 鍓嶇疆鑺傜偣 ID锛岀敤浜庣敾甯冨睍绀烘墽琛岃矾寰�
+ - `inputs` (object) 鑺傜偣涓墍鏈変娇鐢ㄥ埌鐨勫墠缃妭鐐瑰彉閲忓唴瀹�
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `event: text_chunk` 鏂囨湰鐗囨
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `event` (string) 鍥哄畾涓� `text_chunk`
+ - `data` (object) 璇︾粏鍐呭
+ - `text` (string) 鏂囨湰鍐呭
+ - `from_variable_selector` (array) 鏂囨湰鏉ユ簮璺緞锛屽府鍔╁紑鍙戣�呬簡瑙f枃鏈槸鐢卞摢涓妭鐐圭殑鍝釜鍙橀噺鐢熸垚鐨�
+ - `event: node_finished` node 鎵ц缁撴潫锛屾垚鍔熷け璐ュ悓涓�浜嬩欢涓笉鍚岀姸鎬�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `event` (string) 鍥哄畾涓� `node_finished`
+ - `data` (object) 璇︾粏鍐呭
+ - `id` (string) node 鎵ц ID
+ - `node_id` (string) 鑺傜偣 ID
+ - `index` (int) 鎵ц搴忓彿锛岀敤浜庡睍绀� Tracing Node 椤哄簭
+ - `predecessor_node_id` (string) optional 鍓嶇疆鑺傜偣 ID锛岀敤浜庣敾甯冨睍绀烘墽琛岃矾寰�
+ - `inputs` (object) 鑺傜偣涓墍鏈変娇鐢ㄥ埌鐨勫墠缃妭鐐瑰彉閲忓唴瀹�
+ - `process_data` (json) Optional 鑺傜偣杩囩▼鏁版嵁
+ - `outputs` (json) Optional 杈撳嚭鍐呭
+ - `status` (string) 鎵ц鐘舵�� `running` / `succeeded` / `failed` / `stopped`
+ - `error` (string) Optional 閿欒鍘熷洜
+ - `elapsed_time` (float) Optional 鑰楁椂(s)
+ - `execution_metadata` (json) 鍏冩暟鎹�
+ - `total_tokens` (int) optional 鎬讳娇鐢� tokens
+ - `total_price` (decimal) optional 鎬昏垂鐢�
+ - `currency` (string) optional 璐у竵锛屽 `USD` / `RMB`
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `event: workflow_finished` workflow 鎵ц缁撴潫锛屾垚鍔熷け璐ュ悓涓�浜嬩欢涓笉鍚岀姸鎬�
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `workflow_run_id` (string) workflow 鎵ц ID
+ - `event` (string) 鍥哄畾涓� `workflow_finished`
+ - `data` (object) 璇︾粏鍐呭
+ - `id` (string) workflow 鎵ц ID
+ - `workflow_id` (string) 鍏宠仈 Workflow ID
+ - `status` (string) 鎵ц鐘舵�� `running` / `succeeded` / `failed` / `stopped`
+ - `outputs` (json) Optional 杈撳嚭鍐呭
+ - `error` (string) Optional 閿欒鍘熷洜
+ - `elapsed_time` (float) Optional 鑰楁椂(s)
+ - `total_tokens` (int) Optional 鎬讳娇鐢� tokens
+ - `total_steps` (int) 鎬绘鏁帮紙鍐椾綑锛夛紝榛樿 0
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `finished_at` (timestamp) 缁撴潫鏃堕棿
+ - `event: tts_message` TTS 闊抽娴佷簨浠讹紝鍗筹細璇煶鍚堟垚杈撳嚭銆傚唴瀹规槸Mp3鏍煎紡鐨勯煶棰戝潡锛屼娇鐢� base64 缂栫爜鍚庣殑瀛楃涓诧紝鎾斁鐨勬椂鍊欑洿鎺ヨВ鐮佸嵆鍙��(寮�鍚嚜鍔ㄦ挱鏀炬墠鏈夋娑堟伅)
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `audio` (string) 璇煶鍚堟垚涔嬪悗鐨勯煶棰戝潡浣跨敤 Base64 缂栫爜涔嬪悗鐨勬枃鏈唴瀹癸紝鎾斁鐨勬椂鍊欑洿鎺� base64 瑙g爜閫佸叆鎾斁鍣ㄥ嵆鍙�
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: tts_message_end` TTS 闊抽娴佺粨鏉熶簨浠讹紝鏀跺埌杩欎釜浜嬩欢琛ㄧず闊抽娴佽繑鍥炵粨鏉熴��
+ - `task_id` (string) 浠诲姟 ID锛岀敤浜庤姹傝窡韪拰涓嬫柟鐨勫仠姝㈠搷搴旀帴鍙�
+ - `message_id` (string) 娑堟伅鍞竴 ID
+ - `audio` (string) 缁撴潫浜嬩欢鏄病鏈夐煶棰戠殑锛屾墍浠ヨ繖閲屾槸绌哄瓧绗︿覆
+ - `created_at` (int) 鍒涘缓鏃堕棿鎴筹紝濡傦細1705395332
+ - `event: ping` 姣� 10s 涓�娆$殑 ping 浜嬩欢锛屼繚鎸佽繛鎺ュ瓨娲汇��
+
+ ### Errors
+ - 400锛宍invalid_param`锛屼紶鍏ュ弬鏁板紓甯�
+ - 400锛宍app_unavailable`锛孉pp 閰嶇疆涓嶅彲鐢�
+ - 400锛宍provider_not_initialize`锛屾棤鍙敤妯″瀷鍑嵁閰嶇疆
+ - 400锛宍provider_quota_exceeded`锛屾ā鍨嬭皟鐢ㄩ搴︿笉瓒�
+ - 400锛宍model_currently_not_support`锛屽綋鍓嶆ā鍨嬩笉鍙敤
+ - 400锛宍workflow_request_error`锛寃orkflow 鎵ц澶辫触
+ - 500锛屾湇鍔″唴閮ㄥ紓甯�
+
+ </Col>
+ <Col sticky>
+ <CodeGroup title="Request" tag="POST" label="/workflows/run" targetCode={`curl -X POST '${props.appDetail.api_base_url}/workflows/run' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "inputs": ${JSON.stringify(props.inputs)},\n "response_mode": "streaming",\n "user": "abc-123"\n}'\n`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/workflows/run' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "inputs": {},
+ "response_mode": "streaming",
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Example: file array as an input variable">
+ ```json {{ title: 'File variable example' }}
+ {
+ "inputs": {
+ "{variable_name}":
+ [
+ {
+ "transfer_method": "local_file",
+ "upload_file_id": "{upload_file_id}",
+ "type": "{document_type}"
+ }
+ ]
+ }
+ }
+ ```
+ </CodeGroup>
+ ### Blocking Mode
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "workflow_run_id": "djflajgkldjgd",
+ "task_id": "9da23599-e713-473b-982c-4328d4f5c78a",
+ "data": {
+ "id": "fdlsjfjejkghjda",
+ "workflow_id": "fldjaslkfjlsda",
+ "status": "succeeded",
+ "outputs": {
+ "text": "Nice to meet you."
+ },
+ "error": null,
+ "elapsed_time": 0.875,
+ "total_tokens": 3562,
+ "total_steps": 8,
+ "created_at": 1705407629,
+ "finished_at": 1727807631
+ }
+ }
+ ```
+ </CodeGroup>
+ ### Streaming Mode
+ <CodeGroup title="Response">
+ ```streaming {{ title: 'Response' }}
+ data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}}
+ data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}}
+ data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}}
+ data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}}
+ data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
+ data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}
+ ```
+ </CodeGroup>
+ <CodeGroup title="File upload sample code">
+ ```json {{ title: 'File upload sample code' }}
+ import requests
+ import json
+
+ def upload_file(file_path, user):
+ upload_url = "https://api.dify.ai/v1/files/upload"
+ headers = {
+ "Authorization": "Bearer app-xxxxxxxx",
+ }
+
+ try:
+ print("涓婁紶鏂囦欢涓�...")
+ with open(file_path, 'rb') as file:
+ files = {
+ 'file': (file_path, file, 'text/plain') # 纭繚鏂囦欢浠ラ�傚綋鐨凪IME绫诲瀷涓婁紶
+ }
+ data = {
+ "user": user,
+ "type": "TXT" # 璁剧疆鏂囦欢绫诲瀷涓篢XT
+ }
+
+ response = requests.post(upload_url, headers=headers, files=files, data=data)
+ if response.status_code == 201: # 201 琛ㄧず鍒涘缓鎴愬姛
+ print("鏂囦欢涓婁紶鎴愬姛")
+ return response.json().get("id") # 鑾峰彇涓婁紶鐨勬枃浠� ID
+ else:
+ print(f"鏂囦欢涓婁紶澶辫触锛岀姸鎬佺爜: {response.status_code}")
+ return None
+ except Exception as e:
+ print(f"鍙戠敓閿欒: {str(e)}")
+ return None
+
+ def run_workflow(file_id, user, response_mode="blocking"):
+ workflow_url = "https://api.dify.ai/v1/workflows/run"
+ headers = {
+ "Authorization": "Bearer app-xxxxxxxxx",
+ "Content-Type": "application/json"
+ }
+
+ data = {
+ "inputs": {
+ "orig_mail": [{
+ "transfer_method": "local_file",
+ "upload_file_id": file_id,
+ "type": "document"
+ }]
+ },
+ "response_mode": response_mode,
+ "user": user
+ }
+
+ try:
+ print("杩愯宸ヤ綔娴�...")
+ response = requests.post(workflow_url, headers=headers, json=data)
+ if response.status_code == 200:
+ print("宸ヤ綔娴佹墽琛屾垚鍔�")
+ return response.json()
+ else:
+ print(f"宸ヤ綔娴佹墽琛屽け璐ワ紝鐘舵�佺爜: {response.status_code}")
+ return {"status": "error", "message": f"Failed to execute workflow, status code: {response.status_code}"}
+ except Exception as e:
+ print(f"鍙戠敓閿欒: {str(e)}")
+ return {"status": "error", "message": str(e)}
+
+ # 浣跨敤绀轰緥
+ file_path = "{your_file_path}"
+ user = "difyuser"
+
+ # 涓婁紶鏂囦欢
+ file_id = upload_file(file_path, user)
+ if file_id:
+ # 鏂囦欢涓婁紶鎴愬姛锛岀户缁繍琛屽伐浣滄祦
+ result = run_workflow(file_id, user)
+ print(result)
+ else:
+ print("鏂囦欢涓婁紶澶辫触锛屾棤娉曟墽琛屽伐浣滄祦")
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/workflows/run/:workflow_run_id'
+ method='GET'
+ title='鑾峰彇workflow鎵ц鎯呭喌'
+ name='#get-workflow-run-detail'
+/>
+<Row>
+ <Col>
+ 鏍规嵁 workflow 鎵ц ID 鑾峰彇 workflow 浠诲姟褰撳墠鎵ц缁撴灉
+ ### Path
+ - `workflow_run_id` (string) workflow_run_id锛屽彲鍦ㄦ祦寮忚繑鍥� Chunk 涓幏鍙�
+ ### Response
+ - `id` (string) workflow 鎵ц ID
+ - `workflow_id` (string) 鍏宠仈鐨� Workflow ID
+ - `status` (string) 鎵ц鐘舵�� `running` / `succeeded` / `failed` / `stopped`
+ - `inputs` (json) 浠诲姟杈撳叆鍐呭
+ - `outputs` (json) 浠诲姟杈撳嚭鍐呭
+ - `error` (string) 閿欒鍘熷洜
+ - `total_steps` (int) 浠诲姟鎵ц鎬绘鏁�
+ - `total_tokens` (int) 浠诲姟鎵ц鎬� tokens
+ - `created_at` (timestamp) 浠诲姟寮�濮嬫椂闂�
+ - `finished_at` (timestamp) 浠诲姟缁撴潫鏃堕棿
+ - `elapsed_time` (float) 鑰楁椂(s)
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="GET" label="/workflows/run/:workflow_run_id" targetCode={`curl -X GET '${props.appDetail.api_base_url}/workflows/run/:workflow_run_id' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/workflows/run/:workflow_run_id' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json'
+ ```
+ </CodeGroup>
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "b1ad3277-089e-42c6-9dff-6820d94fbc76",
+ "workflow_id": "19eff89f-ec03-4f75-b0fc-897e7effea02",
+ "status": "succeeded",
+ "inputs": "{\"sys.files\": [], \"sys.user_id\": \"abc-123\"}",
+ "outputs": null,
+ "error": null,
+ "total_steps": 3,
+ "total_tokens": 0,
+ "created_at": 1705407629,
+ "finished_at": 1727807631,
+ "elapsed_time": 30.098514399956912
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/workflows/tasks/:task_id/stop'
+ method='POST'
+ title='鍋滄鍝嶅簲'
+ name='#stop-generatebacks'
+/>
+<Row>
+ <Col>
+ 浠呮敮鎸佹祦寮忔ā寮忋��
+ ### Path
+ - `task_id` (string) 浠诲姟 ID锛屽彲鍦ㄦ祦寮忚繑鍥� Chunk 涓幏鍙�
+ ### Request Body
+ - `user` (string) Required
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屽繀椤诲拰鍙戦�佹秷鎭帴鍙d紶鍏� user 淇濇寔涓�鑷淬��
+ ### Response
+ - `result` (string) 鍥哄畾杩斿洖 "success"
+ </Col>
+ <Col sticky>
+ ### Request Example
+ <CodeGroup title="Request" tag="POST" label="/workflows/tasks/:task_id/stop" targetCode={`curl -X POST '${props.appDetail.api_base_url}/workflows/tasks/:task_id/stop' \\\n-H 'Authorization: Bearer {api_key}' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{"user": "abc-123"}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/workflows/tasks/:task_id/stop' \
+ -H 'Authorization: Bearer {api_key}' \
+ -H 'Content-Type: application/json' \
+ --data-raw '{
+ "user": "abc-123"
+ }'
+ ```
+ </CodeGroup>
+
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "result": "success"
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/files/upload'
+ method='POST'
+ title='涓婁紶鏂囦欢'
+ name='#files-upload'
+/>
+<Row>
+ <Col>
+ 涓婁紶鏂囦欢骞跺湪鍙戦�佹秷鎭椂浣跨敤锛屽彲瀹炵幇鍥炬枃澶氭ā鎬佺悊瑙c��
+ 鏀寔鎮ㄧ殑宸ヤ綔娴佺▼鎵�鏀寔鐨勪换浣曟牸寮忋��
+ <i>涓婁紶鐨勬枃浠朵粎渚涘綋鍓嶇粓绔敤鎴蜂娇鐢ㄣ��</i>
+
+ ### Request Body
+ 璇ユ帴鍙i渶浣跨敤 `multipart/form-data` 杩涜璇锋眰銆�
+ <Properties>
+ <Property name='file' type='file' key='file'>
+ 瑕佷笂浼犵殑鏂囦欢銆�
+ </Property>
+ <Property name='user' type='string' key='user'>
+ 鐢ㄦ埛鏍囪瘑锛岀敤浜庡畾涔夌粓绔敤鎴风殑韬唤锛屽繀椤诲拰鍙戦�佹秷鎭帴鍙d紶鍏� user 淇濇寔涓�鑷淬��
+ </Property>
+ </Properties>
+
+ ### Response
+ 鎴愬姛涓婁紶鍚庯紝鏈嶅姟鍣ㄤ細杩斿洖鏂囦欢鐨� ID 鍜岀浉鍏充俊鎭��
+ - `id` (uuid) ID
+ - `name` (string) 鏂囦欢鍚�
+ - `size` (int) 鏂囦欢澶у皬锛坆yte锛�
+ - `extension` (string) 鏂囦欢鍚庣紑
+ - `mime_type` (string) 鏂囦欢 mime-type
+ - `created_by` (uuid) 涓婁紶浜� ID
+ - `created_at` (timestamp) 涓婁紶鏃堕棿
+
+ ### Errors
+ - 400锛宍no_file_uploaded`锛屽繀椤绘彁渚涙枃浠�
+ - 400锛宍too_many_files`锛岀洰鍓嶅彧鎺ュ彈涓�涓枃浠�
+ - 400锛宍unsupported_preview`锛岃鏂囦欢涓嶆敮鎸侀瑙�
+ - 400锛宍unsupported_estimate`锛岃鏂囦欢涓嶆敮鎸佷及绠�
+ - 413锛宍file_too_large`锛屾枃浠跺お澶�
+ - 415锛宍unsupported_file_type`锛屼笉鏀寔鐨勬墿灞曞悕锛屽綋鍓嶅彧鎺ュ彈鏂囨。绫绘枃浠�
+ - 503锛宍s3_connection_failed`锛屾棤娉曡繛鎺ュ埌 S3 鏈嶅姟
+ - 503锛宍s3_permission_denied`锛屾棤鏉冮檺涓婁紶鏂囦欢鍒� S3
+ - 503锛宍s3_file_too_large`锛屾枃浠惰秴鍑� S3 澶у皬闄愬埗
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="POST" label="/files/upload" targetCode={`curl -X POST '${props.appDetail.api_base_url}/files/upload' \\\n--header 'Authorization: Bearer {api_key}' \\\n--form 'file=@localfile;type=image/[png|jpeg|jpg|webp|gif] \\\n--form 'user=abc-123'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST '${props.appDetail.api_base_url}/files/upload' \
+ --header 'Authorization: Bearer {api_key}' \
+ --form 'file=@"/path/to/file"'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "id": "72fa9618-8f89-4a37-9b33-7e1178a24a67",
+ "name": "example.png",
+ "size": 1024,
+ "extension": "png",
+ "mime_type": "image/png",
+ "created_by": 123,
+ "created_at": 1577836800,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/workflows/logs'
+ method='GET'
+ title='鑾峰彇 workflow 鏃ュ織'
+ name='#Get-Workflow-Logs'
+/>
+<Row>
+ <Col>
+ 鍊掑簭杩斿洖workflow鏃ュ織
+
+ ### Query
+
+ <Properties>
+ <Property name='keyword' type='string' key='keyword'>
+ 鍏抽敭瀛�
+ </Property>
+ <Property name='status' type='string' key='status'>
+ 鎵ц鐘舵�� succeeded/failed/stopped
+ </Property>
+ <Property name='page' type='int' key='page'>
+ 褰撳墠椤电爜, 榛樿1.
+ </Property>
+ <Property name='limit' type='int' key='limit'>
+ 姣忛〉鏉℃暟, 榛樿20.
+ </Property>
+ </Properties>
+
+ ### Response
+ - `page` (int) 褰撳墠椤电爜
+ - `limit` (int) 姣忛〉鏉℃暟
+ - `total` (int) 鎬绘潯鏁�
+ - `has_more` (bool) 鏄惁杩樻湁鏇村鏁版嵁
+ - `data` (array[object]) 褰撳墠椤电爜鐨勬暟鎹�
+ - `id` (string) 鏍囪瘑
+ - `workflow_run` (object) Workflow 鎵ц鏃ュ織
+ - `id` (string) 鏍囪瘑
+ - `version` (string) 鐗堟湰
+ - `status` (string) 鎵ц鐘舵��, `running` / `succeeded` / `failed` / `stopped`
+ - `error` (string) (鍙��) 閿欒
+ - `elapsed_time` (float) 鑰楁椂锛屽崟浣嶇
+ - `total_tokens` (int) 娑堣�楃殑token鏁伴噺
+ - `total_steps` (int) 鎵ц姝ラ闀垮害
+ - `created_at` (timestamp) 寮�濮嬫椂闂�
+ - `finished_at` (timestamp) 缁撴潫鏃堕棿
+ - `created_from` (string) 鏉ユ簮
+ - `created_by_role` (string) 瑙掕壊
+ - `created_by_account` (string) (鍙��) 甯愬彿
+ - `created_by_end_user` (object) 鐢ㄦ埛
+ - `id` (string) 鏍囪瘑
+ - `type` (string) 绫诲瀷
+ - `is_anonymous` (bool) 鏄惁鍖垮悕
+ - `session_id` (string) 浼氳瘽鏍囪瘑
+ - `created_at` (timestamp) 鍒涘缓鏃堕棿
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/workflows/logs" targetCode={`curl -X GET '${props.appDetail.api_base_url}/workflows/logs'\\\n --header 'Authorization: Bearer {api_key}'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/workflows/logs?limit=1'
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+ ### Response Example
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "page": 1,
+ "limit": 1,
+ "total": 7,
+ "has_more": true,
+ "data": [
+ {
+ "id": "e41b93f1-7ca2-40fd-b3a8-999aeb499cc0",
+ "workflow_run": {
+ "id": "c0640fc8-03ef-4481-a96c-8a13b732a36e",
+ "version": "2024-08-01 12:17:09.771832",
+ "status": "succeeded",
+ "error": null,
+ "elapsed_time": 1.3588523610014818,
+ "total_tokens": 0,
+ "total_steps": 3,
+ "created_at": 1726139643,
+ "finished_at": 1726139644
+ },
+ "created_from": "service-api",
+ "created_by_role": "end_user",
+ "created_by_account": null,
+ "created_by_end_user": {
+ "id": "7f7d9117-dd9d-441d-8970-87e5e7e687a3",
+ "type": "service_api",
+ "is_anonymous": false,
+ "session_id": "abc-123"
+ },
+ "created_at": 1726139644
+ }
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+---
+
+<Heading
+ url='/info'
+ method='GET'
+ title='鑾峰彇搴旂敤鍩烘湰淇℃伅'
+ name='#info'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇搴旂敤鐨勫熀鏈俊鎭�
+ ### Response
+ - `name` (string) 搴旂敤鍚嶇О
+ - `description` (string) 搴旂敤鎻忚堪
+ - `tags` (array[string]) 搴旂敤鏍囩
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/info' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+ </CodeGroup>
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "name": "My App",
+ "description": "This is my app.",
+ "tags": [
+ "tag1",
+ "tag2"
+ ]
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/parameters'
+ method='GET'
+ title='鑾峰彇搴旂敤鍙傛暟'
+ name='#parameters'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬杩涘叆椤甸潰涓�寮�濮嬶紝鑾峰彇鍔熻兘寮�鍏炽�佽緭鍏ュ弬鏁板悕绉般�佺被鍨嬪強榛樿鍊肩瓑浣跨敤銆�
+
+ ### Response
+ - `user_input_form` (array[object]) 鐢ㄦ埛杈撳叆琛ㄥ崟閰嶇疆
+ - `text-input` (object) 鏂囨湰杈撳叆鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `paragraph` (object) 娈佃惤鏂囨湰杈撳叆鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `select` (object) 涓嬫媺鎺т欢
+ - `label` (string) 鎺т欢灞曠ず鏍囩鍚�
+ - `variable` (string) 鎺т欢 ID
+ - `required` (bool) 鏄惁蹇呭~
+ - `default` (string) 榛樿鍊�
+ - `options` (array[string]) 閫夐」鍊�
+ - `file_upload` (object) 鏂囦欢涓婁紶閰嶇疆
+ - `image` (object) 鍥剧墖璁剧疆
+ 褰撳墠浠呮敮鎸佸浘鐗囩被鍨嬶細`png`, `jpg`, `jpeg`, `webp`, `gif`
+ - `enabled` (bool) 鏄惁寮�鍚�
+ - `number_limits` (int) 鍥剧墖鏁伴噺闄愬埗锛岄粯璁� 3
+ - `transfer_methods` (array[string]) 浼犻�掓柟寮忓垪琛紝remote_url , local_file锛屽繀閫変竴涓�
+ - `system_parameters` (object) 绯荤粺鍙傛暟
+ - `file_size_limit` (int) 鏂囨。涓婁紶澶у皬闄愬埗 (MB)
+ - `image_file_size_limit` (int) 鍥剧墖鏂囦欢涓婁紶澶у皬闄愬埗锛圡B锛�
+ - `audio_file_size_limit` (int) 闊抽鏂囦欢涓婁紶澶у皬闄愬埗 (MB)
+ - `video_file_size_limit` (int) 瑙嗛鏂囦欢涓婁紶澶у皬闄愬埗 (MB)
+
+ </Col>
+ <Col sticky>
+
+ <CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters'`}>
+
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/parameters' \
+ --header 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "user_input_form": [
+ {
+ "paragraph": {
+ "label": "Query",
+ "variable": "query",
+ "required": true,
+ "default": ""
+ }
+ }
+ ],
+ "file_upload": {
+ "image": {
+ "enabled": false,
+ "number_limits": 3,
+ "detail": "high",
+ "transfer_methods": [
+ "remote_url",
+ "local_file"
+ ]
+ }
+ },
+ "system_parameters": {
+ "file_size_limit": 15,
+ "image_file_size_limit": 10,
+ "audio_file_size_limit": 50,
+ "video_file_size_limit": 100
+ }
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+
+---
+
+<Heading
+ url='/site'
+ method='GET'
+ title='鑾峰彇搴旂敤 WebApp 璁剧疆'
+ name='#site'
+/>
+<Row>
+ <Col>
+ 鐢ㄤ簬鑾峰彇搴旂敤鐨� WebApp 璁剧疆
+ ### Response
+ - `title` (string) WebApp 鍚嶇О
+ - `icon_type` (string) 鍥炬爣绫诲瀷, `emoji`-琛ㄦ儏, `image`-鍥剧墖
+ - `icon` (string) 鍥炬爣, 濡傛灉鏄� `emoji` 绫诲瀷, 鍒欐槸 emoji 琛ㄦ儏绗﹀彿, 濡傛灉鏄� `image` 绫诲瀷, 鍒欐槸鍥剧墖 URL
+ - `icon_background` (string) hex 鏍煎紡鐨勮儗鏅壊
+ - `icon_url` (string) 鍥炬爣 URL
+ - `description` (string) 鎻忚堪
+ - `copyright` (string) 鐗堟潈淇℃伅
+ - `privacy_policy` (string) 闅愮鏀跨瓥閾炬帴
+ - `custom_disclaimer` (string) 鑷畾涔夊厤璐e0鏄�
+ - `default_language` (string) 榛樿璇█
+ - `show_workflow_steps` (bool) 鏄惁鏄剧ず宸ヤ綔娴佽鎯�
+ </Col>
+ <Col>
+ <CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
+ ```bash {{ title: 'cURL' }}
+ curl -X GET '${props.appDetail.api_base_url}/site' \
+ -H 'Authorization: Bearer {api_key}'
+ ```
+
+ </CodeGroup>
+
+ <CodeGroup title="Response">
+ ```json {{ title: 'Response' }}
+ {
+ "title": "My App",
+ "icon_type": "emoji",
+ "icon": "馃槃",
+ "icon_background": "#FFEAD5",
+ "icon_url": null,
+ "description": "This is my app.",
+ "copyright": "all rights reserved",
+ "privacy_policy": "",
+ "custom_disclaimer": "All generated by AI",
+ "default_language": "en-US",
+ "show_workflow_steps": false,
+ }
+ ```
+ </CodeGroup>
+ </Col>
+</Row>
+___
diff --git a/app/components/explore/app-card/index.tsx b/app/components/explore/app-card/index.tsx
new file mode 100644
index 0000000..31d218a
--- /dev/null
+++ b/app/components/explore/app-card/index.tsx
@@ -0,0 +1,70 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { PlusIcon } from '@heroicons/react/20/solid'
+import Button from '../../base/button'
+import cn from '@/utils/classnames'
+import type { App } from '@/models/explore'
+import AppIcon from '@/app/components/base/app-icon'
+import { AppTypeIcon } from '../../app/type-selector'
+export type AppCardProps = {
+ app: App
+ canCreate: boolean
+ onCreate: () => void
+ isExplore: boolean
+}
+
+const AppCard = ({
+ app,
+ canCreate,
+ onCreate,
+ isExplore,
+}: AppCardProps) => {
+ const { t } = useTranslation()
+ const { app: appBasicInfo } = app
+ return (
+ <div className={cn('group relative col-span-1 flex cursor-pointer flex-col overflow-hidden rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg pb-2 shadow-sm transition-all duration-200 ease-in-out hover:shadow-lg')}>
+ <div className='flex h-[66px] shrink-0 grow-0 items-center gap-3 px-[14px] pb-3 pt-[14px]'>
+ <div className='relative shrink-0'>
+ <AppIcon
+ size='large'
+ iconType={appBasicInfo.icon_type}
+ icon={appBasicInfo.icon}
+ background={appBasicInfo.icon_background}
+ imageUrl={appBasicInfo.icon_url}
+ />
+ <AppTypeIcon wrapperClassName='absolute -bottom-0.5 -right-0.5 w-4 h-4 rounded-[4px] border border-divider-regular outline outline-components-panel-on-panel-item-bg'
+ className='h-3 w-3' type={appBasicInfo.mode} />
+ </div>
+ <div className='w-0 grow py-[1px]'>
+ <div className='flex items-center text-sm font-semibold leading-5 text-text-secondary'>
+ <div className='truncate' title={appBasicInfo.name}>{appBasicInfo.name}</div>
+ </div>
+ <div className='flex items-center text-[10px] font-medium leading-[18px] text-text-tertiary'>
+ {appBasicInfo.mode === 'advanced-chat' && <div className='truncate'>{t('app.types.advanced').toUpperCase()}</div>}
+ {appBasicInfo.mode === 'chat' && <div className='truncate'>{t('app.types.chatbot').toUpperCase()}</div>}
+ {appBasicInfo.mode === 'agent-chat' && <div className='truncate'>{t('app.types.agent').toUpperCase()}</div>}
+ {appBasicInfo.mode === 'workflow' && <div className='truncate'>{t('app.types.workflow').toUpperCase()}</div>}
+ {appBasicInfo.mode === 'completion' && <div className='truncate'>{t('app.types.completion').toUpperCase()}</div>}
+ </div>
+ </div>
+ </div>
+ <div className="description-wrapper system-xs-regular h-[90px] px-[14px] text-text-tertiary">
+ <div className='line-clamp-4 group-hover:line-clamp-2'>
+ {app.description}
+ </div>
+ </div>
+ {isExplore && canCreate && (
+ <div className={cn('absolute bottom-0 left-0 right-0 hidden bg-gradient-to-t from-components-panel-gradient-2 from-[60.27%] to-transparent p-4 pt-8 group-hover:flex')}>
+ <div className={cn('flex h-8 w-full items-center space-x-2')}>
+ <Button variant='primary' className='h-7 grow' onClick={() => onCreate()}>
+ <PlusIcon className='mr-1 h-4 w-4' />
+ <span className='text-xs'>{t('explore.appCard.addToWorkspace')}</span>
+ </Button>
+ </div>
+ </div>
+ )}
+ </div>
+ )
+}
+
+export default AppCard
diff --git a/app/components/explore/app-list/index.tsx b/app/components/explore/app-list/index.tsx
new file mode 100644
index 0000000..7e2d990
--- /dev/null
+++ b/app/components/explore/app-list/index.tsx
@@ -0,0 +1,246 @@
+'use client'
+
+import React, { useCallback, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import useSWR from 'swr'
+import { useDebounceFn } from 'ahooks'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import ExploreContext from '@/context/explore-context'
+import type { App } from '@/models/explore'
+import Category from '@/app/components/explore/category'
+import AppCard from '@/app/components/explore/app-card'
+import { fetchAppDetail, fetchAppList } from '@/service/explore'
+import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
+import CreateAppModal from '@/app/components/explore/create-app-modal'
+import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
+import Loading from '@/app/components/base/loading'
+import Input from '@/app/components/base/input'
+import {
+ DSLImportMode,
+} from '@/models/app'
+import { useImportDSL } from '@/hooks/use-import-dsl'
+import DSLConfirmModal from '@/app/components/app/create-from-dsl-modal/dsl-confirm-modal'
+
+type AppsProps = {
+ onSuccess?: () => void
+}
+
+export enum PageType {
+ EXPLORE = 'explore',
+ CREATE = 'create',
+}
+
+const Apps = ({
+ onSuccess,
+}: AppsProps) => {
+ const { t } = useTranslation()
+ const { hasEditPermission } = useContext(ExploreContext)
+ const allCategoriesEn = t('explore.apps.allCategories', { lng: 'en' })
+
+ const [keywords, setKeywords] = useState('')
+ const [searchKeywords, setSearchKeywords] = useState('')
+
+ const { run: handleSearch } = useDebounceFn(() => {
+ setSearchKeywords(keywords)
+ }, { wait: 500 })
+
+ const handleKeywordsChange = (value: string) => {
+ setKeywords(value)
+ handleSearch()
+ }
+
+ const [currentType, setCurrentType] = useState<string>('')
+ const [currCategory, setCurrCategory] = useTabSearchParams({
+ defaultTab: allCategoriesEn,
+ disableSearchParams: false,
+ })
+
+ const {
+ data: { categories, allList },
+ } = useSWR(
+ ['/explore/apps'],
+ () =>
+ fetchAppList().then(({ categories, recommended_apps }) => ({
+ categories,
+ allList: recommended_apps.sort((a, b) => a.position - b.position),
+ })),
+ {
+ fallbackData: {
+ categories: [],
+ allList: [],
+ },
+ },
+ )
+
+ const filteredList = useMemo(() => {
+ if (currCategory === allCategoriesEn) {
+ if (!currentType)
+ return allList
+ else if (currentType === 'chatbot')
+ return allList.filter(item => (item.app.mode === 'chat' || item.app.mode === 'advanced-chat'))
+ else if (currentType === 'agent')
+ return allList.filter(item => (item.app.mode === 'agent-chat'))
+ else
+ return allList.filter(item => (item.app.mode === 'workflow'))
+ }
+ else {
+ if (!currentType)
+ return allList.filter(item => item.category === currCategory)
+ else if (currentType === 'chatbot')
+ return allList.filter(item => (item.app.mode === 'chat' || item.app.mode === 'advanced-chat') && item.category === currCategory)
+ else if (currentType === 'agent')
+ return allList.filter(item => (item.app.mode === 'agent-chat') && item.category === currCategory)
+ else
+ return allList.filter(item => (item.app.mode === 'workflow') && item.category === currCategory)
+ }
+ }, [currentType, currCategory, allCategoriesEn, allList])
+
+ const searchFilteredList = useMemo(() => {
+ if (!searchKeywords || !filteredList || filteredList.length === 0)
+ return filteredList
+
+ const lowerCaseSearchKeywords = searchKeywords.toLowerCase()
+
+ return filteredList.filter(item =>
+ item.app && item.app.name && item.app.name.toLowerCase().includes(lowerCaseSearchKeywords),
+ )
+ }, [searchKeywords, filteredList])
+
+ const [currApp, setCurrApp] = React.useState<App | null>(null)
+ const [isShowCreateModal, setIsShowCreateModal] = React.useState(false)
+
+ const {
+ handleImportDSL,
+ handleImportDSLConfirm,
+ versions,
+ isFetching,
+ } = useImportDSL()
+ const [showDSLConfirmModal, setShowDSLConfirmModal] = useState(false)
+ const onCreate: CreateAppModalProps['onConfirm'] = async ({
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ description,
+ }) => {
+ const { export_data } = await fetchAppDetail(
+ currApp?.app.id as string,
+ )
+ const payload = {
+ mode: DSLImportMode.YAML_CONTENT,
+ yaml_content: export_data,
+ name,
+ icon_type,
+ icon,
+ icon_background,
+ description,
+ }
+ await handleImportDSL(payload, {
+ onSuccess: () => {
+ setIsShowCreateModal(false)
+ },
+ onPending: () => {
+ setShowDSLConfirmModal(true)
+ },
+ })
+ }
+
+ const onConfirmDSL = useCallback(async () => {
+ await handleImportDSLConfirm({
+ onSuccess,
+ })
+ }, [handleImportDSLConfirm, onSuccess])
+
+ if (!categories || categories.length === 0) {
+ return (
+ <div className="flex h-full items-center">
+ <Loading type="area" />
+ </div>
+ )
+ }
+
+ return (
+ <div className={cn(
+ 'flex h-full flex-col border-l-[0.5px] border-divider-regular',
+ )}>
+
+ <div className='shrink-0 px-12 pt-6'>
+ <div className={`mb-1 ${s.textGradient} text-xl font-semibold`}>{t('explore.apps.title')}</div>
+ <div className='text-sm text-text-tertiary'>{t('explore.apps.description')}</div>
+ </div>
+
+ <div className={cn(
+ 'mt-6 flex items-center justify-between px-12',
+ )}>
+ <>
+ <Category
+ list={categories}
+ value={currCategory}
+ onChange={setCurrCategory}
+ allCategoriesEn={allCategoriesEn}
+ />
+ </>
+ <Input
+ showLeftIcon
+ showClearIcon
+ wrapperClassName='w-[200px]'
+ value={keywords}
+ onChange={e => handleKeywordsChange(e.target.value)}
+ onClear={() => handleKeywordsChange('')}
+ />
+
+ </div>
+
+ <div className={cn(
+ 'relative mt-4 flex flex-1 shrink-0 grow flex-col overflow-auto pb-6',
+ )}>
+ <nav
+ className={cn(
+ s.appList,
+ 'grid shrink-0 content-start gap-4 px-6 sm:px-12',
+ )}>
+ {searchFilteredList.map(app => (
+ <AppCard
+ key={app.app_id}
+ isExplore
+ app={app}
+ canCreate={hasEditPermission}
+ onCreate={() => {
+ setCurrApp(app)
+ setIsShowCreateModal(true)
+ }}
+ />
+ ))}
+ </nav>
+ </div>
+ {isShowCreateModal && (
+ <CreateAppModal
+ appIconType={currApp?.app.icon_type || 'emoji'}
+ appIcon={currApp?.app.icon || ''}
+ appIconBackground={currApp?.app.icon_background || ''}
+ appIconUrl={currApp?.app.icon_url}
+ appName={currApp?.app.name || ''}
+ appDescription={currApp?.app.description || ''}
+ show={isShowCreateModal}
+ onConfirm={onCreate}
+ confirmDisabled={isFetching}
+ onHide={() => setIsShowCreateModal(false)}
+ />
+ )}
+ {
+ showDSLConfirmModal && (
+ <DSLConfirmModal
+ versions={versions}
+ onCancel={() => setShowDSLConfirmModal(false)}
+ onConfirm={onConfirmDSL}
+ confirmDisabled={isFetching}
+ />
+ )
+ }
+ </div>
+ )
+}
+
+export default React.memo(Apps)
diff --git a/app/components/explore/app-list/style.module.css b/app/components/explore/app-list/style.module.css
new file mode 100644
index 0000000..241130a
--- /dev/null
+++ b/app/components/explore/app-list/style.module.css
@@ -0,0 +1,29 @@
+.textGradient {
+ background: linear-gradient(to right, rgba(16, 74, 225, 1) 0, rgba(0, 152, 238, 1) 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ text-fill-color: transparent;
+}
+
+.appList {
+ grid-template-columns: repeat(1, minmax(0, 1fr))
+}
+
+@media (min-width: 1624px) {
+ .appList {
+ grid-template-columns: repeat(4, minmax(0, 1fr))
+ }
+}
+
+@media (min-width: 1300px) and (max-width: 1624px) {
+ .appList {
+ grid-template-columns: repeat(3, minmax(0, 1fr))
+ }
+}
+
+@media (min-width: 1025px) and (max-width: 1300px) {
+ .appList {
+ grid-template-columns: repeat(2, minmax(0, 1fr))
+ }
+}
diff --git a/app/components/explore/category.tsx b/app/components/explore/category.tsx
new file mode 100644
index 0000000..51daaa9
--- /dev/null
+++ b/app/components/explore/category.tsx
@@ -0,0 +1,60 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import cn from '@/utils/classnames'
+import exploreI18n from '@/i18n/en-US/explore'
+import type { AppCategory } from '@/models/explore'
+import { ThumbsUp } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
+
+const categoryI18n = exploreI18n.category
+
+export type ICategoryProps = {
+ className?: string
+ list: AppCategory[]
+ value: string
+ onChange: (value: AppCategory | string) => void
+ /**
+ * default value for search param 'category' in en
+ */
+ allCategoriesEn: string
+}
+
+const Category: FC<ICategoryProps> = ({
+ className,
+ list,
+ value,
+ onChange,
+ allCategoriesEn,
+}) => {
+ const { t } = useTranslation()
+ const isAllCategories = !list.includes(value as AppCategory) || value === allCategoriesEn
+
+ const itemClassName = (isSelected: boolean) => cn(
+ 'flex h-[32px] cursor-pointer items-center rounded-lg border-[0.5px] border-transparent px-3 py-[7px] font-medium leading-[18px] text-text-tertiary hover:bg-components-main-nav-nav-button-bg-active',
+ isSelected && 'border-components-main-nav-nav-button-border bg-components-main-nav-nav-button-bg-active text-components-main-nav-nav-button-text-active shadow-xs',
+ )
+
+ return (
+ <div className={cn(className, 'flex flex-wrap space-x-1 text-[13px]')}>
+ <div
+ className={itemClassName(isAllCategories)}
+ onClick={() => onChange(allCategoriesEn)}
+ >
+ <ThumbsUp className='mr-1 h-3.5 w-3.5' />
+ {t('explore.apps.allCategories')}
+ </div>
+ {list.filter(name => name !== allCategoriesEn).map(name => (
+ <div
+ key={name}
+ className={itemClassName(name === value)}
+ onClick={() => onChange(name)}
+ >
+ {(categoryI18n as any)[name] ? t(`explore.category.${name}`) : name}
+ </div>
+ ))}
+ </div>
+ )
+}
+
+export default React.memo(Category)
diff --git a/app/components/explore/create-app-modal/index.tsx b/app/components/explore/create-app-modal/index.tsx
new file mode 100644
index 0000000..f30b286
--- /dev/null
+++ b/app/components/explore/create-app-modal/index.tsx
@@ -0,0 +1,195 @@
+'use client'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiCloseLine, RiCommandLine, RiCornerDownLeftLine } from '@remixicon/react'
+import { useDebounceFn, useKeyPress } from 'ahooks'
+import AppIconPicker from '../../base/app-icon-picker'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import Input from '@/app/components/base/input'
+import Textarea from '@/app/components/base/textarea'
+import Switch from '@/app/components/base/switch'
+import Toast from '@/app/components/base/toast'
+import AppIcon from '@/app/components/base/app-icon'
+import { useProviderContext } from '@/context/provider-context'
+import AppsFull from '@/app/components/billing/apps-full-in-dialog'
+import type { AppIconType } from '@/types/app'
+import { noop } from 'lodash-es'
+
+export type CreateAppModalProps = {
+ show: boolean
+ isEditModal?: boolean
+ appName: string
+ appDescription: string
+ appIconType: AppIconType | null
+ appIcon: string
+ appIconBackground?: string | null
+ appIconUrl?: string | null
+ appMode?: string
+ appUseIconAsAnswerIcon?: boolean
+ onConfirm: (info: {
+ name: string
+ icon_type: AppIconType
+ icon: string
+ icon_background?: string
+ description: string
+ use_icon_as_answer_icon?: boolean
+ }) => Promise<void>
+ confirmDisabled?: boolean
+ onHide: () => void
+}
+
+const CreateAppModal = ({
+ show = false,
+ isEditModal = false,
+ appIconType,
+ appIcon: _appIcon,
+ appIconBackground,
+ appIconUrl,
+ appName,
+ appDescription,
+ appMode,
+ appUseIconAsAnswerIcon,
+ onConfirm,
+ confirmDisabled,
+ onHide,
+}: CreateAppModalProps) => {
+ const { t } = useTranslation()
+
+ const [name, setName] = React.useState(appName)
+ const [appIcon, setAppIcon] = useState(
+ () => appIconType === 'image'
+ ? { type: 'image' as const, fileId: _appIcon, url: appIconUrl }
+ : { type: 'emoji' as const, icon: _appIcon, background: appIconBackground },
+ )
+ const [showAppIconPicker, setShowAppIconPicker] = useState(false)
+ const [description, setDescription] = useState(appDescription || '')
+ const [useIconAsAnswerIcon, setUseIconAsAnswerIcon] = useState(appUseIconAsAnswerIcon || false)
+
+ const { plan, enableBilling } = useProviderContext()
+ const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
+
+ const submit = useCallback(() => {
+ if (!name.trim()) {
+ Toast.notify({ type: 'error', message: t('explore.appCustomize.nameRequired') })
+ return
+ }
+ onConfirm({
+ name,
+ icon_type: appIcon.type,
+ icon: appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId,
+ icon_background: appIcon.type === 'emoji' ? appIcon.background! : undefined,
+ description,
+ use_icon_as_answer_icon: useIconAsAnswerIcon,
+ })
+ onHide()
+ }, [name, appIcon, description, useIconAsAnswerIcon, onConfirm, onHide, t])
+
+ const { run: handleSubmit } = useDebounceFn(submit, { wait: 300 })
+
+ useKeyPress(['meta.enter', 'ctrl.enter'], () => {
+ if (show && !(!isEditModal && isAppsFull) && name.trim())
+ handleSubmit()
+ })
+
+ useKeyPress('esc', () => {
+ if (show)
+ onHide()
+ })
+
+ return (
+ <>
+ <Modal
+ isShow={show}
+ onClose={noop}
+ className='relative !max-w-[480px] px-8'
+ >
+ <div className='absolute right-4 top-4 cursor-pointer p-2' onClick={onHide}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ {isEditModal && (
+ <div className='mb-9 text-xl font-semibold leading-[30px] text-text-primary'>{t('app.editAppTitle')}</div>
+ )}
+ {!isEditModal && (
+ <div className='mb-9 text-xl font-semibold leading-[30px] text-text-primary'>{t('explore.appCustomize.title', { name: appName })}</div>
+ )}
+ <div className='mb-9'>
+ {/* icon & name */}
+ <div className='pt-2'>
+ <div className='py-2 text-sm font-medium leading-[20px] text-text-primary'>{t('app.newApp.captionName')}</div>
+ <div className='flex items-center justify-between space-x-2'>
+ <AppIcon
+ size='large'
+ onClick={() => { setShowAppIconPicker(true) }}
+ className='cursor-pointer'
+ iconType={appIcon.type}
+ icon={appIcon.type === 'image' ? appIcon.fileId : appIcon.icon}
+ background={appIcon.type === 'image' ? undefined : appIcon.background}
+ imageUrl={appIcon.type === 'image' ? appIcon.url : undefined}
+ />
+ <Input
+ value={name}
+ onChange={e => setName(e.target.value)}
+ placeholder={t('app.newApp.appNamePlaceholder') || ''}
+ className='h-10 grow'
+ />
+ </div>
+ </div>
+ {/* description */}
+ <div className='pt-2'>
+ <div className='py-2 text-sm font-medium leading-[20px] text-text-primary'>{t('app.newApp.captionDescription')}</div>
+ <Textarea
+ className='resize-none'
+ placeholder={t('app.newApp.appDescriptionPlaceholder') || ''}
+ value={description}
+ onChange={e => setDescription(e.target.value)}
+ />
+ </div>
+ {/* answer icon */}
+ {isEditModal && (appMode === 'chat' || appMode === 'advanced-chat' || appMode === 'agent-chat') && (
+ <div className='pt-2'>
+ <div className='flex items-center justify-between'>
+ <div className='py-2 text-sm font-medium leading-[20px] text-text-primary'>{t('app.answerIcon.title')}</div>
+ <Switch
+ defaultValue={useIconAsAnswerIcon}
+ onChange={v => setUseIconAsAnswerIcon(v)}
+ />
+ </div>
+ <p className='body-xs-regular text-text-tertiary'>{t('app.answerIcon.descriptionInExplore')}</p>
+ </div>
+ )}
+ {!isEditModal && isAppsFull && <AppsFull className='mt-4' loc='app-explore-create' />}
+ </div>
+ <div className='flex flex-row-reverse'>
+ <Button
+ disabled={(!isEditModal && isAppsFull) || !name.trim() || confirmDisabled}
+ className='ml-2 w-24 gap-1'
+ variant='primary'
+ onClick={handleSubmit}
+ >
+ <span>{!isEditModal ? t('common.operation.create') : t('common.operation.save')}</span>
+ <div className='flex gap-0.5'>
+ <RiCommandLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' />
+ <RiCornerDownLeftLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' />
+ </div>
+ </Button>
+ <Button className='w-24' onClick={onHide}>{t('common.operation.cancel')}</Button>
+ </div>
+ </Modal>
+ {showAppIconPicker && <AppIconPicker
+ onSelect={(payload) => {
+ setAppIcon(payload)
+ setShowAppIconPicker(false)
+ }}
+ onClose={() => {
+ setAppIcon(appIconType === 'image'
+ ? { type: 'image' as const, url: appIconUrl, fileId: _appIcon }
+ : { type: 'emoji' as const, icon: _appIcon, background: appIconBackground })
+ setShowAppIconPicker(false)
+ }}
+ />}
+ </>
+ )
+}
+
+export default CreateAppModal
diff --git a/app/components/explore/index.tsx b/app/components/explore/index.tsx
new file mode 100644
index 0000000..5175b46
--- /dev/null
+++ b/app/components/explore/index.tsx
@@ -0,0 +1,63 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import ExploreContext from '@/context/explore-context'
+import Sidebar from '@/app/components/explore/sidebar'
+import { useAppContext } from '@/context/app-context'
+import { fetchMembers } from '@/service/common'
+import type { InstalledApp } from '@/models/explore'
+
+export type IExploreProps = {
+ children: React.ReactNode
+}
+
+const Explore: FC<IExploreProps> = ({
+ children,
+}) => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const [controlUpdateInstalledApps, setControlUpdateInstalledApps] = useState(0)
+ const { userProfile, isCurrentWorkspaceDatasetOperator } = useAppContext()
+ const [hasEditPermission, setHasEditPermission] = useState(false)
+ const [installedApps, setInstalledApps] = useState<InstalledApp[]>([])
+
+ useEffect(() => {
+ document.title = `${t('explore.title')} - Dify`;
+ (async () => {
+ const { accounts } = await fetchMembers({ url: '/workspaces/current/members', params: {} })
+ if (!accounts)
+ return
+ const currUser = accounts.find(account => account.id === userProfile.id)
+ setHasEditPermission(currUser?.role !== 'normal')
+ })()
+ }, [])
+
+ useEffect(() => {
+ if (isCurrentWorkspaceDatasetOperator)
+ return router.replace('/datasets')
+ }, [isCurrentWorkspaceDatasetOperator])
+
+ return (
+ <div className='flex h-full overflow-hidden border-t border-divider-regular bg-background-body'>
+ <ExploreContext.Provider
+ value={
+ {
+ controlUpdateInstalledApps,
+ setControlUpdateInstalledApps,
+ hasEditPermission,
+ installedApps,
+ setInstalledApps,
+ }
+ }
+ >
+ <Sidebar controlUpdateInstalledApps={controlUpdateInstalledApps} />
+ <div className='w-0 grow'>
+ {children}
+ </div>
+ </ExploreContext.Provider>
+ </div>
+ )
+}
+export default React.memo(Explore)
diff --git a/app/components/explore/installed-app/index.tsx b/app/components/explore/installed-app/index.tsx
new file mode 100644
index 0000000..62f9452
--- /dev/null
+++ b/app/components/explore/installed-app/index.tsx
@@ -0,0 +1,42 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useContext } from 'use-context-selector'
+import ExploreContext from '@/context/explore-context'
+import TextGenerationApp from '@/app/components/share/text-generation'
+import Loading from '@/app/components/base/loading'
+import ChatWithHistory from '@/app/components/base/chat/chat-with-history'
+
+export type IInstalledAppProps = {
+ id: string
+}
+
+const InstalledApp: FC<IInstalledAppProps> = ({
+ id,
+}) => {
+ const { installedApps } = useContext(ExploreContext)
+ const installedApp = installedApps.find(item => item.id === id)
+
+ if (!installedApp) {
+ return (
+ <div className='flex h-full items-center'>
+ <Loading type='area' />
+ </div>
+ )
+ }
+
+ return (
+ <div className='h-full py-2 pl-0 pr-2 sm:p-2'>
+ {installedApp.app.mode !== 'completion' && installedApp.app.mode !== 'workflow' && (
+ <ChatWithHistory installedAppInfo={installedApp} className='overflow-hidden rounded-2xl shadow-md' />
+ )}
+ {installedApp.app.mode === 'completion' && (
+ <TextGenerationApp isInstalledApp installedAppInfo={installedApp}/>
+ )}
+ {installedApp.app.mode === 'workflow' && (
+ <TextGenerationApp isWorkflow isInstalledApp installedAppInfo={installedApp}/>
+ )}
+ </div>
+ )
+}
+export default React.memo(InstalledApp)
diff --git a/app/components/explore/item-operation/index.tsx b/app/components/explore/item-operation/index.tsx
new file mode 100644
index 0000000..6fd11fd
--- /dev/null
+++ b/app/components/explore/item-operation/index.tsx
@@ -0,0 +1,90 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
+import {
+ RiDeleteBinLine,
+ RiEditLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { useBoolean } from 'ahooks'
+import { Pin02 } from '../../base/icons/src/vender/line/general'
+
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
+
+export type IItemOperationProps = {
+ className?: string
+ isItemHovering?: boolean
+ isPinned: boolean
+ isShowRenameConversation?: boolean
+ onRenameConversation?: () => void
+ isShowDelete: boolean
+ togglePin: () => void
+ onDelete: () => void
+}
+
+const ItemOperation: FC<IItemOperationProps> = ({
+ className,
+ isItemHovering,
+ isPinned,
+ togglePin,
+ isShowRenameConversation,
+ onRenameConversation,
+ isShowDelete,
+ onDelete,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const ref = useRef(null)
+ const [isHovering, { setTrue: setIsHovering, setFalse: setNotHovering }] = useBoolean(false)
+ useEffect(() => {
+ if (!isItemHovering && !isHovering)
+ setOpen(false)
+ }, [isItemHovering, isHovering])
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={4}
+ >
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ >
+ <div className={cn(className, s.btn, 'h-6 w-6 rounded-md border-none py-1', (isItemHovering || open) && `${s.open} !bg-components-actionbar-bg !shadow-none`)}></div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent
+ className="z-50"
+ >
+ <div
+ ref={ref}
+ className={'min-w-[120px] rounded-lg border border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-[5px]'}
+ onMouseEnter={setIsHovering}
+ onMouseLeave={setNotHovering}
+ onClick={(e) => {
+ e.stopPropagation()
+ }}
+ >
+ <div className={cn(s.actionItem, 'group hover:bg-state-base-hover')} onClick={togglePin}>
+ <Pin02 className='h-4 w-4 shrink-0 text-text-secondary' />
+ <span className={s.actionName}>{isPinned ? t('explore.sidebar.action.unpin') : t('explore.sidebar.action.pin')}</span>
+ </div>
+ {isShowRenameConversation && (
+ <div className={cn(s.actionItem, 'group hover:bg-state-base-hover')} onClick={onRenameConversation}>
+ <RiEditLine className='h-4 w-4 shrink-0 text-text-secondary' />
+ <span className={s.actionName}>{t('explore.sidebar.action.rename')}</span>
+ </div>
+ )}
+ {isShowDelete && (
+ <div className={cn(s.actionItem, s.deleteActionItem, 'group hover:bg-state-base-hover')} onClick={onDelete} >
+ <RiDeleteBinLine className={cn(s.deleteActionItemChild, 'h-4 w-4 shrink-0 stroke-current stroke-2 text-text-secondary')} />
+ <span className={cn(s.actionName, s.deleteActionItemChild)}>{t('explore.sidebar.action.delete')}</span>
+ </div>
+ )}
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(ItemOperation)
diff --git a/app/components/explore/item-operation/style.module.css b/app/components/explore/item-operation/style.module.css
new file mode 100644
index 0000000..7d4a46a
--- /dev/null
+++ b/app/components/explore/item-operation/style.module.css
@@ -0,0 +1,33 @@
+.actionItem {
+ @apply h-9 py-2 px-3 mx-1 flex items-center gap-2 rounded-lg cursor-pointer;
+}
+
+.actionName {
+ @apply text-text-secondary text-sm;
+}
+
+.commonIcon {
+ @apply w-4 h-4 inline-block align-middle;
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-size: contain;
+}
+
+.actionIcon {
+ @apply bg-gray-500;
+ mask-image: url(~@/assets/action.svg);
+}
+
+body .btn.open,
+body .btn:hover {
+ background: url(~@/assets/action.svg) center center no-repeat transparent;
+ background-size: 16px 16px;
+}
+
+body .btn:hover {
+ background-color: #F2F4F7;
+}
+
+.deleteActionItem:hover .deleteActionItemChild {
+ @apply text-red-500;
+}
diff --git a/app/components/explore/sidebar/app-nav-item/index.tsx b/app/components/explore/sidebar/app-nav-item/index.tsx
new file mode 100644
index 0000000..9b3ca09
--- /dev/null
+++ b/app/components/explore/sidebar/app-nav-item/index.tsx
@@ -0,0 +1,75 @@
+'use client'
+import React, { useRef } from 'react'
+
+import { useRouter } from 'next/navigation'
+import { useHover } from 'ahooks'
+import cn from '@/utils/classnames'
+import ItemOperation from '@/app/components/explore/item-operation'
+import AppIcon from '@/app/components/base/app-icon'
+import type { AppIconType } from '@/types/app'
+
+export type IAppNavItemProps = {
+ isMobile: boolean
+ name: string
+ id: string
+ icon_type: AppIconType | null
+ icon: string
+ icon_background: string
+ icon_url: string
+ isSelected: boolean
+ isPinned: boolean
+ togglePin: () => void
+ uninstallable: boolean
+ onDelete: (id: string) => void
+}
+
+export default function AppNavItem({
+ isMobile,
+ name,
+ id,
+ icon_type,
+ icon,
+ icon_background,
+ icon_url,
+ isSelected,
+ isPinned,
+ togglePin,
+ uninstallable,
+ onDelete,
+}: IAppNavItemProps) {
+ const router = useRouter()
+ const url = `/explore/installed/${id}`
+ const ref = useRef(null)
+ const isHovering = useHover(ref)
+ return (
+ <div
+ ref={ref}
+ key={id}
+ className={cn('system-sm-medium flex h-8 items-center justify-between rounded-lg px-2 text-sm font-normal text-components-menu-item-text mobile:justify-center mobile:px-1',
+ isSelected ? 'bg-state-base-active text-components-menu-item-text-active' : 'hover:bg-state-base-hover hover:text-components-menu-item-text-hover',
+ )}
+ onClick={() => {
+ router.push(url) // use Link causes popup item always trigger jump. Can not be solved by e.stopPropagation().
+ }}
+ >
+ {isMobile && <AppIcon size='tiny' iconType={icon_type} icon={icon} background={icon_background} imageUrl={icon_url} />}
+ {!isMobile && (
+ <>
+ <div className='flex w-0 grow items-center space-x-2'>
+ <AppIcon size='tiny' iconType={icon_type} icon={icon} background={icon_background} imageUrl={icon_url} />
+ <div className='overflow-hidden text-ellipsis whitespace-nowrap' title={name}>{name}</div>
+ </div>
+ <div className='h-6 shrink-0' onClick={e => e.stopPropagation()}>
+ <ItemOperation
+ isPinned={isPinned}
+ isItemHovering={isHovering}
+ togglePin={togglePin}
+ isShowDelete={!uninstallable && !isSelected}
+ onDelete={() => onDelete(id)}
+ />
+ </div>
+ </>
+ )}
+ </div>
+ )
+}
diff --git a/app/components/explore/sidebar/index.tsx b/app/components/explore/sidebar/index.tsx
new file mode 100644
index 0000000..fe5935b
--- /dev/null
+++ b/app/components/explore/sidebar/index.tsx
@@ -0,0 +1,153 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { useSelectedLayoutSegments } from 'next/navigation'
+import Link from 'next/link'
+import Toast from '../../base/toast'
+import Item from './app-nav-item'
+import cn from '@/utils/classnames'
+import { fetchInstalledAppList as doFetchInstalledAppList, uninstallApp, updatePinStatus } from '@/service/explore'
+import ExploreContext from '@/context/explore-context'
+import Confirm from '@/app/components/base/confirm'
+import Divider from '@/app/components/base/divider'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+
+const SelectedDiscoveryIcon = () => (
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="current" xmlns="http://www.w3.org/2000/svg">
+ <path fillRule="evenodd" clipRule="evenodd" d="M13.4135 1.11725C13.5091 1.09983 13.6483 1.08355 13.8078 1.11745C14.0143 1.16136 14.2017 1.26953 14.343 1.42647C14.4521 1.54766 14.5076 1.67634 14.5403 1.76781C14.5685 1.84673 14.593 1.93833 14.6136 2.01504L15.5533 5.5222C15.5739 5.5989 15.5985 5.69049 15.6135 5.77296C15.6309 5.86852 15.6472 6.00771 15.6133 6.16722C15.5694 6.37378 15.4612 6.56114 15.3043 6.70245C15.1831 6.81157 15.0544 6.86706 14.9629 6.89975C14.884 6.92796 14.7924 6.95247 14.7157 6.97299L14.676 6.98364C14.3365 7.07461 14.0437 7.15309 13.7972 7.19802C13.537 7.24543 13.2715 7.26736 12.9946 7.20849C12.7513 7.15677 12.5213 7.06047 12.3156 6.92591L9.63273 7.64477C9.86399 7.97104 9.99992 8.36965 9.99992 8.80001C9.99992 9.2424 9.85628 9.65124 9.6131 9.98245L12.5508 14.291C12.7582 14.5952 12.6797 15.01 12.3755 15.2174C12.0713 15.4248 11.6566 15.3464 11.4492 15.0422L8.51171 10.7339C8.34835 10.777 8.17682 10.8 7.99992 10.8C7.82305 10.8 7.65155 10.777 7.48823 10.734L4.5508 15.0422C4.34338 15.3464 3.92863 15.4248 3.62442 15.2174C3.32021 15.01 3.24175 14.5952 3.44916 14.291L6.3868 9.98254C6.14358 9.65132 5.99992 9.24244 5.99992 8.80001C5.99992 8.73795 6.00274 8.67655 6.00827 8.61594L4.59643 8.99424C4.51973 9.01483 4.42813 9.03941 4.34567 9.05444C4.25011 9.07185 4.11092 9.08814 3.95141 9.05423C3.74485 9.01033 3.55748 8.90215 3.41618 8.74522C3.38535 8.71097 3.3588 8.67614 3.33583 8.64171L2.49206 8.8678C2.41536 8.88838 2.32376 8.91296 2.2413 8.92799C2.14574 8.94541 2.00655 8.96169 1.84704 8.92779C1.64048 8.88388 1.45311 8.77571 1.31181 8.61877C1.20269 8.49759 1.1472 8.3689 1.1145 8.27744C1.08629 8.1985 1.06177 8.10689 1.04125 8.03018L0.791701 7.09885C0.771119 7.02215 0.746538 6.93055 0.731508 6.84809C0.714092 6.75253 0.697808 6.61334 0.731712 6.45383C0.775619 6.24726 0.883793 6.0599 1.04073 5.9186C1.16191 5.80948 1.2906 5.75399 1.38206 5.72129C1.461 5.69307 1.55261 5.66856 1.62932 5.64804L2.47318 5.42193C2.47586 5.38071 2.48143 5.33735 2.49099 5.29237C2.5349 5.08581 2.64307 4.89844 2.80001 4.75714C2.92119 4.64802 3.04988 4.59253 3.14134 4.55983C3.22027 4.53162 3.31189 4.50711 3.3886 4.48658L11.1078 2.41824C11.2186 2.19888 11.3697 2.00049 11.5545 1.83406C11.7649 1.64462 12.0058 1.53085 12.2548 1.44183C12.4907 1.35749 12.7836 1.27904 13.123 1.18809L13.1628 1.17744C13.2395 1.15686 13.3311 1.13228 13.4135 1.11725ZM13.3642 2.5039C13.0648 2.58443 12.8606 2.64126 12.7036 2.69735C12.5325 2.75852 12.4742 2.80016 12.4467 2.82492C12.3421 2.91912 12.2699 3.04403 12.2407 3.18174C12.233 3.21793 12.2261 3.28928 12.2587 3.46805C12.2927 3.6545 12.3564 3.89436 12.4559 4.26563L12.5594 4.652C12.6589 5.02328 12.7236 5.26287 12.7874 5.44133C12.8486 5.61244 12.8902 5.67079 12.915 5.69829C13.0092 5.80291 13.1341 5.87503 13.2718 5.9043C13.308 5.91199 13.3793 5.91887 13.5581 5.88629C13.7221 5.85641 13.9273 5.80352 14.2269 5.72356L13.3642 2.5039Z" fill="currentColor" />
+ </svg>
+)
+
+const DiscoveryIcon = () => (
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="current" xmlns="http://www.w3.org/2000/svg">
+ <path d="M8.74786 9.89676L12.0003 14.6669M7.25269 9.89676L4.00027 14.6669M9.3336 8.80031C9.3336 9.53669 8.73665 10.1336 8.00027 10.1336C7.26389 10.1336 6.66694 9.53669 6.66694 8.80031C6.66694 8.06393 7.26389 7.46698 8.00027 7.46698C8.73665 7.46698 9.3336 8.06393 9.3336 8.80031ZM11.4326 3.02182L3.57641 5.12689C3.39609 5.1752 3.30593 5.19936 3.24646 5.25291C3.19415 5.30001 3.15809 5.36247 3.14345 5.43132C3.12681 5.5096 3.15097 5.59976 3.19929 5.78008L3.78595 7.96951C3.83426 8.14984 3.85842 8.24 3.91197 8.29947C3.95907 8.35178 4.02153 8.38784 4.09038 8.40248C4.16866 8.41911 4.25882 8.39496 4.43914 8.34664L12.2953 6.24158L11.4326 3.02182ZM14.5285 6.33338C13.8072 6.52665 13.4466 6.62328 13.1335 6.55673C12.8581 6.49819 12.6082 6.35396 12.4198 6.14471C12.2056 5.90682 12.109 5.54618 11.9157 4.82489L11.8122 4.43852C11.6189 3.71722 11.5223 3.35658 11.5889 3.04347C11.6474 2.76805 11.7916 2.51823 12.0009 2.32982C12.2388 2.11563 12.5994 2.019 13.3207 1.82573C13.501 1.77741 13.5912 1.75325 13.6695 1.76989C13.7383 1.78452 13.8008 1.82058 13.8479 1.87289C13.9014 1.93237 13.9256 2.02253 13.9739 2.20285L14.9057 5.68018C14.954 5.86051 14.9781 5.95067 14.9615 6.02894C14.9469 6.0978 14.9108 6.16025 14.8585 6.20736C14.799 6.2609 14.7088 6.28506 14.5285 6.33338ZM2.33475 8.22033L3.23628 7.97876C3.4166 7.93044 3.50676 7.90628 3.56623 7.85274C3.61854 7.80563 3.6546 7.74318 3.66924 7.67433C3.68588 7.59605 3.66172 7.50589 3.6134 7.32556L3.37184 6.42403C3.32352 6.24371 3.29936 6.15355 3.24581 6.09408C3.19871 6.04176 3.13626 6.00571 3.0674 5.99107C2.98912 5.97443 2.89896 5.99859 2.71864 6.04691L1.81711 6.28847C1.63678 6.33679 1.54662 6.36095 1.48715 6.4145C1.43484 6.4616 1.39878 6.52405 1.38415 6.59291C1.36751 6.67119 1.39167 6.76135 1.43998 6.94167L1.68155 7.8432C1.72987 8.02352 1.75402 8.11369 1.80757 8.17316C1.85467 8.22547 1.91713 8.26153 1.98598 8.27616C2.06426 8.2928 2.15442 8.26864 2.33475 8.22033Z" stroke="currentColor" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round" />
+ </svg>
+)
+
+const SelectedChatIcon = () => (
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fillRule="evenodd" clipRule="evenodd" d="M8.00016 1.3335C4.31826 1.3335 1.3335 4.31826 1.3335 8.00016C1.3335 8.88571 1.50651 9.7325 1.8212 10.5074C1.84962 10.5773 1.86597 10.6178 1.87718 10.6476L1.88058 10.6568L1.88016 10.66C1.87683 10.6846 1.87131 10.7181 1.86064 10.7821L1.46212 13.1732C1.44424 13.2803 1.42423 13.4001 1.41638 13.5041C1.40782 13.6176 1.40484 13.7981 1.48665 13.9888C1.58779 14.2246 1.77569 14.4125 2.0115 14.5137C2.20224 14.5955 2.38274 14.5925 2.49619 14.5839C2.60025 14.5761 2.72006 14.5561 2.82715 14.5382L5.2182 14.1397C5.28222 14.129 5.31576 14.1235 5.34036 14.1202L5.34353 14.1197L5.35274 14.1231C5.38258 14.1344 5.42298 14.1507 5.49297 14.1791C6.26783 14.4938 7.11462 14.6668 8.00016 14.6668C11.6821 14.6668 14.6668 11.6821 14.6668 8.00016C14.6668 4.31826 11.6821 1.3335 8.00016 1.3335ZM4.00016 8.00016C4.00016 7.44788 4.44788 7.00016 5.00016 7.00016C5.55245 7.00016 6.00016 7.44788 6.00016 8.00016C6.00016 8.55245 5.55245 9.00016 5.00016 9.00016C4.44788 9.00016 4.00016 8.55245 4.00016 8.00016ZM7.00016 8.00016C7.00016 7.44788 7.44788 7.00016 8.00016 7.00016C8.55245 7.00016 9.00016 7.44788 9.00016 8.00016C9.00016 8.55245 8.55245 9.00016 8.00016 9.00016C7.44788 9.00016 7.00016 8.55245 7.00016 8.00016ZM11.0002 7.00016C10.4479 7.00016 10.0002 7.44788 10.0002 8.00016C10.0002 8.55245 10.4479 9.00016 11.0002 9.00016C11.5524 9.00016 12.0002 8.55245 12.0002 8.00016C12.0002 7.44788 11.5524 7.00016 11.0002 7.00016Z" fill="#155EEF" />
+ </svg>
+)
+
+const ChatIcon = () => (
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M5 8H5.00667M8 8H8.00667M11 8H11.0067M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 8.7981 2.15582 9.5598 2.43871 10.2563C2.49285 10.3897 2.51992 10.4563 2.532 10.5102C2.54381 10.5629 2.54813 10.6019 2.54814 10.6559C2.54814 10.7111 2.53812 10.7713 2.51807 10.8916L2.12275 13.2635C2.08135 13.5119 2.06065 13.6361 2.09917 13.7259C2.13289 13.8045 2.19552 13.8671 2.27412 13.9008C2.36393 13.9393 2.48812 13.9186 2.73651 13.8772L5.10843 13.4819C5.22872 13.4619 5.28887 13.4519 5.34409 13.4519C5.3981 13.4519 5.43711 13.4562 5.48981 13.468C5.54369 13.4801 5.61035 13.5072 5.74366 13.5613C6.4402 13.8442 7.2019 14 8 14ZM5.33333 8C5.33333 8.1841 5.1841 8.33333 5 8.33333C4.81591 8.33333 4.66667 8.1841 4.66667 8C4.66667 7.81591 4.81591 7.66667 5 7.66667C5.1841 7.66667 5.33333 7.81591 5.33333 8ZM8.33333 8C8.33333 8.1841 8.1841 8.33333 8 8.33333C7.81591 8.33333 7.66667 8.1841 7.66667 8C7.66667 7.81591 7.81591 7.66667 8 7.66667C8.1841 7.66667 8.33333 7.81591 8.33333 8ZM11.3333 8C11.3333 8.1841 11.1841 8.33333 11 8.33333C10.8159 8.33333 10.6667 8.1841 10.6667 8C10.6667 7.81591 10.8159 7.66667 11 7.66667C11.1841 7.66667 11.3333 7.81591 11.3333 8Z" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" />
+ </svg>
+)
+
+export type IExploreSideBarProps = {
+ controlUpdateInstalledApps: number
+}
+
+const SideBar: FC<IExploreSideBarProps> = ({
+ controlUpdateInstalledApps,
+}) => {
+ const { t } = useTranslation()
+ const segments = useSelectedLayoutSegments()
+ const lastSegment = segments.slice(-1)[0]
+ const isDiscoverySelected = lastSegment === 'apps'
+ const isChatSelected = lastSegment === 'chat'
+ const { installedApps, setInstalledApps } = useContext(ExploreContext)
+
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ const fetchInstalledAppList = async () => {
+ const { installed_apps }: any = await doFetchInstalledAppList()
+ setInstalledApps(installed_apps)
+ }
+
+ const [showConfirm, setShowConfirm] = useState(false)
+ const [currId, setCurrId] = useState('')
+ const handleDelete = async () => {
+ const id = currId
+ await uninstallApp(id)
+ setShowConfirm(false)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.remove'),
+ })
+ fetchInstalledAppList()
+ }
+
+ const handleUpdatePinStatus = async (id: string, isPinned: boolean) => {
+ await updatePinStatus(id, isPinned)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.success'),
+ })
+ fetchInstalledAppList()
+ }
+
+ useEffect(() => {
+ fetchInstalledAppList()
+ }, [])
+
+ useEffect(() => {
+ fetchInstalledAppList()
+ }, [controlUpdateInstalledApps])
+
+ const pinnedAppsCount = installedApps.filter(({ is_pinned }) => is_pinned).length
+ return (
+ <div className='w-fit shrink-0 cursor-pointer border-r border-divider-burn px-4 pt-6 sm:w-[216px]'>
+ <div className={cn(isDiscoverySelected ? 'text-text-accent' : 'text-text-tertiary')}>
+ <Link
+ href='/explore/apps'
+ className={cn(isDiscoverySelected ? ' bg-components-main-nav-nav-button-bg-active' : 'font-medium hover:bg-state-base-hover',
+ 'flex h-9 items-center gap-2 rounded-lg px-3 mobile:w-fit mobile:justify-center mobile:px-2 pc:w-full pc:justify-start')}
+ style={isDiscoverySelected ? { boxShadow: '0px 1px 2px rgba(16, 24, 40, 0.05)' } : {}}
+ >
+ {isDiscoverySelected ? <SelectedDiscoveryIcon /> : <DiscoveryIcon />}
+ {!isMobile && <div className='text-sm'>{t('explore.sidebar.discovery')}</div>}
+ </Link>
+ </div>
+ {installedApps.length > 0 && (
+ <div className='mt-10'>
+ <p className='break-all pl-2 text-xs font-medium uppercase text-text-tertiary mobile:px-0'>{t('explore.sidebar.workspace')}</p>
+ <div className='mt-3 space-y-1 overflow-y-auto overflow-x-hidden'
+ style={{
+ height: 'calc(100vh - 250px)',
+ }}
+ >
+ {installedApps.map(({ id, is_pinned, uninstallable, app: { name, icon_type, icon, icon_url, icon_background } }, index) => (
+ <React.Fragment key={id}>
+ <Item
+ isMobile={isMobile}
+ name={name}
+ icon_type={icon_type}
+ icon={icon}
+ icon_background={icon_background}
+ icon_url={icon_url}
+ id={id}
+ isSelected={lastSegment?.toLowerCase() === id}
+ isPinned={is_pinned}
+ togglePin={() => handleUpdatePinStatus(id, !is_pinned)}
+ uninstallable={uninstallable}
+ onDelete={(id) => {
+ setCurrId(id)
+ setShowConfirm(true)
+ }}
+ />
+ {index === pinnedAppsCount - 1 && index !== installedApps.length - 1 && <Divider />}
+ </React.Fragment>
+ ))}
+ </div>
+ </div>
+ )}
+ {showConfirm && (
+ <Confirm
+ title={t('explore.sidebar.delete.title')}
+ content={t('explore.sidebar.delete.content')}
+ isShow={showConfirm}
+ onConfirm={handleDelete}
+ onCancel={() => setShowConfirm(false)}
+ />
+ )}
+ </div>
+ )
+}
+
+export default React.memo(SideBar)
diff --git a/app/components/header/account-about/index.tsx b/app/components/header/account-about/index.tsx
new file mode 100644
index 0000000..6129b48
--- /dev/null
+++ b/app/components/header/account-about/index.tsx
@@ -0,0 +1,87 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import Link from 'next/link'
+import dayjs from 'dayjs'
+import { RiCloseLine } from '@remixicon/react'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import type { LangGeniusVersionResponse } from '@/models/common'
+import { IS_CE_EDITION } from '@/config'
+import DifyLogo from '@/app/components/base/logo/dify-logo'
+import { noop } from 'lodash-es'
+
+type IAccountSettingProps = {
+ langeniusVersionInfo: LangGeniusVersionResponse
+ onCancel: () => void
+}
+
+export default function AccountAbout({
+ langeniusVersionInfo,
+ onCancel,
+}: IAccountSettingProps) {
+ const { t } = useTranslation()
+ const isLatest = langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version
+
+ return (
+ <Modal
+ isShow
+ onClose={noop}
+ className='!w-[480px] !max-w-[480px] !px-6 !py-4'
+ >
+ <div>
+ <div className='absolute right-4 top-4 flex h-8 w-8 cursor-pointer items-center justify-center' onClick={onCancel}>
+ <RiCloseLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ <div className='flex flex-col items-center gap-4 py-8'>
+ <DifyLogo size='large' className='mx-auto' />
+ <div className='text-center text-xs font-normal text-text-tertiary'>Version {langeniusVersionInfo?.current_version}</div>
+ <div className='flex flex-col items-center gap-2 text-center text-xs font-normal text-text-secondary'>
+ <div>漏 {dayjs().year()} LangGenius, Inc., Contributors.</div>
+ <div className='text-text-accent'>
+ {
+ IS_CE_EDITION
+ ? <Link href={'https://github.com/langgenius/dify/blob/main/LICENSE'} target='_blank' rel='noopener noreferrer'>Open Source License</Link>
+ : <>
+ <Link href='https://dify.ai/privacy' target='_blank' rel='noopener noreferrer'>Privacy Policy</Link>,
+ <Link href='https://dify.ai/terms' target='_blank' rel='noopener noreferrer'>Terms of Service</Link>
+ </>
+ }
+ </div>
+ </div>
+ </div>
+ <div className='-mx-8 mb-4 h-[0.5px] bg-divider-regular' />
+ <div className='flex items-center justify-between'>
+ <div className='text-xs font-medium text-text-tertiary'>
+ {
+ isLatest
+ ? t('common.about.latestAvailable', { version: langeniusVersionInfo.latest_version })
+ : t('common.about.nowAvailable', { version: langeniusVersionInfo.latest_version })
+ }
+ </div>
+ <div className='flex items-center'>
+ <Button className='mr-2' size='small'>
+ <Link
+ href={'https://github.com/langgenius/dify/releases'}
+ target='_blank' rel='noopener noreferrer'
+ >
+ {t('common.about.changeLog')}
+ </Link>
+ </Button>
+ {
+ !isLatest && !IS_CE_EDITION && (
+ <Button variant='primary' size='small'>
+ <Link
+ href={langeniusVersionInfo.release_notes}
+ target='_blank' rel='noopener noreferrer'
+ >
+ {t('common.about.updateNow')}
+ </Link>
+ </Button>
+ )
+ }
+ </div>
+ </div>
+ </div>
+ </Modal>
+ )
+}
diff --git a/app/components/header/account-dropdown/compliance.tsx b/app/components/header/account-dropdown/compliance.tsx
new file mode 100644
index 0000000..b584968
--- /dev/null
+++ b/app/components/header/account-dropdown/compliance.tsx
@@ -0,0 +1,185 @@
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import { RiArrowDownCircleLine, RiArrowRightSLine, RiVerifiedBadgeLine } from '@remixicon/react'
+import type { FC, MouseEvent } from 'react'
+import { Fragment, useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useMutation } from '@tanstack/react-query'
+import PremiumBadge from '../../base/premium-badge'
+import SparklesSoft from '../../base/icons/src/public/common/SparklesSoft'
+import Button from '../../base/button'
+import Soc2 from '../../base/icons/src/public/common/Soc2'
+import Iso from '../../base/icons/src/public/common/Iso'
+import Gdpr from '../../base/icons/src/public/common/Gdpr'
+import Toast from '../../base/toast'
+import Tooltip from '../../base/tooltip'
+import cn from '@/utils/classnames'
+import { useProviderContext } from '@/context/provider-context'
+import { Plan } from '@/app/components/billing/type'
+import { useModalContext } from '@/context/modal-context'
+import { getDocDownloadUrl } from '@/service/common'
+
+enum DocName {
+ SOC2_Type_I = 'SOC2_Type_I',
+ SOC2_Type_II = 'SOC2_Type_II',
+ ISO_27001 = 'ISO_27001',
+ GDPR = 'GDPR',
+}
+
+type UpgradeOrDownloadProps = {
+ doc_name: DocName
+}
+const UpgradeOrDownload: FC<UpgradeOrDownloadProps> = ({ doc_name }) => {
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+ const { setShowPricingModal, setShowAccountSettingModal } = useModalContext()
+ const isFreePlan = plan.type === Plan.sandbox
+
+ const handlePlanClick = useCallback(() => {
+ if (isFreePlan)
+ setShowPricingModal()
+ else
+ setShowAccountSettingModal({ payload: 'billing' })
+ }, [isFreePlan, setShowAccountSettingModal, setShowPricingModal])
+
+ const { isPending, mutate: downloadCompliance } = useMutation({
+ mutationKey: ['downloadCompliance', doc_name],
+ mutationFn: async () => {
+ try {
+ const ret = await getDocDownloadUrl(doc_name)
+ const a = document.createElement('a')
+ a.href = ret.url
+ a.click()
+ Toast.notify({
+ type: 'success',
+ message: t('common.operation.downloadSuccess'),
+ })
+ }
+ catch (error) {
+ console.error(error)
+ Toast.notify({
+ type: 'error',
+ message: t('common.operation.downloadFailed'),
+ })
+ }
+ },
+ })
+ const whichPlanCanDownloadCompliance = {
+ [DocName.SOC2_Type_I]: [Plan.professional, Plan.team],
+ [DocName.SOC2_Type_II]: [Plan.team],
+ [DocName.ISO_27001]: [Plan.team],
+ [DocName.GDPR]: [Plan.team, Plan.professional, Plan.sandbox],
+ }
+
+ const isCurrentPlanCanDownload = whichPlanCanDownloadCompliance[doc_name].includes(plan.type)
+ const handleDownloadClick = useCallback((e: MouseEvent<HTMLButtonElement>) => {
+ e.preventDefault()
+ downloadCompliance()
+ }, [downloadCompliance])
+ if (isCurrentPlanCanDownload) {
+ return <Button loading={isPending} disabled={isPending} size='small' variant='secondary' className='flex items-center gap-[1px]' onClick={handleDownloadClick}>
+ <RiArrowDownCircleLine className='size-[14px] text-components-button-secondary-text-disabled' />
+ <span className='system-xs-medium px-[3px] text-components-button-secondary-text'>{t('common.operation.download')}</span>
+ </Button>
+ }
+ const upgradeTooltip: Record<Plan, string> = {
+ [Plan.sandbox]: t('common.compliance.sandboxUpgradeTooltip'),
+ [Plan.professional]: t('common.compliance.professionalUpgradeTooltip'),
+ [Plan.team]: '',
+ [Plan.enterprise]: '',
+ }
+ return <Tooltip asChild={false} popupContent={upgradeTooltip[plan.type]}>
+ <PremiumBadge color='blue' allowHover={true} onClick={handlePlanClick}>
+ <SparklesSoft className='flex h-3.5 w-3.5 items-center py-[1px] pl-[3px] text-components-premium-badge-indigo-text-stop-0' />
+ <div className='system-xs-medium'>
+ <span className='p-1'>
+ {t('billing.upgradeBtn.encourageShort')}
+ </span>
+ </div>
+ </PremiumBadge>
+ </Tooltip>
+}
+
+export default function Compliance() {
+ const itemClassName = `
+ flex items-center w-full h-10 pl-1 pr-2 py-1 text-text-secondary system-md-regular
+ rounded-lg hover:bg-state-base-hover gap-1
+`
+ const { t } = useTranslation()
+
+ return <Menu as="div" className="relative h-full w-full">
+ {
+ ({ open }) => (
+ <>
+ <MenuButton className={
+ cn('group flex h-9 w-full items-center gap-1 rounded-lg py-2 pl-3 pr-2 hover:bg-state-base-hover',
+ open && 'bg-state-base-hover',
+ )}>
+ <RiVerifiedBadgeLine className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-left text-text-secondary'>{t('common.userProfile.compliance')}</div>
+ <RiArrowRightSLine className='size-[14px] shrink-0 text-text-tertiary' />
+ </MenuButton>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems
+ className={cn(
+ `absolute top-[1px] z-10 max-h-[70vh] w-[337px] origin-top-right -translate-x-full divide-y divide-divider-subtle overflow-y-scroll
+ rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[5px] focus:outline-none
+ `,
+ )}
+ >
+ <div className="px-1 py-1">
+ <MenuItem>
+ <div
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}>
+ <Soc2 className='size-7 shrink-0' />
+ <div className='system-md-regular grow truncate px-1 text-text-secondary'>{t('common.compliance.soc2Type1')}</div>
+ <UpgradeOrDownload doc_name={DocName.SOC2_Type_I} />
+ </div>
+ </MenuItem>
+ <MenuItem>
+ <div
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}>
+ <Soc2 className='size-7 shrink-0' />
+ <div className='system-md-regular grow truncate px-1 text-text-secondary'>{t('common.compliance.soc2Type2')}</div>
+ <UpgradeOrDownload doc_name={DocName.SOC2_Type_II} />
+ </div>
+ </MenuItem>
+ <MenuItem>
+ <div
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}>
+ <Iso className='size-7 shrink-0' />
+ <div className='system-md-regular grow truncate px-1 text-text-secondary'>{t('common.compliance.iso27001')}</div>
+ <UpgradeOrDownload doc_name={DocName.ISO_27001} />
+ </div>
+ </MenuItem>
+ <MenuItem>
+ <div
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}>
+ <Gdpr className='size-7 shrink-0' />
+ <div className='system-md-regular grow truncate px-1 text-text-secondary'>{t('common.compliance.gdpr')}</div>
+ <UpgradeOrDownload doc_name={DocName.GDPR} />
+ </div>
+ </MenuItem>
+ </div>
+ </MenuItems>
+ </Transition>
+ </>
+ )
+ }
+ </Menu>
+}
diff --git a/app/components/header/account-dropdown/index.tsx b/app/components/header/account-dropdown/index.tsx
new file mode 100644
index 0000000..4a08a4c
--- /dev/null
+++ b/app/components/header/account-dropdown/index.tsx
@@ -0,0 +1,223 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { Fragment, useState } from 'react'
+import { useRouter } from 'next/navigation'
+import { useContextSelector } from 'use-context-selector'
+import {
+ RiAccountCircleLine,
+ RiArrowRightUpLine,
+ RiBookOpenLine,
+ RiGithubLine,
+ RiGraduationCapFill,
+ RiInformation2Line,
+ RiLogoutBoxRLine,
+ RiMap2Line,
+ RiSettings3Line,
+ RiStarLine,
+ RiTShirt2Line,
+} from '@remixicon/react'
+import Link from 'next/link'
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import Indicator from '../indicator'
+import AccountAbout from '../account-about'
+import GithubStar from '../github-star'
+import Support from './support'
+import Compliance from './compliance'
+import PremiumBadge from '@/app/components/base/premium-badge'
+import { useGetDocLanguage } from '@/context/i18n'
+import Avatar from '@/app/components/base/avatar'
+import ThemeSwitcher from '@/app/components/base/theme-switcher'
+import { logout } from '@/service/common'
+import AppContext, { useAppContext } from '@/context/app-context'
+import { useProviderContext } from '@/context/provider-context'
+import { useModalContext } from '@/context/modal-context'
+import { LicenseStatus } from '@/types/feature'
+import { IS_CLOUD_EDITION } from '@/config'
+import cn from '@/utils/classnames'
+
+export default function AppSelector() {
+ const itemClassName = `
+ flex items-center w-full h-9 pl-3 pr-2 text-text-secondary system-md-regular
+ rounded-lg hover:bg-state-base-hover cursor-pointer gap-1
+ `
+ const router = useRouter()
+ const [aboutVisible, setAboutVisible] = useState(false)
+ const systemFeatures = useContextSelector(AppContext, v => v.systemFeatures)
+
+ const { t } = useTranslation()
+ const { userProfile, langeniusVersionInfo, isCurrentWorkspaceOwner } = useAppContext()
+ const { isEducationAccount } = useProviderContext()
+ const { setShowAccountSettingModal } = useModalContext()
+ const docLanguage = useGetDocLanguage()
+
+ const handleLogout = async () => {
+ await logout({
+ url: '/logout',
+ params: {},
+ })
+
+ localStorage.removeItem('setup_status')
+ localStorage.removeItem('console_token')
+ localStorage.removeItem('refresh_token')
+
+ router.push('/signin')
+ }
+
+ return (
+ <div className="">
+ <Menu as="div" className="relative inline-block text-left">
+ {
+ ({ open }) => (
+ <>
+ <MenuButton className={cn('inline-flex items-center rounded-[20px] p-0.5 hover:bg-background-default-dodge', open && 'bg-background-default-dodge')}>
+ <Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={36} />
+ </MenuButton>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems
+ className="
+ absolute right-0 mt-1.5 w-60 max-w-80
+ origin-top-right divide-y divide-divider-subtle rounded-xl bg-components-panel-bg-blur shadow-lg
+ backdrop-blur-sm focus:outline-none
+ "
+ >
+ <MenuItem disabled>
+ <div className='flex flex-nowrap items-center py-[13px] pl-3 pr-2'>
+ <div className='grow'>
+ <div className='system-md-medium break-all text-text-primary'>
+ {userProfile.name}
+ {isEducationAccount && (
+ <PremiumBadge size='s' color='blue' className='ml-1 !px-2'>
+ <RiGraduationCapFill className='mr-1 h-3 w-3' />
+ <span className='system-2xs-medium'>EDU</span>
+ </PremiumBadge>
+ )}
+ </div>
+ <div className='system-xs-regular break-all text-text-tertiary'>{userProfile.email}</div>
+ </div>
+ <Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={36} className='mr-3' />
+ </div>
+ </MenuItem>
+ <div className="px-1 py-1">
+ <MenuItem>
+ <Link
+ className={cn(itemClassName, 'group',
+ 'data-[active]:bg-state-base-hover',
+ )}
+ href='/account'
+ target='_self' rel='noopener noreferrer'>
+ <RiAccountCircleLine className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.account.account')}</div>
+ <RiArrowRightUpLine className='size-[14px] shrink-0 text-text-tertiary' />
+ </Link>
+ </MenuItem>
+ <MenuItem>
+ <div className={cn(itemClassName,
+ 'data-[active]:bg-state-base-hover',
+ )} onClick={() => setShowAccountSettingModal({ payload: 'members' })}>
+ <RiSettings3Line className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.settings')}</div>
+ </div>
+ </MenuItem>
+ </div>
+ <div className='p-1'>
+ <MenuItem>
+ <Link
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}
+ href={`https://docs.dify.ai/${docLanguage}/introduction`}
+ target='_blank' rel='noopener noreferrer'>
+ <RiBookOpenLine className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.helpCenter')}</div>
+ <RiArrowRightUpLine className='size-[14px] shrink-0 text-text-tertiary' />
+ </Link>
+ </MenuItem>
+ <Support />
+ {IS_CLOUD_EDITION && isCurrentWorkspaceOwner && <Compliance />}
+ </div>
+ <div className='p-1'>
+ <MenuItem>
+ <Link
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}
+ href='https://roadmap.dify.ai'
+ target='_blank' rel='noopener noreferrer'>
+ <RiMap2Line className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.roadmap')}</div>
+ <RiArrowRightUpLine className='size-[14px] shrink-0 text-text-tertiary' />
+ </Link>
+ </MenuItem>
+ {systemFeatures.license.status === LicenseStatus.NONE && <MenuItem>
+ <Link
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}
+ href='https://github.com/langgenius/dify'
+ target='_blank' rel='noopener noreferrer'>
+ <RiGithubLine className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.github')}</div>
+ <div className='flex items-center gap-0.5 rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-[5px] py-[3px]'>
+ <RiStarLine className='size-3 shrink-0 text-text-tertiary' />
+ <GithubStar className='system-2xs-medium-uppercase text-text-tertiary' />
+ </div>
+ </Link>
+ </MenuItem>}
+ {
+ document?.body?.getAttribute('data-public-site-about') !== 'hide' && (
+ <MenuItem>
+ <div className={cn(itemClassName, 'justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )} onClick={() => setAboutVisible(true)}>
+ <RiInformation2Line className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.about')}</div>
+ <div className='flex shrink-0 items-center'>
+ <div className='system-xs-regular mr-2 text-text-tertiary'>{langeniusVersionInfo.current_version}</div>
+ <Indicator color={langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version ? 'green' : 'orange'} />
+ </div>
+ </div>
+ </MenuItem>
+ )
+ }
+ </div>
+ <MenuItem disabled>
+ <div className='p-1'>
+ <div className={cn(itemClassName, 'hover:bg-transparent')}>
+ <RiTShirt2Line className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.theme.theme')}</div>
+ <ThemeSwitcher/>
+ </div>
+ </div>
+ </MenuItem>
+ <MenuItem>
+ <div className='p-1' onClick={() => handleLogout()}>
+ <div
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}
+ >
+ <RiLogoutBoxRLine className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.logout')}</div>
+ </div>
+ </div>
+ </MenuItem>
+ </MenuItems>
+ </Transition>
+ </>
+ )
+ }
+ </Menu>
+ {
+ aboutVisible && <AccountAbout onCancel={() => setAboutVisible(false)} langeniusVersionInfo={langeniusVersionInfo} />
+ }
+ </div >
+ )
+}
diff --git a/app/components/header/account-dropdown/support.tsx b/app/components/header/account-dropdown/support.tsx
new file mode 100644
index 0000000..e4731d2
--- /dev/null
+++ b/app/components/header/account-dropdown/support.tsx
@@ -0,0 +1,94 @@
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import { RiArrowRightSLine, RiArrowRightUpLine, RiDiscordLine, RiFeedbackLine, RiMailSendLine, RiQuestionLine } from '@remixicon/react'
+import { Fragment } from 'react'
+import Link from 'next/link'
+import { useTranslation } from 'react-i18next'
+import { mailToSupport } from '../utils/util'
+import cn from '@/utils/classnames'
+import { useProviderContext } from '@/context/provider-context'
+import { Plan } from '@/app/components/billing/type'
+import { useAppContext } from '@/context/app-context'
+
+export default function Support() {
+ const itemClassName = `
+ flex items-center w-full h-9 pl-3 pr-2 text-text-secondary system-md-regular
+ rounded-lg hover:bg-state-base-hover cursor-pointer gap-1
+`
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+ const { userProfile, langeniusVersionInfo } = useAppContext()
+ const canEmailSupport = plan.type === Plan.professional || plan.type === Plan.team || plan.type === Plan.enterprise
+
+ return <Menu as="div" className="relative h-full w-full">
+ {
+ ({ open }) => (
+ <>
+ <MenuButton className={
+ cn('group flex h-9 w-full items-center gap-1 rounded-lg py-2 pl-3 pr-2 hover:bg-state-base-hover',
+ open && 'bg-state-base-hover',
+ )}>
+ <RiQuestionLine className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-left text-text-secondary'>{t('common.userProfile.support')}</div>
+ <RiArrowRightSLine className='size-[14px] shrink-0 text-text-tertiary' />
+ </MenuButton>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems
+ className={cn(
+ `absolute top-[1px] z-10 max-h-[70vh] w-[216px] origin-top-right -translate-x-full divide-y divide-divider-subtle overflow-y-scroll
+ rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[5px] focus:outline-none
+ `,
+ )}
+ >
+ <div className="px-1 py-1">
+ {canEmailSupport && <MenuItem>
+ <a
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}
+ href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)}
+ target='_blank' rel='noopener noreferrer'>
+ <RiMailSendLine className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.emailSupport')}</div>
+ <RiArrowRightUpLine className='size-[14px] shrink-0 text-text-tertiary' />
+ </a>
+ </MenuItem>}
+ <MenuItem>
+ <Link
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}
+ href='https://github.com/langgenius/dify/discussions/categories/feedbacks'
+ target='_blank' rel='noopener noreferrer'>
+ <RiFeedbackLine className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.communityFeedback')}</div>
+ <RiArrowRightUpLine className='size-[14px] shrink-0 text-text-tertiary' />
+ </Link>
+ </MenuItem>
+ <MenuItem>
+ <Link
+ className={cn(itemClassName, 'group justify-between',
+ 'data-[active]:bg-state-base-hover',
+ )}
+ href='https://discord.gg/5AEfbxcd9k'
+ target='_blank' rel='noopener noreferrer'>
+ <RiDiscordLine className='size-4 shrink-0 text-text-tertiary' />
+ <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.community')}</div>
+ <RiArrowRightUpLine className='size-[14px] shrink-0 text-text-tertiary' />
+ </Link>
+ </MenuItem>
+ </div>
+ </MenuItems>
+ </Transition>
+ </>
+ )
+ }
+ </Menu>
+}
diff --git a/app/components/header/account-dropdown/workplace-selector/index.module.css b/app/components/header/account-dropdown/workplace-selector/index.module.css
new file mode 100644
index 0000000..c3184f7
--- /dev/null
+++ b/app/components/header/account-dropdown/workplace-selector/index.module.css
@@ -0,0 +1,5 @@
+.popup {
+ left: 4px;
+ transform: translateX(-100%);
+ box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03);
+}
diff --git a/app/components/header/account-dropdown/workplace-selector/index.tsx b/app/components/header/account-dropdown/workplace-selector/index.tsx
new file mode 100644
index 0000000..b62e607
--- /dev/null
+++ b/app/components/header/account-dropdown/workplace-selector/index.tsx
@@ -0,0 +1,94 @@
+import { Fragment } from 'react'
+import { useContext } from 'use-context-selector'
+import { useTranslation } from 'react-i18next'
+import { Menu, MenuButton, MenuItems, Transition } from '@headlessui/react'
+import { RiArrowDownSLine } from '@remixicon/react'
+import cn from '@/utils/classnames'
+import { WEB_PREFIX } from '@/config'
+import PlanBadge from '@/app/components/header/plan-badge'
+import { switchWorkspace } from '@/service/common'
+import { useWorkspacesContext } from '@/context/workspace-context'
+import { ToastContext } from '@/app/components/base/toast'
+import type { Plan } from '@/app/components/billing/type'
+
+const WorkplaceSelector = () => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const { workspaces } = useWorkspacesContext()
+ const currentWorkspace = workspaces.find(v => v.current)
+
+ const handleSwitchWorkspace = async (tenant_id: string) => {
+ try {
+ if (currentWorkspace?.id === tenant_id)
+ return
+ await switchWorkspace({ url: '/workspaces/switch', body: { tenant_id } })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ location.assign(WEB_PREFIX)
+ }
+ catch {
+ notify({ type: 'error', message: t('common.provider.saveFailed') })
+ }
+ }
+
+ return (
+ <Menu as="div" className="relative h-full w-full">
+ {
+ ({ open }) => (
+ <>
+ <MenuButton className={cn(
+ `
+ group flex w-full cursor-pointer items-center
+ gap-1.5 p-0.5 hover:bg-state-base-hover ${open && 'bg-state-base-hover'} rounded-[10px]
+ `,
+ )}>
+ <div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px]'>
+ <span className='h-6 bg-gradient-to-r from-components-avatar-shape-fill-stop-0 to-components-avatar-shape-fill-stop-100 bg-clip-text align-middle font-semibold uppercase leading-6 text-shadow-shadow-1 opacity-90'>{currentWorkspace?.name[0]?.toLocaleUpperCase()}</span>
+ </div>
+ <div className='flex flex-row'>
+ <div className={'system-sm-medium max-w-[160px] truncate text-text-secondary'}>{currentWorkspace?.name}</div>
+ <RiArrowDownSLine className='h-4 w-4 text-text-secondary' />
+ </div>
+ </MenuButton>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems
+ className={cn(
+ `
+ shadows-shadow-lg absolute left-[-15px] mt-1 flex max-h-[400px] w-[280px] flex-col items-start overflow-y-auto rounded-xl
+ bg-components-panel-bg-blur backdrop-blur-[5px]
+ `,
+ )}
+ >
+ <div className="flex w-full flex-col items-start self-stretch rounded-xl border-[0.5px] border-components-panel-border p-1 pb-2 shadow-lg ">
+ <div className='flex items-start self-stretch px-3 pb-0.5 pt-1'>
+ <span className='system-xs-medium-uppercase flex-1 text-text-tertiary'>{t('common.userProfile.workspace')}</span>
+ </div>
+ {
+ workspaces.map(workspace => (
+ <div className='flex items-center gap-2 self-stretch rounded-lg py-1 pl-3 pr-2 hover:bg-state-base-hover' key={workspace.id} onClick={() => handleSwitchWorkspace(workspace.id)}>
+ <div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px]'>
+ <span className='h-6 bg-gradient-to-r from-components-avatar-shape-fill-stop-0 to-components-avatar-shape-fill-stop-100 bg-clip-text align-middle font-semibold uppercase leading-6 text-shadow-shadow-1 opacity-90'>{workspace?.name[0]?.toLocaleUpperCase()}</span>
+ </div>
+ <div className='system-md-regular line-clamp-1 grow cursor-pointer overflow-hidden text-ellipsis text-text-secondary'>{workspace.name}</div>
+ <PlanBadge plan={workspace.plan as Plan} />
+ </div>
+ ))
+ }
+ </div>
+ </MenuItems>
+ </Transition>
+ </>
+ )
+ }
+ </Menu>
+ )
+}
+
+export default WorkplaceSelector
diff --git a/app/components/header/account-setting/Integrations-page/index.module.css b/app/components/header/account-setting/Integrations-page/index.module.css
new file mode 100644
index 0000000..7c2a883
--- /dev/null
+++ b/app/components/header/account-setting/Integrations-page/index.module.css
@@ -0,0 +1,24 @@
+.google-icon {
+ background: url(../../assets/google.svg) center center no-repeat;
+ background-size: 16px 16px;
+}
+
+.github-icon {
+ background: url(../../assets/github.svg) center center no-repeat;
+ background-size: 16px 16px;
+}
+
+.twitter-icon {
+ background: url(../../assets/twitter.svg) center center no-repeat;
+ background-size: 16px 16px;
+}
+
+.bitbucket-icon {
+ background: url(../../assets/bitbucket.svg) center center no-repeat;
+ background-size: 16px 16px;
+}
+
+.salesforce-icon {
+ background: url(../../assets/salesforce.svg) center center no-repeat;
+ background-size: 24px auto;
+}
diff --git a/app/components/header/account-setting/Integrations-page/index.tsx b/app/components/header/account-setting/Integrations-page/index.tsx
new file mode 100644
index 0000000..0d346e0
--- /dev/null
+++ b/app/components/header/account-setting/Integrations-page/index.tsx
@@ -0,0 +1,74 @@
+'use client'
+
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import Link from 'next/link'
+import s from './index.module.css'
+import classNames from '@/utils/classnames'
+import { fetchAccountIntegrates } from '@/service/common'
+
+const titleClassName = `
+ mb-2 text-sm font-medium text-gray-900
+`
+
+export default function IntegrationsPage() {
+ const { t } = useTranslation()
+
+ const integrateMap = {
+ google: {
+ name: t('common.integrations.google'),
+ description: t('common.integrations.googleAccount'),
+ },
+ github: {
+ name: t('common.integrations.github'),
+ description: t('common.integrations.githubAccount'),
+ },
+ }
+
+ const { data } = useSWR({ url: '/account/integrates' }, fetchAccountIntegrates)
+ const integrates = data?.data?.length ? data.data : []
+
+ return (
+ <>
+ <div className='mb-8'>
+ <div className={titleClassName}>{t('common.integrations.connected')}</div>
+ {
+ integrates.map(integrate => (
+ <div key={integrate.provider} className='mb-2 flex items-center rounded-lg border-[0.5px] border-gray-200 bg-gray-50 px-3 py-2'>
+ <div className={classNames('w-8 h-8 mr-3 bg-white rounded-lg border border-gray-100', s[`${integrate.provider}-icon`])} />
+ <div className='grow'>
+ <div className='text-sm font-medium leading-[21px] text-gray-800'>{integrateMap[integrate.provider].name}</div>
+ <div className='text-xs font-normal leading-[18px] text-gray-500'>{integrateMap[integrate.provider].description}</div>
+ </div>
+ {
+ !integrate.is_bound && (
+ <Link
+ className='flex h-8 cursor-pointer items-center rounded-lg border border-gray-200 bg-white px-[7px] text-xs font-medium text-gray-700'
+ href={integrate.link}
+ target='_blank' rel='noopener noreferrer'>
+ {t('common.integrations.connect')}
+ </Link>
+ )
+ }
+ </div>
+ ))
+ }
+ </div>
+ {/* <div className='mb-8'>
+ <div className={titleClassName}>Add a service </div>
+ {
+ services.map(service => (
+ <div key={service.key} className='mb-2 flex items-center px-3 py-2 bg-gray-50 border-[0.5px] border-gray-200 rounded-lg'>
+ <div className={classNames('w-8 h-8 mr-3 bg-white rounded-lg border border-gray-100', s[`${service.key}-icon`])} />
+ <div className='grow'>
+ <div className='leading-[21px] text-sm font-medium text-gray-800'>{service.name}</div>
+ <div className='leading-[18px] text-xs font-normal text-gray-500'>{service.description}</div>
+ </div>
+ <Button className='text-xs font-medium text-gray-800'>Connect</Button>
+ </div>
+ ))
+ }
+ </div> */}
+ </>
+ )
+}
diff --git a/app/components/header/account-setting/api-based-extension-page/empty.tsx b/app/components/header/account-setting/api-based-extension-page/empty.tsx
new file mode 100644
index 0000000..a7c7391
--- /dev/null
+++ b/app/components/header/account-setting/api-based-extension-page/empty.tsx
@@ -0,0 +1,28 @@
+import { useTranslation } from 'react-i18next'
+import {
+ RiExternalLinkLine,
+ RiPuzzle2Line,
+} from '@remixicon/react'
+
+const Empty = () => {
+ const { t } = useTranslation()
+
+ return (
+ <div className='mb-2 rounded-xl bg-background-section p-6'>
+ <div className='mb-3 flex h-10 w-10 items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg-alt shadow-lg backdrop-blur-sm'>
+ <RiPuzzle2Line className='h-5 w-5 text-text-accent' />
+ </div>
+ <div className='system-sm-medium mb-1 text-text-secondary'>{t('common.apiBasedExtension.title')}</div>
+ <a
+ className='system-xs-regular flex items-center text-text-accent'
+ href={t('common.apiBasedExtension.linkUrl') || '/'}
+ target='_blank' rel='noopener noreferrer'
+ >
+ {t('common.apiBasedExtension.link')}
+ <RiExternalLinkLine className='ml-1 h-3 w-3' />
+ </a>
+ </div>
+ )
+}
+
+export default Empty
diff --git a/app/components/header/account-setting/api-based-extension-page/index.tsx b/app/components/header/account-setting/api-based-extension-page/index.tsx
new file mode 100644
index 0000000..d16c4f2
--- /dev/null
+++ b/app/components/header/account-setting/api-based-extension-page/index.tsx
@@ -0,0 +1,57 @@
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import {
+ RiAddLine,
+} from '@remixicon/react'
+import Item from './item'
+import Empty from './empty'
+import Button from '@/app/components/base/button'
+import { useModalContext } from '@/context/modal-context'
+import { fetchApiBasedExtensionList } from '@/service/common'
+
+const ApiBasedExtensionPage = () => {
+ const { t } = useTranslation()
+ const { setShowApiBasedExtensionModal } = useModalContext()
+ const { data, mutate, isLoading } = useSWR(
+ '/api-based-extension',
+ fetchApiBasedExtensionList,
+ )
+
+ const handleOpenApiBasedExtensionModal = () => {
+ setShowApiBasedExtensionModal({
+ payload: {},
+ onSaveCallback: () => mutate(),
+ })
+ }
+
+ return (
+ <div>
+ {
+ !isLoading && !data?.length && (
+ <Empty />
+ )
+ }
+ {
+ !isLoading && !!data?.length && (
+ data.map(item => (
+ <Item
+ key={item.id}
+ data={item}
+ onUpdate={() => mutate()}
+ />
+ ))
+ )
+ }
+ <Button
+ variant='secondary'
+ className='w-full'
+ onClick={handleOpenApiBasedExtensionModal}
+ >
+ <RiAddLine className='mr-1 h-4 w-4' />
+ {t('common.apiBasedExtension.add')}
+ </Button>
+ </div>
+ )
+}
+
+export default ApiBasedExtensionPage
diff --git a/app/components/header/account-setting/api-based-extension-page/item.tsx b/app/components/header/account-setting/api-based-extension-page/item.tsx
new file mode 100644
index 0000000..5a9ed24
--- /dev/null
+++ b/app/components/header/account-setting/api-based-extension-page/item.tsx
@@ -0,0 +1,74 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiDeleteBinLine,
+ RiEditLine,
+} from '@remixicon/react'
+import Button from '@/app/components/base/button'
+import type { ApiBasedExtension } from '@/models/common'
+import { useModalContext } from '@/context/modal-context'
+import { deleteApiBasedExtension } from '@/service/common'
+import Confirm from '@/app/components/base/confirm'
+
+type ItemProps = {
+ data: ApiBasedExtension
+ onUpdate: () => void
+}
+const Item: FC<ItemProps> = ({
+ data,
+ onUpdate,
+}) => {
+ const { t } = useTranslation()
+ const { setShowApiBasedExtensionModal } = useModalContext()
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
+
+ const handleOpenApiBasedExtensionModal = () => {
+ setShowApiBasedExtensionModal({
+ payload: data,
+ onSaveCallback: () => onUpdate(),
+ })
+ }
+ const handleDeleteApiBasedExtension = async () => {
+ await deleteApiBasedExtension(`/api-based-extension/${data.id}`)
+
+ setShowDeleteConfirm(false)
+ onUpdate()
+ }
+
+ return (
+ <div className='group mb-2 flex items-center rounded-xl border-[0.5px] border-transparent bg-components-input-bg-normal px-4 py-2 hover:border-components-input-border-active hover:shadow-xs'>
+ <div className='grow'>
+ <div className='mb-0.5 text-[13px] font-medium text-text-secondary'>{data.name}</div>
+ <div className='text-xs text-text-tertiary'>{data.api_endpoint}</div>
+ </div>
+ <div className='hidden items-center group-hover:flex'>
+ <Button
+ className='mr-1'
+ onClick={handleOpenApiBasedExtensionModal}
+ >
+ <RiEditLine className='mr-1 h-4 w-4' />
+ {t('common.operation.edit')}
+ </Button>
+ <Button
+ onClick={() => setShowDeleteConfirm(true)}
+ >
+ <RiDeleteBinLine className='mr-1 h-4 w-4' />
+ {t('common.operation.delete')}
+ </Button>
+ </div>
+ {
+ showDeleteConfirm
+ && <Confirm
+ isShow={showDeleteConfirm}
+ onCancel={() => setShowDeleteConfirm(false)}
+ title={`${t('common.operation.delete')} 鈥�${data.name}鈥�?`}
+ onConfirm={handleDeleteApiBasedExtension}
+ confirmText={t('common.operation.delete') || ''}
+ />
+ }
+ </div>
+ )
+}
+
+export default Item
diff --git a/app/components/header/account-setting/api-based-extension-page/modal.tsx b/app/components/header/account-setting/api-based-extension-page/modal.tsx
new file mode 100644
index 0000000..53f7673
--- /dev/null
+++ b/app/components/header/account-setting/api-based-extension-page/modal.tsx
@@ -0,0 +1,150 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import { BookOpen01 } from '@/app/components/base/icons/src/vender/line/education'
+import type { ApiBasedExtension } from '@/models/common'
+import {
+ addApiBasedExtension,
+ updateApiBasedExtension,
+} from '@/service/common'
+import { useToastContext } from '@/app/components/base/toast'
+import { noop } from 'lodash-es'
+
+export type ApiBasedExtensionData = {
+ name?: string
+ apiEndpoint?: string
+ apiKey?: string
+}
+
+type ApiBasedExtensionModalProps = {
+ data: ApiBasedExtension
+ onCancel: () => void
+ onSave?: (newData: ApiBasedExtension) => void
+}
+const ApiBasedExtensionModal: FC<ApiBasedExtensionModalProps> = ({
+ data,
+ onCancel,
+ onSave,
+}) => {
+ const { t } = useTranslation()
+ const [localeData, setLocaleData] = useState(data)
+ const [loading, setLoading] = useState(false)
+ const { notify } = useToastContext()
+ const handleDataChange = (type: string, value: string) => {
+ setLocaleData({ ...localeData, [type]: value })
+ }
+ const handleSave = async () => {
+ setLoading(true)
+
+ if (localeData && localeData.api_key && localeData.api_key?.length < 5) {
+ notify({ type: 'error', message: t('common.apiBasedExtension.modal.apiKey.lengthError') })
+ setLoading(false)
+ return
+ }
+
+ try {
+ let res: ApiBasedExtension = {}
+ if (!data.id) {
+ res = await addApiBasedExtension({
+ url: '/api-based-extension',
+ body: localeData,
+ })
+ }
+ else {
+ res = await updateApiBasedExtension({
+ url: `/api-based-extension/${data.id}`,
+ body: {
+ ...localeData,
+ api_key: data.api_key === localeData.api_key ? '[__HIDDEN__]' : localeData.api_key,
+ },
+ })
+
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ }
+
+ if (onSave)
+ onSave(res)
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ return (
+ <Modal
+ isShow
+ onClose={noop}
+ className='!w-[640px] !max-w-none !p-8 !pb-6'
+ >
+ <div className='mb-2 text-xl font-semibold text-text-primary'>
+ {
+ data.name
+ ? t('common.apiBasedExtension.modal.editTitle')
+ : t('common.apiBasedExtension.modal.title')
+ }
+ </div>
+ <div className='py-2'>
+ <div className='text-sm font-medium leading-9 text-text-primary'>
+ {t('common.apiBasedExtension.modal.name.title')}
+ </div>
+ <input
+ value={localeData.name || ''}
+ onChange={e => handleDataChange('name', e.target.value)}
+ className='block h-9 w-full appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-text-primary outline-none'
+ placeholder={t('common.apiBasedExtension.modal.name.placeholder') || ''}
+ />
+ </div>
+ <div className='py-2'>
+ <div className='flex h-9 items-center justify-between text-sm font-medium text-text-primary'>
+ {t('common.apiBasedExtension.modal.apiEndpoint.title')}
+ <a
+ href={t('common.apiBasedExtension.linkUrl') || '/'}
+ target='_blank' rel='noopener noreferrer'
+ className='group flex items-center text-xs font-normal text-text-accent'
+ >
+ <BookOpen01 className='mr-1 h-3 w-3' />
+ {t('common.apiBasedExtension.link')}
+ </a>
+ </div>
+ <input
+ value={localeData.api_endpoint || ''}
+ onChange={e => handleDataChange('api_endpoint', e.target.value)}
+ className='block h-9 w-full appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-text-primary outline-none'
+ placeholder={t('common.apiBasedExtension.modal.apiEndpoint.placeholder') || ''}
+ />
+ </div>
+ <div className='py-2'>
+ <div className='text-sm font-medium leading-9 text-text-primary'>
+ {t('common.apiBasedExtension.modal.apiKey.title')}
+ </div>
+ <div className='flex items-center'>
+ <input
+ value={localeData.api_key || ''}
+ onChange={e => handleDataChange('api_key', e.target.value)}
+ className='mr-2 block h-9 grow appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-text-primary outline-none'
+ placeholder={t('common.apiBasedExtension.modal.apiKey.placeholder') || ''}
+ />
+ </div>
+ </div>
+ <div className='mt-6 flex items-center justify-end'>
+ <Button
+ onClick={onCancel}
+ className='mr-2'
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ disabled={!localeData.name || !localeData.api_endpoint || !localeData.api_key || loading}
+ onClick={handleSave}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ </Modal>
+ )
+}
+
+export default ApiBasedExtensionModal
diff --git a/app/components/header/account-setting/api-based-extension-page/selector.tsx b/app/components/header/account-setting/api-based-extension-page/selector.tsx
new file mode 100644
index 0000000..19d034a
--- /dev/null
+++ b/app/components/header/account-setting/api-based-extension-page/selector.tsx
@@ -0,0 +1,127 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import useSWR from 'swr'
+import { useTranslation } from 'react-i18next'
+import {
+ RiAddLine,
+ RiArrowDownSLine,
+} from '@remixicon/react'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import {
+ ArrowUpRight,
+} from '@/app/components/base/icons/src/vender/line/arrows'
+import { useModalContext } from '@/context/modal-context'
+import { fetchApiBasedExtensionList } from '@/service/common'
+
+type ApiBasedExtensionSelectorProps = {
+ value: string
+ onChange: (value: string) => void
+}
+
+const ApiBasedExtensionSelector: FC<ApiBasedExtensionSelectorProps> = ({
+ value,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const {
+ setShowAccountSettingModal,
+ setShowApiBasedExtensionModal,
+ } = useModalContext()
+ const { data, mutate } = useSWR(
+ '/api-based-extension',
+ fetchApiBasedExtensionList,
+ )
+ const handleSelect = (id: string) => {
+ onChange(id)
+ setOpen(false)
+ }
+
+ const currentItem = data?.find(item => item.id === value)
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)} className='w-full'>
+ {
+ currentItem
+ ? (
+ <div className='flex h-9 cursor-pointer items-center justify-between rounded-lg bg-components-input-bg-normal pl-3 pr-2.5'>
+ <div className='text-sm text-text-primary'>{currentItem.name}</div>
+ <div className='flex items-center'>
+ <div className='mr-1.5 w-[270px] truncate text-right text-xs text-text-quaternary'>
+ {currentItem.api_endpoint}
+ </div>
+ <RiArrowDownSLine className={`h-4 w-4 text-text-secondary ${!open && 'opacity-60'}`} />
+ </div>
+ </div>
+ )
+ : (
+ <div className='flex h-9 cursor-pointer items-center justify-between rounded-lg bg-components-input-bg-normal pl-3 pr-2.5 text-sm text-text-quaternary'>
+ {t('common.apiBasedExtension.selector.placeholder')}
+ <RiArrowDownSLine className={`h-4 w-4 text-text-secondary ${!open && 'opacity-60'}`} />
+ </div>
+ )
+ }
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[102] w-[calc(100%-32px)] max-w-[576px]'>
+ <div className='z-10 w-full rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg'>
+ <div className='p-1'>
+ <div className='flex items-center justify-between px-3 pb-1 pt-2'>
+ <div className='text-xs font-medium text-text-tertiary'>
+ {t('common.apiBasedExtension.selector.title')}
+ </div>
+ <div
+ className='flex cursor-pointer items-center text-xs text-text-accent'
+ onClick={() => {
+ setOpen(false)
+ setShowAccountSettingModal({ payload: 'api-based-extension' })
+ }}
+ >
+ {t('common.apiBasedExtension.selector.manage')}
+ <ArrowUpRight className='ml-0.5 h-3 w-3' />
+ </div>
+ </div>
+ <div className='max-h-[250px] overflow-y-auto'>
+ {
+ data?.map(item => (
+ <div
+ key={item.id}
+ className='w-full cursor-pointer rounded-md px-3 py-1.5 text-left hover:stroke-state-base-hover'
+ onClick={() => handleSelect(item.id!)}
+ >
+ <div className='text-sm text-text-primary'>{item.name}</div>
+ <div className='text-xs text-text-tertiary'>{item.api_endpoint}</div>
+ </div>
+ ))
+ }
+ </div>
+ </div>
+ <div className='h-[1px] bg-divider-regular' />
+ <div className='p-1'>
+ <div
+ className='flex h-8 cursor-pointer items-center px-3 text-sm text-text-accent'
+ onClick={() => {
+ setOpen(false)
+ setShowApiBasedExtensionModal({ payload: {}, onSaveCallback: () => mutate() })
+ }}
+ >
+ <RiAddLine className='mr-2 h-4 w-4' />
+ {t('common.operation.add')}
+ </div>
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default ApiBasedExtensionSelector
diff --git a/app/components/header/account-setting/collapse/index.tsx b/app/components/header/account-setting/collapse/index.tsx
new file mode 100644
index 0000000..e028f03
--- /dev/null
+++ b/app/components/header/account-setting/collapse/index.tsx
@@ -0,0 +1,54 @@
+import { useState } from 'react'
+import { ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/24/outline'
+import classNames from '@/utils/classnames'
+
+export type IItem = {
+ key: string
+ name: string
+}
+type ICollapse = {
+ title: string | undefined
+ items: IItem[]
+ renderItem: (item: IItem) => React.ReactNode
+ onSelect?: (item: IItem) => void
+ wrapperClassName?: string
+}
+const Collapse = ({
+ title,
+ items,
+ renderItem,
+ onSelect,
+ wrapperClassName,
+}: ICollapse) => {
+ const [open, setOpen] = useState(false)
+
+ const toggle = () => setOpen(!open)
+
+ return (
+ <div className={classNames('bg-background-section-burn rounded-xl overflow-hidden', wrapperClassName)}>
+ <div className='flex cursor-pointer items-center justify-between px-3 py-2 text-xs font-medium leading-[18px] text-text-secondary' onClick={toggle}>
+ {title}
+ {
+ open
+ ? <ChevronDownIcon className='h-3 w-3 text-components-button-tertiary-text' />
+ : <ChevronRightIcon className='h-3 w-3 text-components-button-tertiary-text' />
+ }
+ </div>
+ {
+ open && (
+ <div className='mx-1 mb-1 rounded-lg border-t border-divider-subtle bg-components-panel-on-panel-item-bg py-1'>
+ {
+ items.map(item => (
+ <div key={item.key} onClick={() => onSelect && onSelect(item)}>
+ {renderItem(item)}
+ </div>
+ ))
+ }
+ </div>
+ )
+ }
+ </div>
+ )
+}
+
+export default Collapse
diff --git a/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx b/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx
new file mode 100644
index 0000000..38efdcb
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx
@@ -0,0 +1,85 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useState } from 'react'
+import useSWR from 'swr'
+import Panel from '../panel'
+import { DataSourceType } from '../panel/types'
+import type { DataSourceNotion as TDataSourceNotion } from '@/models/common'
+import { useAppContext } from '@/context/app-context'
+import { fetchNotionConnection } from '@/service/common'
+import NotionIcon from '@/app/components/base/notion-icon'
+import { noop } from 'lodash-es'
+
+const Icon: FC<{
+ src: string
+ name: string
+ className: string
+}> = ({ src, name, className }) => {
+ return (
+ <NotionIcon
+ src={src}
+ name={name}
+ className={className}
+ />
+ )
+}
+type Props = {
+ workspaces: TDataSourceNotion[]
+}
+
+const DataSourceNotion: FC<Props> = ({
+ workspaces,
+}) => {
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const [canConnectNotion, setCanConnectNotion] = useState(false)
+ const { data } = useSWR(canConnectNotion ? '/oauth/data-source/notion' : null, fetchNotionConnection)
+
+ const connected = !!workspaces.length
+
+ const handleConnectNotion = () => {
+ if (!isCurrentWorkspaceManager)
+ return
+
+ setCanConnectNotion(true)
+ }
+
+ const handleAuthAgain = () => {
+ if (data?.data)
+ window.location.href = data.data
+ else
+ setCanConnectNotion(true)
+ }
+
+ useEffect(() => {
+ if (data?.data)
+ window.location.href = data.data
+ }, [data])
+ return (
+ <Panel
+ type={DataSourceType.notion}
+ isConfigured={connected}
+ onConfigure={handleConnectNotion}
+ readOnly={!isCurrentWorkspaceManager}
+ isSupportList
+ configuredList={workspaces.map(workspace => ({
+ id: workspace.id,
+ logo: ({ className }: { className: string }) => (
+ <Icon
+ src={workspace.source_info.workspace_icon!}
+ name={workspace.source_info.workspace_name}
+ className={className}
+ />),
+ name: workspace.source_info.workspace_name,
+ isActive: workspace.is_bound,
+ notionConfig: {
+ total: workspace.source_info.total || 0,
+ },
+ }))}
+ onRemove={noop} // handled in operation/index.tsx
+ notionActions={{
+ onChangeAuthorizedPage: handleAuthAgain,
+ }}
+ />
+ )
+}
+export default React.memo(DataSourceNotion)
diff --git a/app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx b/app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx
new file mode 100644
index 0000000..bcf24d6
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx
@@ -0,0 +1,101 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { Fragment } from 'react'
+import { useSWRConfig } from 'swr'
+import {
+ RiDeleteBinLine,
+ RiLoopLeftLine,
+ RiMoreFill,
+ RiStickyNoteAddLine,
+} from '@remixicon/react'
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import { syncDataSourceNotion, updateDataSourceNotionAction } from '@/service/common'
+import Toast from '@/app/components/base/toast'
+import cn from '@/utils/classnames'
+
+type OperateProps = {
+ payload: {
+ id: string
+ total: number
+ }
+ onAuthAgain: () => void
+}
+export default function Operate({
+ payload,
+ onAuthAgain,
+}: OperateProps) {
+ const { t } = useTranslation()
+ const { mutate } = useSWRConfig()
+
+ const updateIntegrates = () => {
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.success'),
+ })
+ mutate({ url: 'data-source/integrates' })
+ }
+ const handleSync = async () => {
+ await syncDataSourceNotion({ url: `/oauth/data-source/notion/${payload.id}/sync` })
+ updateIntegrates()
+ }
+ const handleRemove = async () => {
+ await updateDataSourceNotionAction({ url: `/data-source/integrates/${payload.id}/disable` })
+ updateIntegrates()
+ }
+
+ return (
+ <Menu as="div" className="relative inline-block text-left">
+ {
+ ({ open }) => (
+ <>
+ <MenuButton className={cn('flex h-8 w-8 items-center justify-center rounded-lg hover:bg-state-base-hover', open && 'bg-state-base-hover')}>
+ <RiMoreFill className='h-4 w-4 text-text-secondary' />
+ </MenuButton>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems className="absolute right-0 top-9 w-60 max-w-80 origin-top-right rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm">
+ <div className="px-1 py-1">
+ <MenuItem>
+ <div
+ className='flex cursor-pointer rounded-lg px-3 py-2 hover:bg-state-base-hover'
+ onClick={onAuthAgain}
+ >
+ <RiStickyNoteAddLine className='mr-2 mt-[2px] h-4 w-4 text-text-tertiary' />
+ <div>
+ <div className='system-sm-semibold text-text-secondary'>{t('common.dataSource.notion.changeAuthorizedPages')}</div>
+ <div className='system-xs-regular text-text-tertiary'>
+ {payload.total} {t('common.dataSource.notion.pagesAuthorized')}
+ </div>
+ </div>
+ </div>
+ </MenuItem>
+ <MenuItem>
+ <div className='flex cursor-pointer rounded-lg px-3 py-2 hover:bg-state-base-hover' onClick={handleSync}>
+ <RiLoopLeftLine className='mr-2 mt-[2px] h-4 w-4 text-text-tertiary' />
+ <div className='system-sm-semibold text-text-secondary'>{t('common.dataSource.notion.sync')}</div>
+ </div>
+ </MenuItem>
+ </div>
+ <MenuItem>
+ <div className='border-t border-divider-subtle p-1'>
+ <div className='flex cursor-pointer rounded-lg px-3 py-2 hover:bg-state-base-hover' onClick={handleRemove}>
+ <RiDeleteBinLine className='mr-2 mt-[2px] h-4 w-4 text-text-tertiary' />
+ <div className='system-sm-semibold text-text-secondary'>{t('common.dataSource.notion.remove')}</div>
+ </div>
+ </div>
+ </MenuItem>
+ </MenuItems>
+ </Transition>
+ </>
+ )
+ }
+ </Menu>
+ )
+}
diff --git a/app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.tsx b/app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.tsx
new file mode 100644
index 0000000..81ee35a
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.tsx
@@ -0,0 +1,161 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+} from '@/app/components/base/portal-to-follow-elem'
+import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
+import Button from '@/app/components/base/button'
+import type { FirecrawlConfig } from '@/models/common'
+import Field from '@/app/components/datasets/create/website/base/field'
+import Toast from '@/app/components/base/toast'
+import { createDataSourceApiKeyBinding } from '@/service/datasets'
+import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
+type Props = {
+ onCancel: () => void
+ onSaved: () => void
+}
+
+const I18N_PREFIX = 'datasetCreation.firecrawl'
+
+const DEFAULT_BASE_URL = 'https://api.firecrawl.dev'
+
+const ConfigFirecrawlModal: FC<Props> = ({
+ onCancel,
+ onSaved,
+}) => {
+ const { t } = useTranslation()
+ const [isSaving, setIsSaving] = useState(false)
+ const [config, setConfig] = useState<FirecrawlConfig>({
+ api_key: '',
+ base_url: '',
+ })
+
+ const handleConfigChange = useCallback((key: string) => {
+ return (value: string | number) => {
+ setConfig(prev => ({ ...prev, [key]: value as string }))
+ }
+ }, [])
+
+ const handleSave = useCallback(async () => {
+ if (isSaving)
+ return
+ let errorMsg = ''
+ if (config.base_url && !((config.base_url.startsWith('http://') || config.base_url.startsWith('https://'))))
+ errorMsg = t('common.errorMsg.urlError')
+ if (!errorMsg) {
+ if (!config.api_key) {
+ errorMsg = t('common.errorMsg.fieldRequired', {
+ field: 'API Key',
+ })
+ }
+ }
+
+ if (errorMsg) {
+ Toast.notify({
+ type: 'error',
+ message: errorMsg,
+ })
+ return
+ }
+ const postData = {
+ category: 'website',
+ provider: 'firecrawl',
+ credentials: {
+ auth_type: 'bearer',
+ config: {
+ api_key: config.api_key,
+ base_url: config.base_url || DEFAULT_BASE_URL,
+ },
+ },
+ }
+ try {
+ setIsSaving(true)
+ await createDataSourceApiKeyBinding(postData)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.success'),
+ })
+ }
+ finally {
+ setIsSaving(false)
+ }
+
+ onSaved()
+ }, [config.api_key, config.base_url, onSaved, t, isSaving])
+
+ return (
+ <PortalToFollowElem open>
+ <PortalToFollowElemContent className='z-[60] h-full w-full'>
+ <div className='fixed inset-0 flex items-center justify-center bg-background-overlay'>
+ <div className='mx-2 max-h-[calc(100vh-120px)] w-[640px] overflow-y-auto rounded-2xl bg-components-panel-bg shadow-xl'>
+ <div className='px-8 pt-8'>
+ <div className='mb-4 flex items-center justify-between'>
+ <div className='system-xl-semibold text-text-primary'>{t(`${I18N_PREFIX}.configFirecrawl`)}</div>
+ </div>
+
+ <div className='space-y-4'>
+ <Field
+ label='API Key'
+ labelClassName='!text-sm'
+ isRequired
+ value={config.api_key}
+ onChange={handleConfigChange('api_key')}
+ placeholder={t(`${I18N_PREFIX}.apiKeyPlaceholder`)!}
+ />
+ <Field
+ label='Base URL'
+ labelClassName='!text-sm'
+ value={config.base_url}
+ onChange={handleConfigChange('base_url')}
+ placeholder={DEFAULT_BASE_URL}
+ />
+ </div>
+ <div className='my-8 flex h-8 items-center justify-between'>
+ <a className='flex items-center space-x-1 text-xs font-normal leading-[18px] text-text-accent' target='_blank' href='https://www.firecrawl.dev/account'>
+ <span>{t(`${I18N_PREFIX}.getApiKeyLinkText`)}</span>
+ <LinkExternal02 className='h-3 w-3' />
+ </a>
+ <div className='flex'>
+ <Button
+ size='large'
+ className='mr-2'
+ onClick={onCancel}
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ size='large'
+ onClick={handleSave}
+ loading={isSaving}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+
+ </div>
+ </div>
+ <div className='border-t-[0.5px] border-t-divider-regular'>
+ <div className='flex items-center justify-center bg-background-section-burn py-3 text-xs text-text-tertiary'>
+ <Lock01 className='mr-1 h-3 w-3 text-text-tertiary' />
+ {t('common.modelProvider.encrypted.front')}
+ <a
+ className='mx-1 text-text-accent'
+ target='_blank' rel='noopener noreferrer'
+ href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
+ >
+ PKCS1_OAEP
+ </a>
+ {t('common.modelProvider.encrypted.back')}
+ </div>
+ </div>
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(ConfigFirecrawlModal)
diff --git a/app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.tsx b/app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.tsx
new file mode 100644
index 0000000..1e57e2f
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.tsx
@@ -0,0 +1,140 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+} from '@/app/components/base/portal-to-follow-elem'
+import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
+import Button from '@/app/components/base/button'
+import { DataSourceProvider } from '@/models/common'
+import Field from '@/app/components/datasets/create/website/base/field'
+import Toast from '@/app/components/base/toast'
+import { createDataSourceApiKeyBinding } from '@/service/datasets'
+import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
+type Props = {
+ onCancel: () => void
+ onSaved: () => void
+}
+
+const I18N_PREFIX = 'datasetCreation.jinaReader'
+
+const ConfigJinaReaderModal: FC<Props> = ({
+ onCancel,
+ onSaved,
+}) => {
+ const { t } = useTranslation()
+ const [isSaving, setIsSaving] = useState(false)
+ const [apiKey, setApiKey] = useState('')
+
+ const handleSave = useCallback(async () => {
+ if (isSaving)
+ return
+ let errorMsg = ''
+ if (!errorMsg) {
+ if (!apiKey) {
+ errorMsg = t('common.errorMsg.fieldRequired', {
+ field: 'API Key',
+ })
+ }
+ }
+
+ if (errorMsg) {
+ Toast.notify({
+ type: 'error',
+ message: errorMsg,
+ })
+ return
+ }
+ const postData = {
+ category: 'website',
+ provider: DataSourceProvider.jinaReader,
+ credentials: {
+ auth_type: 'bearer',
+ config: {
+ api_key: apiKey,
+ },
+ },
+ }
+ try {
+ setIsSaving(true)
+ await createDataSourceApiKeyBinding(postData)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.success'),
+ })
+ }
+ finally {
+ setIsSaving(false)
+ }
+
+ onSaved()
+ }, [apiKey, onSaved, t, isSaving])
+
+ return (
+ <PortalToFollowElem open>
+ <PortalToFollowElemContent className='z-[60] h-full w-full'>
+ <div className='fixed inset-0 flex items-center justify-center bg-background-overlay'>
+ <div className='mx-2 max-h-[calc(100vh-120px)] w-[640px] overflow-y-auto rounded-2xl bg-components-panel-bg shadow-xl'>
+ <div className='px-8 pt-8'>
+ <div className='mb-4 flex items-center justify-between'>
+ <div className='system-xl-semibold text-text-primary'>{t(`${I18N_PREFIX}.configJinaReader`)}</div>
+ </div>
+
+ <div className='space-y-4'>
+ <Field
+ label='API Key'
+ labelClassName='!text-sm'
+ isRequired
+ value={apiKey}
+ onChange={(value: string | number) => setApiKey(value as string)}
+ placeholder={t(`${I18N_PREFIX}.apiKeyPlaceholder`)!}
+ />
+ </div>
+ <div className='my-8 flex h-8 items-center justify-between'>
+ <a className='flex items-center space-x-1 text-xs font-normal leading-[18px] text-text-accent' target='_blank' href='https://jina.ai/reader/'>
+ <span>{t(`${I18N_PREFIX}.getApiKeyLinkText`)}</span>
+ <LinkExternal02 className='h-3 w-3' />
+ </a>
+ <div className='flex'>
+ <Button
+ size='large'
+ className='mr-2'
+ onClick={onCancel}
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ size='large'
+ onClick={handleSave}
+ loading={isSaving}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+
+ </div>
+ </div>
+ <div className='border-t-[0.5px] border-t-divider-regular'>
+ <div className='flex items-center justify-center bg-background-section-burn py-3 text-xs text-text-tertiary'>
+ <Lock01 className='mr-1 h-3 w-3 text-text-tertiary' />
+ {t('common.modelProvider.encrypted.front')}
+ <a
+ className='mx-1 text-text-accent'
+ target='_blank' rel='noopener noreferrer'
+ href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
+ >
+ PKCS1_OAEP
+ </a>
+ {t('common.modelProvider.encrypted.back')}
+ </div>
+ </div>
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(ConfigJinaReaderModal)
diff --git a/app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.tsx b/app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.tsx
new file mode 100644
index 0000000..ff85353
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.tsx
@@ -0,0 +1,161 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+} from '@/app/components/base/portal-to-follow-elem'
+import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
+import Button from '@/app/components/base/button'
+import type { WatercrawlConfig } from '@/models/common'
+import Field from '@/app/components/datasets/create/website/base/field'
+import Toast from '@/app/components/base/toast'
+import { createDataSourceApiKeyBinding } from '@/service/datasets'
+import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
+type Props = {
+ onCancel: () => void
+ onSaved: () => void
+}
+
+const I18N_PREFIX = 'datasetCreation.watercrawl'
+
+const DEFAULT_BASE_URL = 'https://app.watercrawl.dev'
+
+const ConfigWatercrawlModal: FC<Props> = ({
+ onCancel,
+ onSaved,
+}) => {
+ const { t } = useTranslation()
+ const [isSaving, setIsSaving] = useState(false)
+ const [config, setConfig] = useState<WatercrawlConfig>({
+ api_key: '',
+ base_url: '',
+ })
+
+ const handleConfigChange = useCallback((key: string) => {
+ return (value: string | number) => {
+ setConfig(prev => ({ ...prev, [key]: value as string }))
+ }
+ }, [])
+
+ const handleSave = useCallback(async () => {
+ if (isSaving)
+ return
+ let errorMsg = ''
+ if (config.base_url && !((config.base_url.startsWith('http://') || config.base_url.startsWith('https://'))))
+ errorMsg = t('common.errorMsg.urlError')
+ if (!errorMsg) {
+ if (!config.api_key) {
+ errorMsg = t('common.errorMsg.fieldRequired', {
+ field: 'API Key',
+ })
+ }
+ }
+
+ if (errorMsg) {
+ Toast.notify({
+ type: 'error',
+ message: errorMsg,
+ })
+ return
+ }
+ const postData = {
+ category: 'website',
+ provider: 'watercrawl',
+ credentials: {
+ auth_type: 'x-api-key',
+ config: {
+ api_key: config.api_key,
+ base_url: config.base_url || DEFAULT_BASE_URL,
+ },
+ },
+ }
+ try {
+ setIsSaving(true)
+ await createDataSourceApiKeyBinding(postData)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.success'),
+ })
+ }
+ finally {
+ setIsSaving(false)
+ }
+
+ onSaved()
+ }, [config.api_key, config.base_url, onSaved, t, isSaving])
+
+ return (
+ <PortalToFollowElem open>
+ <PortalToFollowElemContent className='z-[60] h-full w-full'>
+ <div className='fixed inset-0 flex items-center justify-center bg-background-overlay'>
+ <div className='mx-2 max-h-[calc(100vh-120px)] w-[640px] overflow-y-auto rounded-2xl bg-components-panel-bg shadow-xl'>
+ <div className='px-8 pt-8'>
+ <div className='mb-4 flex items-center justify-between'>
+ <div className='system-xl-semibold text-text-primary'>{t(`${I18N_PREFIX}.configWatercrawl`)}</div>
+ </div>
+
+ <div className='space-y-4'>
+ <Field
+ label='API Key'
+ labelClassName='!text-sm'
+ isRequired
+ value={config.api_key}
+ onChange={handleConfigChange('api_key')}
+ placeholder={t(`${I18N_PREFIX}.apiKeyPlaceholder`)!}
+ />
+ <Field
+ label='Base URL'
+ labelClassName='!text-sm'
+ value={config.base_url}
+ onChange={handleConfigChange('base_url')}
+ placeholder={DEFAULT_BASE_URL}
+ />
+ </div>
+ <div className='my-8 flex h-8 items-center justify-between'>
+ <a className='flex items-center space-x-1 text-xs font-normal leading-[18px] text-text-accent' target='_blank' href='https://app.watercrawl.dev/'>
+ <span>{t(`${I18N_PREFIX}.getApiKeyLinkText`)}</span>
+ <LinkExternal02 className='h-3 w-3' />
+ </a>
+ <div className='flex'>
+ <Button
+ size='large'
+ className='mr-2'
+ onClick={onCancel}
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ size='large'
+ onClick={handleSave}
+ loading={isSaving}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+
+ </div>
+ </div>
+ <div className='border-t-[0.5px] border-t-divider-regular'>
+ <div className='flex items-center justify-center bg-background-section-burn py-3 text-xs text-text-tertiary'>
+ <Lock01 className='mr-1 h-3 w-3 text-text-tertiary' />
+ {t('common.modelProvider.encrypted.front')}
+ <a
+ className='mx-1 text-text-accent'
+ target='_blank' rel='noopener noreferrer'
+ href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
+ >
+ PKCS1_OAEP
+ </a>
+ {t('common.modelProvider.encrypted.back')}
+ </div>
+ </div>
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+export default React.memo(ConfigWatercrawlModal)
diff --git a/app/components/header/account-setting/data-source-page/data-source-website/index.tsx b/app/components/header/account-setting/data-source-page/data-source-website/index.tsx
new file mode 100644
index 0000000..911bf01
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/data-source-website/index.tsx
@@ -0,0 +1,132 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import Panel from '../panel'
+import { DataSourceType } from '../panel/types'
+import ConfigFirecrawlModal from './config-firecrawl-modal'
+import ConfigWatercrawlModal from './config-watercrawl-modal'
+import ConfigJinaReaderModal from './config-jina-reader-modal'
+import cn from '@/utils/classnames'
+import s from '@/app/components/datasets/create/website/index.module.css'
+import { fetchDataSources, removeDataSourceApiKeyBinding } from '@/service/datasets'
+
+import type { DataSourceItem } from '@/models/common'
+import { DataSourceProvider } from '@/models/common'
+import { useAppContext } from '@/context/app-context'
+import Toast from '@/app/components/base/toast'
+
+type Props = {
+ provider: DataSourceProvider
+}
+
+const DataSourceWebsite: FC<Props> = ({ provider }) => {
+ const { t } = useTranslation()
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const [sources, setSources] = useState<DataSourceItem[]>([])
+ const checkSetApiKey = useCallback(async () => {
+ const res = await fetchDataSources() as any
+ const list = res.sources
+ setSources(list)
+ }, [])
+
+ useEffect(() => {
+ checkSetApiKey()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+
+ const [configTarget, setConfigTarget] = useState<DataSourceProvider | null>(null)
+ const showConfig = useCallback((provider: DataSourceProvider) => {
+ setConfigTarget(provider)
+ }, [setConfigTarget])
+
+ const hideConfig = useCallback(() => {
+ setConfigTarget(null)
+ }, [setConfigTarget])
+
+ const handleAdded = useCallback(() => {
+ checkSetApiKey()
+ hideConfig()
+ }, [checkSetApiKey, hideConfig])
+
+ const getIdByProvider = (provider: DataSourceProvider): string | undefined => {
+ const source = sources.find(item => item.provider === provider)
+ return source?.id
+ }
+
+ const getProviderName = (provider: DataSourceProvider): string => {
+ if (provider === DataSourceProvider.fireCrawl)
+ return 'Firecrawl'
+
+ if (provider === DataSourceProvider.waterCrawl)
+ return 'WaterCrawl'
+
+ return 'Jina Reader'
+ }
+
+ const handleRemove = useCallback((provider: DataSourceProvider) => {
+ return async () => {
+ const dataSourceId = getIdByProvider(provider)
+ if (dataSourceId) {
+ await removeDataSourceApiKeyBinding(dataSourceId)
+ setSources(sources.filter(item => item.provider !== provider))
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.remove'),
+ })
+ }
+ }
+ }, [sources, t])
+
+ return (
+ <>
+ <Panel
+ type={DataSourceType.website}
+ provider={provider}
+ isConfigured={sources.find(item => item.provider === provider) !== undefined}
+ onConfigure={() => showConfig(provider)}
+ readOnly={!isCurrentWorkspaceManager}
+ configuredList={sources.filter(item => item.provider === provider).map(item => ({
+ id: item.id,
+ logo: ({ className }: { className: string }) => {
+ if (item.provider === DataSourceProvider.fireCrawl) {
+ return (
+ <div
+ className={cn(className, 'ml-3 flex h-5 w-5 items-center justify-center rounded border border-divider-subtle !bg-background-default text-xs font-medium text-text-tertiary')}>馃敟</div>
+ )
+ }
+
+ if (item.provider === DataSourceProvider.waterCrawl) {
+ return (
+ <div
+ className={cn(className, 'ml-3 flex h-5 w-5 items-center justify-center rounded border border-divider-subtle !bg-background-default text-xs font-medium text-text-tertiary')}>
+ <span className={s.watercrawlLogo}/>
+ </div>
+ )
+ }
+ return (
+ <div
+ className={cn(className, 'ml-3 flex h-5 w-5 items-center justify-center rounded border border-divider-subtle !bg-background-default text-xs font-medium text-text-tertiary')}>
+ <span className={s.jinaLogo}/>
+ </div>
+ )
+ },
+ name: getProviderName(item.provider),
+ isActive: true,
+ }))}
+ onRemove={handleRemove(provider)}
+ />
+ {configTarget === DataSourceProvider.fireCrawl && (
+ <ConfigFirecrawlModal onSaved={handleAdded} onCancel={hideConfig}/>
+ )}
+ {configTarget === DataSourceProvider.waterCrawl && (
+ <ConfigWatercrawlModal onSaved={handleAdded} onCancel={hideConfig}/>
+ )}
+ {configTarget === DataSourceProvider.jinaReader && (
+ <ConfigJinaReaderModal onSaved={handleAdded} onCancel={hideConfig}/>
+ )}
+ </>
+
+ )
+}
+export default React.memo(DataSourceWebsite)
diff --git a/app/components/header/account-setting/data-source-page/index.module.css b/app/components/header/account-setting/data-source-page/index.module.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/index.module.css
diff --git a/app/components/header/account-setting/data-source-page/index.tsx b/app/components/header/account-setting/data-source-page/index.tsx
new file mode 100644
index 0000000..fb13813
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/index.tsx
@@ -0,0 +1,20 @@
+import useSWR from 'swr'
+import DataSourceNotion from './data-source-notion'
+import DataSourceWebsite from './data-source-website'
+import { fetchDataSource } from '@/service/common'
+import { DataSourceProvider } from '@/models/common'
+import { ENABLE_WEBSITE_FIRECRAWL, ENABLE_WEBSITE_JINAREADER, ENABLE_WEBSITE_WATERCRAWL } from '@/config'
+
+export default function DataSourcePage() {
+ const { data } = useSWR({ url: 'data-source/integrates' }, fetchDataSource)
+ const notionWorkspaces = data?.data.filter(item => item.provider === 'notion') || []
+
+ return (
+ <div className='mb-8'>
+ <DataSourceNotion workspaces={notionWorkspaces} />
+ {ENABLE_WEBSITE_JINAREADER && <DataSourceWebsite provider={DataSourceProvider.jinaReader} />}
+ {ENABLE_WEBSITE_FIRECRAWL && <DataSourceWebsite provider={DataSourceProvider.fireCrawl} />}
+ {ENABLE_WEBSITE_WATERCRAWL && <DataSourceWebsite provider={DataSourceProvider.waterCrawl} />}
+ </div>
+ )
+}
diff --git a/app/components/header/account-setting/data-source-page/panel/config-item.tsx b/app/components/header/account-setting/data-source-page/panel/config-item.tsx
new file mode 100644
index 0000000..6faf840
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/panel/config-item.tsx
@@ -0,0 +1,83 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiDeleteBinLine,
+} from '@remixicon/react'
+import Indicator from '../../../indicator'
+import Operate from '../data-source-notion/operate'
+import { DataSourceType } from './types'
+import s from './style.module.css'
+import cn from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+export type ConfigItemType = {
+ id: string
+ logo: any
+ name: string
+ isActive: boolean
+ notionConfig?: {
+ total: number
+ }
+}
+
+type Props = {
+ type: DataSourceType
+ payload: ConfigItemType
+ onRemove: () => void
+ notionActions?: {
+ onChangeAuthorizedPage: () => void
+ }
+ readOnly: boolean
+}
+
+const ConfigItem: FC<Props> = ({
+ type,
+ payload,
+ onRemove,
+ notionActions,
+ readOnly,
+}) => {
+ const { t } = useTranslation()
+ const isNotion = type === DataSourceType.notion
+ const isWebsite = type === DataSourceType.website
+ const onChangeAuthorizedPage = notionActions?.onChangeAuthorizedPage || noop
+
+ return (
+ <div className={cn(s['workspace-item'], 'mb-1 flex items-center rounded-lg bg-components-panel-on-panel-item-bg py-1 pr-1')} key={payload.id}>
+ <payload.logo className='ml-3 mr-1.5' />
+ <div className='system-sm-medium grow truncate py-[7px] text-text-secondary' title={payload.name}>{payload.name}</div>
+ {
+ payload.isActive
+ ? <Indicator className='mr-[6px] shrink-0' color='green' />
+ : <Indicator className='mr-[6px] shrink-0' color='yellow' />
+ }
+ <div className={`system-xs-semibold-uppercase mr-3 shrink-0 ${payload.isActive ? 'text-util-colors-green-green-600' : 'text-util-colors-warning-warning-600'}`}>
+ {
+ payload.isActive
+ ? t(isNotion ? 'common.dataSource.notion.connected' : 'common.dataSource.website.active')
+ : t(isNotion ? 'common.dataSource.notion.disconnected' : 'common.dataSource.website.inactive')
+ }
+ </div>
+ <div className='mr-2 h-3 w-[1px] bg-divider-regular' />
+ {isNotion && (
+ <Operate payload={{
+ id: payload.id,
+ total: payload.notionConfig?.total || 0,
+ }} onAuthAgain={onChangeAuthorizedPage}
+ />
+ )}
+
+ {
+ isWebsite && !readOnly && (
+ <div className='cursor-pointer rounded-md p-2 text-text-tertiary hover:bg-state-base-hover' onClick={onRemove} >
+ <RiDeleteBinLine className='h-4 w-4' />
+ </div>
+ )
+ }
+
+ </div>
+ )
+}
+export default React.memo(ConfigItem)
diff --git a/app/components/header/account-setting/data-source-page/panel/index.tsx b/app/components/header/account-setting/data-source-page/panel/index.tsx
new file mode 100644
index 0000000..95ab9a6
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/panel/index.tsx
@@ -0,0 +1,145 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiAddLine } from '@remixicon/react'
+import type { ConfigItemType } from './config-item'
+import ConfigItem from './config-item'
+
+import s from './style.module.css'
+import { DataSourceType } from './types'
+import Button from '@/app/components/base/button'
+import { DataSourceProvider } from '@/models/common'
+import cn from '@/utils/classnames'
+
+type Props = {
+ type: DataSourceType
+ provider?: DataSourceProvider
+ isConfigured: boolean
+ onConfigure: () => void
+ readOnly: boolean
+ isSupportList?: boolean
+ configuredList: ConfigItemType[]
+ onRemove: () => void
+ notionActions?: {
+ onChangeAuthorizedPage: () => void
+ }
+}
+
+const Panel: FC<Props> = ({
+ type,
+ provider,
+ isConfigured,
+ onConfigure,
+ readOnly,
+ configuredList,
+ isSupportList,
+ onRemove,
+ notionActions,
+}) => {
+ const { t } = useTranslation()
+ const isNotion = type === DataSourceType.notion
+ const isWebsite = type === DataSourceType.website
+
+ const getProviderName = (): string => {
+ if (provider === DataSourceProvider.fireCrawl) return '馃敟 Firecrawl'
+ if (provider === DataSourceProvider.waterCrawl) return 'WaterCrawl'
+ return 'Jina Reader'
+ }
+
+ return (
+ <div className='mb-2 rounded-xl bg-background-section-burn'>
+ <div className='flex items-center px-3 py-[9px]'>
+ <div className={cn(s[`${type}-icon`], 'mr-3 h-8 w-8 rounded-lg border border-divider-subtle !bg-background-default')} />
+ <div className='grow'>
+ <div className='flex h-5 items-center'>
+ <div className='text-sm font-medium text-text-primary'>{t(`common.dataSource.${type}.title`)}</div>
+ {isWebsite && (
+ <div className='ml-1 rounded-md bg-components-badge-white-to-dark px-1.5 text-xs font-medium leading-[18px] text-text-secondary'>
+ <span className='text-text-tertiary'>{t('common.dataSource.website.with')}</span> {getProviderName()}
+ </div>
+ )}
+ </div>
+ {
+ !isConfigured && (
+ <div className='system-xs-medium text-text-tertiary'>
+ {t(`common.dataSource.${type}.description`)}
+ </div>
+ )
+ }
+ </div>
+ {isNotion && (
+ <>
+ {
+ isConfigured
+ ? (
+ <Button
+ disabled={readOnly}
+ className='ml-3'
+ onClick={onConfigure}
+ >
+ {t('common.dataSource.configure')}
+ </Button>
+ )
+ : (
+ <>
+ {isSupportList && <div
+ className={
+ `system-sm-medium flex min-h-7 items-center rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-3 py-1 text-components-button-secondary-accent-text
+ ${!readOnly ? 'cursor-pointer' : 'cursor-default opacity-50 grayscale'}`
+ }
+ onClick={onConfigure}
+ >
+ <RiAddLine className='mr-[5px] h-4 w-4 text-components-button-secondary-accent-text' />
+ {t('common.dataSource.connect')}
+ </div>}
+ </>
+ )
+ }
+ </>
+ )}
+
+ {isWebsite && !isConfigured && (
+ <div
+ className={
+ `ml-3 flex h-7 items-center rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg
+ px-3 text-xs font-medium text-components-button-secondary-accent-text
+ ${!readOnly ? 'cursor-pointer' : 'cursor-default opacity-50 grayscale'}`
+ }
+ onClick={!readOnly ? onConfigure : undefined}
+ >
+ {t('common.dataSource.configure')}
+ </div>
+ )}
+
+ </div>
+ {
+ isConfigured && (
+ <>
+ <div className='flex h-[18px] items-center px-3'>
+ <div className='system-xs-medium text-text-tertiary'>
+ {isNotion ? t('common.dataSource.notion.connectedWorkspace') : t('common.dataSource.website.configuredCrawlers')}
+ </div>
+ <div className='ml-3 grow border-t border-t-divider-subtle' />
+ </div>
+ <div className='px-3 pb-3 pt-2'>
+ {
+ configuredList.map(item => (
+ <ConfigItem
+ key={item.id}
+ type={type}
+ payload={item}
+ onRemove={onRemove}
+ notionActions={notionActions}
+ readOnly={readOnly}
+ />
+ ))
+ }
+ </div>
+ </>
+ )
+ }
+ </div>
+ )
+}
+export default React.memo(Panel)
diff --git a/app/components/header/account-setting/data-source-page/panel/style.module.css b/app/components/header/account-setting/data-source-page/panel/style.module.css
new file mode 100644
index 0000000..ac9be02
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/panel/style.module.css
@@ -0,0 +1,17 @@
+.notion-icon {
+ background: #ffffff url(../../../assets/notion.svg) center center no-repeat;
+ background-size: 20px 20px;
+}
+
+.website-icon {
+ background: #ffffff url(../../../../datasets/create/assets/web.svg) center center no-repeat;
+ background-size: 20px 20px;
+}
+
+.workspace-item {
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+}
+
+.workspace-item:last-of-type {
+ margin-bottom: 0;
+}
diff --git a/app/components/header/account-setting/data-source-page/panel/types.ts b/app/components/header/account-setting/data-source-page/panel/types.ts
new file mode 100644
index 0000000..345bc10
--- /dev/null
+++ b/app/components/header/account-setting/data-source-page/panel/types.ts
@@ -0,0 +1,4 @@
+export enum DataSourceType {
+ notion = 'notion',
+ website = 'website',
+}
diff --git a/app/components/header/account-setting/index.tsx b/app/components/header/account-setting/index.tsx
new file mode 100644
index 0000000..b2a3c82
--- /dev/null
+++ b/app/components/header/account-setting/index.tsx
@@ -0,0 +1,229 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { useEffect, useRef, useState } from 'react'
+import {
+ RiBrain2Fill,
+ RiBrain2Line,
+ RiCloseLine,
+ RiColorFilterFill,
+ RiColorFilterLine,
+ RiDatabase2Fill,
+ RiDatabase2Line,
+ RiGroup2Fill,
+ RiGroup2Line,
+ RiMoneyDollarCircleFill,
+ RiMoneyDollarCircleLine,
+ RiPuzzle2Fill,
+ RiPuzzle2Line,
+ RiTranslate2,
+} from '@remixicon/react'
+import Button from '../../base/button'
+import MembersPage from './members-page'
+import LanguagePage from './language-page'
+import ApiBasedExtensionPage from './api-based-extension-page'
+import DataSourcePage from './data-source-page'
+import ModelProviderPage from './model-provider-page'
+import cn from '@/utils/classnames'
+import BillingPage from '@/app/components/billing/billing-page'
+import CustomPage from '@/app/components/custom/custom-page'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import { useProviderContext } from '@/context/provider-context'
+import { useAppContext } from '@/context/app-context'
+import MenuDialog from '@/app/components/header/account-setting/menu-dialog'
+import Input from '@/app/components/base/input'
+
+const iconClassName = `
+ w-5 h-5 mr-2
+`
+
+type IAccountSettingProps = {
+ onCancel: () => void
+ activeTab?: string
+}
+
+type GroupItem = {
+ key: string
+ name: string
+ description?: string
+ icon: React.JSX.Element
+ activeIcon: React.JSX.Element
+}
+
+export default function AccountSetting({
+ onCancel,
+ activeTab = 'members',
+}: IAccountSettingProps) {
+ const [activeMenu, setActiveMenu] = useState(activeTab)
+ const { t } = useTranslation()
+ const { enableBilling, enableReplaceWebAppLogo } = useProviderContext()
+ const { isCurrentWorkspaceDatasetOperator } = useAppContext()
+
+ const workplaceGroupItems = (() => {
+ if (isCurrentWorkspaceDatasetOperator)
+ return []
+ return [
+ {
+ key: 'provider',
+ name: t('common.settings.provider'),
+ icon: <RiBrain2Line className={iconClassName} />,
+ activeIcon: <RiBrain2Fill className={iconClassName} />,
+ },
+ {
+ key: 'members',
+ name: t('common.settings.members'),
+ icon: <RiGroup2Line className={iconClassName} />,
+ activeIcon: <RiGroup2Fill className={iconClassName} />,
+ },
+ {
+ // Use key false to hide this item
+ key: enableBilling ? 'billing' : false,
+ name: t('common.settings.billing'),
+ description: t('billing.plansCommon.receiptInfo'),
+ icon: <RiMoneyDollarCircleLine className={iconClassName} />,
+ activeIcon: <RiMoneyDollarCircleFill className={iconClassName} />,
+ },
+ {
+ key: 'data-source',
+ name: t('common.settings.dataSource'),
+ icon: <RiDatabase2Line className={iconClassName} />,
+ activeIcon: <RiDatabase2Fill className={iconClassName} />,
+ },
+ {
+ key: 'api-based-extension',
+ name: t('common.settings.apiBasedExtension'),
+ icon: <RiPuzzle2Line className={iconClassName} />,
+ activeIcon: <RiPuzzle2Fill className={iconClassName} />,
+ },
+ {
+ key: (enableReplaceWebAppLogo || enableBilling) ? 'custom' : false,
+ name: t('custom.custom'),
+ icon: <RiColorFilterLine className={iconClassName} />,
+ activeIcon: <RiColorFilterFill className={iconClassName} />,
+ },
+ ].filter(item => !!item.key) as GroupItem[]
+ })()
+
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ const menuItems = [
+ {
+ key: 'workspace-group',
+ name: t('common.settings.workplaceGroup'),
+ items: workplaceGroupItems,
+ },
+ {
+ key: 'account-group',
+ name: t('common.settings.generalGroup'),
+ items: [
+ {
+ key: 'language',
+ name: t('common.settings.language'),
+ icon: <RiTranslate2 className={iconClassName} />,
+ activeIcon: <RiTranslate2 className={iconClassName} />,
+ },
+ ],
+ },
+ ]
+ const scrollRef = useRef<HTMLDivElement>(null)
+ const [scrolled, setScrolled] = useState(false)
+ useEffect(() => {
+ const targetElement = scrollRef.current
+ const scrollHandle = (e: Event) => {
+ const userScrolled = (e.target as HTMLDivElement).scrollTop > 0
+ setScrolled(userScrolled)
+ }
+ targetElement?.addEventListener('scroll', scrollHandle)
+ return () => {
+ targetElement?.removeEventListener('scroll', scrollHandle)
+ }
+ }, [])
+
+ const activeItem = [...menuItems[0].items, ...menuItems[1].items].find(item => item.key === activeMenu)
+
+ const [searchValue, setSearchValue] = useState<string>('')
+
+ return (
+ <MenuDialog
+ show
+ onClose={onCancel}
+ >
+ <div className='mx-auto flex h-[100vh] max-w-[1048px]'>
+ <div className='flex w-[44px] flex-col border-r border-divider-burn pl-4 pr-6 sm:w-[224px]'>
+ <div className='title-2xl-semi-bold mb-8 mt-6 px-3 py-2 text-text-primary'>{t('common.userProfile.settings')}</div>
+ <div className='w-full'>
+ {
+ menuItems.map(menuItem => (
+ <div key={menuItem.key} className='mb-2'>
+ {!isCurrentWorkspaceDatasetOperator && (
+ <div className='system-xs-medium-uppercase mb-0.5 py-2 pb-1 pl-3 text-text-tertiary'>{menuItem.name}</div>
+ )}
+ <div>
+ {
+ menuItem.items.map(item => (
+ <div
+ key={item.key}
+ className={cn(
+ 'mb-0.5 flex h-[37px] cursor-pointer items-center rounded-lg p-1 pl-3 text-sm',
+ activeMenu === item.key ? 'system-sm-semibold bg-state-base-active text-components-menu-item-text-active' : 'system-sm-medium text-components-menu-item-text')}
+ title={item.name}
+ onClick={() => setActiveMenu(item.key)}
+ >
+ {activeMenu === item.key ? item.activeIcon : item.icon}
+ {!isMobile && <div className='truncate'>{item.name}</div>}
+ </div>
+ ))
+ }
+ </div>
+ </div>
+ ))
+ }
+ </div>
+ </div>
+ <div className='relative flex w-[824px]'>
+ <div className='absolute -right-11 top-6 z-[9999] flex flex-col items-center'>
+ <Button
+ variant='tertiary'
+ size='large'
+ className='px-2'
+ onClick={onCancel}
+ >
+ <RiCloseLine className='h-5 w-5' />
+ </Button>
+ <div className='system-2xs-medium-uppercase mt-1 text-text-tertiary'>ESC</div>
+ </div>
+ <div ref={scrollRef} className='w-full overflow-y-auto bg-components-panel-bg pb-4'>
+ <div className={cn('sticky top-0 z-20 mx-8 mb-[18px] flex items-center bg-components-panel-bg pb-2 pt-[27px]', scrolled && 'border-b border-divider-regular')}>
+ <div className='title-2xl-semi-bold shrink-0 text-text-primary'>
+ {activeItem?.name}
+ {activeItem?.description && (
+ <div className='system-sm-regular mt-1 text-text-tertiary'>{activeItem?.description}</div>
+ )}
+ </div>
+ {activeItem?.key === 'provider' && (
+ <div className='flex grow justify-end'>
+ <Input
+ showLeftIcon
+ wrapperClassName='!w-[200px]'
+ className='!h-8 !text-[13px]'
+ onChange={e => setSearchValue(e.target.value)}
+ value={searchValue}
+ />
+ </div>
+ )}
+ </div>
+ <div className='px-4 pt-2 sm:px-8'>
+ {activeMenu === 'provider' && <ModelProviderPage searchText={searchValue} />}
+ {activeMenu === 'members' && <MembersPage />}
+ {activeMenu === 'billing' && <BillingPage />}
+ {activeMenu === 'data-source' && <DataSourcePage />}
+ {activeMenu === 'api-based-extension' && <ApiBasedExtensionPage />}
+ {activeMenu === 'custom' && <CustomPage />}
+ {activeMenu === 'language' && <LanguagePage />}
+ </div>
+ </div>
+ </div>
+ </div>
+ </MenuDialog>
+ )
+}
diff --git a/app/components/header/account-setting/key-validator/KeyInput.tsx b/app/components/header/account-setting/key-validator/KeyInput.tsx
new file mode 100644
index 0000000..414f4f2
--- /dev/null
+++ b/app/components/header/account-setting/key-validator/KeyInput.tsx
@@ -0,0 +1,77 @@
+import type { ChangeEvent } from 'react'
+import {
+ ValidatedErrorIcon,
+ ValidatedErrorMessage,
+ ValidatedSuccessIcon,
+ ValidatingTip,
+} from './ValidateStatus'
+import { ValidatedStatus } from './declarations'
+import type { ValidatedStatusState } from './declarations'
+
+type KeyInputProps = {
+ value?: string
+ name: string
+ placeholder: string
+ className?: string
+ onChange: (v: string) => void
+ onFocus?: () => void
+ validating: boolean
+ validatedStatusState: ValidatedStatusState
+}
+
+const KeyInput = ({
+ value,
+ name,
+ placeholder,
+ className,
+ onChange,
+ onFocus,
+ validating,
+ validatedStatusState,
+}: KeyInputProps) => {
+ const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
+ const inputValue = e.target.value
+ onChange(inputValue)
+ }
+
+ const getValidatedIcon = () => {
+ if (validatedStatusState.status === ValidatedStatus.Error || validatedStatusState.status === ValidatedStatus.Exceed)
+ return <ValidatedErrorIcon />
+
+ if (validatedStatusState.status === ValidatedStatus.Success)
+ return <ValidatedSuccessIcon />
+ }
+ const getValidatedTip = () => {
+ if (validating)
+ return <ValidatingTip />
+
+ if (validatedStatusState.status === ValidatedStatus.Error)
+ return <ValidatedErrorMessage errorMessage={validatedStatusState.message ?? ''} />
+ }
+
+ return (
+ <div className={className}>
+ <div className="mb-2 text-[13px] font-medium text-gray-800">{name}</div>
+ <div className='
+ flex items-center rounded-lg bg-white px-3
+ shadow-xs
+ '>
+ <input
+ className='
+ mr-2 w-full appearance-none
+ bg-transparent py-[9px] text-xs font-medium
+ leading-[18px] text-gray-700 outline-none
+ '
+ value={value}
+ placeholder={placeholder}
+ onChange={handleChange}
+ onFocus={onFocus}
+ />
+ {getValidatedIcon()}
+ </div>
+ {getValidatedTip()}
+ </div>
+ )
+}
+
+export default KeyInput
diff --git a/app/components/header/account-setting/key-validator/Operate.tsx b/app/components/header/account-setting/key-validator/Operate.tsx
new file mode 100644
index 0000000..c3cfd1d
--- /dev/null
+++ b/app/components/header/account-setting/key-validator/Operate.tsx
@@ -0,0 +1,87 @@
+import { useTranslation } from 'react-i18next'
+import Indicator from '../../indicator'
+import type { Status } from './declarations'
+
+type OperateProps = {
+ isOpen: boolean
+ status: Status
+ disabled?: boolean
+ onCancel: () => void
+ onSave: () => void
+ onAdd: () => void
+ onEdit: () => void
+}
+
+const Operate = ({
+ isOpen,
+ status,
+ disabled,
+ onCancel,
+ onSave,
+ onAdd,
+ onEdit,
+}: OperateProps) => {
+ const { t } = useTranslation()
+
+ if (isOpen) {
+ return (
+ <div className='flex items-center'>
+ <div className='
+ mr-[5px] flex
+ h-7 cursor-pointer items-center rounded-md px-3
+ text-xs font-medium text-gray-700
+ ' onClick={onCancel} >
+ {t('common.operation.cancel')}
+ </div>
+ <div className='
+ flex h-7
+ cursor-pointer items-center rounded-md bg-primary-700 px-3
+ text-xs font-medium text-white
+ ' onClick={onSave}>
+ {t('common.operation.save')}
+ </div>
+ </div>
+ )
+ }
+
+ if (status === 'add') {
+ return (
+ <div className={
+ `flex h-[28px] cursor-pointer items-center rounded-md border border-gray-200
+ bg-white px-3 text-xs font-medium text-gray-700 ${disabled && 'cursor-default opacity-50'}}`
+ } onClick={() => !disabled && onAdd()}>
+ {t('common.provider.addKey')}
+ </div>
+ )
+ }
+
+ if (status === 'fail' || status === 'success') {
+ return (
+ <div className='flex items-center'>
+ {
+ status === 'fail' && (
+ <div className='mr-4 flex items-center'>
+ <div className='text-xs text-[#D92D20]'>{t('common.provider.invalidApiKey')}</div>
+ <Indicator color='red' className='ml-2' />
+ </div>
+ )
+ }
+ {
+ status === 'success' && (
+ <Indicator color='green' className='mr-4' />
+ )
+ }
+ <div className={
+ `flex h-[28px] cursor-pointer items-center rounded-md border border-gray-200
+ bg-white px-3 text-xs font-medium text-gray-700 ${disabled && 'cursor-default opacity-50'}}`
+ } onClick={() => !disabled && onEdit()}>
+ {t('common.provider.editKey')}
+ </div>
+ </div>
+ )
+ }
+
+ return null
+}
+
+export default Operate
diff --git a/app/components/header/account-setting/key-validator/ValidateStatus.tsx b/app/components/header/account-setting/key-validator/ValidateStatus.tsx
new file mode 100644
index 0000000..4abbb5c
--- /dev/null
+++ b/app/components/header/account-setting/key-validator/ValidateStatus.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from 'react-i18next'
+import {
+ RiErrorWarningFill,
+} from '@remixicon/react'
+import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/general'
+
+export const ValidatedErrorIcon = () => {
+ return <RiErrorWarningFill className='h-4 w-4 text-[#D92D20]' />
+}
+
+export const ValidatedSuccessIcon = () => {
+ return <CheckCircle className='h-4 w-4 text-[#039855]' />
+}
+
+export const ValidatingTip = () => {
+ const { t } = useTranslation()
+ return (
+ <div className={'mt-2 text-xs font-normal text-primary-600'}>
+ {t('common.provider.validating')}
+ </div>
+ )
+}
+
+export const ValidatedErrorMessage = ({ errorMessage }: { errorMessage: string }) => {
+ const { t } = useTranslation()
+
+ return (
+ <div className={'mt-2 text-xs font-normal text-[#D92D20]'}>
+ {t('common.provider.validatedError')}{errorMessage}
+ </div>
+ )
+}
diff --git a/app/components/header/account-setting/key-validator/declarations.ts b/app/components/header/account-setting/key-validator/declarations.ts
new file mode 100644
index 0000000..7e14fa1
--- /dev/null
+++ b/app/components/header/account-setting/key-validator/declarations.ts
@@ -0,0 +1,43 @@
+import type { Dispatch, SetStateAction } from 'react'
+
+export enum ValidatedStatus {
+ Success = 'success',
+ Error = 'error',
+ Exceed = 'exceed',
+}
+
+export type ValidatedStatusState = {
+ status?: ValidatedStatus
+ message?: string
+}
+
+export type Status = 'add' | 'fail' | 'success'
+
+export type ValidateValue = Record<string, any>
+
+export type ValidateCallback = {
+ before: (v?: ValidateValue) => boolean | undefined
+ run?: (v?: ValidateValue) => Promise<ValidatedStatusState>
+}
+
+export type Form = {
+ key: string
+ title: string
+ placeholder: string
+ value?: string
+ validate?: ValidateCallback
+ handleFocus?: (v: ValidateValue, dispatch: Dispatch<SetStateAction<ValidateValue>>) => void
+}
+
+export type KeyFrom = {
+ text: string
+ link: string
+}
+
+export type KeyValidatorProps = {
+ type: string
+ title: React.ReactNode
+ status: Status
+ forms: Form[]
+ keyFrom: KeyFrom
+}
diff --git a/app/components/header/account-setting/key-validator/hooks.ts b/app/components/header/account-setting/key-validator/hooks.ts
new file mode 100644
index 0000000..d03f85c
--- /dev/null
+++ b/app/components/header/account-setting/key-validator/hooks.ts
@@ -0,0 +1,31 @@
+import { useState } from 'react'
+import { useDebounceFn } from 'ahooks'
+import type { DebouncedFunc } from 'lodash-es'
+import { ValidatedStatus } from './declarations'
+import type { ValidateCallback, ValidateValue, ValidatedStatusState } from './declarations'
+
+export const useValidate: (value: ValidateValue) => [DebouncedFunc<(validateCallback: ValidateCallback) => Promise<void>>, boolean, ValidatedStatusState] = (value) => {
+ const [validating, setValidating] = useState(false)
+ const [validatedStatus, setValidatedStatus] = useState<ValidatedStatusState>({})
+
+ const { run } = useDebounceFn(async (validateCallback: ValidateCallback) => {
+ if (!validateCallback.before(value)) {
+ setValidating(false)
+ setValidatedStatus({})
+ return
+ }
+ setValidating(true)
+
+ if (validateCallback.run) {
+ const res = await validateCallback?.run(value)
+ setValidatedStatus(
+ res.status === 'success'
+ ? { status: ValidatedStatus.Success }
+ : { status: ValidatedStatus.Error, message: res.message })
+
+ setValidating(false)
+ }
+ }, { wait: 1000 })
+
+ return [run, validating, validatedStatus]
+}
diff --git a/app/components/header/account-setting/key-validator/index.tsx b/app/components/header/account-setting/key-validator/index.tsx
new file mode 100644
index 0000000..798477a
--- /dev/null
+++ b/app/components/header/account-setting/key-validator/index.tsx
@@ -0,0 +1,122 @@
+import { useState } from 'react'
+import Operate from './Operate'
+import KeyInput from './KeyInput'
+import { useValidate } from './hooks'
+import type { Form, KeyFrom, Status, ValidateValue } from './declarations'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
+
+export type KeyValidatorProps = {
+ type: string
+ title: React.ReactNode
+ status: Status
+ forms: Form[]
+ keyFrom: KeyFrom
+ onSave: (v: ValidateValue) => Promise<boolean | undefined>
+ disabled?: boolean
+}
+
+const KeyValidator = ({
+ type,
+ title,
+ status,
+ forms,
+ keyFrom,
+ onSave,
+ disabled,
+}: KeyValidatorProps) => {
+ const triggerKey = `plugins/${type}`
+ const { eventEmitter } = useEventEmitterContextContext()
+ const [isOpen, setIsOpen] = useState(false)
+ const prevValue = forms.reduce((prev: ValidateValue, next: Form) => {
+ prev[next.key] = next.value
+ return prev
+ }, {})
+ const [value, setValue] = useState(prevValue)
+ const [validate, validating, validatedStatusState] = useValidate(value)
+
+ eventEmitter?.useSubscription((v) => {
+ if (v !== triggerKey) {
+ setIsOpen(false)
+ setValue(prevValue)
+ validate({ before: () => false })
+ }
+ })
+
+ const handleCancel = () => {
+ eventEmitter?.emit('')
+ }
+
+ const handleSave = async () => {
+ if (await onSave(value))
+ eventEmitter?.emit('')
+ }
+
+ const handleAdd = () => {
+ setIsOpen(true)
+ eventEmitter?.emit(triggerKey)
+ }
+
+ const handleEdit = () => {
+ setIsOpen(true)
+ eventEmitter?.emit(triggerKey)
+ }
+
+ const handleChange = (form: Form, val: string) => {
+ setValue({ ...value, [form.key]: val })
+
+ if (form.validate)
+ validate(form.validate)
+ }
+
+ const handleFocus = (form: Form) => {
+ if (form.handleFocus)
+ form.handleFocus(value, setValue)
+ }
+
+ return (
+ <div className='mb-2 rounded-md border-[0.5px] border-gray-200 bg-gray-50'>
+ <div className={
+ `flex h-[52px] cursor-pointer items-center justify-between px-4 ${isOpen && 'border-b-[0.5px] border-b-gray-200'}`
+ }>
+ {title}
+ <Operate
+ isOpen={isOpen}
+ status={status}
+ onCancel={handleCancel}
+ onSave={handleSave}
+ onAdd={handleAdd}
+ onEdit={handleEdit}
+ disabled={disabled}
+ />
+ </div>
+ {
+ isOpen && !disabled && (
+ <div className='px-4 py-3'>
+ {
+ forms.map(form => (
+ <KeyInput
+ key={form.key}
+ className='mb-4'
+ name={form.title}
+ placeholder={form.placeholder}
+ value={value[form.key] as string || ''}
+ onChange={v => handleChange(form, v)}
+ onFocus={() => handleFocus(form)}
+ validating={validating}
+ validatedStatusState={validatedStatusState}
+ />
+ ))
+ }
+ <a className="flex cursor-pointer items-center text-xs text-primary-600" href={keyFrom.link} target='_blank' rel='noopener noreferrer'>
+ {keyFrom.text}
+ <LinkExternal02 className='ml-1 h-3 w-3 text-primary-600' />
+ </a>
+ </div>
+ )
+ }
+ </div>
+ )
+}
+
+export default KeyValidator
diff --git a/app/components/header/account-setting/language-page/index.module.css b/app/components/header/account-setting/language-page/index.module.css
new file mode 100644
index 0000000..7c2a883
--- /dev/null
+++ b/app/components/header/account-setting/language-page/index.module.css
@@ -0,0 +1,24 @@
+.google-icon {
+ background: url(../../assets/google.svg) center center no-repeat;
+ background-size: 16px 16px;
+}
+
+.github-icon {
+ background: url(../../assets/github.svg) center center no-repeat;
+ background-size: 16px 16px;
+}
+
+.twitter-icon {
+ background: url(../../assets/twitter.svg) center center no-repeat;
+ background-size: 16px 16px;
+}
+
+.bitbucket-icon {
+ background: url(../../assets/bitbucket.svg) center center no-repeat;
+ background-size: 16px 16px;
+}
+
+.salesforce-icon {
+ background: url(../../assets/salesforce.svg) center center no-repeat;
+ background-size: 24px auto;
+}
diff --git a/app/components/header/account-setting/language-page/index.tsx b/app/components/header/account-setting/language-page/index.tsx
new file mode 100644
index 0000000..7d3e09f
--- /dev/null
+++ b/app/components/header/account-setting/language-page/index.tsx
@@ -0,0 +1,86 @@
+'use client'
+
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useContext } from 'use-context-selector'
+import { useAppContext } from '@/context/app-context'
+import { SimpleSelect } from '@/app/components/base/select'
+import type { Item } from '@/app/components/base/select'
+import { updateUserProfile } from '@/service/common'
+import { ToastContext } from '@/app/components/base/toast'
+import I18n from '@/context/i18n'
+import { timezones } from '@/utils/timezone'
+import { languages } from '@/i18n/language'
+
+const titleClassName = `
+ mb-2 system-sm-semibold text-text-secondary
+`
+
+export default function LanguagePage() {
+ const { locale, setLocaleOnClient } = useContext(I18n)
+ const { userProfile, mutateUserProfile } = useAppContext()
+ const { notify } = useContext(ToastContext)
+ const [editing, setEditing] = useState(false)
+ const { t } = useTranslation()
+
+ const handleSelectLanguage = async (item: Item) => {
+ const url = '/account/interface-language'
+ const bodyKey = 'interface_language'
+
+ setEditing(true)
+ try {
+ await updateUserProfile({ url, body: { [bodyKey]: item.value } })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+
+ setLocaleOnClient(item.value.toString())
+ }
+ catch (e) {
+ notify({ type: 'error', message: (e as Error).message })
+ }
+ finally {
+ setEditing(false)
+ }
+ }
+
+ const handleSelectTimezone = async (item: Item) => {
+ const url = '/account/timezone'
+ const bodyKey = 'timezone'
+
+ setEditing(true)
+ try {
+ await updateUserProfile({ url, body: { [bodyKey]: item.value } })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+
+ mutateUserProfile()
+ }
+ catch (e) {
+ notify({ type: 'error', message: (e as Error).message })
+ }
+ finally {
+ setEditing(false)
+ }
+ }
+
+ return (
+ <>
+ <div className='mb-8'>
+ <div className={titleClassName}>{t('common.language.displayLanguage')}</div>
+ <SimpleSelect
+ defaultValue={locale || userProfile.interface_language}
+ items={languages.filter(item => item.supported)}
+ onSelect={item => handleSelectLanguage(item)}
+ disabled={editing}
+ />
+ </div>
+ <div className='mb-8'>
+ <div className={titleClassName}>{t('common.language.timezone')}</div>
+ <SimpleSelect
+ defaultValue={userProfile.timezone}
+ items={timezones}
+ onSelect={item => handleSelectTimezone(item)}
+ disabled={editing}
+ />
+ </div>
+ </>
+ )
+}
diff --git a/app/components/header/account-setting/members-page/edit-workspace-modal/index.module.css b/app/components/header/account-setting/members-page/edit-workspace-modal/index.module.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/components/header/account-setting/members-page/edit-workspace-modal/index.module.css
diff --git a/app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx b/app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx
new file mode 100644
index 0000000..2c11c36
--- /dev/null
+++ b/app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx
@@ -0,0 +1,90 @@
+'use client'
+import cn from '@/utils/classnames'
+import Modal from '@/app/components/base/modal'
+import Input from '@/app/components/base/input'
+import { WEB_PREFIX } from '@/config'
+import { useTranslation } from 'react-i18next'
+import { useState } from 'react'
+import { useContext } from 'use-context-selector'
+import s from './index.module.css'
+import Button from '@/app/components/base/button'
+import { RiCloseLine } from '@remixicon/react'
+import { useAppContext } from '@/context/app-context'
+import { updateWorkspaceInfo } from '@/service/common'
+import { ToastContext } from '@/app/components/base/toast'
+import { noop } from 'lodash-es'
+
+type IEditWorkspaceModalProps = {
+ onCancel: () => void
+}
+const EditWorkspaceModal = ({
+ onCancel,
+}: IEditWorkspaceModalProps) => {
+ const { t } = useTranslation()
+ const { notify } = useContext(ToastContext)
+ const { currentWorkspace, isCurrentWorkspaceOwner } = useAppContext()
+ const [name, setName] = useState<string>(currentWorkspace.name)
+
+ const changeWorkspaceInfo = async (name: string) => {
+ try {
+ await updateWorkspaceInfo({
+ url: '/workspaces/info',
+ body: {
+ name,
+ },
+ })
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ location.assign(WEB_PREFIX)
+ }
+ catch {
+ notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
+ }
+ }
+
+ return (
+ <div className={cn(s.wrap)}>
+ <Modal overflowVisible isShow onClose={noop} className={cn(s.modal)}>
+ <div className='mb-2 flex justify-between'>
+ <div className='text-xl font-semibold text-text-primary'>{t('common.account.editWorkspaceInfo')}</div>
+ <RiCloseLine className='h-4 w-4 cursor-pointer text-text-tertiary' onClick={onCancel} />
+ </div>
+ <div>
+ <div className='mb-2 text-sm font-medium text-text-primary'>{t('common.account.workspaceName')}</div>
+ <Input
+ className='mb-2'
+ value={name}
+ placeholder={t('common.account.workspaceNamePlaceholder')}
+ onChange={(e) => {
+ setName(e.target.value)
+ }}
+ onClear={() => {
+ setName(currentWorkspace.name)
+ }}
+ />
+
+ <div className='sticky bottom-0 -mx-2 mt-2 flex flex-wrap items-center justify-end gap-x-2 bg-components-panel-bg px-2 pt-4'>
+ <Button
+ size='large'
+ onClick={onCancel}
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ size='large'
+ variant='primary'
+ onClick={() => {
+ changeWorkspaceInfo(name)
+ onCancel()
+ }}
+ disabled={!isCurrentWorkspaceOwner}
+ >
+ {t('common.operation.confirm')}
+ </Button>
+ </div>
+
+ </div>
+ </Modal>
+ </div>
+ )
+}
+export default EditWorkspaceModal
diff --git a/app/components/header/account-setting/members-page/index.tsx b/app/components/header/account-setting/members-page/index.tsx
new file mode 100644
index 0000000..939834e
--- /dev/null
+++ b/app/components/header/account-setting/members-page/index.tsx
@@ -0,0 +1,178 @@
+'use client'
+import { useState } from 'react'
+import useSWR from 'swr'
+import dayjs from 'dayjs'
+import 'dayjs/locale/zh-cn'
+import relativeTime from 'dayjs/plugin/relativeTime'
+import { useContext } from 'use-context-selector'
+import { RiUserAddLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import InviteModal from './invite-modal'
+import InvitedModal from './invited-modal'
+import EditWorkspaceModal from './edit-workspace-modal'
+import Operation from './operation'
+import { fetchMembers } from '@/service/common'
+import I18n from '@/context/i18n'
+import { useAppContext } from '@/context/app-context'
+import Avatar from '@/app/components/base/avatar'
+import type { InvitationResult } from '@/models/common'
+import { useProviderContext } from '@/context/provider-context'
+import { Plan } from '@/app/components/billing/type'
+import Button from '@/app/components/base/button'
+import UpgradeBtn from '@/app/components/billing/upgrade-btn'
+import { NUM_INFINITE } from '@/app/components/billing/config'
+import { LanguagesSupported } from '@/i18n/language'
+import cn from '@/utils/classnames'
+import Tooltip from '@/app/components/base/tooltip'
+import { RiPencilLine } from '@remixicon/react'
+dayjs.extend(relativeTime)
+
+const MembersPage = () => {
+ const { t } = useTranslation()
+ const RoleMap = {
+ owner: t('common.members.owner'),
+ admin: t('common.members.admin'),
+ editor: t('common.members.editor'),
+ dataset_operator: t('common.members.datasetOperator'),
+ normal: t('common.members.normal'),
+ }
+ const { locale } = useContext(I18n)
+
+ const { userProfile, currentWorkspace, isCurrentWorkspaceOwner, isCurrentWorkspaceManager, systemFeatures } = useAppContext()
+ const { data, mutate } = useSWR(
+ {
+ url: '/workspaces/current/members',
+ params: {},
+ },
+ fetchMembers,
+ )
+ const [inviteModalVisible, setInviteModalVisible] = useState(false)
+ const [invitationResults, setInvitationResults] = useState<InvitationResult[]>([])
+ const [invitedModalVisible, setInvitedModalVisible] = useState(false)
+ const accounts = data?.accounts || []
+ const { plan, enableBilling } = useProviderContext()
+ const isNotUnlimitedMemberPlan = enableBilling && plan.type !== Plan.team && plan.type !== Plan.enterprise
+ const isMemberFull = enableBilling && isNotUnlimitedMemberPlan && accounts.length >= plan.total.teamMembers
+ const [editWorkspaceModalVisible, setEditWorkspaceModalVisible] = useState(false)
+
+ return (
+ <>
+ <div className='flex flex-col'>
+ <div className='mb-4 flex items-center gap-3 rounded-xl border-l-[0.5px] border-t-[0.5px] border-divider-subtle bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1 p-3 pr-5'>
+ <div className='flex h-12 w-12 items-center justify-center rounded-xl bg-components-icon-bg-blue-solid text-[20px]'>
+ <span className='bg-gradient-to-r from-components-avatar-shape-fill-stop-0 to-components-avatar-shape-fill-stop-100 bg-clip-text font-semibold uppercase text-shadow-shadow-1 opacity-90'>{currentWorkspace?.name[0]?.toLocaleUpperCase()}</span>
+ </div>
+ <div className='grow'>
+ <div className='system-md-semibold flex items-center gap-1 text-text-secondary'>
+ <span>{currentWorkspace?.name}</span>
+ {isCurrentWorkspaceOwner && <span>
+ <Tooltip
+ popupContent={t('common.account.editWorkspaceInfo')}
+ needsDelay
+ >
+ <div
+ className='cursor-pointer rounded-md p-1 hover:bg-black/5'
+ onClick={() => {
+ setEditWorkspaceModalVisible(true)
+ }}
+ >
+ <RiPencilLine className='h-4 w-4 text-text-tertiary' />
+ </div>
+ </Tooltip>
+ </span>}
+ </div>
+ <div className='system-xs-medium mt-1 text-text-tertiary'>
+ {enableBilling && isNotUnlimitedMemberPlan
+ ? (
+ <div className='flex space-x-1'>
+ <div>{t('billing.plansCommon.member')}{locale !== LanguagesSupported[1] && accounts.length > 1 && 's'}</div>
+ <div className=''>{accounts.length}</div>
+ <div>/</div>
+ <div>{plan.total.teamMembers === NUM_INFINITE ? t('billing.plansCommon.unlimited') : plan.total.teamMembers}</div>
+ </div>
+ )
+ : (
+ <div className='flex space-x-1'>
+ <div>{accounts.length}</div>
+ <div>{t('billing.plansCommon.memberAfter')}{locale !== LanguagesSupported[1] && accounts.length > 1 && 's'}</div>
+ </div>
+ )}
+ </div>
+
+ </div>
+ {isMemberFull && (
+ <UpgradeBtn className='mr-2' loc='member-invite' />
+ )}
+ <Button variant='primary' className={cn('shrink-0')} disabled={!isCurrentWorkspaceManager || isMemberFull} onClick={() => setInviteModalVisible(true)}>
+ <RiUserAddLine className='mr-1 h-4 w-4' />
+ {t('common.members.invite')}
+ </Button>
+ </div>
+ <div className='overflow-visible lg:overflow-visible'>
+ <div className='flex min-w-[480px] items-center border-b border-divider-regular py-[7px]'>
+ <div className='system-xs-medium-uppercase grow px-3 text-text-tertiary'>{t('common.members.name')}</div>
+ <div className='system-xs-medium-uppercase w-[104px] shrink-0 text-text-tertiary'>{t('common.members.lastActive')}</div>
+ <div className='system-xs-medium-uppercase w-[96px] shrink-0 px-3 text-text-tertiary'>{t('common.members.role')}</div>
+ </div>
+ <div className='relative min-w-[480px]'>
+ {
+ accounts.map(account => (
+ <div key={account.id} className='flex border-b border-divider-subtle'>
+ <div className='flex grow items-center px-3 py-2'>
+ <Avatar avatar={account.avatar_url} size={24} className='mr-2' name={account.name} />
+ <div className=''>
+ <div className='system-sm-medium text-text-secondary'>
+ {account.name}
+ {account.status === 'pending' && <span className='system-xs-medium ml-1 text-text-warning'>{t('common.members.pending')}</span>}
+ {userProfile.email === account.email && <span className='system-xs-regular text-text-tertiary'>{t('common.members.you')}</span>}
+ </div>
+ <div className='system-xs-regular text-text-tertiary'>{account.email}</div>
+ </div>
+ </div>
+ <div className='system-sm-regular flex w-[104px] shrink-0 items-center py-2 text-text-secondary'>{dayjs(Number((account.last_active_at || account.created_at)) * 1000).locale(locale === 'zh-Hans' ? 'zh-cn' : 'en').fromNow()}</div>
+ <div className='flex w-[96px] shrink-0 items-center'>
+ {
+ isCurrentWorkspaceOwner && account.role !== 'owner'
+ ? <Operation member={account} operatorRole={currentWorkspace.role} onOperate={mutate} />
+ : <div className='system-sm-regular px-3 text-text-secondary'>{RoleMap[account.role] || RoleMap.normal}</div>
+ }
+ </div>
+ </div>
+ ))
+ }
+ </div>
+ </div>
+ </div>
+ {
+ inviteModalVisible && (
+ <InviteModal
+ isEmailSetup={systemFeatures.is_email_setup}
+ onCancel={() => setInviteModalVisible(false)}
+ onSend={(invitationResults) => {
+ setInvitedModalVisible(true)
+ setInvitationResults(invitationResults)
+ mutate()
+ }}
+ />
+ )
+ }
+ {
+ invitedModalVisible && (
+ <InvitedModal
+ invitationResults={invitationResults}
+ onCancel={() => setInvitedModalVisible(false)}
+ />
+ )
+ }
+ {
+ editWorkspaceModalVisible && (
+ <EditWorkspaceModal
+ onCancel={() => setEditWorkspaceModalVisible(false)}
+ />
+ )
+ }
+ </>
+ )
+}
+
+export default MembersPage
diff --git a/app/components/header/account-setting/members-page/invite-modal/index.module.css b/app/components/header/account-setting/members-page/invite-modal/index.module.css
new file mode 100644
index 0000000..fbaa118
--- /dev/null
+++ b/app/components/header/account-setting/members-page/invite-modal/index.module.css
@@ -0,0 +1,12 @@
+.modal {
+ padding: 24px 32px !important;
+ width: 400px !important;
+}
+
+.emailsInput {
+ background-color: rgb(243 244 246 / var(--tw-bg-opacity)) !important;
+}
+
+.emailBackground {
+ background-color: white !important;
+}
diff --git a/app/components/header/account-setting/members-page/invite-modal/index.tsx b/app/components/header/account-setting/members-page/invite-modal/index.tsx
new file mode 100644
index 0000000..107166b
--- /dev/null
+++ b/app/components/header/account-setting/members-page/invite-modal/index.tsx
@@ -0,0 +1,123 @@
+'use client'
+import { useCallback, useState } from 'react'
+import { useContext } from 'use-context-selector'
+import { RiCloseLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { ReactMultiEmail } from 'react-multi-email'
+import { RiErrorWarningFill } from '@remixicon/react'
+import RoleSelector from './role-selector'
+import s from './index.module.css'
+import cn from '@/utils/classnames'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import { inviteMember } from '@/service/common'
+import { emailRegex } from '@/config'
+import { ToastContext } from '@/app/components/base/toast'
+import type { InvitationResult } from '@/models/common'
+import I18n from '@/context/i18n'
+import 'react-multi-email/dist/style.css'
+import { noop } from 'lodash-es'
+
+type IInviteModalProps = {
+ isEmailSetup: boolean
+ onCancel: () => void
+ onSend: (invitationResults: InvitationResult[]) => void
+}
+
+const InviteModal = ({
+ isEmailSetup,
+ onCancel,
+ onSend,
+}: IInviteModalProps) => {
+ const { t } = useTranslation()
+ const [emails, setEmails] = useState<string[]>([])
+ const { notify } = useContext(ToastContext)
+
+ const { locale } = useContext(I18n)
+ const [role, setRole] = useState<string>('normal')
+
+ const handleSend = useCallback(async () => {
+ if (emails.map((email: string) => emailRegex.test(email)).every(Boolean)) {
+ try {
+ const { result, invitation_results } = await inviteMember({
+ url: '/workspaces/current/members/invite-email',
+ body: { emails, role, language: locale },
+ })
+
+ if (result === 'success') {
+ onCancel()
+ onSend(invitation_results)
+ }
+ }
+ catch { }
+ }
+ else {
+ notify({ type: 'error', message: t('common.members.emailInvalid') })
+ }
+ }, [role, emails, notify, onCancel, onSend, t])
+
+ return (
+ <div className={cn(s.wrap)}>
+ <Modal overflowVisible isShow onClose={noop} className={cn(s.modal)}>
+ <div className='mb-2 flex justify-between'>
+ <div className='text-xl font-semibold text-text-primary'>{t('common.members.inviteTeamMember')}</div>
+ <RiCloseLine className='h-4 w-4 cursor-pointer text-text-tertiary' onClick={onCancel} />
+ </div>
+ <div className='mb-3 text-[13px] text-text-tertiary'>{t('common.members.inviteTeamMemberTip')}</div>
+ {!isEmailSetup && (
+ <div className='grow basis-0 overflow-y-auto pb-4'>
+ <div className='relative mb-1 rounded-xl border border-components-panel-border p-2 shadow-xs'>
+ <div className='absolute left-0 top-0 h-full w-full rounded-xl opacity-40' style={{ background: 'linear-gradient(92deg, rgba(255, 171, 0, 0.25) 18.12%, rgba(255, 255, 255, 0.00) 167.31%)' }}></div>
+ <div className='relative flex h-full w-full items-start'>
+ <div className='mr-0.5 shrink-0 p-0.5'>
+ <RiErrorWarningFill className='h-5 w-5 text-text-warning' />
+ </div>
+ <div className='system-xs-medium text-text-primary'>
+ <span>{t('common.members.emailNotSetup')}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ )}
+
+ <div>
+ <div className='mb-2 text-sm font-medium text-text-primary'>{t('common.members.email')}</div>
+ <div className='mb-8 flex h-36 items-stretch'>
+ <ReactMultiEmail
+ className={cn('w-full border-components-input-border-active !bg-components-input-bg-normal px-3 pt-2 outline-none',
+ 'appearance-none overflow-y-auto rounded-lg text-sm !text-text-primary',
+ )}
+ autoFocus
+ emails={emails}
+ inputClassName='bg-transparent'
+ onChange={setEmails}
+ getLabel={(email, index, removeEmail) =>
+ <div data-tag key={index} className={cn('bg-components-button-secondary-bg')}>
+ <div data-tag-item>{email}</div>
+ <span data-tag-handle onClick={() => removeEmail(index)}>
+ 脳
+ </span>
+ </div>
+ }
+ placeholder={t('common.members.emailPlaceholder') || ''}
+ />
+ </div>
+ <div className='mb-6'>
+ <RoleSelector value={role} onChange={setRole} />
+ </div>
+ <Button
+ tabIndex={0}
+ className='w-full'
+ onClick={handleSend}
+ disabled={!emails.length}
+ variant='primary'
+ >
+ {t('common.members.sendInvite')}
+ </Button>
+ </div>
+ </Modal>
+ </div>
+ )
+}
+
+export default InviteModal
diff --git a/app/components/header/account-setting/members-page/invite-modal/role-selector.tsx b/app/components/header/account-setting/members-page/invite-modal/role-selector.tsx
new file mode 100644
index 0000000..0a28d79
--- /dev/null
+++ b/app/components/header/account-setting/members-page/invite-modal/role-selector.tsx
@@ -0,0 +1,95 @@
+import { useTranslation } from 'react-i18next'
+import cn from 'classnames'
+import React, { useState } from 'react'
+import { RiArrowDownSLine } from '@remixicon/react'
+import { useProviderContext } from '@/context/provider-context'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { Check } from '@/app/components/base/icons/src/vender/line/general'
+
+export type RoleSelectorProps = {
+ value: string
+ onChange: (role: string) => void
+}
+
+const RoleSelector = ({ value, onChange }: RoleSelectorProps) => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const { datasetOperatorEnabled } = useProviderContext()
+
+ const toHump = (name: string) => name.replace(/_(\w)/g, (all, letter) => letter.toUpperCase())
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <div className='relative'>
+ <PortalToFollowElemTrigger
+ onClick={() => setOpen(v => !v)}
+ className='block'
+ >
+ <div className={cn('flex cursor-pointer items-center rounded-lg bg-components-input-bg-normal px-3 py-2 hover:bg-state-base-hover', open && 'bg-state-base-hover')}>
+ <div className='mr-2 grow text-sm leading-5 text-text-primary'>{t('common.members.invitedAsRole', { role: t(`common.members.${toHump(value)}`) })}</div>
+ <RiArrowDownSLine className='h-4 w-4 shrink-0 text-text-secondary' />
+ </div>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[1002]'>
+ <div className='relative w-[336px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg'>
+ <div className='p-1'>
+ <div className='cursor-pointer rounded-lg p-2 hover:bg-state-base-hover' onClick={() => {
+ onChange('normal')
+ setOpen(false)
+ }}>
+ <div className='relative pl-5'>
+ <div className='text-sm leading-5 text-text-secondary'>{t('common.members.normal')}</div>
+ <div className='text-xs leading-[18px] text-text-tertiary'>{t('common.members.normalTip')}</div>
+ {value === 'normal' && <Check className='absolute left-0 top-0.5 h-4 w-4 text-text-accent'/>}
+ </div>
+ </div>
+ <div className='cursor-pointer rounded-lg p-2 hover:bg-state-base-hover' onClick={() => {
+ onChange('editor')
+ setOpen(false)
+ }}>
+ <div className='relative pl-5'>
+ <div className='text-sm leading-5 text-text-secondary'>{t('common.members.editor')}</div>
+ <div className='text-xs leading-[18px] text-text-tertiary'>{t('common.members.editorTip')}</div>
+ {value === 'editor' && <Check className='absolute left-0 top-0.5 h-4 w-4 text-text-accent'/>}
+ </div>
+ </div>
+ <div className='cursor-pointer rounded-lg p-2 hover:bg-state-base-hover' onClick={() => {
+ onChange('admin')
+ setOpen(false)
+ }}>
+ <div className='relative pl-5'>
+ <div className='text-sm leading-5 text-text-secondary'>{t('common.members.admin')}</div>
+ <div className='text-xs leading-[18px] text-text-tertiary'>{t('common.members.adminTip')}</div>
+ {value === 'admin' && <Check className='absolute left-0 top-0.5 h-4 w-4 text-text-accent'/>}
+ </div>
+ </div>
+ {datasetOperatorEnabled && (
+ <div className='cursor-pointer rounded-lg p-2 hover:bg-state-base-hover' onClick={() => {
+ onChange('dataset_operator')
+ setOpen(false)
+ }}>
+ <div className='relative pl-5'>
+ <div className='text-sm leading-5 text-text-secondary'>{t('common.members.datasetOperator')}</div>
+ <div className='text-xs leading-[18px] text-text-tertiary'>{t('common.members.datasetOperatorTip')}</div>
+ {value === 'dataset_operator' && <Check className='absolute left-0 top-0.5 h-4 w-4 text-text-accent'/>}
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </div>
+ </PortalToFollowElem>
+ )
+}
+
+export default RoleSelector
diff --git a/app/components/header/account-setting/members-page/invited-modal/assets/copied.svg b/app/components/header/account-setting/members-page/invited-modal/assets/copied.svg
new file mode 100644
index 0000000..de5f86c
--- /dev/null
+++ b/app/components/header/account-setting/members-page/invited-modal/assets/copied.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M10.6665 2.66683C11.2865 2.66683 11.5965 2.66683 11.8508 2.73498C12.541 2.91991 13.0801 3.45901 13.265 4.14919C13.3332 4.40352 13.3332 4.71352 13.3332 5.3335V11.4668C13.3332 12.5869 13.3332 13.147 13.1152 13.5748C12.9234 13.9511 12.6175 14.2571 12.2412 14.4488C11.8133 14.6668 11.2533 14.6668 10.1332 14.6668H5.8665C4.7464 14.6668 4.18635 14.6668 3.75852 14.4488C3.3822 14.2571 3.07624 13.9511 2.88449 13.5748C2.6665 13.147 2.6665 12.5869 2.6665 11.4668V5.3335C2.6665 4.71352 2.6665 4.40352 2.73465 4.14919C2.91959 3.45901 3.45868 2.91991 4.14887 2.73498C4.4032 2.66683 4.71319 2.66683 5.33317 2.66683M5.99984 10.0002L7.33317 11.3335L10.3332 8.3335M6.39984 4.00016H9.59984C9.9732 4.00016 10.1599 4.00016 10.3025 3.9275C10.4279 3.86359 10.5299 3.7616 10.5938 3.63616C10.6665 3.49355 10.6665 3.30686 10.6665 2.9335V2.40016C10.6665 2.02679 10.6665 1.84011 10.5938 1.6975C10.5299 1.57206 10.4279 1.47007 10.3025 1.40616C10.1599 1.3335 9.97321 1.3335 9.59984 1.3335H6.39984C6.02647 1.3335 5.83978 1.3335 5.69718 1.40616C5.57174 1.47007 5.46975 1.57206 5.40583 1.6975C5.33317 1.84011 5.33317 2.02679 5.33317 2.40016V2.9335C5.33317 3.30686 5.33317 3.49355 5.40583 3.63616C5.46975 3.7616 5.57174 3.86359 5.69718 3.9275C5.83978 4.00016 6.02647 4.00016 6.39984 4.00016Z" stroke="#1D2939" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/header/account-setting/members-page/invited-modal/assets/copy-hover.svg b/app/components/header/account-setting/members-page/invited-modal/assets/copy-hover.svg
new file mode 100644
index 0000000..ca8334a
--- /dev/null
+++ b/app/components/header/account-setting/members-page/invited-modal/assets/copy-hover.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M10.6665 2.66634H11.9998C12.3535 2.66634 12.6926 2.80682 12.9426 3.05687C13.1927 3.30691 13.3332 3.64605 13.3332 3.99967V13.333C13.3332 13.6866 13.1927 14.0258 12.9426 14.2758C12.6926 14.5259 12.3535 14.6663 11.9998 14.6663H3.99984C3.64622 14.6663 3.30708 14.5259 3.05703 14.2758C2.80698 14.0258 2.6665 13.6866 2.6665 13.333V3.99967C2.6665 3.64605 2.80698 3.30691 3.05703 3.05687C3.30708 2.80682 3.64622 2.66634 3.99984 2.66634H5.33317M5.99984 1.33301H9.99984C10.368 1.33301 10.6665 1.63148 10.6665 1.99967V3.33301C10.6665 3.7012 10.368 3.99967 9.99984 3.99967H5.99984C5.63165 3.99967 5.33317 3.7012 5.33317 3.33301V1.99967C5.33317 1.63148 5.63165 1.33301 5.99984 1.33301Z" stroke="#1D2939" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/header/account-setting/members-page/invited-modal/assets/copy.svg b/app/components/header/account-setting/members-page/invited-modal/assets/copy.svg
new file mode 100644
index 0000000..18d2b4e
--- /dev/null
+++ b/app/components/header/account-setting/members-page/invited-modal/assets/copy.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M10.6665 2.66634H11.9998C12.3535 2.66634 12.6926 2.80682 12.9426 3.05687C13.1927 3.30691 13.3332 3.64605 13.3332 3.99967V13.333C13.3332 13.6866 13.1927 14.0258 12.9426 14.2758C12.6926 14.5259 12.3535 14.6663 11.9998 14.6663H3.99984C3.64622 14.6663 3.30708 14.5259 3.05703 14.2758C2.80698 14.0258 2.6665 13.6866 2.6665 13.333V3.99967C2.6665 3.64605 2.80698 3.30691 3.05703 3.05687C3.30708 2.80682 3.64622 2.66634 3.99984 2.66634H5.33317M5.99984 1.33301H9.99984C10.368 1.33301 10.6665 1.63148 10.6665 1.99967V3.33301C10.6665 3.7012 10.368 3.99967 9.99984 3.99967H5.99984C5.63165 3.99967 5.33317 3.7012 5.33317 3.33301V1.99967C5.33317 1.63148 5.63165 1.33301 5.99984 1.33301Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/header/account-setting/members-page/invited-modal/index.module.css b/app/components/header/account-setting/members-page/invited-modal/index.module.css
new file mode 100644
index 0000000..9647043
--- /dev/null
+++ b/app/components/header/account-setting/members-page/invited-modal/index.module.css
@@ -0,0 +1,21 @@
+.modal {
+ padding: 32px !important;
+ width: 480px !important;
+ /* background: linear-gradient(180deg, rgba(3, 152, 85, 0.05) 0%, rgba(3, 152, 85, 0) 22.44%), #F9FAFB !important; */
+}
+
+.copyIcon {
+ background-image: url(./assets/copy.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.copyIcon:hover {
+ background-image: url(./assets/copy-hover.svg);
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.copyIcon.copied {
+ background-image: url(./assets/copied.svg);
+}
diff --git a/app/components/header/account-setting/members-page/invited-modal/index.tsx b/app/components/header/account-setting/members-page/invited-modal/index.tsx
new file mode 100644
index 0000000..2719708
--- /dev/null
+++ b/app/components/header/account-setting/members-page/invited-modal/index.tsx
@@ -0,0 +1,99 @@
+import { CheckCircleIcon } from '@heroicons/react/24/solid'
+import { XMarkIcon } from '@heroicons/react/24/outline'
+import { RiQuestionLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { useMemo } from 'react'
+import InvitationLink from './invitation-link'
+import s from './index.module.css'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import { IS_CE_EDITION } from '@/config'
+import type { InvitationResult } from '@/models/common'
+import Tooltip from '@/app/components/base/tooltip'
+import { noop } from 'lodash-es'
+
+export type SuccessInvitationResult = Extract<InvitationResult, { status: 'success' }>
+export type FailedInvitationResult = Extract<InvitationResult, { status: 'failed' }>
+
+type IInvitedModalProps = {
+ invitationResults: InvitationResult[]
+ onCancel: () => void
+}
+const InvitedModal = ({
+ invitationResults,
+ onCancel,
+}: IInvitedModalProps) => {
+ const { t } = useTranslation()
+
+ const successInvitationResults = useMemo<SuccessInvitationResult[]>(() => invitationResults?.filter(item => item.status === 'success') as SuccessInvitationResult[], [invitationResults])
+ const failedInvitationResults = useMemo<FailedInvitationResult[]>(() => invitationResults?.filter(item => item.status !== 'success') as FailedInvitationResult[], [invitationResults])
+
+ return (
+ <div className={s.wrap}>
+ <Modal isShow onClose={noop} className={s.modal}>
+ <div className='mb-3 flex justify-between'>
+ <div className='
+ flex h-12 w-12 items-center justify-center rounded-xl
+ border-[0.5px] border-components-panel-border bg-background-section-burn
+ shadow-xl
+ '>
+ <CheckCircleIcon className='h-[22px] w-[22px] text-[#039855]' />
+ </div>
+ <XMarkIcon className='h-4 w-4 cursor-pointer' onClick={onCancel} />
+ </div>
+ <div className='mb-1 text-xl font-semibold text-text-primary'>{t('common.members.invitationSent')}</div>
+ {!IS_CE_EDITION && (
+ <div className='mb-10 text-sm text-text-tertiary'>{t('common.members.invitationSentTip')}</div>
+ )}
+ {IS_CE_EDITION && (
+ <>
+ <div className='mb-5 text-sm text-text-tertiary'>{t('common.members.invitationSentTip')}</div>
+ <div className='mb-9 flex flex-col gap-2'>
+ {
+ !!successInvitationResults.length
+ && <>
+ <div className='font-Medium py-2 text-sm text-text-primary'>{t('common.members.invitationLink')}</div>
+ {successInvitationResults.map(item =>
+ <InvitationLink key={item.email} value={item} />)}
+ </>
+ }
+ {
+ !!failedInvitationResults.length
+ && <>
+ <div className='font-Medium py-2 text-sm text-text-primary'>{t('common.members.failedInvitationEmails')}</div>
+ <div className='flex flex-wrap justify-between gap-y-1'>
+ {
+ failedInvitationResults.map(item =>
+ <div key={item.email} className='flex justify-center rounded-md border border-red-300 bg-orange-50 px-1'>
+ <Tooltip
+ popupContent={item.message}
+ >
+ <div className='flex items-center justify-center gap-1 text-sm'>
+ {item.email}
+ <RiQuestionLine className='h-4 w-4 text-red-300' />
+ </div>
+ </Tooltip>
+ </div>,
+ )
+ }
+ </div>
+ </>
+ }
+ </div>
+ </>
+ )}
+ <div className='flex justify-end'>
+ <Button
+ className='w-[96px]'
+ onClick={onCancel}
+ variant='primary'
+ >
+ {t('common.members.ok')}
+ </Button>
+ </div>
+ </Modal>
+ </div>
+ )
+}
+
+export default InvitedModal
diff --git a/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx b/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx
new file mode 100644
index 0000000..2426f7b
--- /dev/null
+++ b/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx
@@ -0,0 +1,62 @@
+'use client'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
+import { t } from 'i18next'
+import copy from 'copy-to-clipboard'
+import s from './index.module.css'
+import type { SuccessInvitationResult } from '.'
+import Tooltip from '@/app/components/base/tooltip'
+import { randomString } from '@/utils'
+
+type IInvitationLinkProps = {
+ value: SuccessInvitationResult
+}
+
+const InvitationLink = ({
+ value,
+}: IInvitationLinkProps) => {
+ const [isCopied, setIsCopied] = useState(false)
+ const selector = useRef(`invite-link-${randomString(4)}`)
+
+ const copyHandle = useCallback(() => {
+ // No prefix is needed here because the backend has already processed it
+ copy(`${!value.url.startsWith('http') ? window.location.origin : ''}${value.url}`)
+ setIsCopied(true)
+ }, [value])
+
+ useEffect(() => {
+ if (isCopied) {
+ const timeout = setTimeout(() => {
+ setIsCopied(false)
+ }, 1000)
+
+ return () => {
+ clearTimeout(timeout)
+ }
+ }
+ }, [isCopied])
+
+ return (
+ <div className='flex items-center rounded-lg border border-components-input-border-active bg-components-input-bg-normal py-2 hover:bg-state-base-hover'>
+ <div className="flex h-5 grow items-center">
+ <div className='relative h-full grow text-[13px]'>
+ <Tooltip
+ popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
+ >
+ <div className='r-0 absolute left-0 top-0 w-full cursor-pointer truncate pl-2 pr-2' onClick={copyHandle}>{value.url}</div>
+ </Tooltip>
+ </div>
+ <div className="h-4 shrink-0 border bg-divider-regular" />
+ <Tooltip
+ popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
+ >
+ <div className="shrink-0 px-0.5">
+ <div className={`box-border flex h-[30px] w-[30px] cursor-pointer items-center justify-center rounded-lg hover:bg-state-base-hover ${s.copyIcon} ${isCopied ? s.copied : ''}`} onClick={copyHandle}>
+ </div>
+ </div>
+ </Tooltip>
+ </div>
+ </div>
+ )
+}
+
+export default InvitationLink
diff --git a/app/components/header/account-setting/members-page/operation/index.tsx b/app/components/header/account-setting/members-page/operation/index.tsx
new file mode 100644
index 0000000..46f842d
--- /dev/null
+++ b/app/components/header/account-setting/members-page/operation/index.tsx
@@ -0,0 +1,134 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { Fragment, useMemo } from 'react'
+import { useContext } from 'use-context-selector'
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import { CheckIcon, ChevronDownIcon } from '@heroicons/react/24/outline'
+import { useProviderContext } from '@/context/provider-context'
+import cn from '@/utils/classnames'
+import type { Member } from '@/models/common'
+import { deleteMemberOrCancelInvitation, updateMemberRole } from '@/service/common'
+import { ToastContext } from '@/app/components/base/toast'
+
+type IOperationProps = {
+ member: Member
+ operatorRole: string
+ onOperate: () => void
+}
+
+const Operation = ({
+ member,
+ operatorRole,
+ onOperate,
+}: IOperationProps) => {
+ const { t } = useTranslation()
+ const { datasetOperatorEnabled } = useProviderContext()
+ const RoleMap = {
+ owner: t('common.members.owner'),
+ admin: t('common.members.admin'),
+ editor: t('common.members.editor'),
+ normal: t('common.members.normal'),
+ dataset_operator: t('common.members.datasetOperator'),
+ }
+ const roleList = useMemo(() => {
+ if (operatorRole === 'owner') {
+ return [
+ ...['admin', 'editor', 'normal'],
+ ...(datasetOperatorEnabled ? ['dataset_operator'] : []),
+ ]
+ }
+ if (operatorRole === 'admin') {
+ return [
+ ...['editor', 'normal'],
+ ...(datasetOperatorEnabled ? ['dataset_operator'] : []),
+ ]
+ }
+ return []
+ }, [operatorRole, datasetOperatorEnabled])
+ const { notify } = useContext(ToastContext)
+ const toHump = (name: string) => name.replace(/_(\w)/g, (all, letter) => letter.toUpperCase())
+ const handleDeleteMemberOrCancelInvitation = async () => {
+ try {
+ await deleteMemberOrCancelInvitation({ url: `/workspaces/current/members/${member.id}` })
+ onOperate()
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ }
+ catch {
+
+ }
+ }
+ const handleUpdateMemberRole = async (role: string) => {
+ try {
+ await updateMemberRole({
+ url: `/workspaces/current/members/${member.id}/update-role`,
+ body: { role },
+ })
+ onOperate()
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ }
+ catch {
+
+ }
+ }
+
+ return (
+ <Menu as="div" className="relative h-full w-full">
+ {
+ ({ open }) => (
+ <>
+ <MenuButton className={cn('system-sm-regular group flex h-full w-full cursor-pointer items-center justify-between px-3 text-text-secondary hover:bg-state-base-hover', open && 'bg-state-base-hover')}>
+ {RoleMap[member.role] || RoleMap.normal}
+ <ChevronDownIcon className={cn('h-4 w-4 group-hover:block', open ? 'block' : 'hidden')} />
+ </MenuButton>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems
+ className={cn('absolute right-0 top-[52px] z-10 origin-top-right rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm')}
+ >
+ <div className="p-1">
+ {
+ roleList.map(role => (
+ <MenuItem key={role}>
+ <div className='flex cursor-pointer rounded-lg px-3 py-2 hover:bg-state-base-hover' onClick={() => handleUpdateMemberRole(role)}>
+ {
+ role === member.role
+ ? <CheckIcon className='mr-1 mt-[2px] h-4 w-4 text-text-accent' />
+ : <div className='mr-1 mt-[2px] h-4 w-4 text-text-accent' />
+ }
+ <div>
+ <div className='system-sm-semibold whitespace-nowrap text-text-secondary'>{t(`common.members.${toHump(role)}`)}</div>
+ <div className='system-xs-regular whitespace-nowrap text-text-tertiary'>{t(`common.members.${toHump(role)}Tip`)}</div>
+ </div>
+ </div>
+ </MenuItem>
+ ))
+ }
+ </div>
+ <MenuItem>
+ <div className='border-t border-divider-subtle p-1'>
+ <div className='flex cursor-pointer rounded-lg px-3 py-2 hover:bg-state-base-hover' onClick={handleDeleteMemberOrCancelInvitation}>
+ <div className='mr-1 mt-[2px] h-4 w-4 text-text-accent' />
+ <div>
+ <div className='system-sm-semibold whitespace-nowrap text-text-secondary'>{t('common.members.removeFromTeam')}</div>
+ <div className='system-xs-regular whitespace-nowrap text-text-tertiary'>{t('common.members.removeFromTeamTip')}</div>
+ </div>
+ </div>
+ </div>
+ </MenuItem>
+ </MenuItems>
+ </Transition>
+ </>
+ )
+ }
+ </Menu>
+ )
+}
+
+export default Operation
diff --git a/app/components/header/account-setting/menu-dialog.tsx b/app/components/header/account-setting/menu-dialog.tsx
new file mode 100644
index 0000000..ad3a1e7
--- /dev/null
+++ b/app/components/header/account-setting/menu-dialog.tsx
@@ -0,0 +1,60 @@
+import { Fragment, useCallback, useEffect } from 'react'
+import type { ReactNode } from 'react'
+import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react'
+import cn from '@/utils/classnames'
+import { noop } from 'lodash-es'
+
+type DialogProps = {
+ className?: string
+ children: ReactNode
+ show: boolean
+ onClose?: () => void
+}
+
+const MenuDialog = ({
+ className,
+ children,
+ show,
+ onClose,
+}: DialogProps) => {
+ const close = useCallback(() => onClose?.(), [onClose])
+
+ useEffect(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === 'Escape') {
+ event.preventDefault()
+ close()
+ }
+ }
+
+ document.addEventListener('keydown', handleKeyDown)
+ return () => {
+ document.removeEventListener('keydown', handleKeyDown)
+ }
+ }, [close])
+
+ return (
+ <Transition appear show={show} as={Fragment}>
+ <Dialog as="div" className="relative z-[60]" onClose={noop}>
+ <div className="fixed inset-0">
+ <div className="flex min-h-full flex-col items-center justify-center">
+ <TransitionChild>
+ <DialogPanel className={cn(
+ 'relative h-full w-full grow overflow-hidden bg-background-sidenav-bg p-0 text-left align-middle backdrop-blur-md transition-all',
+ 'duration-300 ease-in data-[closed]:scale-95 data-[closed]:opacity-0',
+ 'data-[enter]:scale-100 data-[enter]:opacity-100',
+ 'data-[enter]:scale-95 data-[leave]:opacity-0',
+ className,
+ )}>
+ <div className='absolute right-0 top-0 h-full w-1/2 bg-components-panel-bg' />
+ {children}
+ </DialogPanel>
+ </TransitionChild>
+ </div>
+ </div>
+ </Dialog>
+ </Transition >
+ )
+}
+
+export default MenuDialog
diff --git a/app/components/header/account-setting/model-provider-page/declarations.ts b/app/components/header/account-setting/model-provider-page/declarations.ts
new file mode 100644
index 0000000..12dd9b3
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/declarations.ts
@@ -0,0 +1,271 @@
+export type FormValue = Record<string, any>
+
+export type TypeWithI18N<T = string> = {
+ en_US: T
+ zh_Hans: T
+ [key: string]: T
+}
+
+export enum FormTypeEnum {
+ textInput = 'text-input',
+ textNumber = 'number-input',
+ secretInput = 'secret-input',
+ select = 'select',
+ radio = 'radio',
+ boolean = 'boolean',
+ files = 'files',
+ file = 'file',
+ modelSelector = 'model-selector',
+ toolSelector = 'tool-selector',
+ multiToolSelector = 'array[tools]',
+ appSelector = 'app-selector',
+}
+
+export type FormOption = {
+ label: TypeWithI18N
+ value: string
+ show_on: FormShowOnObject[]
+}
+
+export enum ModelTypeEnum {
+ textGeneration = 'llm',
+ textEmbedding = 'text-embedding',
+ rerank = 'rerank',
+ speech2text = 'speech2text',
+ moderation = 'moderation',
+ tts = 'tts',
+}
+
+export const MODEL_TYPE_TEXT = {
+ [ModelTypeEnum.textGeneration]: 'LLM',
+ [ModelTypeEnum.textEmbedding]: 'Text Embedding',
+ [ModelTypeEnum.rerank]: 'Rerank',
+ [ModelTypeEnum.speech2text]: 'Speech2text',
+ [ModelTypeEnum.moderation]: 'Moderation',
+ [ModelTypeEnum.tts]: 'TTS',
+}
+
+export enum ConfigurationMethodEnum {
+ predefinedModel = 'predefined-model',
+ customizableModel = 'customizable-model',
+ fetchFromRemote = 'fetch-from-remote',
+}
+
+export enum ModelFeatureEnum {
+ toolCall = 'tool-call',
+ multiToolCall = 'multi-tool-call',
+ agentThought = 'agent-thought',
+ streamToolCall = 'stream-tool-call',
+ vision = 'vision',
+ video = 'video',
+ document = 'document',
+ audio = 'audio',
+ StructuredOutput = 'structured-output',
+}
+
+export enum ModelFeatureTextEnum {
+ toolCall = 'Tool Call',
+ multiToolCall = 'Multi Tool Call',
+ agentThought = 'Agent Thought',
+ vision = 'Vision',
+ video = 'Video',
+ document = 'Document',
+ audio = 'Audio',
+}
+
+export enum ModelStatusEnum {
+ active = 'active',
+ noConfigure = 'no-configure',
+ quotaExceeded = 'quota-exceeded',
+ noPermission = 'no-permission',
+ disabled = 'disabled',
+}
+
+export const MODEL_STATUS_TEXT: { [k: string]: TypeWithI18N } = {
+ 'no-configure': {
+ en_US: 'No Configure',
+ zh_Hans: '鏈厤缃嚟鎹�',
+ },
+ 'quota-exceeded': {
+ en_US: 'Quota Exceeded',
+ zh_Hans: '棰濆害涓嶈冻',
+ },
+ 'no-permission': {
+ en_US: 'No Permission',
+ zh_Hans: '鏃犱娇鐢ㄦ潈闄�',
+ },
+}
+
+export enum CustomConfigurationStatusEnum {
+ active = 'active',
+ noConfigure = 'no-configure',
+}
+
+export type FormShowOnObject = {
+ variable: string
+ value: string
+}
+
+export type CredentialFormSchemaBase = {
+ variable: string
+ label: TypeWithI18N
+ type: FormTypeEnum
+ required: boolean
+ default?: string
+ tooltip?: TypeWithI18N
+ show_on: FormShowOnObject[]
+ url?: string
+ scope?: string
+}
+
+export type CredentialFormSchemaTextInput = CredentialFormSchemaBase & {
+ max_length?: number;
+ placeholder?: TypeWithI18N,
+ template?: {
+ enabled: boolean
+ },
+ auto_generate?: {
+ type: string
+ }
+}
+export type CredentialFormSchemaNumberInput = CredentialFormSchemaBase & { min?: number; max?: number; placeholder?: TypeWithI18N }
+export type CredentialFormSchemaSelect = CredentialFormSchemaBase & { options: FormOption[]; placeholder?: TypeWithI18N }
+export type CredentialFormSchemaRadio = CredentialFormSchemaBase & { options: FormOption[] }
+export type CredentialFormSchemaSecretInput = CredentialFormSchemaBase & { placeholder?: TypeWithI18N }
+export type CredentialFormSchema = CredentialFormSchemaTextInput | CredentialFormSchemaSelect | CredentialFormSchemaRadio | CredentialFormSchemaSecretInput
+
+export type ModelItem = {
+ model: string
+ label: TypeWithI18N
+ model_type: ModelTypeEnum
+ features?: ModelFeatureEnum[]
+ fetch_from: ConfigurationMethodEnum
+ status: ModelStatusEnum
+ model_properties: Record<string, string | number>
+ load_balancing_enabled: boolean
+ deprecated?: boolean
+}
+
+export enum PreferredProviderTypeEnum {
+ system = 'system',
+ custom = 'custom',
+}
+
+export enum CurrentSystemQuotaTypeEnum {
+ trial = 'trial',
+ free = 'free',
+ paid = 'paid',
+}
+
+export enum QuotaUnitEnum {
+ times = 'times',
+ tokens = 'tokens',
+ credits = 'credits',
+}
+
+export type QuotaConfiguration = {
+ quota_type: CurrentSystemQuotaTypeEnum
+ quota_unit: QuotaUnitEnum
+ quota_limit: number
+ quota_used: number
+ last_used: number
+ is_valid: boolean
+}
+
+export type ModelProvider = {
+ provider: string
+ label: TypeWithI18N
+ description?: TypeWithI18N
+ help: {
+ title: TypeWithI18N
+ url: TypeWithI18N
+ }
+ icon_small: TypeWithI18N
+ icon_large: TypeWithI18N
+ background?: string
+ supported_model_types: ModelTypeEnum[]
+ configurate_methods: ConfigurationMethodEnum[]
+ provider_credential_schema: {
+ credential_form_schemas: CredentialFormSchema[]
+ }
+ model_credential_schema: {
+ model: {
+ label: TypeWithI18N
+ placeholder: TypeWithI18N
+ }
+ credential_form_schemas: CredentialFormSchema[]
+ }
+ preferred_provider_type: PreferredProviderTypeEnum
+ custom_configuration: {
+ status: CustomConfigurationStatusEnum
+ }
+ system_configuration: {
+ enabled: boolean
+ current_quota_type: CurrentSystemQuotaTypeEnum
+ quota_configurations: QuotaConfiguration[]
+ }
+}
+
+export type Model = {
+ provider: string
+ icon_large: TypeWithI18N
+ icon_small: TypeWithI18N
+ label: TypeWithI18N
+ models: ModelItem[]
+ status: ModelStatusEnum
+}
+
+export type DefaultModelResponse = {
+ model: string
+ model_type: ModelTypeEnum
+ provider: {
+ provider: string
+ icon_large: TypeWithI18N
+ icon_small: TypeWithI18N
+ }
+}
+
+export type DefaultModel = {
+ provider: string
+ model: string
+}
+
+export type CustomConfigurationModelFixedFields = {
+ __model_name: string
+ __model_type: ModelTypeEnum
+}
+
+export type ModelParameterRule = {
+ default?: number | string | boolean | string[]
+ help?: TypeWithI18N
+ label: TypeWithI18N
+ min?: number
+ max?: number
+ name: string
+ precision?: number
+ required: false
+ type: string
+ use_template?: string
+ options?: string[]
+ tagPlaceholder?: TypeWithI18N
+}
+
+export type ModelLoadBalancingConfigEntry = {
+ /** model balancing config entry id */
+ id?: string
+ /** is config entry enabled */
+ enabled?: boolean
+ /** config entry name */
+ name: string
+ /** model balancing credential */
+ credentials: Record<string, string | undefined | boolean>
+ /** is config entry currently removed from Round-robin queue */
+ in_cooldown?: boolean
+ /** cooldown time (in seconds) */
+ ttl?: number
+}
+
+export type ModelLoadBalancingConfig = {
+ enabled: boolean
+ configs: ModelLoadBalancingConfigEntry[]
+}
diff --git a/app/components/header/account-setting/model-provider-page/hooks.spec.ts b/app/components/header/account-setting/model-provider-page/hooks.spec.ts
new file mode 100644
index 0000000..b7a56f7
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/hooks.spec.ts
@@ -0,0 +1,87 @@
+import { renderHook } from '@testing-library/react'
+import { useLanguage } from './hooks'
+import { useContext } from 'use-context-selector'
+import { after } from 'node:test'
+
+jest.mock('swr', () => ({
+ __esModule: true,
+ default: jest.fn(), // mock useSWR
+ useSWRConfig: jest.fn(),
+}))
+
+// mock use-context-selector
+jest.mock('use-context-selector', () => ({
+ useContext: jest.fn(),
+}))
+
+// mock service/common functions
+jest.mock('@/service/common', () => ({
+ fetchDefaultModal: jest.fn(),
+ fetchModelList: jest.fn(),
+ fetchModelProviderCredentials: jest.fn(),
+ fetchModelProviders: jest.fn(),
+ getPayUrl: jest.fn(),
+}))
+
+// mock context hooks
+jest.mock('@/context/i18n', () => ({
+ __esModule: true,
+ default: jest.fn(),
+}))
+
+jest.mock('@/context/provider-context', () => ({
+ useProviderContext: jest.fn(),
+}))
+
+jest.mock('@/context/modal-context', () => ({
+ useModalContextSelector: jest.fn(),
+}))
+
+jest.mock('@/context/event-emitter', () => ({
+ useEventEmitterContextContext: jest.fn(),
+}))
+
+// mock plugins
+jest.mock('@/app/components/plugins/marketplace/hooks', () => ({
+ useMarketplacePlugins: jest.fn(),
+}))
+
+jest.mock('@/app/components/plugins/marketplace/utils', () => ({
+ getMarketplacePluginsByCollectionId: jest.fn(),
+}))
+
+jest.mock('./provider-added-card', () => jest.fn())
+
+after(() => {
+ jest.resetModules()
+ jest.clearAllMocks()
+})
+
+describe('useLanguage', () => {
+ it('should replace hyphen with underscore in locale', () => {
+ (useContext as jest.Mock).mockReturnValue({
+ locale: 'en-US',
+ })
+ const { result } = renderHook(() => useLanguage())
+ expect(result.current).toBe('en_US')
+ })
+
+ it('should return locale as is if no hyphen exists', () => {
+ (useContext as jest.Mock).mockReturnValue({
+ locale: 'enUS',
+ })
+
+ const { result } = renderHook(() => useLanguage())
+ expect(result.current).toBe('enUS')
+ })
+
+ it('should handle multiple hyphens', () => {
+ // Mock the I18n context return value
+ (useContext as jest.Mock).mockReturnValue({
+ locale: 'zh-Hans-CN',
+ })
+
+ const { result } = renderHook(() => useLanguage())
+ expect(result.current).toBe('zh_Hans-CN')
+ })
+})
diff --git a/app/components/header/account-setting/model-provider-page/hooks.ts b/app/components/header/account-setting/model-provider-page/hooks.ts
new file mode 100644
index 0000000..48acaeb
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/hooks.ts
@@ -0,0 +1,353 @@
+import {
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react'
+import useSWR, { useSWRConfig } from 'swr'
+import { useContext } from 'use-context-selector'
+import type {
+ CustomConfigurationModelFixedFields,
+ DefaultModel,
+ DefaultModelResponse,
+ Model,
+ ModelProvider,
+ ModelTypeEnum,
+} from './declarations'
+import {
+ ConfigurationMethodEnum,
+ CustomConfigurationStatusEnum,
+ ModelStatusEnum,
+} from './declarations'
+import I18n from '@/context/i18n'
+import {
+ fetchDefaultModal,
+ fetchModelList,
+ fetchModelProviderCredentials,
+ fetchModelProviders,
+ getPayUrl,
+} from '@/service/common'
+import { useProviderContext } from '@/context/provider-context'
+import {
+ useMarketplacePlugins,
+} from '@/app/components/plugins/marketplace/hooks'
+import type { Plugin } from '@/app/components/plugins/types'
+import { PluginType } from '@/app/components/plugins/types'
+import { getMarketplacePluginsByCollectionId } from '@/app/components/plugins/marketplace/utils'
+import { useModalContextSelector } from '@/context/modal-context'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './provider-added-card'
+
+type UseDefaultModelAndModelList = (
+ defaultModel: DefaultModelResponse | undefined,
+ modelList: Model[],
+) => [DefaultModel | undefined, (model: DefaultModel) => void]
+export const useSystemDefaultModelAndModelList: UseDefaultModelAndModelList = (
+ defaultModel,
+ modelList,
+) => {
+ const currentDefaultModel = useMemo(() => {
+ const currentProvider = modelList.find(provider => provider.provider === defaultModel?.provider.provider)
+ const currentModel = currentProvider?.models.find(model => model.model === defaultModel?.model)
+ const currentDefaultModel = currentProvider && currentModel && {
+ model: currentModel.model,
+ provider: currentProvider.provider,
+ }
+
+ return currentDefaultModel
+ }, [defaultModel, modelList])
+ const [defaultModelState, setDefaultModelState] = useState<DefaultModel | undefined>(currentDefaultModel)
+ const handleDefaultModelChange = useCallback((model: DefaultModel) => {
+ setDefaultModelState(model)
+ }, [])
+ useEffect(() => {
+ setDefaultModelState(currentDefaultModel)
+ }, [currentDefaultModel])
+
+ return [defaultModelState, handleDefaultModelChange]
+}
+
+export const useLanguage = () => {
+ const { locale } = useContext(I18n)
+ return locale.replace('-', '_')
+}
+
+export const useProviderCredentialsAndLoadBalancing = (
+ provider: string,
+ configurationMethod: ConfigurationMethodEnum,
+ configured?: boolean,
+ currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
+) => {
+ const { data: predefinedFormSchemasValue, mutate: mutatePredefined } = useSWR(
+ (configurationMethod === ConfigurationMethodEnum.predefinedModel && configured)
+ ? `/workspaces/current/model-providers/${provider}/credentials`
+ : null,
+ fetchModelProviderCredentials,
+ )
+ const { data: customFormSchemasValue, mutate: mutateCustomized } = useSWR(
+ (configurationMethod === ConfigurationMethodEnum.customizableModel && currentCustomConfigurationModelFixedFields)
+ ? `/workspaces/current/model-providers/${provider}/models/credentials?model=${currentCustomConfigurationModelFixedFields?.__model_name}&model_type=${currentCustomConfigurationModelFixedFields?.__model_type}`
+ : null,
+ fetchModelProviderCredentials,
+ )
+
+ const credentials = useMemo(() => {
+ return configurationMethod === ConfigurationMethodEnum.predefinedModel
+ ? predefinedFormSchemasValue?.credentials
+ : customFormSchemasValue?.credentials
+ ? {
+ ...customFormSchemasValue?.credentials,
+ ...currentCustomConfigurationModelFixedFields,
+ }
+ : undefined
+ }, [
+ configurationMethod,
+ currentCustomConfigurationModelFixedFields,
+ customFormSchemasValue?.credentials,
+ predefinedFormSchemasValue?.credentials,
+ ])
+
+ const mutate = useMemo(() => () => {
+ mutatePredefined()
+ mutateCustomized()
+ }, [mutateCustomized, mutatePredefined])
+
+ return {
+ credentials,
+ loadBalancing: (configurationMethod === ConfigurationMethodEnum.predefinedModel
+ ? predefinedFormSchemasValue
+ : customFormSchemasValue
+ )?.load_balancing,
+ mutate,
+ }
+ // as ([Record<string, string | boolean | undefined> | undefined, ModelLoadBalancingConfig | undefined])
+}
+
+export const useModelList = (type: ModelTypeEnum) => {
+ const { data, mutate, isLoading } = useSWR(`/workspaces/current/models/model-types/${type}`, fetchModelList)
+
+ return {
+ data: data?.data || [],
+ mutate,
+ isLoading,
+ }
+}
+
+export const useDefaultModel = (type: ModelTypeEnum) => {
+ const { data, mutate, isLoading } = useSWR(`/workspaces/current/default-model?model_type=${type}`, fetchDefaultModal)
+
+ return {
+ data: data?.data,
+ mutate,
+ isLoading,
+ }
+}
+
+export const useCurrentProviderAndModel = (modelList: Model[], defaultModel?: DefaultModel) => {
+ const currentProvider = modelList.find(provider => provider.provider === defaultModel?.provider)
+ const currentModel = currentProvider?.models.find(model => model.model === defaultModel?.model)
+
+ return {
+ currentProvider,
+ currentModel,
+ }
+}
+
+export const useTextGenerationCurrentProviderAndModelAndModelList = (defaultModel?: DefaultModel) => {
+ const { textGenerationModelList } = useProviderContext()
+ const activeTextGenerationModelList = textGenerationModelList.filter(model => model.status === ModelStatusEnum.active)
+ const {
+ currentProvider,
+ currentModel,
+ } = useCurrentProviderAndModel(textGenerationModelList, defaultModel)
+
+ return {
+ currentProvider,
+ currentModel,
+ textGenerationModelList,
+ activeTextGenerationModelList,
+ }
+}
+
+export const useModelListAndDefaultModel = (type: ModelTypeEnum) => {
+ const { data: modelList } = useModelList(type)
+ const { data: defaultModel } = useDefaultModel(type)
+
+ return {
+ modelList,
+ defaultModel,
+ }
+}
+
+export const useModelListAndDefaultModelAndCurrentProviderAndModel = (type: ModelTypeEnum) => {
+ const { modelList, defaultModel } = useModelListAndDefaultModel(type)
+ const { currentProvider, currentModel } = useCurrentProviderAndModel(
+ modelList,
+ { provider: defaultModel?.provider.provider || '', model: defaultModel?.model || '' },
+ )
+
+ return {
+ modelList,
+ defaultModel,
+ currentProvider,
+ currentModel,
+ }
+}
+
+export const useUpdateModelList = () => {
+ const { mutate } = useSWRConfig()
+
+ const updateModelList = useCallback((type: ModelTypeEnum) => {
+ mutate(`/workspaces/current/models/model-types/${type}`)
+ }, [mutate])
+
+ return updateModelList
+}
+
+export const useAnthropicBuyQuota = () => {
+ const [loading, setLoading] = useState(false)
+
+ const handleGetPayUrl = async () => {
+ if (loading)
+ return
+
+ setLoading(true)
+ try {
+ const res = await getPayUrl('/workspaces/current/model-providers/anthropic/checkout-url')
+
+ window.location.href = res.url
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ return handleGetPayUrl
+}
+
+export const useModelProviders = () => {
+ const { data: providersData, mutate, isLoading } = useSWR('/workspaces/current/model-providers', fetchModelProviders)
+
+ return {
+ data: providersData?.data || [],
+ mutate,
+ isLoading,
+ }
+}
+
+export const useUpdateModelProviders = () => {
+ const { mutate } = useSWRConfig()
+
+ const updateModelProviders = useCallback(() => {
+ mutate('/workspaces/current/model-providers')
+ }, [mutate])
+
+ return updateModelProviders
+}
+
+export const useMarketplaceAllPlugins = (providers: ModelProvider[], searchText: string) => {
+ const exclude = useMemo(() => {
+ return providers.map(provider => provider.provider.replace(/(.+)\/([^/]+)$/, '$1'))
+ }, [providers])
+ const [collectionPlugins, setCollectionPlugins] = useState<Plugin[]>([])
+
+ const {
+ plugins,
+ queryPlugins,
+ queryPluginsWithDebounced,
+ isLoading,
+ } = useMarketplacePlugins()
+
+ const getCollectionPlugins = useCallback(async () => {
+ const collectionPlugins = await getMarketplacePluginsByCollectionId('__model-settings-pinned-models')
+
+ setCollectionPlugins(collectionPlugins)
+ }, [])
+
+ useEffect(() => {
+ getCollectionPlugins()
+ }, [getCollectionPlugins])
+
+ useEffect(() => {
+ if (searchText) {
+ queryPluginsWithDebounced({
+ query: searchText,
+ category: PluginType.model,
+ exclude,
+ type: 'plugin',
+ sortBy: 'install_count',
+ sortOrder: 'DESC',
+ })
+ }
+ else {
+ queryPlugins({
+ query: '',
+ category: PluginType.model,
+ type: 'plugin',
+ pageSize: 1000,
+ exclude,
+ sortBy: 'install_count',
+ sortOrder: 'DESC',
+ })
+ }
+ }, [queryPlugins, queryPluginsWithDebounced, searchText, exclude])
+
+ const allPlugins = useMemo(() => {
+ const allPlugins = [...collectionPlugins.filter(plugin => !exclude.includes(plugin.plugin_id))]
+
+ if (plugins?.length) {
+ for (let i = 0; i < plugins.length; i++) {
+ const plugin = plugins[i]
+
+ if (plugin.type !== 'bundle' && !allPlugins.find(p => p.plugin_id === plugin.plugin_id))
+ allPlugins.push(plugin)
+ }
+ }
+
+ return allPlugins
+ }, [plugins, collectionPlugins, exclude])
+
+ return {
+ plugins: allPlugins,
+ isLoading,
+ }
+}
+
+export const useModelModalHandler = () => {
+ const setShowModelModal = useModalContextSelector(state => state.setShowModelModal)
+ const updateModelProviders = useUpdateModelProviders()
+ const updateModelList = useUpdateModelList()
+ const { eventEmitter } = useEventEmitterContextContext()
+
+ return (
+ provider: ModelProvider,
+ configurationMethod: ConfigurationMethodEnum,
+ CustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
+ ) => {
+ setShowModelModal({
+ payload: {
+ currentProvider: provider,
+ currentConfigurationMethod: configurationMethod,
+ currentCustomConfigurationModelFixedFields: CustomConfigurationModelFixedFields,
+ },
+ onSaveCallback: () => {
+ updateModelProviders()
+
+ provider.supported_model_types.forEach((type) => {
+ updateModelList(type)
+ })
+
+ if (configurationMethod === ConfigurationMethodEnum.customizableModel
+ && provider.custom_configuration.status === CustomConfigurationStatusEnum.active) {
+ eventEmitter?.emit({
+ type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST,
+ payload: provider.provider,
+ } as any)
+
+ if (CustomConfigurationModelFixedFields?.__model_type)
+ updateModelList(CustomConfigurationModelFixedFields.__model_type)
+ }
+ },
+ })
+ }
+}
diff --git a/app/components/header/account-setting/model-provider-page/index.tsx b/app/components/header/account-setting/model-provider-page/index.tsx
new file mode 100644
index 0000000..7c4e2ea
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/index.tsx
@@ -0,0 +1,161 @@
+import { useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useDebounce } from 'ahooks'
+import {
+ RiAlertFill,
+ RiBrainLine,
+} from '@remixicon/react'
+import SystemModelSelector from './system-model-selector'
+import ProviderAddedCard from './provider-added-card'
+import type {
+ ConfigurationMethodEnum,
+ CustomConfigurationModelFixedFields,
+ ModelProvider,
+} from './declarations'
+import {
+ CustomConfigurationStatusEnum,
+ ModelTypeEnum,
+} from './declarations'
+import {
+ useDefaultModel,
+ useModelModalHandler,
+} from './hooks'
+import InstallFromMarketplace from './install-from-marketplace'
+import { useProviderContext } from '@/context/provider-context'
+import cn from '@/utils/classnames'
+import { useSelector as useAppContextSelector } from '@/context/app-context'
+
+type Props = {
+ searchText: string
+}
+
+const FixedModelProvider = ['langgenius/openai/openai', 'langgenius/anthropic/anthropic']
+
+const ModelProviderPage = ({ searchText }: Props) => {
+ const debouncedSearchText = useDebounce(searchText, { wait: 500 })
+ const { t } = useTranslation()
+ const { data: textGenerationDefaultModel } = useDefaultModel(ModelTypeEnum.textGeneration)
+ const { data: embeddingsDefaultModel } = useDefaultModel(ModelTypeEnum.textEmbedding)
+ const { data: rerankDefaultModel } = useDefaultModel(ModelTypeEnum.rerank)
+ const { data: speech2textDefaultModel } = useDefaultModel(ModelTypeEnum.speech2text)
+ const { data: ttsDefaultModel } = useDefaultModel(ModelTypeEnum.tts)
+ const { modelProviders: providers } = useProviderContext()
+ const { enable_marketplace } = useAppContextSelector(s => s.systemFeatures)
+ const defaultModelNotConfigured = !textGenerationDefaultModel && !embeddingsDefaultModel && !speech2textDefaultModel && !rerankDefaultModel && !ttsDefaultModel
+ const [configuredProviders, notConfiguredProviders] = useMemo(() => {
+ const configuredProviders: ModelProvider[] = []
+ const notConfiguredProviders: ModelProvider[] = []
+
+ providers.forEach((provider) => {
+ if (
+ provider.custom_configuration.status === CustomConfigurationStatusEnum.active
+ || (
+ provider.system_configuration.enabled === true
+ && provider.system_configuration.quota_configurations.find(item => item.quota_type === provider.system_configuration.current_quota_type)
+ )
+ )
+ configuredProviders.push(provider)
+ else
+ notConfiguredProviders.push(provider)
+ })
+
+ configuredProviders.sort((a, b) => {
+ if (FixedModelProvider.includes(a.provider) && FixedModelProvider.includes(b.provider))
+ return FixedModelProvider.indexOf(a.provider) - FixedModelProvider.indexOf(b.provider) > 0 ? 1 : -1
+ else if (FixedModelProvider.includes(a.provider))
+ return -1
+ else if (FixedModelProvider.includes(b.provider))
+ return 1
+ return 0
+ })
+
+ return [configuredProviders, notConfiguredProviders]
+ }, [providers])
+ const [filteredConfiguredProviders, filteredNotConfiguredProviders] = useMemo(() => {
+ const filteredConfiguredProviders = configuredProviders.filter(
+ provider => provider.provider.toLowerCase().includes(debouncedSearchText.toLowerCase())
+ || Object.values(provider.label).some(text => text.toLowerCase().includes(debouncedSearchText.toLowerCase())),
+ )
+ const filteredNotConfiguredProviders = notConfiguredProviders.filter(
+ provider => provider.provider.toLowerCase().includes(debouncedSearchText.toLowerCase())
+ || Object.values(provider.label).some(text => text.toLowerCase().includes(debouncedSearchText.toLowerCase())),
+ )
+
+ return [filteredConfiguredProviders, filteredNotConfiguredProviders]
+ }, [configuredProviders, debouncedSearchText, notConfiguredProviders])
+
+ const handleOpenModal = useModelModalHandler()
+
+ return (
+ <div className='relative -mt-2 pt-1'>
+ <div className={cn('mb-2 flex items-center')}>
+ <div className='system-md-semibold grow text-text-primary'>{t('common.modelProvider.models')}</div>
+ <div className={cn(
+ 'relative flex shrink-0 items-center justify-end gap-2 rounded-lg border border-transparent p-px',
+ defaultModelNotConfigured && 'border-components-panel-border bg-components-panel-bg-blur pl-2 shadow-xs',
+ )}>
+ {defaultModelNotConfigured && <div className='absolute bottom-0 left-0 right-0 top-0 opacity-40' style={{ background: 'linear-gradient(92deg, rgba(247, 144, 9, 0.25) 0%, rgba(255, 255, 255, 0.00) 100%)' }} />}
+ {defaultModelNotConfigured && (
+ <div className='system-xs-medium flex items-center gap-1 text-text-primary'>
+ <RiAlertFill className='h-4 w-4 text-text-warning-secondary' />
+ {t('common.modelProvider.notConfigured')}
+ </div>
+ )}
+ <SystemModelSelector
+ notConfigured={defaultModelNotConfigured}
+ textGenerationDefaultModel={textGenerationDefaultModel}
+ embeddingsDefaultModel={embeddingsDefaultModel}
+ rerankDefaultModel={rerankDefaultModel}
+ speech2textDefaultModel={speech2textDefaultModel}
+ ttsDefaultModel={ttsDefaultModel}
+ />
+ </div>
+ </div>
+ {!filteredConfiguredProviders?.length && (
+ <div className='mb-2 rounded-[10px] bg-workflow-process-bg p-4'>
+ <div className='flex h-10 w-10 items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg backdrop-blur'>
+ <RiBrainLine className='h-5 w-5 text-text-primary' />
+ </div>
+ <div className='system-sm-medium mt-2 text-text-secondary'>{t('common.modelProvider.emptyProviderTitle')}</div>
+ <div className='system-xs-regular mt-1 text-text-tertiary'>{t('common.modelProvider.emptyProviderTip')}</div>
+ </div>
+ )}
+ {!!filteredConfiguredProviders?.length && (
+ <div className='relative'>
+ {filteredConfiguredProviders?.map(provider => (
+ <ProviderAddedCard
+ key={provider.provider}
+ provider={provider}
+ onOpenModal={(configurationMethod: ConfigurationMethodEnum, currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => handleOpenModal(provider, configurationMethod, currentCustomConfigurationModelFixedFields)}
+ />
+ ))}
+ </div>
+ )}
+ {!!filteredNotConfiguredProviders?.length && (
+ <>
+ <div className='system-md-semibold mb-2 flex items-center pt-2 text-text-primary'>{t('common.modelProvider.toBeConfigured')}</div>
+ <div className='relative'>
+ {filteredNotConfiguredProviders?.map(provider => (
+ <ProviderAddedCard
+ notConfigured
+ key={provider.provider}
+ provider={provider}
+ onOpenModal={(configurationMethod: ConfigurationMethodEnum, currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => handleOpenModal(provider, configurationMethod, currentCustomConfigurationModelFixedFields)}
+ />
+ ))}
+ </div>
+ </>
+ )}
+ {
+ enable_marketplace && (
+ <InstallFromMarketplace
+ providers={providers}
+ searchText={searchText}
+ />
+ )
+ }
+ </div>
+ )
+}
+
+export default ModelProviderPage
diff --git a/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx b/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx
new file mode 100644
index 0000000..818007a
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx
@@ -0,0 +1,83 @@
+import { useCallback, useState } from 'react'
+import { useTheme } from 'next-themes'
+import { useTranslation } from 'react-i18next'
+import Link from 'next/link'
+import {
+ RiArrowDownSLine,
+ RiArrowRightUpLine,
+} from '@remixicon/react'
+import type {
+ ModelProvider,
+} from './declarations'
+import {
+ useMarketplaceAllPlugins,
+} from './hooks'
+import Divider from '@/app/components/base/divider'
+import Loading from '@/app/components/base/loading'
+import ProviderCard from '@/app/components/plugins/provider-card'
+import List from '@/app/components/plugins/marketplace/list'
+import type { Plugin } from '@/app/components/plugins/types'
+import { MARKETPLACE_URL_PREFIX } from '@/config'
+import cn from '@/utils/classnames'
+import { getLocaleOnClient } from '@/i18n'
+
+type InstallFromMarketplaceProps = {
+ providers: ModelProvider[]
+ searchText: string
+}
+const InstallFromMarketplace = ({
+ providers,
+ searchText,
+}: InstallFromMarketplaceProps) => {
+ const { t } = useTranslation()
+ const { theme } = useTheme()
+ const [collapse, setCollapse] = useState(false)
+ const locale = getLocaleOnClient()
+ const {
+ plugins: allPlugins,
+ isLoading: isAllPluginsLoading,
+ } = useMarketplaceAllPlugins(providers, searchText)
+
+ const cardRender = useCallback((plugin: Plugin) => {
+ if (plugin.type === 'bundle')
+ return null
+
+ return <ProviderCard key={plugin.plugin_id} payload={plugin} />
+ }, [])
+
+ return (
+ <div className='mb-2'>
+ <Divider className='!mt-4 h-px' />
+ <div className='flex items-center justify-between'>
+ <div className='system-md-semibold flex cursor-pointer items-center gap-1 text-text-primary' onClick={() => setCollapse(!collapse)}>
+ <RiArrowDownSLine className={cn('h-4 w-4', collapse && '-rotate-90')} />
+ {t('common.modelProvider.installProvider')}
+ </div>
+ <div className='mb-2 flex items-center pt-2'>
+ <span className='system-sm-regular pr-1 text-text-tertiary'>{t('common.modelProvider.discoverMore')}</span>
+ <Link target="_blank" href={`${MARKETPLACE_URL_PREFIX}${theme ? `?theme=${theme}` : ''}`} className='system-sm-medium inline-flex items-center text-text-accent'>
+ {t('plugin.marketplace.difyMarketplace')}
+ <RiArrowRightUpLine className='h-4 w-4' />
+ </Link>
+ </div>
+ </div>
+ {!collapse && isAllPluginsLoading && <Loading type='area' />}
+ {
+ !isAllPluginsLoading && !collapse && (
+ <List
+ marketplaceCollections={[]}
+ marketplaceCollectionPluginsMap={{}}
+ plugins={allPlugins}
+ showInstallButton
+ locale={locale}
+ cardContainerClassName='grid grid-cols-2 gap-2'
+ cardRender={cardRender}
+ emptyClassName='h-auto'
+ />
+ )
+ }
+ </div>
+ )
+}
+
+export default InstallFromMarketplace
diff --git a/app/components/header/account-setting/model-provider-page/model-badge/index.tsx b/app/components/header/account-setting/model-provider-page/model-badge/index.tsx
new file mode 100644
index 0000000..d272e96
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-badge/index.tsx
@@ -0,0 +1,22 @@
+import type { FC, ReactNode } from 'react'
+import classNames from '@/utils/classnames'
+
+type ModelBadgeProps = {
+ className?: string
+ children?: ReactNode
+}
+const ModelBadge: FC<ModelBadgeProps> = ({
+ className,
+ children,
+}) => {
+ return (
+ <div className={classNames(
+ 'flex items-center px-1 h-[18px] rounded-[5px] border border-divider-deep system-2xs-medium-uppercase text-text-tertiary cursor-default',
+ className,
+ )}>
+ {children}
+ </div>
+ )
+}
+
+export default ModelBadge
diff --git a/app/components/header/account-setting/model-provider-page/model-icon/index.tsx b/app/components/header/account-setting/model-provider-page/model-icon/index.tsx
new file mode 100644
index 0000000..d302def
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-icon/index.tsx
@@ -0,0 +1,50 @@
+import type { FC } from 'react'
+import type {
+ Model,
+ ModelProvider,
+} from '../declarations'
+import { useLanguage } from '../hooks'
+import { Group } from '@/app/components/base/icons/src/vender/other'
+import { OpenaiBlue, OpenaiViolet } from '@/app/components/base/icons/src/public/llm'
+import cn from '@/utils/classnames'
+import { renderI18nObject } from '@/i18n'
+
+type ModelIconProps = {
+ provider?: Model | ModelProvider
+ modelName?: string
+ className?: string
+ isDeprecated?: boolean
+}
+const ModelIcon: FC<ModelIconProps> = ({
+ provider,
+ className,
+ modelName,
+ isDeprecated = false,
+}) => {
+ const language = useLanguage()
+ if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.includes('gpt-4o'))
+ return <div className='flex items-center justify-center'><OpenaiBlue className={cn('h-5 w-5', className)} /></div>
+ if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.startsWith('gpt-4'))
+ return <div className='flex items-center justify-center'><OpenaiViolet className={cn('h-5 w-5', className)} /></div>
+
+ if (provider?.icon_small) {
+ return (
+ <div className={cn('flex h-5 w-5 items-center justify-center', isDeprecated && 'opacity-50', className)}>
+ <img alt='model-icon' src={renderI18nObject(provider.icon_small, language)}/>
+ </div>
+ )
+ }
+
+ return (
+ <div className={cn(
+ 'flex h-5 w-5 items-center justify-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle',
+ className,
+ )}>
+ <div className='flex h-5 w-5 items-center justify-center opacity-35'>
+ <Group className='h-3 w-3 text-text-tertiary' />
+ </div>
+ </div>
+ )
+}
+
+export default ModelIcon
diff --git a/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx b/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx
new file mode 100644
index 0000000..c5af4ed
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx
@@ -0,0 +1,424 @@
+import { useCallback, useState } from 'react'
+import type { ReactNode } from 'react'
+import { ValidatingTip } from '../../key-validator/ValidateStatus'
+import type {
+ CredentialFormSchema,
+ CredentialFormSchemaNumberInput,
+ CredentialFormSchemaRadio,
+ CredentialFormSchemaSecretInput,
+ CredentialFormSchemaSelect,
+ CredentialFormSchemaTextInput,
+ FormValue,
+} from '../declarations'
+import { FormTypeEnum } from '../declarations'
+import { useLanguage } from '../hooks'
+import Input from './Input'
+import cn from '@/utils/classnames'
+import { SimpleSelect } from '@/app/components/base/select'
+import Tooltip from '@/app/components/base/tooltip'
+import Radio from '@/app/components/base/radio'
+import ModelParameterModal from '@/app/components/plugins/plugin-detail-panel/model-selector'
+import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
+import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector'
+import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector'
+import RadioE from '@/app/components/base/radio/ui'
+import type {
+ NodeOutPutVar,
+} from '@/app/components/workflow/types'
+import type { Node } from 'reactflow'
+
+type FormProps<
+ CustomFormSchema extends Omit<CredentialFormSchema, 'type'> & { type: string } = never,
+> = {
+ className?: string
+ itemClassName?: string
+ fieldLabelClassName?: string
+ value: FormValue
+ onChange: (val: FormValue) => void
+ formSchemas: Array<CredentialFormSchema | CustomFormSchema>
+ validating: boolean
+ validatedSuccess?: boolean
+ showOnVariableMap: Record<string, string[]>
+ isEditMode: boolean
+ isAgentStrategy?: boolean
+ readonly?: boolean
+ inputClassName?: string
+ isShowDefaultValue?: boolean
+ fieldMoreInfo?: (payload: CredentialFormSchema | CustomFormSchema) => ReactNode
+ customRenderField?: (
+ formSchema: CustomFormSchema,
+ props: Omit<FormProps<CustomFormSchema>, 'override' | 'customRenderField'>
+ ) => ReactNode
+ // If return falsy value, this field will fallback to default render
+ override?: [Array<FormTypeEnum>, (formSchema: CredentialFormSchema, props: Omit<FormProps<CustomFormSchema>, 'override' | 'customRenderField'>) => ReactNode]
+ nodeId?: string
+ nodeOutputVars?: NodeOutPutVar[],
+ availableNodes?: Node[],
+}
+
+function Form<
+ CustomFormSchema extends Omit<CredentialFormSchema, 'type'> & { type: string } = never,
+>({
+ className,
+ itemClassName,
+ fieldLabelClassName,
+ value,
+ onChange,
+ formSchemas,
+ validating,
+ validatedSuccess,
+ showOnVariableMap,
+ isEditMode,
+ isAgentStrategy = false,
+ readonly,
+ inputClassName,
+ isShowDefaultValue = false,
+ fieldMoreInfo,
+ customRenderField,
+ override,
+ nodeId,
+ nodeOutputVars,
+ availableNodes,
+}: FormProps<CustomFormSchema>) {
+ const language = useLanguage()
+ const [changeKey, setChangeKey] = useState('')
+ const filteredProps: Omit<FormProps<CustomFormSchema>, 'override' | 'customRenderField'> = {
+ className,
+ itemClassName,
+ fieldLabelClassName,
+ value,
+ onChange,
+ formSchemas,
+ validating,
+ validatedSuccess,
+ showOnVariableMap,
+ isEditMode,
+ readonly,
+ inputClassName,
+ isShowDefaultValue,
+ fieldMoreInfo,
+ }
+
+ const handleFormChange = (key: string, val: string | boolean) => {
+ if (isEditMode && (key === '__model_type' || key === '__model_name'))
+ return
+
+ setChangeKey(key)
+ const shouldClearVariable: Record<string, string | undefined> = {}
+ if (showOnVariableMap[key]?.length) {
+ showOnVariableMap[key].forEach((clearVariable) => {
+ const schema = formSchemas.find(it => it.variable === clearVariable)
+ shouldClearVariable[clearVariable] = schema ? schema.default : undefined
+ })
+ }
+ onChange({ ...value, [key]: val, ...shouldClearVariable })
+ }
+
+ const handleModelChanged = useCallback((key: string, model: any) => {
+ const newValue = {
+ ...value[key],
+ ...model,
+ type: FormTypeEnum.modelSelector,
+ }
+ onChange({ ...value, [key]: newValue })
+ }, [onChange, value])
+
+ const renderField = (formSchema: CredentialFormSchema | CustomFormSchema) => {
+ const tooltip = formSchema.tooltip
+ const tooltipContent = (tooltip && (
+ <Tooltip
+ popupContent={<div className='w-[200px]'>
+ {tooltip[language] || tooltip.en_US}
+ </div>}
+ triggerClassName='ml-1 w-4 h-4'
+ asChild={false} />
+ ))
+ if (override) {
+ const [overrideTypes, overrideRender] = override
+ if (overrideTypes.includes(formSchema.type as FormTypeEnum)) {
+ const node = overrideRender(formSchema as CredentialFormSchema, filteredProps)
+ if (node)
+ return node
+ }
+ }
+
+ if (formSchema.type === FormTypeEnum.textInput || formSchema.type === FormTypeEnum.secretInput || formSchema.type === FormTypeEnum.textNumber) {
+ const {
+ variable, label, placeholder, required, show_on,
+ } = formSchema as (CredentialFormSchemaTextInput | CredentialFormSchemaSecretInput)
+
+ if (show_on.length && !show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value))
+ return null
+
+ const disabled = readonly || (isEditMode && (variable === '__model_type' || variable === '__model_name'))
+ return (
+ <div key={variable} className={cn(itemClassName, 'py-3')}>
+ <div className={cn(fieldLabelClassName, 'system-sm-semibold flex items-center py-2 text-text-secondary')}>
+ {label[language] || label.en_US}
+ {required && (
+ <span className='ml-1 text-red-500'>*</span>
+ )}
+ {tooltipContent}
+ </div>
+ <Input
+ className={cn(inputClassName, `${disabled && 'cursor-not-allowed opacity-60'}`)}
+ value={(isShowDefaultValue && ((value[variable] as string) === '' || value[variable] === undefined || value[variable] === null)) ? formSchema.default : value[variable]}
+ onChange={val => handleFormChange(variable, val)}
+ validated={validatedSuccess}
+ placeholder={placeholder?.[language] || placeholder?.en_US}
+ disabled={disabled}
+ type={formSchema.type === FormTypeEnum.secretInput ? 'password'
+ : formSchema.type === FormTypeEnum.textNumber ? 'number'
+ : 'text'}
+ {...(formSchema.type === FormTypeEnum.textNumber ? { min: (formSchema as CredentialFormSchemaNumberInput).min, max: (formSchema as CredentialFormSchemaNumberInput).max } : {})} />
+ {fieldMoreInfo?.(formSchema)}
+ {validating && changeKey === variable && <ValidatingTip />}
+ </div>
+ )
+ }
+
+ if (formSchema.type === FormTypeEnum.radio) {
+ const {
+ options, variable, label, show_on, required,
+ } = formSchema as CredentialFormSchemaRadio
+
+ if (show_on.length && !show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value))
+ return null
+
+ const disabled = isEditMode && (variable === '__model_type' || variable === '__model_name')
+
+ return (
+ <div key={variable} className={cn(itemClassName, 'py-3')}>
+ <div className={cn(fieldLabelClassName, 'system-sm-semibold flex items-center py-2 text-text-secondary')}>
+ {label[language] || label.en_US}
+ {required && (
+ <span className='ml-1 text-red-500'>*</span>
+ )}
+ {tooltipContent}
+ </div>
+ <div className={cn('grid gap-3', `grid-cols-${options?.length}`)}>
+ {options.filter((option) => {
+ if (option.show_on.length)
+ return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
+
+ return true
+ }).map(option => (
+ <div
+ className={`
+ flex cursor-pointer items-center gap-2 rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg px-3 py-2
+ ${value[variable] === option.value && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg shadow-sm'}
+ ${disabled && '!cursor-not-allowed opacity-60'}
+ `}
+ onClick={() => handleFormChange(variable, option.value)}
+ key={`${variable}-${option.value}`}
+ >
+ <RadioE isChecked={value[variable] === option.value} />
+
+ <div className='system-sm-regular text-text-secondary'>{option.label[language] || option.label.en_US}</div>
+ </div>
+ ))}
+ </div>
+ {fieldMoreInfo?.(formSchema)}
+ {validating && changeKey === variable && <ValidatingTip />}
+ </div>
+ )
+ }
+
+ if (formSchema.type === FormTypeEnum.select) {
+ const {
+ options, variable, label, show_on, required, placeholder,
+ } = formSchema as CredentialFormSchemaSelect
+
+ if (show_on.length && !show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value))
+ return null
+
+ return (
+ <div key={variable} className={cn(itemClassName, 'py-3')}>
+ <div className={cn(fieldLabelClassName, 'system-sm-semibold flex items-center py-2 text-text-secondary')}>
+ {label[language] || label.en_US}
+
+ {required && (
+ <span className='ml-1 text-red-500'>*</span>
+ )}
+ {tooltipContent}
+ </div>
+ <SimpleSelect
+ wrapperClassName='h-8'
+ className={cn(inputClassName)}
+ disabled={readonly}
+ defaultValue={(isShowDefaultValue && ((value[variable] as string) === '' || value[variable] === undefined || value[variable] === null)) ? formSchema.default : value[variable]}
+ items={options.filter((option) => {
+ if (option.show_on.length)
+ return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
+
+ return true
+ }).map(option => ({ value: option.value, name: option.label[language] || option.label.en_US }))}
+ onSelect={item => handleFormChange(variable, item.value as string)}
+ placeholder={placeholder?.[language] || placeholder?.en_US} />
+ {fieldMoreInfo?.(formSchema)}
+ {validating && changeKey === variable && <ValidatingTip />}
+ </div>
+ )
+ }
+
+ if (formSchema.type === FormTypeEnum.boolean) {
+ const {
+ variable, label, show_on, required,
+ } = formSchema as CredentialFormSchemaRadio
+
+ if (show_on.length && !show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value))
+ return null
+
+ return (
+ <div key={variable} className={cn(itemClassName, 'py-3')}>
+ <div className='system-sm-semibold flex items-center justify-between py-2 text-text-secondary'>
+ <div className='flex items-center space-x-2'>
+ <span className={cn(fieldLabelClassName, 'system-sm-regular flex items-center py-2 text-text-secondary')}>{label[language] || label.en_US}</span>
+ {required && (
+ <span className='ml-1 text-red-500'>*</span>
+ )}
+ {tooltipContent}
+ </div>
+ <Radio.Group
+ className='flex items-center'
+ value={value[variable] === null ? undefined : (value[variable] ? 1 : 0)}
+ onChange={val => handleFormChange(variable, val === 1)}
+ >
+ <Radio value={1} className='!mr-1'>True</Radio>
+ <Radio value={0}>False</Radio>
+ </Radio.Group>
+ </div>
+ {fieldMoreInfo?.(formSchema)}
+ </div>
+ )
+ }
+
+ if (formSchema.type === FormTypeEnum.modelSelector) {
+ const {
+ variable, label, required, scope,
+ } = formSchema as (CredentialFormSchemaTextInput | CredentialFormSchemaSecretInput)
+ return (
+ <div key={variable} className={cn(itemClassName, 'py-3')}>
+ <div className={cn(fieldLabelClassName, 'system-sm-semibold flex items-center py-2 text-text-secondary')}>
+ {label[language] || label.en_US}
+ {required && (
+ <span className='ml-1 text-red-500'>*</span>
+ )}
+ {tooltipContent}
+ </div>
+ <ModelParameterModal
+ popupClassName='!w-[387px]'
+ isAdvancedMode
+ isInWorkflow
+ isAgentStrategy={isAgentStrategy}
+ value={value[variable]}
+ setModel={model => handleModelChanged(variable, model)}
+ readonly={readonly}
+ scope={scope} />
+ {fieldMoreInfo?.(formSchema)}
+ {validating && changeKey === variable && <ValidatingTip />}
+ </div>
+ )
+ }
+
+ if (formSchema.type === FormTypeEnum.toolSelector) {
+ const {
+ variable,
+ label,
+ required,
+ scope,
+ } = formSchema as (CredentialFormSchemaTextInput | CredentialFormSchemaSecretInput)
+ return (
+ <div key={variable} className={cn(itemClassName, 'py-3')}>
+ <div className={cn(fieldLabelClassName, 'system-sm-semibold flex items-center py-2 text-text-secondary')}>
+ {label[language] || label.en_US}
+ {required && (
+ <span className='ml-1 text-red-500'>*</span>
+ )}
+ {tooltipContent}
+ </div>
+ <ToolSelector
+ scope={scope}
+ nodeId={nodeId}
+ nodeOutputVars={nodeOutputVars || []}
+ availableNodes={availableNodes || []}
+ disabled={readonly}
+ value={value[variable]}
+ // selectedTools={value[variable] ? [value[variable]] : []}
+ onSelect={item => handleFormChange(variable, item as any)}
+ onDelete={() => handleFormChange(variable, null as any)}
+ />
+ {fieldMoreInfo?.(formSchema)}
+ {validating && changeKey === variable && <ValidatingTip />}
+ </div>
+ )
+ }
+
+ if (formSchema.type === FormTypeEnum.multiToolSelector) {
+ const {
+ variable,
+ label,
+ tooltip,
+ required,
+ scope,
+ } = formSchema as (CredentialFormSchemaTextInput | CredentialFormSchemaSecretInput)
+
+ return (
+ <div key={variable} className={cn(itemClassName, 'py-3')}>
+ <MultipleToolSelector
+ disabled={readonly}
+ nodeId={nodeId}
+ nodeOutputVars={nodeOutputVars || []}
+ availableNodes={availableNodes || []}
+ scope={scope}
+ label={label[language] || label.en_US}
+ required={required}
+ tooltip={tooltip?.[language] || tooltip?.en_US}
+ value={value[variable] || []}
+ onChange={item => handleFormChange(variable, item as any)}
+ supportCollapse
+ />
+ {fieldMoreInfo?.(formSchema)}
+ {validating && changeKey === variable && <ValidatingTip />}
+ </div>
+ )
+ }
+
+ if (formSchema.type === FormTypeEnum.appSelector) {
+ const {
+ variable, label, required, scope,
+ } = formSchema as (CredentialFormSchemaTextInput | CredentialFormSchemaSecretInput)
+
+ return (
+ <div key={variable} className={cn(itemClassName, 'py-3')}>
+ <div className={cn(fieldLabelClassName, 'system-sm-semibold flex items-center py-2 text-text-secondary')}>
+ {label[language] || label.en_US}
+ {required && (
+ <span className='ml-1 text-red-500'>*</span>
+ )}
+ {tooltipContent}
+ </div>
+ <AppSelector
+ disabled={readonly}
+ scope={scope}
+ value={value[variable]}
+ onSelect={item => handleFormChange(variable, { ...item, type: FormTypeEnum.appSelector } as any)} />
+ {fieldMoreInfo?.(formSchema)}
+ {validating && changeKey === variable && <ValidatingTip />}
+ </div>
+ )
+ }
+
+ // @ts-expect-error it work
+ if (!Object.values(FormTypeEnum).includes(formSchema.type))
+ return customRenderField?.(formSchema as CustomFormSchema, filteredProps)
+ }
+
+ return (
+ <div className={className}>
+ {formSchemas.map(formSchema => renderField(formSchema))}
+ </div>
+ )
+}
+
+export default Form
diff --git a/app/components/header/account-setting/model-provider-page/model-modal/Input.tsx b/app/components/header/account-setting/model-provider-page/model-modal/Input.tsx
new file mode 100644
index 0000000..a19e330
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-modal/Input.tsx
@@ -0,0 +1,74 @@
+import type { FC } from 'react'
+import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/general'
+
+type InputProps = {
+ value?: string
+ onChange: (v: string) => void
+ onFocus?: () => void
+ placeholder?: string
+ validated?: boolean
+ className?: string
+ disabled?: boolean
+ type?: string
+ min?: number
+ max?: number
+}
+const Input: FC<InputProps> = ({
+ value,
+ onChange,
+ onFocus,
+ placeholder,
+ validated,
+ className,
+ disabled,
+ type = 'text',
+ min,
+ max,
+}) => {
+ const toLimit = (v: string) => {
+ const minNum = Number.parseFloat(`${min}`)
+ const maxNum = Number.parseFloat(`${max}`)
+ if (!isNaN(minNum) && Number.parseFloat(v) < minNum) {
+ onChange(`${min}`)
+ return
+ }
+
+ if (!isNaN(maxNum) && Number.parseFloat(v) > maxNum)
+ onChange(`${max}`)
+ }
+ return (
+ <div className='relative'>
+ <input
+ autoComplete="new-password"
+ tabIndex={0}
+ className={`
+ block h-8 w-full appearance-none rounded-lg border border-transparent bg-components-input-bg-normal px-3 text-sm
+ text-components-input-text-filled caret-primary-600 outline-none
+ placeholder:text-sm placeholder:text-text-tertiary
+ hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active
+ focus:bg-components-input-bg-active focus:shadow-xs
+ ${validated && 'pr-[30px]'}
+ ${className}
+ `}
+ placeholder={placeholder || ''}
+ onChange={e => onChange(e.target.value)}
+ onBlur={e => toLimit(e.target.value)}
+ onFocus={onFocus}
+ value={value}
+ disabled={disabled}
+ type={type}
+ min={min}
+ max={max}
+ />
+ {
+ validated && (
+ <div className='absolute right-2.5 top-2.5'>
+ <CheckCircle className='h-4 w-4 text-[#039855]' />
+ </div>
+ )
+ }
+ </div>
+ )
+}
+
+export default Input
diff --git a/app/components/header/account-setting/model-provider-page/model-modal/index.tsx b/app/components/header/account-setting/model-provider-page/model-modal/index.tsx
new file mode 100644
index 0000000..bc98081
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-modal/index.tsx
@@ -0,0 +1,401 @@
+import type { FC } from 'react'
+import {
+ memo,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiErrorWarningFill,
+} from '@remixicon/react'
+import type {
+ CredentialFormSchema,
+ CredentialFormSchemaRadio,
+ CredentialFormSchemaSelect,
+ CustomConfigurationModelFixedFields,
+ FormValue,
+ ModelLoadBalancingConfig,
+ ModelLoadBalancingConfigEntry,
+ ModelProvider,
+} from '../declarations'
+import {
+ ConfigurationMethodEnum,
+ CustomConfigurationStatusEnum,
+ FormTypeEnum,
+} from '../declarations'
+import {
+ genModelNameFormSchema,
+ genModelTypeFormSchema,
+ removeCredentials,
+ saveCredentials,
+} from '../utils'
+import {
+ useLanguage,
+ useProviderCredentialsAndLoadBalancing,
+} from '../hooks'
+import { useValidate } from '../../key-validator/hooks'
+import { ValidatedStatus } from '../../key-validator/declarations'
+import ModelLoadBalancingConfigs from '../provider-added-card/model-load-balancing-configs'
+import Form from './Form'
+import Button from '@/app/components/base/button'
+import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
+import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+} from '@/app/components/base/portal-to-follow-elem'
+import { useToastContext } from '@/app/components/base/toast'
+import Confirm from '@/app/components/base/confirm'
+import { useAppContext } from '@/context/app-context'
+
+type ModelModalProps = {
+ provider: ModelProvider
+ configurateMethod: ConfigurationMethodEnum
+ currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
+ onCancel: () => void
+ onSave: () => void
+}
+
+const ModelModal: FC<ModelModalProps> = ({
+ provider,
+ configurateMethod,
+ currentCustomConfigurationModelFixedFields,
+ onCancel,
+ onSave,
+}) => {
+ const providerFormSchemaPredefined = configurateMethod === ConfigurationMethodEnum.predefinedModel
+ const {
+ credentials: formSchemasValue,
+ loadBalancing: originalConfig,
+ mutate,
+ } = useProviderCredentialsAndLoadBalancing(
+ provider.provider,
+ configurateMethod,
+ providerFormSchemaPredefined && provider.custom_configuration.status === CustomConfigurationStatusEnum.active,
+ currentCustomConfigurationModelFixedFields,
+ )
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const isEditMode = !!formSchemasValue && isCurrentWorkspaceManager
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const language = useLanguage()
+ const [loading, setLoading] = useState(false)
+ const [showConfirm, setShowConfirm] = useState(false)
+
+ const [draftConfig, setDraftConfig] = useState<ModelLoadBalancingConfig>()
+ const originalConfigMap = useMemo(() => {
+ if (!originalConfig)
+ return {}
+ return originalConfig?.configs.reduce((prev, config) => {
+ if (config.id)
+ prev[config.id] = config
+ return prev
+ }, {} as Record<string, ModelLoadBalancingConfigEntry>)
+ }, [originalConfig])
+ useEffect(() => {
+ if (originalConfig && !draftConfig)
+ setDraftConfig(originalConfig)
+ }, [draftConfig, originalConfig])
+
+ const formSchemas = useMemo(() => {
+ return providerFormSchemaPredefined
+ ? provider.provider_credential_schema.credential_form_schemas
+ : [
+ genModelTypeFormSchema(provider.supported_model_types),
+ genModelNameFormSchema(provider.model_credential_schema?.model),
+ ...(draftConfig?.enabled ? [] : provider.model_credential_schema.credential_form_schemas),
+ ]
+ }, [
+ providerFormSchemaPredefined,
+ provider.provider_credential_schema?.credential_form_schemas,
+ provider.supported_model_types,
+ provider.model_credential_schema?.credential_form_schemas,
+ provider.model_credential_schema?.model,
+ draftConfig?.enabled,
+ ])
+ const [
+ requiredFormSchemas,
+ defaultFormSchemaValue,
+ showOnVariableMap,
+ ] = useMemo(() => {
+ const requiredFormSchemas: CredentialFormSchema[] = []
+ const defaultFormSchemaValue: Record<string, string | number> = {}
+ const showOnVariableMap: Record<string, string[]> = {}
+
+ formSchemas.forEach((formSchema) => {
+ if (formSchema.required)
+ requiredFormSchemas.push(formSchema)
+
+ if (formSchema.default)
+ defaultFormSchemaValue[formSchema.variable] = formSchema.default
+
+ if (formSchema.show_on.length) {
+ formSchema.show_on.forEach((showOnItem) => {
+ if (!showOnVariableMap[showOnItem.variable])
+ showOnVariableMap[showOnItem.variable] = []
+
+ if (!showOnVariableMap[showOnItem.variable].includes(formSchema.variable))
+ showOnVariableMap[showOnItem.variable].push(formSchema.variable)
+ })
+ }
+
+ if (formSchema.type === FormTypeEnum.select || formSchema.type === FormTypeEnum.radio) {
+ (formSchema as (CredentialFormSchemaRadio | CredentialFormSchemaSelect)).options.forEach((option) => {
+ if (option.show_on.length) {
+ option.show_on.forEach((showOnItem) => {
+ if (!showOnVariableMap[showOnItem.variable])
+ showOnVariableMap[showOnItem.variable] = []
+
+ if (!showOnVariableMap[showOnItem.variable].includes(formSchema.variable))
+ showOnVariableMap[showOnItem.variable].push(formSchema.variable)
+ })
+ }
+ })
+ }
+ })
+
+ return [
+ requiredFormSchemas,
+ defaultFormSchemaValue,
+ showOnVariableMap,
+ ]
+ }, [formSchemas])
+ const initialFormSchemasValue: Record<string, string | number> = useMemo(() => {
+ return {
+ ...defaultFormSchemaValue,
+ ...formSchemasValue,
+ } as unknown as Record<string, string | number>
+ }, [formSchemasValue, defaultFormSchemaValue])
+ const [value, setValue] = useState(initialFormSchemasValue)
+ useEffect(() => {
+ setValue(initialFormSchemasValue)
+ }, [initialFormSchemasValue])
+ const [_, validating, validatedStatusState] = useValidate(value)
+ const filteredRequiredFormSchemas = requiredFormSchemas.filter((requiredFormSchema) => {
+ if (requiredFormSchema.show_on.length && requiredFormSchema.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value))
+ return true
+
+ if (!requiredFormSchema.show_on.length)
+ return true
+
+ return false
+ })
+
+ const handleValueChange = (v: FormValue) => {
+ setValue(v)
+ }
+
+ const extendedSecretFormSchemas = useMemo(
+ () =>
+ (providerFormSchemaPredefined
+ ? provider.provider_credential_schema.credential_form_schemas
+ : [
+ genModelTypeFormSchema(provider.supported_model_types),
+ genModelNameFormSchema(provider.model_credential_schema?.model),
+ ...provider.model_credential_schema.credential_form_schemas,
+ ]).filter(({ type }) => type === FormTypeEnum.secretInput),
+ [
+ provider.model_credential_schema?.credential_form_schemas,
+ provider.model_credential_schema?.model,
+ provider.provider_credential_schema?.credential_form_schemas,
+ provider.supported_model_types,
+ providerFormSchemaPredefined,
+ ],
+ )
+
+ const encodeSecretValues = useCallback((v: FormValue) => {
+ const result = { ...v }
+ extendedSecretFormSchemas.forEach(({ variable }) => {
+ if (result[variable] === formSchemasValue?.[variable] && result[variable] !== undefined)
+ result[variable] = '[__HIDDEN__]'
+ })
+ return result
+ }, [extendedSecretFormSchemas, formSchemasValue])
+
+ const encodeConfigEntrySecretValues = useCallback((entry: ModelLoadBalancingConfigEntry) => {
+ const result = { ...entry }
+ extendedSecretFormSchemas.forEach(({ variable }) => {
+ if (entry.id && result.credentials[variable] === originalConfigMap[entry.id]?.credentials?.[variable])
+ result.credentials[variable] = '[__HIDDEN__]'
+ })
+ return result
+ }, [extendedSecretFormSchemas, originalConfigMap])
+
+ const handleSave = async () => {
+ try {
+ setLoading(true)
+ const res = await saveCredentials(
+ providerFormSchemaPredefined,
+ provider.provider,
+ encodeSecretValues(value),
+ {
+ ...draftConfig,
+ enabled: Boolean(draftConfig?.enabled),
+ configs: draftConfig?.configs.map(encodeConfigEntrySecretValues) || [],
+ },
+ )
+ if (res.result === 'success') {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ mutate()
+ onSave()
+ onCancel()
+ }
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ const handleRemove = async () => {
+ try {
+ setLoading(true)
+
+ const res = await removeCredentials(
+ providerFormSchemaPredefined,
+ provider.provider,
+ value,
+ )
+ if (res.result === 'success') {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ mutate()
+ onSave()
+ onCancel()
+ }
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ const renderTitlePrefix = () => {
+ const prefix = isEditMode ? t('common.operation.setup') : t('common.operation.add')
+ return `${prefix} ${provider.label[language] || provider.label.en_US}`
+ }
+
+ return (
+ <PortalToFollowElem open>
+ <PortalToFollowElemContent className='z-[60] h-full w-full'>
+ <div className='fixed inset-0 flex items-center justify-center bg-black/[.25]'>
+ <div className='mx-2 w-[640px] overflow-auto rounded-2xl bg-components-panel-bg shadow-xl'>
+ <div className='px-8 pt-8'>
+ <div className='mb-2 flex items-center'>
+ <div className='text-xl font-semibold text-text-primary'>{renderTitlePrefix()}</div>
+ </div>
+
+ <div className='max-h-[calc(100vh-320px)] overflow-y-auto'>
+ <Form
+ value={value}
+ onChange={handleValueChange}
+ formSchemas={formSchemas}
+ validating={validating}
+ validatedSuccess={validatedStatusState.status === ValidatedStatus.Success}
+ showOnVariableMap={showOnVariableMap}
+ isEditMode={isEditMode}
+ />
+ <div className='mb-4 mt-1 border-t-[0.5px] border-t-divider-regular' />
+ <ModelLoadBalancingConfigs withSwitch {...{
+ draftConfig,
+ setDraftConfig,
+ provider,
+ currentCustomConfigurationModelFixedFields,
+ configurationMethod: configurateMethod,
+ }} />
+ </div>
+
+ <div className='sticky bottom-0 -mx-2 mt-2 flex flex-wrap items-center justify-between gap-y-2 bg-components-panel-bg px-2 pb-6 pt-4'>
+ {
+ (provider.help && (provider.help.title || provider.help.url))
+ ? (
+ <a
+ href={provider.help?.url[language] || provider.help?.url.en_US}
+ target='_blank' rel='noopener noreferrer'
+ className='inline-flex items-center text-xs text-primary-600'
+ onClick={e => !provider.help.url && e.preventDefault()}
+ >
+ {provider.help.title?.[language] || provider.help.url[language] || provider.help.title?.en_US || provider.help.url.en_US}
+ <LinkExternal02 className='ml-1 h-3 w-3' />
+ </a>
+ )
+ : <div />
+ }
+ <div>
+ {
+ isEditMode && (
+ <Button
+ variant='warning'
+ size='large'
+ className='mr-2'
+ onClick={() => setShowConfirm(true)}
+ >
+ {t('common.operation.remove')}
+ </Button>
+ )
+ }
+ <Button
+ size='large'
+ className='mr-2'
+ onClick={onCancel}
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ size='large'
+ variant='primary'
+ onClick={handleSave}
+ disabled={
+ loading
+ || filteredRequiredFormSchemas.some(item => value[item.variable] === undefined)
+ || (draftConfig?.enabled && (draftConfig?.configs.filter(config => config.enabled).length ?? 0) < 2)
+ }
+
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ </div>
+ </div>
+ <div className='border-t-[0.5px] border-t-divider-regular'>
+ {
+ (validatedStatusState.status === ValidatedStatus.Error && validatedStatusState.message)
+ ? (
+ <div className='flex bg-background-section-burn px-[10px] py-3 text-xs text-[#D92D20]'>
+ <RiErrorWarningFill className='mr-2 mt-[1px] h-[14px] w-[14px]' />
+ {validatedStatusState.message}
+ </div>
+ )
+ : (
+ <div className='flex items-center justify-center bg-background-section-burn py-3 text-xs text-text-tertiary'>
+ <Lock01 className='mr-1 h-3 w-3 text-text-tertiary' />
+ {t('common.modelProvider.encrypted.front')}
+ <a
+ className='mx-1 text-text-accent'
+ target='_blank' rel='noopener noreferrer'
+ href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
+ >
+ PKCS1_OAEP
+ </a>
+ {t('common.modelProvider.encrypted.back')}
+ </div>
+ )
+ }
+ </div>
+ </div>
+ {
+ showConfirm && (
+ <Confirm
+ title={t('common.modelProvider.confirmDelete')}
+ isShow={showConfirm}
+ onCancel={() => setShowConfirm(false)}
+ onConfirm={handleRemove}
+ />
+ )
+ }
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default memo(ModelModal)
diff --git a/app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal.tsx b/app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal.tsx
new file mode 100644
index 0000000..d6285a7
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal.tsx
@@ -0,0 +1,348 @@
+import type { FC } from 'react'
+import {
+ memo,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiErrorWarningFill,
+} from '@remixicon/react'
+import type {
+ CredentialFormSchema,
+ CredentialFormSchemaRadio,
+ CredentialFormSchemaSelect,
+ CredentialFormSchemaTextInput,
+ CustomConfigurationModelFixedFields,
+ FormValue,
+ ModelLoadBalancingConfigEntry,
+ ModelProvider,
+} from '../declarations'
+import {
+ ConfigurationMethodEnum,
+ FormTypeEnum,
+} from '../declarations'
+
+import {
+ useLanguage,
+} from '../hooks'
+import { useValidate } from '../../key-validator/hooks'
+import { ValidatedStatus } from '../../key-validator/declarations'
+import { validateLoadBalancingCredentials } from '../utils'
+import Form from './Form'
+import Button from '@/app/components/base/button'
+import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
+import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+} from '@/app/components/base/portal-to-follow-elem'
+import { useToastContext } from '@/app/components/base/toast'
+import Confirm from '@/app/components/base/confirm'
+
+type ModelModalProps = {
+ provider: ModelProvider
+ configurationMethod: ConfigurationMethodEnum
+ currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
+ entry?: ModelLoadBalancingConfigEntry
+ onCancel: () => void
+ onSave: (entry: ModelLoadBalancingConfigEntry) => void
+ onRemove: () => void
+}
+
+const ModelLoadBalancingEntryModal: FC<ModelModalProps> = ({
+ provider,
+ configurationMethod,
+ currentCustomConfigurationModelFixedFields,
+ entry,
+ onCancel,
+ onSave,
+ onRemove,
+}) => {
+ const providerFormSchemaPredefined = configurationMethod === ConfigurationMethodEnum.predefinedModel
+ // const { credentials: formSchemasValue } = useProviderCredentialsAndLoadBalancing(
+ // provider.provider,
+ // configurationMethod,
+ // providerFormSchemaPredefined && provider.custom_configuration.status === CustomConfigurationStatusEnum.active,
+ // currentCustomConfigurationModelFixedFields,
+ // )
+ const isEditMode = !!entry
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const language = useLanguage()
+ const [loading, setLoading] = useState(false)
+ const [showConfirm, setShowConfirm] = useState(false)
+ const formSchemas = useMemo(() => {
+ return [
+ {
+ type: FormTypeEnum.textInput,
+ label: {
+ en_US: 'Config Name',
+ zh_Hans: '閰嶇疆鍚嶇О',
+ },
+ variable: 'name',
+ required: true,
+ show_on: [],
+ placeholder: {
+ en_US: 'Enter your Config Name here',
+ zh_Hans: '杈撳叆閰嶇疆鍚嶇О',
+ },
+ } as CredentialFormSchemaTextInput,
+ ...(
+ providerFormSchemaPredefined
+ ? provider.provider_credential_schema.credential_form_schemas
+ : provider.model_credential_schema.credential_form_schemas
+ ),
+ ]
+ }, [
+ providerFormSchemaPredefined,
+ provider.provider_credential_schema?.credential_form_schemas,
+ provider.model_credential_schema?.credential_form_schemas,
+ ])
+
+ const [
+ requiredFormSchemas,
+ secretFormSchemas,
+ defaultFormSchemaValue,
+ showOnVariableMap,
+ ] = useMemo(() => {
+ const requiredFormSchemas: CredentialFormSchema[] = []
+ const secretFormSchemas: CredentialFormSchema[] = []
+ const defaultFormSchemaValue: Record<string, string | number> = {}
+ const showOnVariableMap: Record<string, string[]> = {}
+
+ formSchemas.forEach((formSchema) => {
+ if (formSchema.required)
+ requiredFormSchemas.push(formSchema)
+
+ if (formSchema.type === FormTypeEnum.secretInput)
+ secretFormSchemas.push(formSchema)
+
+ if (formSchema.default)
+ defaultFormSchemaValue[formSchema.variable] = formSchema.default
+
+ if (formSchema.show_on.length) {
+ formSchema.show_on.forEach((showOnItem) => {
+ if (!showOnVariableMap[showOnItem.variable])
+ showOnVariableMap[showOnItem.variable] = []
+
+ if (!showOnVariableMap[showOnItem.variable].includes(formSchema.variable))
+ showOnVariableMap[showOnItem.variable].push(formSchema.variable)
+ })
+ }
+
+ if (formSchema.type === FormTypeEnum.select || formSchema.type === FormTypeEnum.radio) {
+ (formSchema as (CredentialFormSchemaRadio | CredentialFormSchemaSelect)).options.forEach((option) => {
+ if (option.show_on.length) {
+ option.show_on.forEach((showOnItem) => {
+ if (!showOnVariableMap[showOnItem.variable])
+ showOnVariableMap[showOnItem.variable] = []
+
+ if (!showOnVariableMap[showOnItem.variable].includes(formSchema.variable))
+ showOnVariableMap[showOnItem.variable].push(formSchema.variable)
+ })
+ }
+ })
+ }
+ })
+
+ return [
+ requiredFormSchemas,
+ secretFormSchemas,
+ defaultFormSchemaValue,
+ showOnVariableMap,
+ ]
+ }, [formSchemas])
+ const [initialValue, setInitialValue] = useState<ModelLoadBalancingConfigEntry['credentials']>()
+ useEffect(() => {
+ if (entry && !initialValue) {
+ setInitialValue({
+ ...defaultFormSchemaValue,
+ ...entry.credentials,
+ id: entry.id,
+ name: entry.name,
+ } as Record<string, string | undefined | boolean>)
+ }
+ }, [entry, defaultFormSchemaValue, initialValue])
+ const formSchemasValue = useMemo(() => ({
+ ...currentCustomConfigurationModelFixedFields,
+ ...initialValue,
+ }), [currentCustomConfigurationModelFixedFields, initialValue])
+ const initialFormSchemasValue: Record<string, string | number> = useMemo(() => {
+ return {
+ ...defaultFormSchemaValue,
+ ...formSchemasValue,
+ } as Record<string, string | number>
+ }, [formSchemasValue, defaultFormSchemaValue])
+ const [value, setValue] = useState(initialFormSchemasValue)
+ useEffect(() => {
+ setValue(initialFormSchemasValue)
+ }, [initialFormSchemasValue])
+ const [_, validating, validatedStatusState] = useValidate(value)
+ const filteredRequiredFormSchemas = requiredFormSchemas.filter((requiredFormSchema) => {
+ if (requiredFormSchema.show_on.length && requiredFormSchema.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value))
+ return true
+
+ if (!requiredFormSchema.show_on.length)
+ return true
+
+ return false
+ })
+ const getSecretValues = useCallback((v: FormValue) => {
+ return secretFormSchemas.reduce((prev, next) => {
+ if (isEditMode && v[next.variable] && v[next.variable] === initialFormSchemasValue[next.variable])
+ prev[next.variable] = '[__HIDDEN__]'
+
+ return prev
+ }, {} as Record<string, string>)
+ }, [initialFormSchemasValue, isEditMode, secretFormSchemas])
+
+ // const handleValueChange = ({ __model_type, __model_name, ...v }: FormValue) => {
+ const handleValueChange = (v: FormValue) => {
+ setValue(v)
+ }
+ const handleSave = async () => {
+ try {
+ setLoading(true)
+
+ const res = await validateLoadBalancingCredentials(
+ providerFormSchemaPredefined,
+ provider.provider,
+ {
+ ...value,
+ ...getSecretValues(value),
+ },
+ entry?.id,
+ )
+ if (res.status === ValidatedStatus.Success) {
+ // notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ const { __model_type, __model_name, name, ...credentials } = value
+ onSave({
+ ...(entry || {}),
+ name: name as string,
+ credentials: credentials as Record<string, string | boolean | undefined>,
+ })
+ // onCancel()
+ }
+ else {
+ notify({ type: 'error', message: res.message || '' })
+ }
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ const handleRemove = () => {
+ onRemove?.()
+ }
+
+ return (
+ <PortalToFollowElem open>
+ <PortalToFollowElemContent className='z-[60] h-full w-full'>
+ <div className='fixed inset-0 flex items-center justify-center bg-black/[.25]'>
+ <div className='mx-2 max-h-[calc(100vh-120px)] w-[640px] overflow-y-auto rounded-2xl bg-white shadow-xl'>
+ <div className='px-8 pt-8'>
+ <div className='mb-2 flex items-center justify-between'>
+ <div className='text-xl font-semibold text-gray-900'>{t(isEditMode ? 'common.modelProvider.editConfig' : 'common.modelProvider.addConfig')}</div>
+ </div>
+ <Form
+ value={value}
+ onChange={handleValueChange}
+ formSchemas={formSchemas}
+ validating={validating}
+ validatedSuccess={validatedStatusState.status === ValidatedStatus.Success}
+ showOnVariableMap={showOnVariableMap}
+ isEditMode={isEditMode}
+ />
+ <div className='sticky bottom-0 flex flex-wrap items-center justify-between gap-y-2 bg-white py-6'>
+ {
+ (provider.help && (provider.help.title || provider.help.url))
+ ? (
+ <a
+ href={provider.help?.url[language] || provider.help?.url.en_US}
+ target='_blank' rel='noopener noreferrer'
+ className='inline-flex items-center text-xs text-primary-600'
+ onClick={e => !provider.help.url && e.preventDefault()}
+ >
+ {provider.help.title?.[language] || provider.help.url[language] || provider.help.title?.en_US || provider.help.url.en_US}
+ <LinkExternal02 className='ml-1 h-3 w-3' />
+ </a>
+ )
+ : <div />
+ }
+ <div>
+ {
+ isEditMode && (
+ <Button
+ size='large'
+ className='mr-2 text-[#D92D20]'
+ onClick={() => setShowConfirm(true)}
+ >
+ {t('common.operation.remove')}
+ </Button>
+ )
+ }
+ <Button
+ size='large'
+ className='mr-2'
+ onClick={onCancel}
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ size='large'
+ variant='primary'
+ onClick={handleSave}
+ disabled={loading || filteredRequiredFormSchemas.some(item => value[item.variable] === undefined)}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ </div>
+ </div>
+ <div className='border-t-[0.5px] border-t-black/5'>
+ {
+ (validatedStatusState.status === ValidatedStatus.Error && validatedStatusState.message)
+ ? (
+ <div className='flex bg-[#FEF3F2] px-[10px] py-3 text-xs text-[#D92D20]'>
+ <RiErrorWarningFill className='mr-2 mt-[1px] h-[14px] w-[14px]' />
+ {validatedStatusState.message}
+ </div>
+ )
+ : (
+ <div className='flex items-center justify-center bg-gray-50 py-3 text-xs text-gray-500'>
+ <Lock01 className='mr-1 h-3 w-3 text-gray-500' />
+ {t('common.modelProvider.encrypted.front')}
+ <a
+ className='mx-1 text-primary-600'
+ target='_blank' rel='noopener noreferrer'
+ href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
+ >
+ PKCS1_OAEP
+ </a>
+ {t('common.modelProvider.encrypted.back')}
+ </div>
+ )
+ }
+ </div>
+ </div>
+ {
+ showConfirm && (
+ <Confirm
+ title={t('common.modelProvider.confirmDelete')}
+ isShow={showConfirm}
+ onCancel={() => setShowConfirm(false)}
+ onConfirm={handleRemove}
+ />
+ )
+ }
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default memo(ModelLoadBalancingEntryModal)
diff --git a/app/components/header/account-setting/model-provider-page/model-name/index.tsx b/app/components/header/account-setting/model-provider-page/model-name/index.tsx
new file mode 100644
index 0000000..f88c751
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-name/index.tsx
@@ -0,0 +1,84 @@
+import type { FC, PropsWithChildren } from 'react'
+import {
+ modelTypeFormat,
+ sizeFormat,
+} from '../utils'
+import { useLanguage } from '../hooks'
+import type { ModelItem } from '../declarations'
+import ModelBadge from '../model-badge'
+import FeatureIcon from '../model-selector/feature-icon'
+import cn from '@/utils/classnames'
+
+type ModelNameProps = PropsWithChildren<{
+ modelItem: ModelItem
+ className?: string
+ showModelType?: boolean
+ modelTypeClassName?: string
+ showMode?: boolean
+ modeClassName?: string
+ showFeatures?: boolean
+ featuresClassName?: string
+ showContextSize?: boolean
+}>
+const ModelName: FC<ModelNameProps> = ({
+ modelItem,
+ className,
+ showModelType,
+ modelTypeClassName,
+ showMode,
+ modeClassName,
+ showFeatures,
+ featuresClassName,
+ showContextSize,
+ children,
+}) => {
+ const language = useLanguage()
+
+ if (!modelItem)
+ return null
+ return (
+ <div className={cn('system-sm-regular flex items-center gap-0.5 overflow-hidden truncate text-ellipsis text-components-input-text-filled', className)}>
+ <div
+ className='truncate'
+ title={modelItem.label[language] || modelItem.label.en_US}
+ >
+ {modelItem.label[language] || modelItem.label.en_US}
+ </div>
+ <div className='flex items-center gap-0.5'>
+ {
+ showModelType && modelItem.model_type && (
+ <ModelBadge className={modelTypeClassName}>
+ {modelTypeFormat(modelItem.model_type)}
+ </ModelBadge>
+ )
+ }
+ {
+ modelItem.model_properties.mode && showMode && (
+ <ModelBadge className={modeClassName}>
+ {(modelItem.model_properties.mode as string).toLocaleUpperCase()}
+ </ModelBadge>
+ )
+ }
+ {
+ showFeatures && modelItem.features?.map(feature => (
+ <FeatureIcon
+ key={feature}
+ feature={feature}
+ className={featuresClassName}
+ />
+ ))
+ }
+ {
+ showContextSize && modelItem.model_properties.context_size && (
+ <ModelBadge>
+ {sizeFormat(modelItem.model_properties.context_size as number)}
+ </ModelBadge>
+ )
+ }
+ </div>
+ {children}
+ </div>
+ )
+}
+
+export default ModelName
diff --git a/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx b/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx
new file mode 100644
index 0000000..f9ab2e3
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx
@@ -0,0 +1,154 @@
+import type { FC } from 'react'
+import { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import type {
+ ModelItem,
+ ModelProvider,
+} from '../declarations'
+import {
+ CustomConfigurationStatusEnum,
+ ModelTypeEnum,
+} from '../declarations'
+import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
+import ConfigurationButton from './configuration-button'
+import Loading from '@/app/components/base/loading'
+import {
+ useModelModalHandler,
+ useUpdateModelList,
+ useUpdateModelProviders,
+} from '../hooks'
+import ModelIcon from '../model-icon'
+import ModelDisplay from './model-display'
+import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button'
+import StatusIndicators from './status-indicators'
+import cn from '@/utils/classnames'
+import { useProviderContext } from '@/context/provider-context'
+import { RiEqualizer2Line } from '@remixicon/react'
+import { useModelInList, usePluginInfo } from '@/service/use-plugins'
+
+export type AgentModelTriggerProps = {
+ open?: boolean
+ disabled?: boolean
+ currentProvider?: ModelProvider
+ currentModel?: ModelItem
+ providerName?: string
+ modelId?: string
+ hasDeprecated?: boolean
+ scope?: string
+}
+
+const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
+ disabled,
+ currentProvider,
+ currentModel,
+ providerName,
+ modelId,
+ hasDeprecated,
+ scope,
+}) => {
+ const { t } = useTranslation()
+ const { modelProviders } = useProviderContext()
+ const updateModelProviders = useUpdateModelProviders()
+ const updateModelList = useUpdateModelList()
+ const { modelProvider, needsConfiguration } = useMemo(() => {
+ const modelProvider = modelProviders.find(item => item.provider === providerName)
+ const needsConfiguration = modelProvider?.custom_configuration.status === CustomConfigurationStatusEnum.noConfigure && !(
+ modelProvider.system_configuration.enabled === true
+ && modelProvider.system_configuration.quota_configurations.find(
+ item => item.quota_type === modelProvider.system_configuration.current_quota_type,
+ )
+ )
+ return {
+ modelProvider,
+ needsConfiguration,
+ }
+ }, [modelProviders, providerName])
+ const [installed, setInstalled] = useState(false)
+ const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
+ const handleOpenModal = useModelModalHandler()
+
+ const { data: inModelList = false } = useModelInList(currentProvider, modelId)
+ const { data: pluginInfo, isLoading: isPluginLoading } = usePluginInfo(providerName)
+
+ if (modelId && isPluginLoading)
+ return <Loading />
+
+ return (
+ <div
+ className={cn(
+ 'group relative flex grow cursor-pointer items-center gap-[2px] rounded-lg bg-components-input-bg-normal p-1 hover:bg-state-base-hover-alt',
+ )}
+ >
+ {modelId ? (
+ <>
+ <ModelIcon
+ className='p-0.5'
+ provider={currentProvider || modelProvider}
+ modelName={currentModel?.model || modelId}
+ isDeprecated={hasDeprecated}
+ />
+ <ModelDisplay
+ currentModel={currentModel}
+ modelId={modelId}
+ />
+ {needsConfiguration && (
+ <ConfigurationButton
+ modelProvider={modelProvider}
+ handleOpenModal={handleOpenModal}
+ />
+ )}
+ <StatusIndicators
+ needsConfiguration={needsConfiguration}
+ modelProvider={!!modelProvider}
+ inModelList={inModelList}
+ disabled={!!disabled}
+ pluginInfo={pluginInfo}
+ t={t}
+ />
+ {!installed && !modelProvider && pluginInfo && (
+ <InstallPluginButton
+ onClick={e => e.stopPropagation()}
+ size={'small'}
+ uniqueIdentifier={pluginInfo.latest_package_identifier}
+ onSuccess={() => {
+ [
+ ModelTypeEnum.textGeneration,
+ ModelTypeEnum.textEmbedding,
+ ModelTypeEnum.rerank,
+ ModelTypeEnum.moderation,
+ ModelTypeEnum.speech2text,
+ ModelTypeEnum.tts,
+ ].forEach((type: ModelTypeEnum) => {
+ if (scope?.includes(type))
+ updateModelList(type)
+ },
+ )
+ updateModelProviders()
+ invalidateInstalledPluginList()
+ setInstalled(true)
+ }}
+ />
+ )}
+ {modelProvider && !disabled && !needsConfiguration && (
+ <div className="flex items-center pr-1">
+ <RiEqualizer2Line className="h-4 w-4 text-text-tertiary group-hover:text-text-secondary" />
+ </div>
+ )}
+ </>
+ ) : (
+ <>
+ <div className="flex grow items-center gap-1 p-1 pl-2">
+ <span className="system-sm-regular overflow-hidden text-ellipsis whitespace-nowrap text-components-input-text-placeholder">
+ {t('workflow.nodes.agent.configureModel')}
+ </span>
+ </div>
+ <div className="flex items-center pr-1">
+ <RiEqualizer2Line className="h-4 w-4 text-text-tertiary group-hover:text-text-secondary" />
+ </div>
+ </>
+ )}
+ </div>
+ )
+}
+
+export default AgentModelTrigger
diff --git a/app/components/header/account-setting/model-provider-page/model-parameter-modal/configuration-button.tsx b/app/components/header/account-setting/model-provider-page/model-parameter-modal/configuration-button.tsx
new file mode 100644
index 0000000..4dcc045
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-parameter-modal/configuration-button.tsx
@@ -0,0 +1,32 @@
+import Button from '@/app/components/base/button'
+import { ConfigurationMethodEnum } from '../declarations'
+import { useTranslation } from 'react-i18next'
+
+type ConfigurationButtonProps = {
+ modelProvider: any
+ handleOpenModal: any
+}
+
+const ConfigurationButton = ({ modelProvider, handleOpenModal }: ConfigurationButtonProps) => {
+ const { t } = useTranslation()
+ return (
+ <Button
+ size="small"
+ className="z-[100]"
+ onClick={(e) => {
+ e.stopPropagation()
+ handleOpenModal(modelProvider, ConfigurationMethodEnum.predefinedModel, undefined)
+ }}
+ >
+ <div className="flex items-center justify-center gap-1 px-[3px]">
+ {t('workflow.nodes.agent.notAuthorized')}
+ </div>
+ <div className="flex h-[14px] w-[14px] items-center justify-center">
+ <div className="h-2 w-2 shrink-0 rounded-[3px] border border-components-badge-status-light-warning-border-inner
+ bg-components-badge-status-light-warning-bg shadow-components-badge-status-light-warning-halo" />
+ </div>
+ </Button>
+ )
+}
+
+export default ConfigurationButton
diff --git a/app/components/header/account-setting/model-provider-page/model-parameter-modal/index.tsx b/app/components/header/account-setting/model-provider-page/model-parameter-modal/index.tsx
new file mode 100644
index 0000000..dd441dd
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-parameter-modal/index.tsx
@@ -0,0 +1,267 @@
+import type {
+ FC,
+ ReactNode,
+} from 'react'
+import { useMemo, useState } from 'react'
+import useSWR from 'swr'
+import { useTranslation } from 'react-i18next'
+import type {
+ DefaultModel,
+ FormValue,
+ ModelParameterRule,
+} from '../declarations'
+import { ModelStatusEnum } from '../declarations'
+import ModelSelector from '../model-selector'
+import {
+ useTextGenerationCurrentProviderAndModelAndModelList,
+} from '../hooks'
+import ParameterItem from './parameter-item'
+import type { ParameterValue } from './parameter-item'
+import Trigger from './trigger'
+import type { TriggerProps } from './trigger'
+import PresetsParameter from './presets-parameter'
+import cn from '@/utils/classnames'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import { fetchModelParameterRules } from '@/service/common'
+import Loading from '@/app/components/base/loading'
+import { useProviderContext } from '@/context/provider-context'
+import { TONE_LIST } from '@/config'
+import { ArrowNarrowLeft } from '@/app/components/base/icons/src/vender/line/arrows'
+
+export type ModelParameterModalProps = {
+ popupClassName?: string
+ portalToFollowElemContentClassName?: string
+ isAdvancedMode: boolean
+ mode: string
+ modelId: string
+ provider: string
+ setModel: (model: { modelId: string; provider: string; mode?: string; features?: string[] }) => void
+ completionParams: FormValue
+ onCompletionParamsChange: (newParams: FormValue) => void
+ hideDebugWithMultipleModel?: boolean
+ debugWithMultipleModel?: boolean
+ onDebugWithMultipleModelChange?: () => void
+ renderTrigger?: (v: TriggerProps) => ReactNode
+ readonly?: boolean
+ isInWorkflow?: boolean
+ scope?: string
+}
+const stopParameterRule: ModelParameterRule = {
+ default: [],
+ help: {
+ en_US: 'Up to four sequences where the API聽will stop generating further tokens. The聽returned text will not contain the stop聽sequence.',
+ zh_Hans: '鏈�澶氬洓涓簭鍒楋紝API 灏嗗仠姝㈢敓鎴愭洿澶氱殑 token銆傝繑鍥炵殑鏂囨湰灏嗕笉鍖呭惈鍋滄搴忓垪銆�',
+ },
+ label: {
+ en_US: 'Stop sequences',
+ zh_Hans: '鍋滄搴忓垪',
+ },
+ name: 'stop',
+ required: false,
+ type: 'tag',
+ tagPlaceholder: {
+ en_US: 'Enter sequence and press Tab',
+ zh_Hans: '杈撳叆搴忓垪骞舵寜 Tab 閿�',
+ },
+}
+
+const PROVIDER_WITH_PRESET_TONE = ['langgenius/openai/openai', 'langgenius/azure_openai/azure_openai']
+const ModelParameterModal: FC<ModelParameterModalProps> = ({
+ popupClassName,
+ portalToFollowElemContentClassName,
+ isAdvancedMode,
+ modelId,
+ provider,
+ setModel,
+ completionParams,
+ onCompletionParamsChange,
+ hideDebugWithMultipleModel,
+ debugWithMultipleModel,
+ onDebugWithMultipleModelChange,
+ renderTrigger,
+ readonly,
+ isInWorkflow,
+}) => {
+ const { t } = useTranslation()
+ const { isAPIKeySet } = useProviderContext()
+ const [open, setOpen] = useState(false)
+ const { data: parameterRulesData, isLoading } = useSWR((provider && modelId) ? `/workspaces/current/model-providers/${provider}/models/parameter-rules?model=${modelId}` : null, fetchModelParameterRules)
+ const {
+ currentProvider,
+ currentModel,
+ activeTextGenerationModelList,
+ } = useTextGenerationCurrentProviderAndModelAndModelList(
+ { provider, model: modelId },
+ )
+
+ const hasDeprecated = !currentProvider || !currentModel
+ const modelDisabled = currentModel?.status !== ModelStatusEnum.active
+ const disabled = !isAPIKeySet || hasDeprecated || modelDisabled
+
+ const parameterRules: ModelParameterRule[] = useMemo(() => {
+ return parameterRulesData?.data || []
+ }, [parameterRulesData])
+
+ const handleParamChange = (key: string, value: ParameterValue) => {
+ onCompletionParamsChange({
+ ...completionParams,
+ [key]: value,
+ })
+ }
+
+ const handleChangeModel = ({ provider, model }: DefaultModel) => {
+ const targetProvider = activeTextGenerationModelList.find(modelItem => modelItem.provider === provider)
+ const targetModelItem = targetProvider?.models.find(modelItem => modelItem.model === model)
+ setModel({
+ modelId: model,
+ provider,
+ mode: targetModelItem?.model_properties.mode as string,
+ features: targetModelItem?.features || [],
+ })
+ }
+
+ const handleSwitch = (key: string, value: boolean, assignValue: ParameterValue) => {
+ if (!value) {
+ const newCompletionParams = { ...completionParams }
+ delete newCompletionParams[key]
+
+ onCompletionParamsChange(newCompletionParams)
+ }
+ if (value) {
+ onCompletionParamsChange({
+ ...completionParams,
+ [key]: assignValue,
+ })
+ }
+ }
+
+ const handleSelectPresetParameter = (toneId: number) => {
+ const tone = TONE_LIST.find(tone => tone.id === toneId)
+ if (tone) {
+ onCompletionParamsChange({
+ ...completionParams,
+ ...tone.config,
+ })
+ }
+ }
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement={isInWorkflow ? 'left' : 'bottom-end'}
+ offset={4}
+ >
+ <div className='relative'>
+ <PortalToFollowElemTrigger
+ onClick={() => {
+ if (readonly)
+ return
+ setOpen(v => !v)
+ }}
+ className='block'
+ >
+ {
+ renderTrigger
+ ? renderTrigger({
+ open,
+ disabled,
+ modelDisabled,
+ hasDeprecated,
+ currentProvider,
+ currentModel,
+ providerName: provider,
+ modelId,
+ })
+ : (
+ <Trigger
+ disabled={disabled}
+ isInWorkflow={isInWorkflow}
+ modelDisabled={modelDisabled}
+ hasDeprecated={hasDeprecated}
+ currentProvider={currentProvider}
+ currentModel={currentModel}
+ providerName={provider}
+ modelId={modelId}
+ />
+ )
+ }
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className={cn('z-[60]', portalToFollowElemContentClassName)}>
+ <div className={cn(popupClassName, 'w-[389px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg')}>
+ <div className={cn('max-h-[420px] overflow-y-auto p-4 pt-3')}>
+ <div className='relative'>
+ <div className={cn('system-sm-semibold mb-1 flex h-6 items-center text-text-secondary')}>
+ {t('common.modelProvider.model').toLocaleUpperCase()}
+ </div>
+ <ModelSelector
+ defaultModel={(provider || modelId) ? { provider, model: modelId } : undefined}
+ modelList={activeTextGenerationModelList}
+ onSelect={handleChangeModel}
+ />
+ </div>
+ {
+ !!parameterRules.length && (
+ <div className='my-3 h-[1px] bg-divider-subtle' />
+ )
+ }
+ {
+ isLoading && (
+ <div className='mt-5'><Loading /></div>
+ )
+ }
+ {
+ !isLoading && !!parameterRules.length && (
+ <div className='mb-2 flex items-center justify-between'>
+ <div className={cn('system-sm-semibold flex h-6 items-center text-text-secondary')}>{t('common.modelProvider.parameters')}</div>
+ {
+ PROVIDER_WITH_PRESET_TONE.includes(provider) && (
+ <PresetsParameter onSelect={handleSelectPresetParameter} />
+ )
+ }
+ </div>
+ )
+ }
+ {
+ !isLoading && !!parameterRules.length && (
+ [
+ ...parameterRules,
+ ...(isAdvancedMode ? [stopParameterRule] : []),
+ ].map(parameter => (
+ <ParameterItem
+ key={`${modelId}-${parameter.name}`}
+ parameterRule={parameter}
+ value={completionParams?.[parameter.name]}
+ onChange={v => handleParamChange(parameter.name, v)}
+ onSwitch={(checked, assignValue) => handleSwitch(parameter.name, checked, assignValue)}
+ isInWorkflow={isInWorkflow}
+ />
+ ))
+ )
+ }
+ </div>
+ {!hideDebugWithMultipleModel && (
+ <div
+ className='bg-components-section-burn system-sm-regular flex h-[50px] cursor-pointer items-center justify-between rounded-b-xl border-t border-t-divider-subtle px-4 text-text-accent'
+ onClick={() => onDebugWithMultipleModelChange?.()}
+ >
+ {
+ debugWithMultipleModel
+ ? t('appDebug.debugAsSingleModel')
+ : t('appDebug.debugAsMultipleModel')
+ }
+ <ArrowNarrowLeft className='h-3 w-3 rotate-180' />
+ </div>
+ )}
+ </div>
+ </PortalToFollowElemContent>
+ </div>
+ </PortalToFollowElem>
+ )
+}
+
+export default ModelParameterModal
diff --git a/app/components/header/account-setting/model-provider-page/model-parameter-modal/model-display.tsx b/app/components/header/account-setting/model-provider-page/model-parameter-modal/model-display.tsx
new file mode 100644
index 0000000..e9e8ec7
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-parameter-modal/model-display.tsx
@@ -0,0 +1,25 @@
+import ModelName from '../model-name'
+
+type ModelDisplayProps = {
+ currentModel: any
+ modelId: string
+}
+
+const ModelDisplay = ({ currentModel, modelId }: ModelDisplayProps) => {
+ return currentModel ? (
+ <ModelName
+ className="flex grow items-center gap-1 px-1 py-[3px]"
+ modelItem={currentModel}
+ showMode
+ showFeatures
+ />
+ ) : (
+ <div className="flex grow items-center gap-1 truncate px-1 py-[3px] opacity-50">
+ <div className="system-sm-regular overflow-hidden text-ellipsis text-components-input-text-filled">
+ {modelId}
+ </div>
+ </div>
+ )
+}
+
+export default ModelDisplay
diff --git a/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx b/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx
new file mode 100644
index 0000000..3e969d7
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx
@@ -0,0 +1,295 @@
+import type { FC } from 'react'
+import { useEffect, useRef, useState } from 'react'
+import type { ModelParameterRule } from '../declarations'
+import { useLanguage } from '../hooks'
+import { isNullOrUndefined } from '../utils'
+import cn from '@/utils/classnames'
+import Switch from '@/app/components/base/switch'
+import Tooltip from '@/app/components/base/tooltip'
+import Slider from '@/app/components/base/slider'
+import Radio from '@/app/components/base/radio'
+import { SimpleSelect } from '@/app/components/base/select'
+import TagInput from '@/app/components/base/tag-input'
+import { useTranslation } from 'react-i18next'
+
+export type ParameterValue = number | string | string[] | boolean | undefined
+
+type ParameterItemProps = {
+ parameterRule: ModelParameterRule
+ value?: ParameterValue
+ onChange?: (value: ParameterValue) => void
+ onSwitch?: (checked: boolean, assignValue: ParameterValue) => void
+ isInWorkflow?: boolean
+}
+const ParameterItem: FC<ParameterItemProps> = ({
+ parameterRule,
+ value,
+ onChange,
+ onSwitch,
+ isInWorkflow,
+}) => {
+ const { t } = useTranslation()
+ const language = useLanguage()
+ const [localValue, setLocalValue] = useState(value)
+ const numberInputRef = useRef<HTMLInputElement>(null)
+
+ const getDefaultValue = () => {
+ let defaultValue: ParameterValue
+
+ if (parameterRule.type === 'int' || parameterRule.type === 'float')
+ defaultValue = isNullOrUndefined(parameterRule.default) ? (parameterRule.min || 0) : parameterRule.default
+ else if (parameterRule.type === 'string' || parameterRule.type === 'text')
+ defaultValue = parameterRule.default || ''
+ else if (parameterRule.type === 'boolean')
+ defaultValue = !isNullOrUndefined(parameterRule.default) ? parameterRule.default : false
+ else if (parameterRule.type === 'tag')
+ defaultValue = !isNullOrUndefined(parameterRule.default) ? parameterRule.default : []
+
+ return defaultValue
+ }
+
+ const renderValue = value ?? localValue ?? getDefaultValue()
+
+ const handleInputChange = (newValue: ParameterValue) => {
+ setLocalValue(newValue)
+
+ if (onChange && (parameterRule.name === 'stop' || !isNullOrUndefined(value) || parameterRule.required))
+ onChange(newValue)
+ }
+
+ const handleNumberInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ let num = +e.target.value
+
+ if (!isNullOrUndefined(parameterRule.max) && num > parameterRule.max!) {
+ num = parameterRule.max as number
+ numberInputRef.current!.value = `${num}`
+ }
+
+ if (!isNullOrUndefined(parameterRule.min) && num < parameterRule.min!)
+ num = parameterRule.min as number
+
+ handleInputChange(num)
+ }
+
+ const handleNumberInputBlur = () => {
+ if (numberInputRef.current)
+ numberInputRef.current.value = renderValue as string
+ }
+
+ const handleSlideChange = (num: number) => {
+ if (!isNullOrUndefined(parameterRule.max) && num > parameterRule.max!) {
+ handleInputChange(parameterRule.max)
+ numberInputRef.current!.value = `${parameterRule.max}`
+ return
+ }
+
+ if (!isNullOrUndefined(parameterRule.min) && num < parameterRule.min!) {
+ handleInputChange(parameterRule.min)
+ numberInputRef.current!.value = `${parameterRule.min}`
+ return
+ }
+
+ handleInputChange(num)
+ numberInputRef.current!.value = `${num}`
+ }
+
+ const handleRadioChange = (v: number) => {
+ handleInputChange(v === 1)
+ }
+
+ const handleStringInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
+ handleInputChange(e.target.value)
+ }
+
+ const handleSelect = (option: { value: string | number; name: string }) => {
+ handleInputChange(option.value)
+ }
+
+ const handleTagChange = (newSequences: string[]) => {
+ handleInputChange(newSequences)
+ }
+
+ const handleSwitch = (checked: boolean) => {
+ if (onSwitch) {
+ const assignValue: ParameterValue = localValue || getDefaultValue()
+
+ onSwitch(checked, assignValue)
+ }
+ }
+
+ useEffect(() => {
+ if ((parameterRule.type === 'int' || parameterRule.type === 'float') && numberInputRef.current)
+ numberInputRef.current.value = `${renderValue}`
+ }, [value])
+
+ const renderInput = () => {
+ const numberInputWithSlide = (parameterRule.type === 'int' || parameterRule.type === 'float')
+ && !isNullOrUndefined(parameterRule.min)
+ && !isNullOrUndefined(parameterRule.max)
+
+ if (parameterRule.type === 'int') {
+ let step = 100
+ if (parameterRule.max) {
+ if (parameterRule.max < 100)
+ step = 1
+ else if (parameterRule.max < 1000)
+ step = 10
+ }
+
+ return (
+ <>
+ {numberInputWithSlide && <Slider
+ className='w-[120px]'
+ value={renderValue as number}
+ min={parameterRule.min}
+ max={parameterRule.max}
+ step={step}
+ onChange={handleSlideChange}
+ />}
+ <input
+ ref={numberInputRef}
+ className='system-sm-regular ml-4 block h-8 w-16 shrink-0 appearance-none rounded-lg bg-components-input-bg-normal pl-3 text-components-input-text-filled outline-none'
+ type='number'
+ max={parameterRule.max}
+ min={parameterRule.min}
+ step={numberInputWithSlide ? step : +`0.${parameterRule.precision || 0}`}
+ onChange={handleNumberInputChange}
+ onBlur={handleNumberInputBlur}
+ />
+ </>
+ )
+ }
+
+ if (parameterRule.type === 'float') {
+ return (
+ <>
+ {numberInputWithSlide && <Slider
+ className='w-[120px]'
+ value={renderValue as number}
+ min={parameterRule.min}
+ max={parameterRule.max}
+ step={0.1}
+ onChange={handleSlideChange}
+ />}
+ <input
+ ref={numberInputRef}
+ className='system-sm-regular ml-4 block h-8 w-16 shrink-0 appearance-none rounded-lg bg-components-input-bg-normal pl-3 text-components-input-text-filled outline-none'
+ type='number'
+ max={parameterRule.max}
+ min={parameterRule.min}
+ step={numberInputWithSlide ? 0.1 : +`0.${parameterRule.precision || 0}`}
+ onChange={handleNumberInputChange}
+ onBlur={handleNumberInputBlur}
+ />
+ </>
+ )
+ }
+
+ if (parameterRule.type === 'boolean') {
+ return (
+ <Radio.Group
+ className='flex w-[178px] items-center'
+ value={renderValue ? 1 : 0}
+ onChange={handleRadioChange}
+ >
+ <Radio value={1} className='w-[83px]'>True</Radio>
+ <Radio value={0} className='w-[83px]'>False</Radio>
+ </Radio.Group>
+ )
+ }
+
+ if (parameterRule.type === 'string' && !parameterRule.options?.length) {
+ return (
+ <input
+ className={cn(isInWorkflow ? 'w-[178px]' : 'w-full', 'system-sm-regular ml-4 flex h-8 appearance-none items-center rounded-lg bg-components-input-bg-normal px-3 text-components-input-text-filled outline-none')}
+ value={renderValue as string}
+ onChange={handleStringInputChange}
+ />
+ )
+ }
+
+ if (parameterRule.type === 'text') {
+ return (
+ <textarea
+ className='system-sm-regular ml-4 h-20 w-full rounded-lg bg-components-input-bg-normal px-1 text-components-input-text-filled'
+ value={renderValue as string}
+ onChange={handleStringInputChange}
+ />
+ )
+ }
+
+ if (parameterRule.type === 'string' && !!parameterRule?.options?.length) {
+ return (
+ <SimpleSelect
+ className='!py-0'
+ wrapperClassName={cn('!h-8 w-full')}
+ defaultValue={renderValue as string}
+ onSelect={handleSelect}
+ items={parameterRule.options.map(option => ({ value: option, name: option }))}
+ />
+ )
+ }
+
+ if (parameterRule.type === 'tag') {
+ return (
+ <div className={cn('!h-8 w-full')}>
+ <TagInput
+ items={renderValue as string[]}
+ onChange={handleTagChange}
+ customizedConfirmKey='Tab'
+ isInWorkflow={isInWorkflow}
+ />
+ </div>
+ )
+ }
+
+ return null
+ }
+
+ return (
+ <div className='mb-2 flex items-center justify-between'>
+ <div className='shrink-0 basis-1/2'>
+ <div className={cn('flex w-full shrink-0 items-center')}>
+ {
+ !parameterRule.required && parameterRule.name !== 'stop' && (
+ <div className='mr-2 w-7'>
+ <Switch
+ defaultValue={!isNullOrUndefined(value)}
+ onChange={handleSwitch}
+ size='md'
+ />
+ </div>
+ )
+ }
+ <div
+ className='system-xs-regular mr-0.5 truncate text-text-secondary'
+ title={parameterRule.label[language] || parameterRule.label.en_US}
+ >
+ {parameterRule.label[language] || parameterRule.label.en_US}
+ </div>
+ {
+ parameterRule.help && (
+ <Tooltip
+ popupContent={(
+ <div className='w-[178px] whitespace-pre-wrap'>{parameterRule.help[language] || parameterRule.help.en_US}</div>
+ )}
+ popupClassName='mr-1'
+ triggerClassName='mr-1 w-4 h-4 shrink-0'
+ />
+ )
+ }
+ </div>
+ {
+ parameterRule.type === 'tag' && (
+ <div className={cn(!isInWorkflow && 'w-[178px]', 'system-xs-regular text-text-tertiary')}>
+ {parameterRule?.tagPlaceholder?.[language]}
+ </div>
+ )
+ }
+ </div>
+ {renderInput()}
+ </div>
+ )
+}
+
+export default ParameterItem
diff --git a/app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter.tsx b/app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter.tsx
new file mode 100644
index 0000000..20a9bdc
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter.tsx
@@ -0,0 +1,63 @@
+import type { FC } from 'react'
+import { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowDownSLine } from '@remixicon/react'
+import Button from '@/app/components/base/button'
+import Dropdown from '@/app/components/base/dropdown'
+import { Brush01 } from '@/app/components/base/icons/src/vender/solid/editor'
+import { Scales02 } from '@/app/components/base/icons/src/vender/solid/FinanceAndECommerce'
+import { Target04 } from '@/app/components/base/icons/src/vender/solid/general'
+import { TONE_LIST } from '@/config'
+import cn from '@/utils/classnames'
+
+type PresetsParameterProps = {
+ onSelect: (toneId: number) => void
+}
+const PresetsParameter: FC<PresetsParameterProps> = ({
+ onSelect,
+}) => {
+ const { t } = useTranslation()
+ const renderTrigger = useCallback((open: boolean) => {
+ return (
+ <Button
+ size={'small'}
+ variant={'secondary'}
+ className={cn(open && 'bg-state-base-hover')}
+ >
+ {t('common.modelProvider.loadPresets')}
+ <RiArrowDownSLine className='ml-0.5 h-3.5 w-3.5' />
+ </Button>
+ )
+ }, [t])
+ const getToneIcon = (toneId: number) => {
+ const className = 'mr-2 w-[14px] h-[14px]'
+ const res = ({
+ 1: <Brush01 className={`${className} text-[#6938EF]`} />,
+ 2: <Scales02 className={`${className} text-indigo-600`} />,
+ 3: <Target04 className={`${className} text-[#107569]`} />,
+ })[toneId]
+ return res
+ }
+ const options = TONE_LIST.slice(0, 3).map((tone) => {
+ return {
+ value: tone.id,
+ text: (
+ <div className='flex h-full items-center'>
+ {getToneIcon(tone.id)}
+ {t(`common.model.tone.${tone.name}`) as string}
+ </div>
+ ),
+ }
+ })
+
+ return (
+ <Dropdown
+ renderTrigger={renderTrigger}
+ items={options}
+ onSelect={item => onSelect(item.value as number)}
+ popupClassName='z-[1003]'
+ />
+ )
+}
+
+export default PresetsParameter
diff --git a/app/components/header/account-setting/model-provider-page/model-parameter-modal/status-indicators.tsx b/app/components/header/account-setting/model-provider-page/model-parameter-modal/status-indicators.tsx
new file mode 100644
index 0000000..02b8cb2
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-parameter-modal/status-indicators.tsx
@@ -0,0 +1,99 @@
+import Tooltip from '@/app/components/base/tooltip'
+import Link from 'next/link'
+import { SwitchPluginVersion } from '@/app/components/workflow/nodes/_base/components/switch-plugin-version'
+import { useInstalledPluginList } from '@/service/use-plugins'
+import { RiErrorWarningFill } from '@remixicon/react'
+
+type StatusIndicatorsProps = {
+ needsConfiguration: boolean
+ modelProvider: boolean
+ inModelList: boolean
+ disabled: boolean
+ pluginInfo: any
+ t: any
+}
+
+const StatusIndicators = ({ needsConfiguration, modelProvider, inModelList, disabled, pluginInfo, t }: StatusIndicatorsProps) => {
+ const { data: pluginList } = useInstalledPluginList()
+ const renderTooltipContent = (title: string, description?: string, linkText?: string, linkHref?: string) => {
+ return (
+ <div className='flex w-[240px] max-w-[240px] flex-col gap-1 px-1 py-1.5' onClick={e => e.stopPropagation()}>
+ <div className='title-xs-semi-bold text-text-primary'>{title}</div>
+ {description && (
+ <div className='body-xs-regular min-w-[200px] text-text-secondary'>
+ {description}
+ </div>
+ )}
+ {linkText && linkHref && (
+ <div className='body-xs-regular z-[100] cursor-pointer text-text-accent'>
+ <Link
+ href={linkHref}
+ onClick={(e) => {
+ e.stopPropagation()
+ }}
+ >
+ {linkText}
+ </Link>
+ </div>
+ )}
+ </div>
+ )
+ }
+ // const installedPluginUniqueIdentifier = pluginList?.plugins.find(plugin => plugin.name === pluginInfo.name)?.plugin_unique_identifier
+ return (
+ <>
+ {/* plugin installed and model is in model list but disabled */}
+ {/* plugin installed from github/local and model is not in model list */}
+ {!needsConfiguration && modelProvider && disabled && (
+ <>
+ {inModelList ? (
+ <Tooltip
+ popupContent={t('workflow.nodes.agent.modelSelectorTooltips.deprecated')}
+ asChild={false}
+ needsDelay={false}
+ >
+ <RiErrorWarningFill className='h-4 w-4 text-text-destructive' />
+ </Tooltip>
+ ) : !pluginInfo ? (
+ <Tooltip
+ popupContent={renderTooltipContent(
+ t('workflow.nodes.agent.modelNotSupport.title'),
+ t('workflow.nodes.agent.modelNotSupport.desc'),
+ t('workflow.nodes.agent.linkToPlugin'),
+ '/plugins',
+ )}
+ asChild={false}
+ needsDelay={true}
+ >
+ <RiErrorWarningFill className='h-4 w-4 text-text-destructive' />
+ </Tooltip>
+ ) : (
+ <SwitchPluginVersion
+ tooltip={renderTooltipContent(
+ t('workflow.nodes.agent.modelNotSupport.title'),
+ t('workflow.nodes.agent.modelNotSupport.descForVersionSwitch'),
+ )}
+ uniqueIdentifier={pluginList?.plugins.find(plugin => plugin.name === pluginInfo.name)?.plugin_unique_identifier ?? ''}
+ />
+ )}
+ </>
+ )}
+ {!modelProvider && !pluginInfo && (
+ <Tooltip
+ popupContent={renderTooltipContent(
+ t('workflow.nodes.agent.modelNotInMarketplace.title'),
+ t('workflow.nodes.agent.modelNotInMarketplace.desc'),
+ t('workflow.nodes.agent.linkToPlugin'),
+ '/plugins',
+ )}
+ asChild={false}
+ needsDelay
+ >
+ <RiErrorWarningFill className='h-4 w-4 text-text-destructive' />
+ </Tooltip>
+ )}
+ </>
+ )
+}
+
+export default StatusIndicators
diff --git a/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger.tsx b/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger.tsx
new file mode 100644
index 0000000..7c96c9a
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger.tsx
@@ -0,0 +1,112 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiArrowDownSLine } from '@remixicon/react'
+import type {
+ Model,
+ ModelItem,
+ ModelProvider,
+} from '../declarations'
+import { MODEL_STATUS_TEXT } from '../declarations'
+import { useLanguage } from '../hooks'
+import ModelIcon from '../model-icon'
+import ModelName from '../model-name'
+import cn from '@/utils/classnames'
+import { useProviderContext } from '@/context/provider-context'
+import { SlidersH } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
+import Tooltip from '@/app/components/base/tooltip'
+
+export type TriggerProps = {
+ open?: boolean
+ disabled?: boolean
+ currentProvider?: ModelProvider | Model
+ currentModel?: ModelItem
+ providerName?: string
+ modelId?: string
+ hasDeprecated?: boolean
+ modelDisabled?: boolean
+ isInWorkflow?: boolean
+}
+const Trigger: FC<TriggerProps> = ({
+ disabled,
+ currentProvider,
+ currentModel,
+ providerName,
+ modelId,
+ hasDeprecated,
+ modelDisabled,
+ isInWorkflow,
+}) => {
+ const { t } = useTranslation()
+ const language = useLanguage()
+ const { modelProviders } = useProviderContext()
+
+ return (
+ <div
+ className={cn(
+ 'relative flex h-8 cursor-pointer items-center rounded-lg px-2',
+ !isInWorkflow && 'border ring-inset hover:ring-[0.5px]',
+ !isInWorkflow && (disabled ? 'border-text-warning bg-state-warning-hover ring-text-warning' : 'border-util-colors-indigo-indigo-600 bg-state-accent-hover ring-util-colors-indigo-indigo-600'),
+ isInWorkflow && 'border border-workflow-block-parma-bg bg-workflow-block-parma-bg pr-[30px] hover:border-components-input-border-active',
+ )}
+ >
+ {
+ currentProvider && (
+ <ModelIcon
+ className='mr-1.5 !h-5 !w-5'
+ provider={currentProvider}
+ modelName={currentModel?.model}
+ />
+ )
+ }
+ {
+ !currentProvider && (
+ <ModelIcon
+ className='mr-1.5 !h-5 !w-5'
+ provider={modelProviders.find(item => item.provider === providerName)}
+ modelName={modelId}
+ />
+ )
+ }
+ {
+ currentModel && (
+ <ModelName
+ className='mr-1.5 text-text-primary'
+ modelItem={currentModel}
+ showMode
+ showFeatures
+ />
+ )
+ }
+ {
+ !currentModel && (
+ <div className='mr-1 truncate text-[13px] font-medium text-text-primary'>
+ {modelId}
+ </div>
+ )
+ }
+ {
+ disabled
+ ? (
+ <Tooltip
+ popupContent={
+ hasDeprecated
+ ? t('common.modelProvider.deprecated')
+ : (modelDisabled && currentModel)
+ ? MODEL_STATUS_TEXT[currentModel.status as string][language]
+ : ''
+ }
+ >
+ <AlertTriangle className='h-4 w-4 text-[#F79009]' />
+ </Tooltip>
+ )
+ : (
+ <SlidersH className={cn(!isInWorkflow ? 'text-indigo-600' : 'text-text-tertiary', 'h-4 w-4 shrink-0')} />
+ )
+ }
+ {isInWorkflow && (<RiArrowDownSLine className='absolute right-2 top-[9px] h-3.5 w-3.5 text-text-tertiary' />)}
+ </div>
+ )
+}
+
+export default Trigger
diff --git a/app/components/header/account-setting/model-provider-page/model-selector/deprecated-model-trigger.tsx b/app/components/header/account-setting/model-provider-page/model-selector/deprecated-model-trigger.tsx
new file mode 100644
index 0000000..0b01635
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-selector/deprecated-model-trigger.tsx
@@ -0,0 +1,54 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import ModelIcon from '../model-icon'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
+import { useProviderContext } from '@/context/provider-context'
+import Tooltip from '@/app/components/base/tooltip'
+import cn from '@/utils/classnames'
+
+type ModelTriggerProps = {
+ modelName: string
+ providerName: string
+ className?: string
+ showWarnIcon?: boolean
+ contentClassName?: string
+}
+const ModelTrigger: FC<ModelTriggerProps> = ({
+ modelName,
+ providerName,
+ className,
+ showWarnIcon,
+ contentClassName,
+}) => {
+ const { t } = useTranslation()
+ const { modelProviders } = useProviderContext()
+ const currentProvider = modelProviders.find(provider => provider.provider === providerName)
+
+ return (
+ <div
+ className={cn('group box-content flex h-8 grow cursor-pointer items-center gap-1 rounded-lg bg-components-input-bg-disabled p-[3px] pl-1', className)}
+ >
+ <div className={cn('flex w-full items-center', contentClassName)}>
+ <div className='flex min-w-0 flex-1 items-center gap-1 py-[1px]'>
+ <ModelIcon
+ className="h-4 w-4"
+ provider={currentProvider}
+ modelName={modelName}
+ />
+ <div className='system-sm-regular truncate text-components-input-text-filled'>
+ {modelName}
+ </div>
+ </div>
+ <div className='flex shrink-0 items-center justify-center'>
+ {showWarnIcon && (
+ <Tooltip popupContent={t('common.modelProvider.deprecated')}>
+ <AlertTriangle className='h-4 w-4 text-text-warning-secondary' />
+ </Tooltip>
+ )}
+ </div>
+ </div>
+ </div>
+ )
+}
+
+export default ModelTrigger
diff --git a/app/components/header/account-setting/model-provider-page/model-selector/empty-trigger.tsx b/app/components/header/account-setting/model-provider-page/model-selector/empty-trigger.tsx
new file mode 100644
index 0000000..613b1c0
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-selector/empty-trigger.tsx
@@ -0,0 +1,40 @@
+import type { FC } from 'react'
+import { RiEqualizer2Line } from '@remixicon/react'
+import { CubeOutline } from '@/app/components/base/icons/src/vender/line/shapes'
+import cn from '@/utils/classnames'
+import { useTranslation } from 'react-i18next'
+type ModelTriggerProps = {
+ open: boolean
+ className?: string
+}
+const ModelTrigger: FC<ModelTriggerProps> = ({
+ open,
+ className,
+}) => {
+ const { t } = useTranslation()
+ return (
+ <div
+ className={cn(
+ 'flex cursor-pointer items-center gap-0.5 rounded-lg bg-components-input-bg-normal p-1 hover:bg-components-input-bg-hover', open && 'bg-components-input-bg-hover',
+ className,
+ )}
+ >
+ <div className='flex grow items-center'>
+ <div className='mr-1.5 flex h-4 w-4 items-center justify-center rounded-[5px] border border-dashed border-divider-regular'>
+ <CubeOutline className='h-3 w-3 text-text-quaternary' />
+ </div>
+ <div
+ className='truncate text-[13px] text-text-tertiary'
+ title='Configure model'
+ >
+ {t('plugin.detailPanel.configureModel')}
+ </div>
+ </div>
+ <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
+ <RiEqualizer2Line className='h-3.5 w-3.5 text-text-tertiary' />
+ </div>
+ </div>
+ )
+}
+
+export default ModelTrigger
diff --git a/app/components/header/account-setting/model-provider-page/model-selector/feature-icon.tsx b/app/components/header/account-setting/model-provider-page/model-selector/feature-icon.tsx
new file mode 100644
index 0000000..b9422a8
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-selector/feature-icon.tsx
@@ -0,0 +1,124 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import ModelBadge from '../model-badge'
+import {
+ ModelFeatureEnum,
+ ModelFeatureTextEnum,
+} from '../declarations'
+import {
+ AudioSupportIcon,
+ DocumentSupportIcon,
+ // MagicBox,
+ MagicEyes,
+ // MagicWand,
+ // Robot,
+ VideoSupportIcon,
+} from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
+import Tooltip from '@/app/components/base/tooltip'
+
+type FeatureIconProps = {
+ feature: ModelFeatureEnum
+ className?: string
+}
+const FeatureIcon: FC<FeatureIconProps> = ({
+ className,
+ feature,
+}) => {
+ const { t } = useTranslation()
+
+ // if (feature === ModelFeatureEnum.agentThought) {
+ // return (
+ // <Tooltip
+ // popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.agentThought })}
+ // >
+ // <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}>
+ // <Robot className='w-3 h-3' />
+ // </ModelBadge>
+ // </Tooltip>
+ // )
+ // }
+
+ // if (feature === ModelFeatureEnum.toolCall) {
+ // return (
+ // <Tooltip
+ // popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.toolCall })}
+ // >
+ // <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}>
+ // <MagicWand className='w-3 h-3' />
+ // </ModelBadge>
+ // </Tooltip>
+ // )
+ // }
+
+ // if (feature === ModelFeatureEnum.multiToolCall) {
+ // return (
+ // <Tooltip
+ // popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.multiToolCall })}
+ // >
+ // <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}>
+ // <MagicBox className='w-3 h-3' />
+ // </ModelBadge>
+ // </Tooltip>
+ // )
+ // }
+
+ if (feature === ModelFeatureEnum.vision) {
+ return (
+ <Tooltip
+ popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.vision })}
+ >
+ <div className='inline-block cursor-help'>
+ <ModelBadge className={`w-[18px] justify-center !px-0 text-text-tertiary ${className}`}>
+ <MagicEyes className='h-3 w-3' />
+ </ModelBadge>
+ </div>
+ </Tooltip>
+ )
+ }
+
+ if (feature === ModelFeatureEnum.document) {
+ return (
+ <Tooltip
+ popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.document })}
+ >
+ <div className='inline-block cursor-help'>
+ <ModelBadge className={`w-[18px] justify-center !px-0 text-text-tertiary ${className}`}>
+ <DocumentSupportIcon className='h-3 w-3' />
+ </ModelBadge>
+ </div>
+ </Tooltip>
+ )
+ }
+
+ if (feature === ModelFeatureEnum.audio) {
+ return (
+ <Tooltip
+ popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.audio })}
+ >
+ <div className='inline-block cursor-help'>
+ <ModelBadge className={`w-[18px] justify-center !px-0 text-text-tertiary ${className}`}>
+ <AudioSupportIcon className='h-3 w-3' />
+ </ModelBadge>
+ </div>
+ </Tooltip>
+ )
+ }
+
+ if (feature === ModelFeatureEnum.video) {
+ return (
+ <Tooltip
+ popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.video })}
+ >
+ <div className='inline-block cursor-help'>
+ <ModelBadge className={`w-[18px] justify-center !px-0 text-text-tertiary ${className}`}>
+ <VideoSupportIcon className='h-3 w-3' />
+ </ModelBadge>
+ </div>
+ </Tooltip>
+ )
+ }
+
+ return null
+}
+
+export default FeatureIcon
diff --git a/app/components/header/account-setting/model-provider-page/model-selector/index.tsx b/app/components/header/account-setting/model-provider-page/model-selector/index.tsx
new file mode 100644
index 0000000..d28959a
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-selector/index.tsx
@@ -0,0 +1,122 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import type {
+ DefaultModel,
+ Model,
+ ModelItem,
+} from '../declarations'
+import { useCurrentProviderAndModel } from '../hooks'
+import ModelTrigger from './model-trigger'
+import EmptyTrigger from './empty-trigger'
+import DeprecatedModelTrigger from './deprecated-model-trigger'
+import Popup from './popup'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import classNames from '@/utils/classnames'
+
+type ModelSelectorProps = {
+ defaultModel?: DefaultModel
+ modelList: Model[]
+ triggerClassName?: string
+ popupClassName?: string
+ onSelect?: (model: DefaultModel) => void
+ readonly?: boolean
+ scopeFeatures?: string[]
+ deprecatedClassName?: string
+ showDeprecatedWarnIcon?: boolean
+}
+const ModelSelector: FC<ModelSelectorProps> = ({
+ defaultModel,
+ modelList,
+ triggerClassName,
+ popupClassName,
+ onSelect,
+ readonly,
+ scopeFeatures = [],
+ deprecatedClassName,
+ showDeprecatedWarnIcon = false,
+}) => {
+ const [open, setOpen] = useState(false)
+ const {
+ currentProvider,
+ currentModel,
+ } = useCurrentProviderAndModel(
+ modelList,
+ defaultModel,
+ )
+
+ const handleSelect = (provider: string, model: ModelItem) => {
+ setOpen(false)
+
+ if (onSelect)
+ onSelect({ provider, model: model.model })
+ }
+
+ const handleToggle = () => {
+ if (readonly)
+ return
+
+ setOpen(v => !v)
+ }
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-start'
+ offset={4}
+ >
+ <div className={classNames('relative')}>
+ <PortalToFollowElemTrigger
+ onClick={handleToggle}
+ className='block'
+ >
+ {
+ currentModel && currentProvider && (
+ <ModelTrigger
+ open={open}
+ provider={currentProvider}
+ model={currentModel}
+ className={triggerClassName}
+ readonly={readonly}
+ />
+ )
+ }
+ {
+ !currentModel && defaultModel && (
+ <DeprecatedModelTrigger
+ modelName={defaultModel?.model || ''}
+ providerName={defaultModel?.provider || ''}
+ className={triggerClassName}
+ showWarnIcon={showDeprecatedWarnIcon}
+ contentClassName={deprecatedClassName}
+ />
+ )
+ }
+ {
+ !defaultModel && (
+ <EmptyTrigger
+ open={open}
+ className={triggerClassName}
+ />
+ )
+ }
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className={`z-[1002] ${popupClassName}`}>
+ <Popup
+ defaultModel={defaultModel}
+ modelList={modelList}
+ onSelect={handleSelect}
+ scopeFeatures={scopeFeatures}
+ onHide={() => setOpen(false)}
+ />
+ </PortalToFollowElemContent>
+ </div>
+ </PortalToFollowElem>
+ )
+}
+
+export default ModelSelector
diff --git a/app/components/header/account-setting/model-provider-page/model-selector/model-trigger.tsx b/app/components/header/account-setting/model-provider-page/model-selector/model-trigger.tsx
new file mode 100644
index 0000000..079bad7
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-selector/model-trigger.tsx
@@ -0,0 +1,78 @@
+import type { FC } from 'react'
+import { RiArrowDownSLine } from '@remixicon/react'
+import type {
+ Model,
+ ModelItem,
+} from '../declarations'
+import {
+ MODEL_STATUS_TEXT,
+ ModelStatusEnum,
+} from '../declarations'
+import { useLanguage } from '../hooks'
+import ModelIcon from '../model-icon'
+import ModelName from '../model-name'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
+import Tooltip from '@/app/components/base/tooltip'
+import cn from '@/utils/classnames'
+
+type ModelTriggerProps = {
+ open: boolean
+ provider: Model
+ model: ModelItem
+ className?: string
+ readonly?: boolean
+}
+const ModelTrigger: FC<ModelTriggerProps> = ({
+ open,
+ provider,
+ model,
+ className,
+ readonly,
+}) => {
+ const language = useLanguage()
+
+ return (
+ <div
+ className={cn(
+ 'group flex h-8 items-center gap-0.5 rounded-lg bg-components-input-bg-normal p-1',
+ !readonly && 'cursor-pointer hover:bg-components-input-bg-hover',
+ open && 'bg-components-input-bg-hover',
+ model.status !== ModelStatusEnum.active && 'bg-components-input-bg-disabled hover:bg-components-input-bg-disabled',
+ className,
+ )}
+ >
+ <ModelIcon
+ className='p-0.5'
+ provider={provider}
+ modelName={model.model}
+ />
+ <div className='flex grow items-center gap-1 truncate px-1 py-[3px]'>
+ <ModelName
+ className='grow'
+ modelItem={model}
+ showMode
+ showFeatures
+ />
+ {!readonly && (
+ <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
+ {
+ model.status !== ModelStatusEnum.active
+ ? (
+ <Tooltip popupContent={MODEL_STATUS_TEXT[model.status][language]}>
+ <AlertTriangle className='h-4 w-4 text-text-warning-secondary' />
+ </Tooltip>
+ )
+ : (
+ <RiArrowDownSLine
+ className='h-3.5 w-3.5 text-text-tertiary'
+ />
+ )
+ }
+ </div>
+ )}
+ </div>
+ </div>
+ )
+}
+
+export default ModelTrigger
diff --git a/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx b/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx
new file mode 100644
index 0000000..e536817
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx
@@ -0,0 +1,195 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiFileTextLine,
+ RiFilmAiLine,
+ RiImageCircleAiLine,
+ RiVoiceAiFill,
+} from '@remixicon/react'
+import type {
+ DefaultModel,
+ Model,
+ ModelItem,
+} from '../declarations'
+import {
+ ModelFeatureEnum,
+ ModelFeatureTextEnum,
+ ModelTypeEnum,
+} from '../declarations'
+import {
+ modelTypeFormat,
+ sizeFormat,
+} from '../utils'
+import {
+ useLanguage,
+ useUpdateModelList,
+ useUpdateModelProviders,
+} from '../hooks'
+import ModelIcon from '../model-icon'
+import ModelName from '../model-name'
+import ModelBadge from '../model-badge'
+import {
+ ConfigurationMethodEnum,
+ ModelStatusEnum,
+} from '../declarations'
+import { Check } from '@/app/components/base/icons/src/vender/line/general'
+import { useModalContext } from '@/context/modal-context'
+import { useProviderContext } from '@/context/provider-context'
+import Tooltip from '@/app/components/base/tooltip'
+import cn from '@/utils/classnames'
+
+type PopupItemProps = {
+ defaultModel?: DefaultModel
+ model: Model
+ onSelect: (provider: string, model: ModelItem) => void
+}
+const PopupItem: FC<PopupItemProps> = ({
+ defaultModel,
+ model,
+ onSelect,
+}) => {
+ const { t } = useTranslation()
+ const language = useLanguage()
+ const { setShowModelModal } = useModalContext()
+ const { modelProviders } = useProviderContext()
+ const updateModelList = useUpdateModelList()
+ const updateModelProviders = useUpdateModelProviders()
+ const currentProvider = modelProviders.find(provider => provider.provider === model.provider)!
+ const handleSelect = (provider: string, modelItem: ModelItem) => {
+ if (modelItem.status !== ModelStatusEnum.active)
+ return
+
+ onSelect(provider, modelItem)
+ }
+ const handleOpenModelModal = () => {
+ setShowModelModal({
+ payload: {
+ currentProvider,
+ currentConfigurationMethod: ConfigurationMethodEnum.predefinedModel,
+ },
+ onSaveCallback: () => {
+ updateModelProviders()
+
+ const modelType = model.models[0].model_type
+
+ if (modelType)
+ updateModelList(modelType)
+ },
+ })
+ }
+
+ return (
+ <div className='mb-1'>
+ <div className='flex h-[22px] items-center px-3 text-xs font-medium text-text-tertiary'>
+ {model.label[language] || model.label.en_US}
+ </div>
+ {
+ model.models.map(modelItem => (
+ <Tooltip
+ key={modelItem.model}
+ position='right'
+ popupClassName='p-3 !w-[206px] bg-components-panel-bg-blur backdrop-blur-sm border-[0.5px] border-components-panel-border rounded-xl'
+ popupContent={
+ <div className='flex flex-col gap-1'>
+ <div className='flex flex-col items-start gap-2'>
+ <ModelIcon
+ className={cn('h-5 w-5 shrink-0')}
+ provider={model}
+ modelName={modelItem.model}
+ />
+ <div className='system-md-medium text-wrap break-words text-text-primary'>{modelItem.label[language] || modelItem.label.en_US}</div>
+ </div>
+ {/* {currentProvider?.description && (
+ <div className='text-text-tertiary system-xs-regular'>{currentProvider?.description?.[language] || currentProvider?.description?.en_US}</div>
+ )} */}
+ <div className='flex flex-wrap gap-1'>
+ {modelItem.model_type && (
+ <ModelBadge>
+ {modelTypeFormat(modelItem.model_type)}
+ </ModelBadge>
+ )}
+ {modelItem.model_properties.mode && (
+ <ModelBadge>
+ {(modelItem.model_properties.mode as string).toLocaleUpperCase()}
+ </ModelBadge>
+ )}
+ {modelItem.model_properties.context_size && (
+ <ModelBadge>
+ {sizeFormat(modelItem.model_properties.context_size as number)}
+ </ModelBadge>
+ )}
+ </div>
+ {modelItem.model_type === ModelTypeEnum.textGeneration && modelItem.features?.some(feature => [ModelFeatureEnum.vision, ModelFeatureEnum.audio, ModelFeatureEnum.video, ModelFeatureEnum.document].includes(feature)) && (
+ <div className='pt-2'>
+ <div className='system-2xs-medium-uppercase mb-1 text-text-tertiary'>{t('common.model.capabilities')}</div>
+ <div className='flex flex-wrap gap-1'>
+ {modelItem.features?.includes(ModelFeatureEnum.vision) && (
+ <ModelBadge>
+ <RiImageCircleAiLine className='mr-0.5 h-3.5 w-3.5' />
+ <span>{ModelFeatureTextEnum.vision}</span>
+ </ModelBadge>
+ )}
+ {modelItem.features?.includes(ModelFeatureEnum.audio) && (
+ <ModelBadge>
+ <RiVoiceAiFill className='mr-0.5 h-3.5 w-3.5' />
+ <span>{ModelFeatureTextEnum.audio}</span>
+ </ModelBadge>
+ )}
+ {modelItem.features?.includes(ModelFeatureEnum.video) && (
+ <ModelBadge>
+ <RiFilmAiLine className='mr-0.5 h-3.5 w-3.5' />
+ <span>{ModelFeatureTextEnum.video}</span>
+ </ModelBadge>
+ )}
+ {modelItem.features?.includes(ModelFeatureEnum.document) && (
+ <ModelBadge>
+ <RiFileTextLine className='mr-0.5 h-3.5 w-3.5' />
+ <span>{ModelFeatureTextEnum.document}</span>
+ </ModelBadge>
+ )}
+ </div>
+ </div>
+ )}
+ </div>
+ }
+ >
+ <div
+ key={modelItem.model}
+ className={cn('group relative flex h-8 items-center gap-1 rounded-lg px-3 py-1.5', modelItem.status === ModelStatusEnum.active ? 'cursor-pointer hover:bg-state-base-hover' : 'cursor-not-allowed hover:bg-state-base-hover-alt')}
+ onClick={() => handleSelect(model.provider, modelItem)}
+ >
+ <div className='flex items-center gap-2'>
+ <ModelIcon
+ className={cn('h-5 w-5 shrink-0')}
+ provider={model}
+ modelName={modelItem.model}
+ />
+ <ModelName
+ className={cn('system-sm-medium text-text-secondary', modelItem.status !== ModelStatusEnum.active && 'opacity-60')}
+ modelItem={modelItem}
+ />
+ </div>
+ {
+ defaultModel?.model === modelItem.model && defaultModel.provider === currentProvider.provider && (
+ <Check className='h-4 w-4 shrink-0 text-text-accent' />
+ )
+ }
+ {
+ modelItem.status === ModelStatusEnum.noConfigure && (
+ <div
+ className='hidden cursor-pointer text-xs font-medium text-text-accent group-hover:block'
+ onClick={handleOpenModelModal}
+ >
+ {t('common.operation.add').toLocaleUpperCase()}
+ </div>
+ )
+ }
+ </div>
+ </Tooltip>
+ ))
+ }
+ </div>
+ )
+}
+
+export default PopupItem
diff --git a/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx b/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx
new file mode 100644
index 0000000..63849bd
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx
@@ -0,0 +1,121 @@
+import type { FC } from 'react'
+import { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiArrowRightUpLine,
+ RiSearchLine,
+} from '@remixicon/react'
+import type {
+ DefaultModel,
+ Model,
+ ModelItem,
+} from '../declarations'
+import { ModelFeatureEnum } from '../declarations'
+import { useLanguage } from '../hooks'
+import PopupItem from './popup-item'
+import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
+import { useModalContext } from '@/context/modal-context'
+import { supportFunctionCall } from '@/utils/tool-call'
+
+type PopupProps = {
+ defaultModel?: DefaultModel
+ modelList: Model[]
+ onSelect: (provider: string, model: ModelItem) => void
+ scopeFeatures?: string[]
+ onHide: () => void
+}
+const Popup: FC<PopupProps> = ({
+ defaultModel,
+ modelList,
+ onSelect,
+ scopeFeatures = [],
+ onHide,
+}) => {
+ const { t } = useTranslation()
+ const language = useLanguage()
+ const [searchText, setSearchText] = useState('')
+ const { setShowAccountSettingModal } = useModalContext()
+
+ const filteredModelList = useMemo(() => {
+ return modelList.map((model) => {
+ const filteredModels = model.models
+ .filter((modelItem) => {
+ if (modelItem.label[language] !== undefined)
+ return modelItem.label[language].toLowerCase().includes(searchText.toLowerCase())
+ return Object.values(modelItem.label).some(label =>
+ label.toLowerCase().includes(searchText.toLowerCase()),
+ )
+ })
+ .filter((modelItem) => {
+ if (scopeFeatures.length === 0)
+ return true
+ return scopeFeatures.every((feature) => {
+ if (feature === ModelFeatureEnum.toolCall)
+ return supportFunctionCall(modelItem.features)
+ return modelItem.features?.some(featureItem => featureItem === feature)
+ })
+ })
+ return { ...model, models: filteredModels }
+ }).filter(model => model.models.length > 0)
+ }, [language, modelList, scopeFeatures, searchText])
+
+ return (
+ <div className='max-h-[480px] w-[320px] overflow-y-auto rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg'>
+ <div className='sticky top-0 z-10 bg-components-panel-bg pb-1 pl-3 pr-2 pt-3'>
+ <div className={`
+ flex h-8 items-center rounded-lg border pl-[9px] pr-[10px]
+ ${searchText ? 'border-components-input-border-active bg-components-input-bg-active shadow-xs' : 'border-transparent bg-components-input-bg-normal'}
+ `}>
+ <RiSearchLine
+ className={`
+ mr-[7px] h-[14px] w-[14px] shrink-0
+ ${searchText ? 'text-text-tertiary' : 'text-text-quaternary'}
+ `}
+ />
+ <input
+ className='block h-[18px] grow appearance-none bg-transparent text-[13px] text-text-primary outline-none'
+ placeholder={t('datasetSettings.form.searchModel') || ''}
+ value={searchText}
+ onChange={e => setSearchText(e.target.value)}
+ />
+ {
+ searchText && (
+ <XCircle
+ className='ml-1.5 h-[14px] w-[14px] shrink-0 cursor-pointer text-text-quaternary'
+ onClick={() => setSearchText('')}
+ />
+ )
+ }
+ </div>
+ </div>
+ <div className='p-1'>
+ {
+ filteredModelList.map(model => (
+ <PopupItem
+ key={model.provider}
+ defaultModel={defaultModel}
+ model={model}
+ onSelect={onSelect}
+ />
+ ))
+ }
+ {
+ !filteredModelList.length && (
+ <div className='break-all px-3 py-1.5 text-center text-xs leading-[18px] text-text-tertiary'>
+ {`No model found for 鈥�${searchText}鈥漙}
+ </div>
+ )
+ }
+ </div>
+ <div className='sticky bottom-0 flex cursor-pointer items-center rounded-b-lg border-t border-divider-subtle bg-components-panel-bg px-4 py-2 text-text-accent-light-mode-only' onClick={() => {
+ onHide()
+ setShowAccountSettingModal({ payload: 'provider' })
+ }}>
+ <span className='system-xs-medium'>{t('common.model.settingsLink')}</span>
+ <RiArrowRightUpLine className='ml-0.5 h-3 w-3' />
+ </div>
+ </div>
+ )
+}
+
+export default Popup
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/add-model-button.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/add-model-button.tsx
new file mode 100644
index 0000000..fc9960f
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/add-model-button.tsx
@@ -0,0 +1,27 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { PlusCircle } from '@/app/components/base/icons/src/vender/solid/general'
+import cn from '@/utils/classnames'
+
+type AddModelButtonProps = {
+ className?: string
+ onClick: () => void
+}
+const AddModelButton: FC<AddModelButtonProps> = ({
+ className,
+ onClick,
+}) => {
+ const { t } = useTranslation()
+
+ return (
+ <span
+ className={cn('system-xs-medium flex h-6 shrink-0 cursor-pointer items-center rounded-md px-1.5 text-text-tertiary hover:bg-components-button-ghost-bg-hover hover:text-components-button-ghost-text', className)}
+ onClick={onClick}
+ >
+ <PlusCircle className='mr-1 h-3 w-3' />
+ {t('common.modelProvider.addModel')}
+ </span>
+ )
+}
+
+export default AddModelButton
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/cooldown-timer.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/cooldown-timer.tsx
new file mode 100644
index 0000000..dea3200
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/cooldown-timer.tsx
@@ -0,0 +1,64 @@
+import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useLatest } from 'ahooks'
+import SimplePieChart from '@/app/components/base/simple-pie-chart'
+import Tooltip from '@/app/components/base/tooltip'
+
+export type CooldownTimerProps = {
+ secondsRemaining?: number
+ onFinish?: () => void
+}
+
+const CooldownTimer = ({ secondsRemaining, onFinish }: CooldownTimerProps) => {
+ const { t } = useTranslation()
+
+ const targetTime = useRef<number>(Date.now())
+ const [currentTime, setCurrentTime] = useState(targetTime.current)
+ const displayTime = useMemo(
+ () => Math.ceil((targetTime.current - currentTime) / 1000),
+ [currentTime],
+ )
+
+ const countdownTimeout = useRef<number>(undefined)
+ const clearCountdown = useCallback(() => {
+ if (countdownTimeout.current) {
+ window.clearTimeout(countdownTimeout.current)
+ countdownTimeout.current = undefined
+ }
+ }, [])
+
+ const onFinishRef = useLatest(onFinish)
+
+ const countdown = useCallback(() => {
+ clearCountdown()
+ countdownTimeout.current = window.setTimeout(() => {
+ const now = Date.now()
+ if (now <= targetTime.current) {
+ setCurrentTime(Date.now())
+ countdown()
+ }
+ else {
+ onFinishRef.current?.()
+ clearCountdown()
+ }
+ }, 1000)
+ }, [clearCountdown, onFinishRef])
+
+ useEffect(() => {
+ const now = Date.now()
+ targetTime.current = now + (secondsRemaining ?? 0) * 1000
+ setCurrentTime(now)
+ countdown()
+ return clearCountdown
+ }, [clearCountdown, countdown, secondsRemaining])
+
+ return displayTime
+ ? (
+ <Tooltip popupContent={t('common.modelProvider.apiKeyRateLimit', { seconds: displayTime })}>
+ <SimplePieChart percentage={Math.round(displayTime / 60 * 100)} className='h-3 w-3' />
+ </Tooltip>
+ )
+ : null
+}
+
+export default memo(CooldownTimer)
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx
new file mode 100644
index 0000000..822df5f
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx
@@ -0,0 +1,114 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiEqualizer2Line } from '@remixicon/react'
+import type { ModelProvider } from '../declarations'
+import {
+ ConfigurationMethodEnum,
+ CustomConfigurationStatusEnum,
+ PreferredProviderTypeEnum,
+} from '../declarations'
+import {
+ useUpdateModelList,
+ useUpdateModelProviders,
+} from '../hooks'
+import PrioritySelector from './priority-selector'
+import PriorityUseTip from './priority-use-tip'
+import { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './index'
+import Indicator from '@/app/components/header/indicator'
+import Button from '@/app/components/base/button'
+import { changeModelProviderPriority } from '@/service/common'
+import { useToastContext } from '@/app/components/base/toast'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+
+type CredentialPanelProps = {
+ provider: ModelProvider
+ onSetup: () => void
+}
+const CredentialPanel: FC<CredentialPanelProps> = ({
+ provider,
+ onSetup,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const { eventEmitter } = useEventEmitterContextContext()
+ const updateModelList = useUpdateModelList()
+ const updateModelProviders = useUpdateModelProviders()
+ const customConfig = provider.custom_configuration
+ const systemConfig = provider.system_configuration
+ const priorityUseType = provider.preferred_provider_type
+ const isCustomConfigured = customConfig.status === CustomConfigurationStatusEnum.active
+ const configurateMethods = provider.configurate_methods
+
+ const handleChangePriority = async (key: PreferredProviderTypeEnum) => {
+ const res = await changeModelProviderPriority({
+ url: `/workspaces/current/model-providers/${provider.provider}/preferred-provider-type`,
+ body: {
+ preferred_provider_type: key,
+ },
+ })
+ if (res.result === 'success') {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ updateModelProviders()
+
+ configurateMethods.forEach((method) => {
+ if (method === ConfigurationMethodEnum.predefinedModel)
+ provider.supported_model_types.forEach(modelType => updateModelList(modelType))
+ })
+
+ eventEmitter?.emit({
+ type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST,
+ payload: provider.provider,
+ } as any)
+ }
+ }
+
+ return (
+ <>
+ {
+ provider.provider_credential_schema && (
+ <div className='relative ml-1 w-[112px] shrink-0 rounded-lg border-[0.5px] border-components-panel-border bg-white/[0.18] p-1'>
+ <div className='system-xs-medium-uppercase mb-1 flex h-5 items-center justify-between pl-2 pr-[7px] pt-1 text-text-tertiary'>
+ API-KEY
+ <Indicator color={isCustomConfigured ? 'green' : 'red'} />
+ </div>
+ <div className='flex items-center gap-0.5'>
+ <Button
+ className='grow'
+ size='small'
+ onClick={onSetup}
+ >
+ <RiEqualizer2Line className='mr-1 h-3.5 w-3.5' />
+ {t('common.operation.setup')}
+ </Button>
+ {
+ systemConfig.enabled && isCustomConfigured && (
+ <PrioritySelector
+ value={priorityUseType}
+ onSelect={handleChangePriority}
+ />
+ )
+ }
+ </div>
+ {
+ priorityUseType === PreferredProviderTypeEnum.custom && systemConfig.enabled && (
+ <PriorityUseTip />
+ )
+ }
+ </div>
+ )
+ }
+ {
+ systemConfig.enabled && isCustomConfigured && !provider.provider_credential_schema && (
+ <div className='ml-1'>
+ <PrioritySelector
+ value={priorityUseType}
+ onSelect={handleChangePriority}
+ />
+ </div>
+ )
+ }
+ </>
+ )
+}
+
+export default CredentialPanel
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/index.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/index.tsx
new file mode 100644
index 0000000..2ff9669
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/index.tsx
@@ -0,0 +1,186 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiArrowRightSLine,
+ RiInformation2Fill,
+ RiLoader2Line,
+} from '@remixicon/react'
+import type {
+ CustomConfigurationModelFixedFields,
+ ModelItem,
+ ModelProvider,
+} from '../declarations'
+import { ConfigurationMethodEnum } from '../declarations'
+import {
+ MODEL_PROVIDER_QUOTA_GET_PAID,
+ modelTypeFormat,
+} from '../utils'
+import ProviderIcon from '../provider-icon'
+import ModelBadge from '../model-badge'
+import CredentialPanel from './credential-panel'
+import QuotaPanel from './quota-panel'
+import ModelList from './model-list'
+import AddModelButton from './add-model-button'
+import { fetchModelProviderModelList } from '@/service/common'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
+import { IS_CE_EDITION } from '@/config'
+import { useAppContext } from '@/context/app-context'
+import cn from '@/utils/classnames'
+
+export const UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST = 'UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST'
+type ProviderAddedCardProps = {
+ notConfigured?: boolean
+ provider: ModelProvider
+ onOpenModal: (configurationMethod: ConfigurationMethodEnum, currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void
+}
+const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
+ notConfigured,
+ provider,
+ onOpenModal,
+}) => {
+ const { t } = useTranslation()
+ const { eventEmitter } = useEventEmitterContextContext()
+ const [fetched, setFetched] = useState(false)
+ const [loading, setLoading] = useState(false)
+ const [collapsed, setCollapsed] = useState(true)
+ const [modelList, setModelList] = useState<ModelItem[]>([])
+ const configurationMethods = provider.configurate_methods.filter(method => method !== ConfigurationMethodEnum.fetchFromRemote)
+ const systemConfig = provider.system_configuration
+ const hasModelList = fetched && !!modelList.length
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const showQuota = systemConfig.enabled && [...MODEL_PROVIDER_QUOTA_GET_PAID].includes(provider.provider) && !IS_CE_EDITION
+ const showCredential = configurationMethods.includes(ConfigurationMethodEnum.predefinedModel) && isCurrentWorkspaceManager
+
+ const getModelList = async (providerName: string) => {
+ if (loading)
+ return
+ try {
+ setLoading(true)
+ const modelsData = await fetchModelProviderModelList(`/workspaces/current/model-providers/${providerName}/models`)
+ setModelList(modelsData.data)
+ setCollapsed(false)
+ setFetched(true)
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+ const handleOpenModelList = () => {
+ if (fetched) {
+ setCollapsed(false)
+ return
+ }
+
+ getModelList(provider.provider)
+ }
+
+ eventEmitter?.useSubscription((v: any) => {
+ if (v?.type === UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST && v.payload === provider.provider)
+ getModelList(v.payload)
+ })
+
+ return (
+ <div
+ className={cn(
+ 'mb-2 rounded-xl border-[0.5px] border-divider-regular bg-third-party-model-bg-default shadow-xs',
+ provider.provider === 'langgenius/openai/openai' && 'bg-third-party-model-bg-openai',
+ provider.provider === 'langgenius/anthropic/anthropic' && 'bg-third-party-model-bg-anthropic',
+ )}
+ >
+ <div className='flex rounded-t-xl py-2 pl-3 pr-2'>
+ <div className='grow px-1 pb-0.5 pt-1'>
+ <ProviderIcon
+ className='mb-2'
+ provider={provider}
+ />
+ <div className='flex gap-0.5'>
+ {
+ provider.supported_model_types.map(modelType => (
+ <ModelBadge key={modelType}>
+ {modelTypeFormat(modelType)}
+ </ModelBadge>
+ ))
+ }
+ </div>
+ </div>
+ {
+ showQuota && (
+ <QuotaPanel
+ provider={provider}
+ />
+ )
+ }
+ {
+ showCredential && (
+ <CredentialPanel
+ onSetup={() => onOpenModal(ConfigurationMethodEnum.predefinedModel)}
+ provider={provider}
+ />
+ )
+ }
+ </div>
+ {
+ collapsed && (
+ <div className='system-xs-medium group flex items-center justify-between border-t border-t-divider-subtle py-1.5 pl-2 pr-[11px] text-text-tertiary'>
+ {(showQuota || !notConfigured) && (
+ <>
+ <div className='flex h-6 items-center pl-1 pr-1.5 leading-6 group-hover:hidden'>
+ {
+ hasModelList
+ ? t('common.modelProvider.modelsNum', { num: modelList.length })
+ : t('common.modelProvider.showModels')
+ }
+ {!loading && <RiArrowRightSLine className='h-4 w-4' />}
+ </div>
+ <div
+ className='hidden h-6 cursor-pointer items-center rounded-lg pl-1 pr-1.5 hover:bg-components-button-ghost-bg-hover group-hover:flex'
+ onClick={handleOpenModelList}
+ >
+ {
+ hasModelList
+ ? t('common.modelProvider.showModelsNum', { num: modelList.length })
+ : t('common.modelProvider.showModels')
+ }
+ {!loading && <RiArrowRightSLine className='h-4 w-4' />}
+ {
+ loading && (
+ <RiLoader2Line className='ml-0.5 h-3 w-3 animate-spin' />
+ )
+ }
+ </div>
+ </>
+ )}
+ {!showQuota && notConfigured && (
+ <div className='flex h-6 items-center pl-1 pr-1.5'>
+ <RiInformation2Fill className='mr-1 h-4 w-4 text-text-accent' />
+ <span className='system-xs-medium text-text-secondary'>{t('common.modelProvider.configureTip')}</span>
+ </div>
+ )}
+ {
+ configurationMethods.includes(ConfigurationMethodEnum.customizableModel) && isCurrentWorkspaceManager && (
+ <AddModelButton
+ onClick={() => onOpenModal(ConfigurationMethodEnum.customizableModel)}
+ className='flex'
+ />
+ )
+ }
+ </div>
+ )
+ }
+ {
+ !collapsed && (
+ <ModelList
+ provider={provider}
+ models={modelList}
+ onCollapse={() => setCollapsed(true)}
+ onConfig={currentCustomConfigurationModelFixedFields => onOpenModal(ConfigurationMethodEnum.customizableModel, currentCustomConfigurationModelFixedFields)}
+ onChange={(provider: string) => getModelList(provider)}
+ />
+ )
+ }
+ </div>
+ )
+}
+
+export default ProviderAddedCard
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx
new file mode 100644
index 0000000..62ad425
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx
@@ -0,0 +1,128 @@
+import { memo, useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useDebounceFn } from 'ahooks'
+import type { CustomConfigurationModelFixedFields, ModelItem, ModelProvider } from '../declarations'
+import { ConfigurationMethodEnum, ModelStatusEnum } from '../declarations'
+import ModelBadge from '../model-badge'
+import ModelIcon from '../model-icon'
+import ModelName from '../model-name'
+import classNames from '@/utils/classnames'
+import Button from '@/app/components/base/button'
+import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
+import { Settings01 } from '@/app/components/base/icons/src/vender/line/general'
+import Switch from '@/app/components/base/switch'
+import Tooltip from '@/app/components/base/tooltip'
+import { useProviderContext, useProviderContextSelector } from '@/context/provider-context'
+import { disableModel, enableModel } from '@/service/common'
+import { Plan } from '@/app/components/billing/type'
+import { useAppContext } from '@/context/app-context'
+
+export type ModelListItemProps = {
+ model: ModelItem
+ provider: ModelProvider
+ isConfigurable: boolean
+ onConfig: (currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void
+ onModifyLoadBalancing?: (model: ModelItem) => void
+}
+
+const ModelListItem = ({ model, provider, isConfigurable, onConfig, onModifyLoadBalancing }: ModelListItemProps) => {
+ const { t } = useTranslation()
+ const { plan } = useProviderContext()
+ const modelLoadBalancingEnabled = useProviderContextSelector(state => state.modelLoadBalancingEnabled)
+ const { isCurrentWorkspaceManager } = useAppContext()
+
+ const toggleModelEnablingStatus = useCallback(async (enabled: boolean) => {
+ if (enabled)
+ await enableModel(`/workspaces/current/model-providers/${provider.provider}/models/enable`, { model: model.model, model_type: model.model_type })
+ else
+ await disableModel(`/workspaces/current/model-providers/${provider.provider}/models/disable`, { model: model.model, model_type: model.model_type })
+ }, [model.model, model.model_type, provider.provider])
+
+ const { run: debouncedToggleModelEnablingStatus } = useDebounceFn(toggleModelEnablingStatus, { wait: 500 })
+
+ const onEnablingStateChange = useCallback(async (value: boolean) => {
+ debouncedToggleModelEnablingStatus(value)
+ }, [debouncedToggleModelEnablingStatus])
+
+ return (
+ <div
+ key={model.model}
+ className={classNames(
+ 'group flex items-center pl-2 pr-2.5 h-8 rounded-lg',
+ isConfigurable && 'hover:bg-components-panel-on-panel-item-bg-hover',
+ model.deprecated && 'opacity-60',
+ )}
+ >
+ <ModelIcon
+ className='mr-2 shrink-0'
+ provider={provider}
+ modelName={model.model}
+ />
+ <ModelName
+ className='system-md-regular grow text-text-secondary'
+ modelItem={model}
+ showModelType
+ showMode
+ showContextSize
+ >
+ {modelLoadBalancingEnabled && !model.deprecated && model.load_balancing_enabled && (
+ <ModelBadge className='ml-1 border-text-accent-secondary uppercase text-text-accent-secondary'>
+ <Balance className='mr-0.5 h-3 w-3' />
+ {t('common.modelProvider.loadBalancingHeadline')}
+ </ModelBadge>
+ )}
+ </ModelName>
+ <div className='flex shrink-0 items-center'>
+ {
+ model.fetch_from === ConfigurationMethodEnum.customizableModel
+ ? (isCurrentWorkspaceManager && (
+ <Button
+ size='small'
+ className='hidden group-hover:flex'
+ onClick={() => onConfig({ __model_name: model.model, __model_type: model.model_type })}
+ >
+ <Settings01 className='mr-1 h-3.5 w-3.5' />
+ {t('common.modelProvider.config')}
+ </Button>
+ ))
+ : (isCurrentWorkspaceManager && (modelLoadBalancingEnabled || plan.type === Plan.sandbox) && !model.deprecated && [ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status))
+ ? (
+ <Button
+ size='small'
+ className='opacity-0 transition-opacity group-hover:opacity-100'
+ onClick={() => onModifyLoadBalancing?.(model)}
+ >
+ <Balance className='mr-1 h-3.5 w-3.5' />
+ {t('common.modelProvider.configLoadBalancing')}
+ </Button>
+ )
+ : null
+ }
+ {
+ model.deprecated
+ ? (
+ <Tooltip
+ popupContent={
+ <span className='font-semibold'>{t('common.modelProvider.modelHasBeenDeprecated')}</span>} offset={{ mainAxis: 4 }
+ }
+ needsDelay
+ >
+ <Switch defaultValue={false} disabled size='md' />
+ </Tooltip>
+ )
+ : (isCurrentWorkspaceManager && (
+ <Switch
+ className='ml-2'
+ defaultValue={model?.status === ModelStatusEnum.active}
+ disabled={![ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status)}
+ size='md'
+ onChange={onEnablingStateChange}
+ />
+ ))
+ }
+ </div>
+ </div>
+ )
+}
+
+export default memo(ModelListItem)
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/model-list.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/model-list.tsx
new file mode 100644
index 0000000..699be6e
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/model-list.tsx
@@ -0,0 +1,102 @@
+import type { FC } from 'react'
+import { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiArrowRightSLine,
+} from '@remixicon/react'
+import type {
+ CustomConfigurationModelFixedFields,
+ ModelItem,
+ ModelProvider,
+} from '../declarations'
+import {
+ ConfigurationMethodEnum,
+} from '../declarations'
+// import Tab from './tab'
+import AddModelButton from './add-model-button'
+import ModelListItem from './model-list-item'
+import { useModalContextSelector } from '@/context/modal-context'
+import { useAppContext } from '@/context/app-context'
+
+type ModelListProps = {
+ provider: ModelProvider
+ models: ModelItem[]
+ onCollapse: () => void
+ onConfig: (currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void
+ onChange?: (provider: string) => void
+}
+const ModelList: FC<ModelListProps> = ({
+ provider,
+ models,
+ onCollapse,
+ onConfig,
+ onChange,
+}) => {
+ const { t } = useTranslation()
+ const configurativeMethods = provider.configurate_methods.filter(method => method !== ConfigurationMethodEnum.fetchFromRemote)
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const isConfigurable = configurativeMethods.includes(ConfigurationMethodEnum.customizableModel)
+
+ const setShowModelLoadBalancingModal = useModalContextSelector(state => state.setShowModelLoadBalancingModal)
+ const onModifyLoadBalancing = useCallback((model: ModelItem) => {
+ setShowModelLoadBalancingModal({
+ provider,
+ model: model!,
+ open: !!model,
+ onClose: () => setShowModelLoadBalancingModal(null),
+ onSave: onChange,
+ })
+ }, [onChange, provider, setShowModelLoadBalancingModal])
+
+ return (
+ <div className='rounded-b-xl px-2 pb-2'>
+ <div className='rounded-lg bg-components-panel-bg py-1'>
+ <div className='flex items-center pl-1 pr-[3px]'>
+ <span className='group mr-2 flex shrink-0 items-center'>
+ <span className='system-xs-medium inline-flex h-6 items-center pl-1 pr-1.5 text-text-tertiary group-hover:hidden'>
+ {t('common.modelProvider.modelsNum', { num: models.length })}
+ <RiArrowRightSLine className='mr-0.5 h-4 w-4 rotate-90' />
+ </span>
+ <span
+ className='system-xs-medium hidden h-6 cursor-pointer items-center rounded-lg bg-state-base-hover pl-1 pr-1.5 text-text-tertiary group-hover:inline-flex'
+ onClick={() => onCollapse()}
+ >
+ {t('common.modelProvider.modelsNum', { num: models.length })}
+ <RiArrowRightSLine className='mr-0.5 h-4 w-4 rotate-90' />
+ </span>
+ </span>
+ {/* {
+ isConfigurable && canSystemConfig && (
+ <span className='flex items-center'>
+ <Tab active='all' onSelect={() => {}} />
+ </span>
+ )
+ } */}
+ {
+ isConfigurable && isCurrentWorkspaceManager && (
+ <div className='flex grow justify-end'>
+ <AddModelButton onClick={() => onConfig()} />
+ </div>
+ )
+ }
+ </div>
+ {
+ models.map(model => (
+ <ModelListItem
+ key={model.model}
+ {...{
+ model,
+ provider,
+ isConfigurable,
+ onConfig,
+ onModifyLoadBalancing,
+ }}
+ />
+ ))
+ }
+ </div>
+ </div>
+ )
+}
+
+export default ModelList
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx
new file mode 100644
index 0000000..f63eef4
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx
@@ -0,0 +1,274 @@
+import type { Dispatch, SetStateAction } from 'react'
+import { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiDeleteBinLine,
+} from '@remixicon/react'
+import type { ConfigurationMethodEnum, CustomConfigurationModelFixedFields, ModelLoadBalancingConfig, ModelLoadBalancingConfigEntry, ModelProvider } from '../declarations'
+import Indicator from '../../../indicator'
+import CooldownTimer from './cooldown-timer'
+import classNames from '@/utils/classnames'
+import Tooltip from '@/app/components/base/tooltip'
+import Switch from '@/app/components/base/switch'
+import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
+import { Edit02, Plus02 } from '@/app/components/base/icons/src/vender/line/general'
+import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
+import { useModalContextSelector } from '@/context/modal-context'
+import UpgradeBtn from '@/app/components/billing/upgrade-btn'
+import s from '@/app/components/custom/style.module.css'
+import GridMask from '@/app/components/base/grid-mask'
+import { useProviderContextSelector } from '@/context/provider-context'
+import { IS_CE_EDITION } from '@/config'
+
+export type ModelLoadBalancingConfigsProps = {
+ draftConfig?: ModelLoadBalancingConfig
+ setDraftConfig: Dispatch<SetStateAction<ModelLoadBalancingConfig | undefined>>
+ provider: ModelProvider
+ configurationMethod: ConfigurationMethodEnum
+ currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
+ withSwitch?: boolean
+ className?: string
+}
+
+const ModelLoadBalancingConfigs = ({
+ draftConfig,
+ setDraftConfig,
+ provider,
+ configurationMethod,
+ currentCustomConfigurationModelFixedFields,
+ withSwitch = false,
+ className,
+}: ModelLoadBalancingConfigsProps) => {
+ const { t } = useTranslation()
+ const modelLoadBalancingEnabled = useProviderContextSelector(state => state.modelLoadBalancingEnabled)
+
+ const updateConfigEntry = useCallback(
+ (
+ index: number,
+ modifier: (entry: ModelLoadBalancingConfigEntry) => ModelLoadBalancingConfigEntry | undefined,
+ ) => {
+ setDraftConfig((prev) => {
+ if (!prev)
+ return prev
+ const newConfigs = [...prev.configs]
+ const modifiedConfig = modifier(newConfigs[index])
+ if (modifiedConfig)
+ newConfigs[index] = modifiedConfig
+ else
+ newConfigs.splice(index, 1)
+ return {
+ ...prev,
+ configs: newConfigs,
+ }
+ })
+ },
+ [setDraftConfig],
+ )
+
+ const toggleModalBalancing = useCallback((enabled: boolean) => {
+ if ((modelLoadBalancingEnabled || !enabled) && draftConfig) {
+ setDraftConfig({
+ ...draftConfig,
+ enabled,
+ })
+ }
+ }, [draftConfig, modelLoadBalancingEnabled, setDraftConfig])
+
+ const toggleConfigEntryEnabled = useCallback((index: number, state?: boolean) => {
+ updateConfigEntry(index, entry => ({
+ ...entry,
+ enabled: typeof state === 'boolean' ? state : !entry.enabled,
+ }))
+ }, [updateConfigEntry])
+
+ const setShowModelLoadBalancingEntryModal = useModalContextSelector(state => state.setShowModelLoadBalancingEntryModal)
+
+ const toggleEntryModal = useCallback((index?: number, entry?: ModelLoadBalancingConfigEntry) => {
+ setShowModelLoadBalancingEntryModal({
+ payload: {
+ currentProvider: provider,
+ currentConfigurationMethod: configurationMethod,
+ currentCustomConfigurationModelFixedFields,
+ entry,
+ index,
+ },
+ onSaveCallback: ({ entry: result }) => {
+ if (entry) {
+ // edit
+ setDraftConfig(prev => ({
+ ...prev,
+ enabled: !!prev?.enabled,
+ configs: prev?.configs.map((config, i) => i === index ? result! : config) || [],
+ }))
+ }
+ else {
+ // add
+ setDraftConfig(prev => ({
+ ...prev,
+ enabled: !!prev?.enabled,
+ configs: (prev?.configs || []).concat([{ ...result!, enabled: true }]),
+ }))
+ }
+ },
+ onRemoveCallback: ({ index }) => {
+ if (index !== undefined && (draftConfig?.configs?.length ?? 0) > index) {
+ setDraftConfig(prev => ({
+ ...prev,
+ enabled: !!prev?.enabled,
+ configs: prev?.configs.filter((_, i) => i !== index) || [],
+ }))
+ }
+ },
+ })
+ }, [
+ configurationMethod,
+ currentCustomConfigurationModelFixedFields,
+ draftConfig?.configs?.length,
+ provider,
+ setDraftConfig,
+ setShowModelLoadBalancingEntryModal,
+ ])
+
+ const clearCountdown = useCallback((index: number) => {
+ updateConfigEntry(index, ({ ttl: _, ...entry }) => {
+ return {
+ ...entry,
+ in_cooldown: false,
+ }
+ })
+ }, [updateConfigEntry])
+
+ if (!draftConfig)
+ return null
+
+ return (
+ <>
+ <div
+ className={classNames(
+ 'min-h-16 bg-components-panel-bg border rounded-xl transition-colors',
+ (withSwitch || !draftConfig.enabled) ? 'border-components-panel-border' : 'border-util-colors-blue-blue-600',
+ (withSwitch || draftConfig.enabled) ? 'cursor-default' : 'cursor-pointer',
+ className,
+ )}
+ onClick={(!withSwitch && !draftConfig.enabled) ? () => toggleModalBalancing(true) : undefined}
+ >
+ <div className='flex select-none items-center gap-2 px-[15px] py-3'>
+ <div className='flex h-8 w-8 shrink-0 grow-0 items-center justify-center rounded-lg border border-util-colors-indigo-indigo-100 bg-util-colors-indigo-indigo-50 text-util-colors-blue-blue-600'>
+ <Balance className='h-4 w-4' />
+ </div>
+ <div className='grow'>
+ <div className='flex items-center gap-1 text-sm text-text-primary'>
+ {t('common.modelProvider.loadBalancing')}
+ <Tooltip
+ popupContent={t('common.modelProvider.loadBalancingInfo')}
+ popupClassName='max-w-[300px]'
+ triggerClassName='w-3 h-3'
+ />
+ </div>
+ <div className='text-xs text-text-tertiary'>{t('common.modelProvider.loadBalancingDescription')}</div>
+ </div>
+ {
+ withSwitch && (
+ <Switch
+ defaultValue={Boolean(draftConfig.enabled)}
+ size='l'
+ className='ml-3 justify-self-end'
+ disabled={!modelLoadBalancingEnabled && !draftConfig.enabled}
+ onChange={value => toggleModalBalancing(value)}
+ />
+ )
+ }
+ </div>
+ {draftConfig.enabled && (
+ <div className='flex flex-col gap-1 px-3 pb-3'>
+ {draftConfig.configs.map((config, index) => {
+ const isProviderManaged = config.name === '__inherit__'
+ return (
+ <div key={config.id || index} className='group flex h-10 items-center rounded-lg border border-components-panel-border bg-components-panel-on-panel-item-bg px-3 shadow-xs'>
+ <div className='flex grow items-center'>
+ <div className='mr-2 flex h-3 w-3 items-center justify-center'>
+ {(config.in_cooldown && Boolean(config.ttl))
+ ? (
+ <CooldownTimer secondsRemaining={config.ttl} onFinish={() => clearCountdown(index)} />
+ )
+ : (
+ <Tooltip popupContent={t('common.modelProvider.apiKeyStatusNormal')}>
+ <Indicator color='green' />
+ </Tooltip>
+ )}
+ </div>
+ <div className='mr-1 text-[13px]'>
+ {isProviderManaged ? t('common.modelProvider.defaultConfig') : config.name}
+ </div>
+ {isProviderManaged && (
+ <span className='rounded-[5px] border border-divider-regular px-1 text-2xs uppercase text-text-tertiary'>{t('common.modelProvider.providerManaged')}</span>
+ )}
+ </div>
+ <div className='flex items-center gap-1'>
+ {!isProviderManaged && (
+ <>
+ <div className='flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100'>
+ <span
+ className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-components-button-secondary-bg text-text-tertiary transition-colors hover:bg-components-button-secondary-bg-hover'
+ onClick={() => toggleEntryModal(index, config)}
+ >
+ <Edit02 className='h-4 w-4' />
+ </span>
+ <span
+ className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-components-button-secondary-bg text-text-tertiary transition-colors hover:bg-components-button-secondary-bg-hover'
+ onClick={() => updateConfigEntry(index, () => undefined)}
+ >
+ <RiDeleteBinLine className='h-4 w-4' />
+ </span>
+ <span className='mr-2 h-3 border-r border-r-divider-subtle' />
+ </div>
+ </>
+ )}
+ <Switch
+ defaultValue={Boolean(config.enabled)}
+ size='md'
+ className='justify-self-end'
+ onChange={value => toggleConfigEntryEnabled(index, value)}
+ />
+ </div>
+ </div>
+ )
+ })}
+
+ <div
+ className='mt-1 flex h-8 items-center px-3 text-[13px] font-medium text-primary-600'
+ onClick={() => toggleEntryModal()}
+ >
+ <div className='flex cursor-pointer items-center'>
+ <Plus02 className='mr-2 h-3 w-3' />{t('common.modelProvider.addConfig')}
+ </div>
+ </div>
+ </div>
+ )}
+ {
+ draftConfig.enabled && draftConfig.configs.length < 2 && (
+ <div className='flex h-[34px] items-center border-t border-t-divider-subtle bg-components-panel-bg px-6 text-xs text-text-secondary'>
+ <AlertTriangle className='mr-1 h-3 w-3 text-[#f79009]' />
+ {t('common.modelProvider.loadBalancingLeastKeyWarning')}
+ </div>
+ )
+ }
+ </div>
+
+ {!modelLoadBalancingEnabled && !IS_CE_EDITION && (
+ <GridMask canvasClassName='!rounded-xl'>
+ <div className='mt-2 flex h-14 items-center justify-between rounded-xl border-[0.5px] border-components-panel-border px-4 shadow-md'>
+ <div
+ className={classNames('text-sm font-semibold leading-tight text-gradient', s.textGradient)}
+ >
+ {t('common.modelProvider.upgradeForLoadBalancing')}
+ </div>
+ <UpgradeBtn />
+ </div>
+ </GridMask>
+ )}
+ </>
+ )
+}
+
+export default ModelLoadBalancingConfigs
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx
new file mode 100644
index 0000000..c258806
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx
@@ -0,0 +1,189 @@
+import { memo, useCallback, useEffect, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import type { ModelItem, ModelLoadBalancingConfig, ModelLoadBalancingConfigEntry, ModelProvider } from '../declarations'
+import { FormTypeEnum } from '../declarations'
+import ModelIcon from '../model-icon'
+import ModelName from '../model-name'
+import { savePredefinedLoadBalancingConfig } from '../utils'
+import ModelLoadBalancingConfigs from './model-load-balancing-configs'
+import classNames from '@/utils/classnames'
+import Modal from '@/app/components/base/modal'
+import Button from '@/app/components/base/button'
+import { fetchModelLoadBalancingConfig } from '@/service/common'
+import Loading from '@/app/components/base/loading'
+import { useToastContext } from '@/app/components/base/toast'
+
+export type ModelLoadBalancingModalProps = {
+ provider: ModelProvider
+ model: ModelItem
+ open?: boolean
+ onClose?: () => void
+ onSave?: (provider: string) => void
+}
+
+// model balancing config modal
+const ModelLoadBalancingModal = ({ provider, model, open = false, onClose, onSave }: ModelLoadBalancingModalProps) => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+
+ const [loading, setLoading] = useState(false)
+
+ const { data, mutate } = useSWR(
+ `/workspaces/current/model-providers/${provider.provider}/models/credentials?model=${model.model}&model_type=${model.model_type}`,
+ fetchModelLoadBalancingConfig,
+ )
+
+ const originalConfig = data?.load_balancing
+ const [draftConfig, setDraftConfig] = useState<ModelLoadBalancingConfig>()
+ const originalConfigMap = useMemo(() => {
+ if (!originalConfig)
+ return {}
+ return originalConfig?.configs.reduce((prev, config) => {
+ if (config.id)
+ prev[config.id] = config
+ return prev
+ }, {} as Record<string, ModelLoadBalancingConfigEntry>)
+ }, [originalConfig])
+ useEffect(() => {
+ if (originalConfig)
+ setDraftConfig(originalConfig)
+ }, [originalConfig])
+
+ const toggleModalBalancing = useCallback((enabled: boolean) => {
+ if (draftConfig) {
+ setDraftConfig({
+ ...draftConfig,
+ enabled,
+ })
+ }
+ }, [draftConfig])
+
+ const extendedSecretFormSchemas = useMemo(
+ () => provider.provider_credential_schema.credential_form_schemas.filter(
+ ({ type }) => type === FormTypeEnum.secretInput,
+ ),
+ [provider.provider_credential_schema.credential_form_schemas],
+ )
+
+ const encodeConfigEntrySecretValues = useCallback((entry: ModelLoadBalancingConfigEntry) => {
+ const result = { ...entry }
+ extendedSecretFormSchemas.forEach(({ variable }) => {
+ if (entry.id && result.credentials[variable] === originalConfigMap[entry.id]?.credentials?.[variable])
+ result.credentials[variable] = '[__HIDDEN__]'
+ })
+ return result
+ }, [extendedSecretFormSchemas, originalConfigMap])
+
+ const handleSave = async () => {
+ try {
+ setLoading(true)
+ const res = await savePredefinedLoadBalancingConfig(
+ provider.provider,
+ ({
+ ...(data?.credentials ?? {}),
+ __model_type: model.model_type,
+ __model_name: model.model,
+ }),
+ {
+ ...draftConfig,
+ enabled: Boolean(draftConfig?.enabled),
+ configs: draftConfig!.configs.map(encodeConfigEntrySecretValues),
+ },
+ )
+ if (res.result === 'success') {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ mutate()
+ onSave?.(provider.provider)
+ onClose?.()
+ }
+ }
+ finally {
+ setLoading(false)
+ }
+ }
+
+ return (
+ <Modal
+ isShow={Boolean(model) && open}
+ onClose={onClose}
+ className='w-[640px] max-w-none px-8 pt-8'
+ title={
+ <div className='pb-3 font-semibold'>
+ <div className='h-[30px]'>{t('common.modelProvider.configLoadBalancing')}</div>
+ {Boolean(model) && (
+ <div className='flex h-5 items-center'>
+ <ModelIcon
+ className='mr-2 shrink-0'
+ provider={provider}
+ modelName={model!.model}
+ />
+ <ModelName
+ className='system-md-regular grow text-text-secondary'
+ modelItem={model!}
+ showModelType
+ showMode
+ showContextSize
+ />
+ </div>
+ )}
+ </div>
+ }
+ >
+ {!draftConfig
+ ? <Loading type='area' />
+ : (
+ <>
+ <div className='py-2'>
+ <div
+ className={classNames(
+ 'min-h-16 bg-components-panel-bg border rounded-xl transition-colors',
+ draftConfig.enabled ? 'border-components-panel-border cursor-pointer' : 'border-util-colors-blue-blue-600 cursor-default',
+ )}
+ onClick={draftConfig.enabled ? () => toggleModalBalancing(false) : undefined}
+ >
+ <div className='flex select-none items-center gap-2 px-[15px] py-3'>
+ <div className='flex h-8 w-8 shrink-0 grow-0 items-center justify-center rounded-lg border border-components-card-border bg-components-card-bg'>
+ {Boolean(model) && (
+ <ModelIcon className='shrink-0' provider={provider} modelName={model!.model} />
+ )}
+ </div>
+ <div className='grow'>
+ <div className='text-sm text-text-secondary'>{t('common.modelProvider.providerManaged')}</div>
+ <div className='text-xs text-text-tertiary'>{t('common.modelProvider.providerManagedDescription')}</div>
+ </div>
+ </div>
+ </div>
+
+ <ModelLoadBalancingConfigs {...{
+ draftConfig,
+ setDraftConfig,
+ provider,
+ currentCustomConfigurationModelFixedFields: {
+ __model_name: model.model,
+ __model_type: model.model_type,
+ },
+ configurationMethod: model.fetch_from,
+ className: 'mt-2',
+ }} />
+ </div>
+
+ <div className='mt-6 flex items-center justify-end gap-2'>
+ <Button onClick={onClose}>{t('common.operation.cancel')}</Button>
+ <Button
+ variant='primary'
+ onClick={handleSave}
+ disabled={
+ loading
+ || (draftConfig?.enabled && (draftConfig?.configs.filter(config => config.enabled).length ?? 0) < 2)
+ }
+ >{t('common.operation.save')}</Button>
+ </div>
+ </>
+ )
+ }
+ </Modal >
+ )
+}
+
+export default memo(ModelLoadBalancingModal)
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/priority-selector.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/priority-selector.tsx
new file mode 100644
index 0000000..193608a
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/priority-selector.tsx
@@ -0,0 +1,76 @@
+import { Fragment } from 'react'
+import type { FC } from 'react'
+import { Popover, PopoverButton, PopoverPanel, Transition } from '@headlessui/react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiCheckLine,
+ RiMoreFill,
+} from '@remixicon/react'
+import { PreferredProviderTypeEnum } from '../declarations'
+import Button from '@/app/components/base/button'
+import cn from '@/utils/classnames'
+
+type SelectorProps = {
+ value?: string
+ onSelect: (key: PreferredProviderTypeEnum) => void
+}
+const Selector: FC<SelectorProps> = ({
+ value,
+ onSelect,
+}) => {
+ const { t } = useTranslation()
+ const options = [
+ {
+ key: PreferredProviderTypeEnum.custom,
+ text: t('common.modelProvider.apiKey'),
+ },
+ {
+ key: PreferredProviderTypeEnum.system,
+ text: t('common.modelProvider.quota'),
+ },
+ ]
+
+ return (
+ <Popover className='relative'>
+ <PopoverButton as='div'>
+ {
+ ({ open }) => (
+ <Button className={cn(
+ 'h-6 w-6 rounded-md px-0',
+ open && 'bg-components-button-secondary-bg-hover',
+ )}>
+ <RiMoreFill className='h-3 w-3' />
+ </Button>
+ )
+ }
+ </PopoverButton>
+ <Transition
+ as={Fragment}
+ leave='transition ease-in duration-100'
+ leaveFrom='opacity-100'
+ leaveTo='opacity-0'
+ >
+ <PopoverPanel className='absolute right-0 top-7 z-10 w-[144px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg'>
+ <div className='p-1'>
+ <div className='px-3 pb-1 pt-2 text-sm font-medium text-text-secondary'>{t('common.modelProvider.card.priorityUse')}</div>
+ {
+ options.map(option => (
+ <PopoverButton as={Fragment} key={option.key}>
+ <div
+ className='flex h-9 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-components-panel-on-panel-item-bg-hover'
+ onClick={() => onSelect(option.key)}
+ >
+ <div className='grow'>{option.text}</div>
+ {value === option.key && <RiCheckLine className='h-4 w-4 text-text-accent' />}
+ </div>
+ </PopoverButton>
+ ))
+ }
+ </div>
+ </PopoverPanel>
+ </Transition>
+ </Popover>
+ )
+}
+
+export default Selector
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/priority-use-tip.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/priority-use-tip.tsx
new file mode 100644
index 0000000..9bb898f
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/priority-use-tip.tsx
@@ -0,0 +1,19 @@
+import { useTranslation } from 'react-i18next'
+import { ChevronDownDouble } from '@/app/components/base/icons/src/vender/line/arrows'
+import Tooltip from '@/app/components/base/tooltip'
+
+const PriorityUseTip = () => {
+ const { t } = useTranslation()
+
+ return (
+ <Tooltip
+ popupContent={t('common.modelProvider.priorityUsing') || ''}
+ >
+ <div className='absolute -right-[5px] -top-[5px] cursor-pointer rounded-[5px] border-[0.5px] border-components-panel-border-subtle bg-util-colors-indigo-indigo-50 shadow-xs'>
+ <ChevronDownDouble className='h-3 w-3 rotate-180 text-util-colors-indigo-indigo-600' />
+ </div>
+ </Tooltip>
+ )
+}
+
+export default PriorityUseTip
diff --git a/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx b/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx
new file mode 100644
index 0000000..b3e871e
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx
@@ -0,0 +1,66 @@
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { ModelProvider } from '../declarations'
+import {
+ CustomConfigurationStatusEnum,
+ PreferredProviderTypeEnum,
+ QuotaUnitEnum,
+} from '../declarations'
+import {
+ MODEL_PROVIDER_QUOTA_GET_PAID,
+} from '../utils'
+import PriorityUseTip from './priority-use-tip'
+import Tooltip from '@/app/components/base/tooltip'
+import { formatNumber } from '@/utils/format'
+
+type QuotaPanelProps = {
+ provider: ModelProvider
+}
+const QuotaPanel: FC<QuotaPanelProps> = ({
+ provider,
+}) => {
+ const { t } = useTranslation()
+
+ const customConfig = provider.custom_configuration
+ const priorityUseType = provider.preferred_provider_type
+ const systemConfig = provider.system_configuration
+ const currentQuota = systemConfig.enabled && systemConfig.quota_configurations.find(item => item.quota_type === systemConfig.current_quota_type)
+ const openaiOrAnthropic = MODEL_PROVIDER_QUOTA_GET_PAID.includes(provider.provider)
+
+ return (
+ <div className='group relative min-w-[112px] shrink-0 rounded-lg border-[0.5px] border-components-panel-border bg-white/[0.18] px-3 py-2 shadow-xs'>
+ <div className='system-xs-medium-uppercase mb-2 flex h-4 items-center text-text-tertiary'>
+ {t('common.modelProvider.quota')}
+ <Tooltip popupContent={
+ openaiOrAnthropic
+ ? t('common.modelProvider.card.tip')
+ : t('common.modelProvider.quotaTip')
+ }
+ />
+ </div>
+ {
+ currentQuota && (
+ <div className='flex h-4 items-center text-xs text-text-tertiary'>
+ <span className='system-md-semibold-uppercase mr-0.5 text-text-secondary'>{formatNumber(Math.max((currentQuota?.quota_limit || 0) - (currentQuota?.quota_used || 0), 0))}</span>
+ {
+ currentQuota?.quota_unit === QuotaUnitEnum.tokens && 'Tokens'
+ }
+ {
+ currentQuota?.quota_unit === QuotaUnitEnum.times && t('common.modelProvider.callTimes')
+ }
+ {
+ currentQuota?.quota_unit === QuotaUnitEnum.credits && t('common.modelProvider.credits')
+ }
+ </div>
+ )
+ }
+ {
+ priorityUseType === PreferredProviderTypeEnum.system && customConfig.status === CustomConfigurationStatusEnum.active && (
+ <PriorityUseTip />
+ )
+ }
+ </div>
+ )
+}
+
+export default QuotaPanel
diff --git a/app/components/header/account-setting/model-provider-page/provider-icon/index.tsx b/app/components/header/account-setting/model-provider-page/provider-icon/index.tsx
new file mode 100644
index 0000000..253269d
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/provider-icon/index.tsx
@@ -0,0 +1,53 @@
+import type { FC } from 'react'
+import type { ModelProvider } from '../declarations'
+import { useLanguage } from '../hooks'
+import { Openai } from '@/app/components/base/icons/src/vender/other'
+import { AnthropicDark, AnthropicLight } from '@/app/components/base/icons/src/public/llm'
+import { renderI18nObject } from '@/i18n'
+import { Theme } from '@/types/app'
+import cn from '@/utils/classnames'
+import useTheme from '@/hooks/use-theme'
+
+type ProviderIconProps = {
+ provider: ModelProvider
+ className?: string
+}
+const ProviderIcon: FC<ProviderIconProps> = ({
+ provider,
+ className,
+}) => {
+ const { theme } = useTheme()
+ const language = useLanguage()
+
+ if (provider.provider === 'langgenius/anthropic/anthropic') {
+ return (
+ <div className='mb-2 py-[7px]'>
+ {theme === Theme.dark && <AnthropicLight className='h-2.5 w-[90px]' />}
+ {theme === Theme.light && <AnthropicDark className='h-2.5 w-[90px]' />}
+ </div>
+ )
+ }
+
+ if (provider.provider === 'langgenius/openai/openai') {
+ return (
+ <div className='mb-2'>
+ <Openai className='h-6 w-auto text-text-inverted-dimmed' />
+ </div>
+ )
+ }
+
+ return (
+ <div className={cn('inline-flex items-center gap-2', className)}>
+ <img
+ alt='provider-icon'
+ src={renderI18nObject(provider.icon_small, language)}
+ className='h-6 w-6'
+ />
+ <div className='system-md-semibold text-text-primary'>
+ {renderI18nObject(provider.label, language)}
+ </div>
+ </div>
+ )
+}
+
+export default ProviderIcon
diff --git a/app/components/header/account-setting/model-provider-page/system-model-selector/index.tsx b/app/components/header/account-setting/model-provider-page/system-model-selector/index.tsx
new file mode 100644
index 0000000..30ba475
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/system-model-selector/index.tsx
@@ -0,0 +1,265 @@
+import type { FC } from 'react'
+import { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { RiEqualizer2Line } from '@remixicon/react'
+import ModelSelector from '../model-selector'
+import {
+ useModelList,
+ useSystemDefaultModelAndModelList,
+ useUpdateModelList,
+} from '../hooks'
+import type {
+ DefaultModel,
+ DefaultModelResponse,
+} from '../declarations'
+import { ModelTypeEnum } from '../declarations'
+import Tooltip from '@/app/components/base/tooltip'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import Button from '@/app/components/base/button'
+import { useProviderContext } from '@/context/provider-context'
+import { updateDefaultModel } from '@/service/common'
+import { useToastContext } from '@/app/components/base/toast'
+import { useAppContext } from '@/context/app-context'
+
+type SystemModelSelectorProps = {
+ textGenerationDefaultModel: DefaultModelResponse | undefined
+ embeddingsDefaultModel: DefaultModelResponse | undefined
+ rerankDefaultModel: DefaultModelResponse | undefined
+ speech2textDefaultModel: DefaultModelResponse | undefined
+ ttsDefaultModel: DefaultModelResponse | undefined
+ notConfigured: boolean
+}
+const SystemModel: FC<SystemModelSelectorProps> = ({
+ textGenerationDefaultModel,
+ embeddingsDefaultModel,
+ rerankDefaultModel,
+ speech2textDefaultModel,
+ ttsDefaultModel,
+ notConfigured,
+}) => {
+ const { t } = useTranslation()
+ const { notify } = useToastContext()
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const { textGenerationModelList } = useProviderContext()
+ const updateModelList = useUpdateModelList()
+ const { data: embeddingModelList } = useModelList(ModelTypeEnum.textEmbedding)
+ const { data: rerankModelList } = useModelList(ModelTypeEnum.rerank)
+ const { data: speech2textModelList } = useModelList(ModelTypeEnum.speech2text)
+ const { data: ttsModelList } = useModelList(ModelTypeEnum.tts)
+ const [changedModelTypes, setChangedModelTypes] = useState<ModelTypeEnum[]>([])
+ const [currentTextGenerationDefaultModel, changeCurrentTextGenerationDefaultModel] = useSystemDefaultModelAndModelList(textGenerationDefaultModel, textGenerationModelList)
+ const [currentEmbeddingsDefaultModel, changeCurrentEmbeddingsDefaultModel] = useSystemDefaultModelAndModelList(embeddingsDefaultModel, embeddingModelList)
+ const [currentRerankDefaultModel, changeCurrentRerankDefaultModel] = useSystemDefaultModelAndModelList(rerankDefaultModel, rerankModelList)
+ const [currentSpeech2textDefaultModel, changeCurrentSpeech2textDefaultModel] = useSystemDefaultModelAndModelList(speech2textDefaultModel, speech2textModelList)
+ const [currentTTSDefaultModel, changeCurrentTTSDefaultModel] = useSystemDefaultModelAndModelList(ttsDefaultModel, ttsModelList)
+ const [open, setOpen] = useState(false)
+
+ const getCurrentDefaultModelByModelType = (modelType: ModelTypeEnum) => {
+ if (modelType === ModelTypeEnum.textGeneration)
+ return currentTextGenerationDefaultModel
+ else if (modelType === ModelTypeEnum.textEmbedding)
+ return currentEmbeddingsDefaultModel
+ else if (modelType === ModelTypeEnum.rerank)
+ return currentRerankDefaultModel
+ else if (modelType === ModelTypeEnum.speech2text)
+ return currentSpeech2textDefaultModel
+ else if (modelType === ModelTypeEnum.tts)
+ return currentTTSDefaultModel
+
+ return undefined
+ }
+ const handleChangeDefaultModel = (modelType: ModelTypeEnum, model: DefaultModel) => {
+ if (modelType === ModelTypeEnum.textGeneration)
+ changeCurrentTextGenerationDefaultModel(model)
+ else if (modelType === ModelTypeEnum.textEmbedding)
+ changeCurrentEmbeddingsDefaultModel(model)
+ else if (modelType === ModelTypeEnum.rerank)
+ changeCurrentRerankDefaultModel(model)
+ else if (modelType === ModelTypeEnum.speech2text)
+ changeCurrentSpeech2textDefaultModel(model)
+ else if (modelType === ModelTypeEnum.tts)
+ changeCurrentTTSDefaultModel(model)
+
+ if (!changedModelTypes.includes(modelType))
+ setChangedModelTypes([...changedModelTypes, modelType])
+ }
+ const handleSave = async () => {
+ const res = await updateDefaultModel({
+ url: '/workspaces/current/default-model',
+ body: {
+ model_settings: [ModelTypeEnum.textGeneration, ModelTypeEnum.textEmbedding, ModelTypeEnum.rerank, ModelTypeEnum.speech2text, ModelTypeEnum.tts].map((modelType) => {
+ return {
+ model_type: modelType,
+ provider: getCurrentDefaultModelByModelType(modelType)?.provider,
+ model: getCurrentDefaultModelByModelType(modelType)?.model,
+ }
+ }),
+ },
+ })
+ if (res.result === 'success') {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ setOpen(false)
+
+ changedModelTypes.forEach((modelType) => {
+ if (modelType === ModelTypeEnum.textGeneration)
+ updateModelList(modelType)
+ else if (modelType === ModelTypeEnum.textEmbedding)
+ updateModelList(modelType)
+ else if (modelType === ModelTypeEnum.rerank)
+ updateModelList(modelType)
+ else if (modelType === ModelTypeEnum.speech2text)
+ updateModelList(modelType)
+ else if (modelType === ModelTypeEnum.tts)
+ updateModelList(modelType)
+ })
+ }
+ }
+
+ return (
+ <PortalToFollowElem
+ open={open}
+ onOpenChange={setOpen}
+ placement='bottom-end'
+ offset={{
+ mainAxis: 4,
+ crossAxis: 8,
+ }}
+ >
+ <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
+ <Button
+ className='relative'
+ variant={notConfigured ? 'primary' : 'secondary'}
+ size='small'
+ >
+ <RiEqualizer2Line className='mr-1 h-3.5 w-3.5' />
+ {t('common.modelProvider.systemModelSettings')}
+ </Button>
+ </PortalToFollowElemTrigger>
+ <PortalToFollowElemContent className='z-[60]'>
+ <div className='w-[360px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg pt-4 shadow-xl'>
+ <div className='px-6 py-1'>
+ <div className='flex h-8 items-center text-[13px] font-medium text-text-primary'>
+ {t('common.modelProvider.systemReasoningModel.key')}
+ <Tooltip
+ popupContent={
+ <div className='w-[261px] text-text-tertiary'>
+ {t('common.modelProvider.systemReasoningModel.tip')}
+ </div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4 shrink-0'
+ />
+ </div>
+ <div>
+ <ModelSelector
+ defaultModel={currentTextGenerationDefaultModel}
+ modelList={textGenerationModelList}
+ onSelect={model => handleChangeDefaultModel(ModelTypeEnum.textGeneration, model)}
+ />
+ </div>
+ </div>
+ <div className='px-6 py-1'>
+ <div className='flex h-8 items-center text-[13px] font-medium text-text-primary'>
+ {t('common.modelProvider.embeddingModel.key')}
+ <Tooltip
+ popupContent={
+ <div className='w-[261px] text-text-tertiary'>
+ {t('common.modelProvider.embeddingModel.tip')}
+ </div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4 shrink-0'
+ />
+ </div>
+ <div>
+ <ModelSelector
+ defaultModel={currentEmbeddingsDefaultModel}
+ modelList={embeddingModelList}
+ onSelect={model => handleChangeDefaultModel(ModelTypeEnum.textEmbedding, model)}
+ />
+ </div>
+ </div>
+ <div className='px-6 py-1'>
+ <div className='flex h-8 items-center text-[13px] font-medium text-text-primary'>
+ {t('common.modelProvider.rerankModel.key')}
+ <Tooltip
+ popupContent={
+ <div className='w-[261px] text-text-tertiary'>
+ {t('common.modelProvider.rerankModel.tip')}
+ </div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4 shrink-0'
+ />
+ </div>
+ <div>
+ <ModelSelector
+ defaultModel={currentRerankDefaultModel}
+ modelList={rerankModelList}
+ onSelect={model => handleChangeDefaultModel(ModelTypeEnum.rerank, model)}
+ />
+ </div>
+ </div>
+ <div className='px-6 py-1'>
+ <div className='flex h-8 items-center text-[13px] font-medium text-text-primary'>
+ {t('common.modelProvider.speechToTextModel.key')}
+ <Tooltip
+ popupContent={
+ <div className='w-[261px] text-text-tertiary'>
+ {t('common.modelProvider.speechToTextModel.tip')}
+ </div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4 shrink-0'
+ />
+ </div>
+ <div>
+ <ModelSelector
+ defaultModel={currentSpeech2textDefaultModel}
+ modelList={speech2textModelList}
+ onSelect={model => handleChangeDefaultModel(ModelTypeEnum.speech2text, model)}
+ />
+ </div>
+ </div>
+ <div className='px-6 py-1'>
+ <div className='flex h-8 items-center text-[13px] font-medium text-text-primary'>
+ {t('common.modelProvider.ttsModel.key')}
+ <Tooltip
+ popupContent={
+ <div className='w-[261px] text-text-tertiary'>
+ {t('common.modelProvider.ttsModel.tip')}
+ </div>
+ }
+ triggerClassName='ml-0.5 w-4 h-4 shrink-0'
+ />
+ </div>
+ <div>
+ <ModelSelector
+ defaultModel={currentTTSDefaultModel}
+ modelList={ttsModelList}
+ onSelect={model => handleChangeDefaultModel(ModelTypeEnum.tts, model)}
+ />
+ </div>
+ </div>
+ <div className='flex items-center justify-end px-6 py-4'>
+ <Button
+ onClick={() => setOpen(false)}
+ >
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ className='ml-2'
+ variant='primary'
+ onClick={handleSave}
+ disabled={!isCurrentWorkspaceManager}
+ >
+ {t('common.operation.save')}
+ </Button>
+ </div>
+ </div>
+ </PortalToFollowElemContent>
+ </PortalToFollowElem>
+ )
+}
+
+export default SystemModel
diff --git a/app/components/header/account-setting/model-provider-page/utils.ts b/app/components/header/account-setting/model-provider-page/utils.ts
new file mode 100644
index 0000000..9056afe
--- /dev/null
+++ b/app/components/header/account-setting/model-provider-page/utils.ts
@@ -0,0 +1,195 @@
+import { ValidatedStatus } from '../key-validator/declarations'
+import type {
+ CredentialFormSchemaRadio,
+ CredentialFormSchemaTextInput,
+ FormValue,
+ ModelLoadBalancingConfig,
+} from './declarations'
+import {
+ ConfigurationMethodEnum,
+ FormTypeEnum,
+ MODEL_TYPE_TEXT,
+ ModelTypeEnum,
+} from './declarations'
+import {
+ deleteModelProvider,
+ setModelProvider,
+ validateModelLoadBalancingCredentials,
+ validateModelProvider,
+} from '@/service/common'
+
+export const MODEL_PROVIDER_QUOTA_GET_PAID = ['langgenius/anthropic/anthropic', 'langgenius/openai/openai', 'langgenius/azure_openai/azure_openai']
+
+export const isNullOrUndefined = (value: any) => {
+ return value === undefined || value === null
+}
+
+export const validateCredentials = async (predefined: boolean, provider: string, v: FormValue) => {
+ let body, url
+
+ if (predefined) {
+ body = {
+ credentials: v,
+ }
+ url = `/workspaces/current/model-providers/${provider}/credentials/validate`
+ }
+ else {
+ const { __model_name, __model_type, ...credentials } = v
+ body = {
+ model: __model_name,
+ model_type: __model_type,
+ credentials,
+ }
+ url = `/workspaces/current/model-providers/${provider}/models/credentials/validate`
+ }
+ try {
+ const res = await validateModelProvider({ url, body })
+ if (res.result === 'success')
+ return Promise.resolve({ status: ValidatedStatus.Success })
+ else
+ return Promise.resolve({ status: ValidatedStatus.Error, message: res.error || 'error' })
+ }
+ catch (e: any) {
+ return Promise.resolve({ status: ValidatedStatus.Error, message: e.message })
+ }
+}
+
+export const validateLoadBalancingCredentials = async (predefined: boolean, provider: string, v: FormValue, id?: string): Promise<{
+ status: ValidatedStatus
+ message?: string
+}> => {
+ const { __model_name, __model_type, ...credentials } = v
+ try {
+ const res = await validateModelLoadBalancingCredentials({
+ url: `/workspaces/current/model-providers/${provider}/models/load-balancing-configs/${id ? `${id}/` : ''}credentials-validate`,
+ body: {
+ model: __model_name,
+ model_type: __model_type,
+ credentials,
+ },
+ })
+ if (res.result === 'success')
+ return Promise.resolve({ status: ValidatedStatus.Success })
+ else
+ return Promise.resolve({ status: ValidatedStatus.Error, message: res.error || 'error' })
+ }
+ catch (e: any) {
+ return Promise.resolve({ status: ValidatedStatus.Error, message: e.message })
+ }
+}
+
+export const saveCredentials = async (predefined: boolean, provider: string, v: FormValue, loadBalancing?: ModelLoadBalancingConfig) => {
+ let body, url
+
+ if (predefined) {
+ body = {
+ config_from: ConfigurationMethodEnum.predefinedModel,
+ credentials: v,
+ load_balancing: loadBalancing,
+ }
+ url = `/workspaces/current/model-providers/${provider}`
+ }
+ else {
+ const { __model_name, __model_type, ...credentials } = v
+ body = {
+ model: __model_name,
+ model_type: __model_type,
+ credentials,
+ load_balancing: loadBalancing,
+ }
+ url = `/workspaces/current/model-providers/${provider}/models`
+ }
+
+ return setModelProvider({ url, body })
+}
+
+export const savePredefinedLoadBalancingConfig = async (provider: string, v: FormValue, loadBalancing?: ModelLoadBalancingConfig) => {
+ const { __model_name, __model_type, ...credentials } = v
+ const body = {
+ config_from: ConfigurationMethodEnum.predefinedModel,
+ model: __model_name,
+ model_type: __model_type,
+ credentials,
+ load_balancing: loadBalancing,
+ }
+ const url = `/workspaces/current/model-providers/${provider}/models`
+
+ return setModelProvider({ url, body })
+}
+
+export const removeCredentials = async (predefined: boolean, provider: string, v: FormValue) => {
+ let url = ''
+ let body
+
+ if (predefined) {
+ url = `/workspaces/current/model-providers/${provider}`
+ }
+ else {
+ if (v) {
+ const { __model_name, __model_type } = v
+ body = {
+ model: __model_name,
+ model_type: __model_type,
+ }
+ url = `/workspaces/current/model-providers/${provider}/models`
+ }
+ }
+
+ return deleteModelProvider({ url, body })
+}
+
+export const sizeFormat = (size: number) => {
+ const remainder = Math.floor(size / 1000)
+ if (remainder < 1)
+ return `${size}`
+ else
+ return `${remainder}K`
+}
+
+export const modelTypeFormat = (modelType: ModelTypeEnum) => {
+ if (modelType === ModelTypeEnum.textEmbedding)
+ return 'TEXT EMBEDDING'
+
+ return modelType.toLocaleUpperCase()
+}
+
+export const genModelTypeFormSchema = (modelTypes: ModelTypeEnum[]) => {
+ return {
+ type: FormTypeEnum.radio,
+ label: {
+ zh_Hans: '妯″瀷绫诲瀷',
+ en_US: 'Model Type',
+ },
+ variable: '__model_type',
+ default: modelTypes[0],
+ required: true,
+ show_on: [],
+ options: modelTypes.map((modelType: ModelTypeEnum) => {
+ return {
+ value: modelType,
+ label: {
+ zh_Hans: MODEL_TYPE_TEXT[modelType],
+ en_US: MODEL_TYPE_TEXT[modelType],
+ },
+ show_on: [],
+ }
+ }),
+ } as CredentialFormSchemaRadio
+}
+
+export const genModelNameFormSchema = (model?: Pick<CredentialFormSchemaTextInput, 'label' | 'placeholder'>) => {
+ return {
+ type: FormTypeEnum.textInput,
+ label: model?.label || {
+ zh_Hans: '妯″瀷鍚嶇О',
+ en_US: 'Model Name',
+ },
+ variable: '__model_name',
+ required: true,
+ show_on: [],
+ placeholder: model?.placeholder || {
+ zh_Hans: '璇疯緭鍏ユā鍨嬪悕绉�',
+ en_US: 'Please enter model name',
+ },
+ } as CredentialFormSchemaTextInput
+}
diff --git a/app/components/header/account-setting/plugin-page/SerpapiPlugin.tsx b/app/components/header/account-setting/plugin-page/SerpapiPlugin.tsx
new file mode 100644
index 0000000..86b7db0
--- /dev/null
+++ b/app/components/header/account-setting/plugin-page/SerpapiPlugin.tsx
@@ -0,0 +1,80 @@
+import { useTranslation } from 'react-i18next'
+import Image from 'next/image'
+import SerpapiLogo from '../../assets/serpapi.png'
+import KeyValidator from '../key-validator'
+import type { Form, ValidateValue } from '../key-validator/declarations'
+import { updatePluginKey, validatePluginKey } from './utils'
+import { useToastContext } from '@/app/components/base/toast'
+import type { PluginProvider } from '@/models/common'
+import { useAppContext } from '@/context/app-context'
+
+type SerpapiPluginProps = {
+ plugin: PluginProvider
+ onUpdate: () => void
+}
+const SerpapiPlugin = ({
+ plugin,
+ onUpdate,
+}: SerpapiPluginProps) => {
+ const { t } = useTranslation()
+ const { isCurrentWorkspaceManager } = useAppContext()
+ const { notify } = useToastContext()
+
+ const forms: Form[] = [{
+ key: 'api_key',
+ title: t('common.plugin.serpapi.apiKey'),
+ placeholder: t('common.plugin.serpapi.apiKeyPlaceholder'),
+ value: plugin.credentials?.api_key,
+ validate: {
+ before: (v) => {
+ if (v?.api_key)
+ return true
+ },
+ run: async (v) => {
+ return validatePluginKey('serpapi', {
+ credentials: {
+ api_key: v?.api_key,
+ },
+ })
+ },
+ },
+ handleFocus: (v, dispatch) => {
+ if (v.api_key === plugin.credentials?.api_key)
+ dispatch({ ...v, api_key: '' })
+ },
+ }]
+
+ const handleSave = async (v: ValidateValue) => {
+ if (!v?.api_key || v?.api_key === plugin.credentials?.api_key)
+ return
+
+ const res = await updatePluginKey('serpapi', {
+ credentials: {
+ api_key: v?.api_key,
+ },
+ })
+
+ if (res.status === 'success') {
+ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+ onUpdate()
+ return true
+ }
+ }
+
+ return (
+ <KeyValidator
+ type='serpapi'
+ title={<Image alt='serpapi logo' src={SerpapiLogo} width={64} />}
+ status={plugin.credentials?.api_key ? 'success' : 'add'}
+ forms={forms}
+ keyFrom={{
+ text: t('common.plugin.serpapi.keyFrom'),
+ link: 'https://serpapi.com/manage-api-key',
+ }}
+ onSave={handleSave}
+ disabled={!isCurrentWorkspaceManager}
+ />
+ )
+}
+
+export default SerpapiPlugin
diff --git a/app/components/header/account-setting/plugin-page/index.tsx b/app/components/header/account-setting/plugin-page/index.tsx
new file mode 100644
index 0000000..bf404b0
--- /dev/null
+++ b/app/components/header/account-setting/plugin-page/index.tsx
@@ -0,0 +1,38 @@
+import useSWR from 'swr'
+import { LockClosedIcon } from '@heroicons/react/24/solid'
+import { useTranslation } from 'react-i18next'
+import Link from 'next/link'
+import SerpapiPlugin from './SerpapiPlugin'
+import { fetchPluginProviders } from '@/service/common'
+import type { PluginProvider } from '@/models/common'
+
+const PluginPage = () => {
+ const { t } = useTranslation()
+ const { data: plugins, mutate } = useSWR('/workspaces/current/tool-providers', fetchPluginProviders)
+
+ const Plugin_MAP: Record<string, (plugin: PluginProvider) => React.JSX.Element> = {
+ serpapi: (plugin: PluginProvider) => <SerpapiPlugin key='serpapi' plugin={plugin} onUpdate={() => mutate()} />,
+ }
+
+ return (
+ <div className='pb-7'>
+ <div>
+ {plugins?.map(plugin => Plugin_MAP[plugin.tool_name](plugin))}
+ </div>
+ <div className='fixed bottom-0 flex h-[42px] w-[472px] items-center bg-white text-xs text-gray-500'>
+ <LockClosedIcon className='mr-1 h-3 w-3' />
+ {t('common.provider.encrypted.front')}
+ <Link
+ className='mx-1 text-primary-600'
+ target='_blank' rel='noopener noreferrer'
+ href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
+ >
+ PKCS1_OAEP
+ </Link>
+ {t('common.provider.encrypted.back')}
+ </div>
+ </div>
+ )
+}
+
+export default PluginPage
diff --git a/app/components/header/account-setting/plugin-page/utils.ts b/app/components/header/account-setting/plugin-page/utils.ts
new file mode 100644
index 0000000..cb9e25a
--- /dev/null
+++ b/app/components/header/account-setting/plugin-page/utils.ts
@@ -0,0 +1,34 @@
+import { ValidatedStatus } from '../key-validator/declarations'
+import { updatePluginProviderAIKey, validatePluginProviderKey } from '@/service/common'
+
+export const validatePluginKey = async (pluginType: string, body: any) => {
+ try {
+ const res = await validatePluginProviderKey({
+ url: `/workspaces/current/tool-providers/${pluginType}/credentials-validate`,
+ body,
+ })
+ if (res.result === 'success')
+ return Promise.resolve({ status: ValidatedStatus.Success })
+ else
+ return Promise.resolve({ status: ValidatedStatus.Error, message: res.error })
+ }
+ catch (e: any) {
+ return Promise.resolve({ status: ValidatedStatus.Error, message: e.message })
+ }
+}
+
+export const updatePluginKey = async (pluginType: string, body: any) => {
+ try {
+ const res = await updatePluginProviderAIKey({
+ url: `/workspaces/current/tool-providers/${pluginType}/credentials`,
+ body,
+ })
+ if (res.result === 'success')
+ return Promise.resolve({ status: ValidatedStatus.Success })
+ else
+ return Promise.resolve({ status: ValidatedStatus.Error, message: res.error })
+ }
+ catch (e: any) {
+ return Promise.resolve({ status: ValidatedStatus.Error, message: e.message })
+ }
+}
diff --git a/app/components/header/app-back/index.tsx b/app/components/header/app-back/index.tsx
new file mode 100644
index 0000000..bfc1736
--- /dev/null
+++ b/app/components/header/app-back/index.tsx
@@ -0,0 +1,36 @@
+'use client'
+
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { ArrowLeftIcon, Squares2X2Icon } from '@heroicons/react/24/solid'
+import classNames from '@/utils/classnames'
+import type { AppDetailResponse } from '@/models/app'
+
+type IAppBackProps = {
+ curApp: AppDetailResponse
+}
+export default function AppBack({ curApp }: IAppBackProps) {
+ const { t } = useTranslation()
+
+ const [hovered, setHovered] = useState(false)
+
+ return (
+ <div
+ className={classNames(`
+ flex items-center h-7 pl-2.5 pr-2
+ text-[#1C64F2] font-semibold cursor-pointer
+ rounded-[10px]
+ ${curApp && 'hover:bg-[#EBF5FF]'}
+ `)}
+ onMouseEnter={() => setHovered(true)}
+ onMouseLeave={() => setHovered(false)}
+ >
+ {
+ (hovered && curApp)
+ ? <ArrowLeftIcon className='mr-1 h-[18px] w-[18px]' />
+ : <Squares2X2Icon className='mr-1 h-[18px] w-[18px]' />
+ }
+ {t('common.menus.apps')}
+ </div>
+ )
+}
diff --git a/app/components/header/app-nav/index.tsx b/app/components/header/app-nav/index.tsx
new file mode 100644
index 0000000..3b90281
--- /dev/null
+++ b/app/components/header/app-nav/index.tsx
@@ -0,0 +1,150 @@
+'use client'
+
+import { useCallback, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useParams } from 'next/navigation'
+import useSWRInfinite from 'swr/infinite'
+import { flatten } from 'lodash-es'
+import produce from 'immer'
+import {
+ RiRobot2Fill,
+ RiRobot2Line,
+} from '@remixicon/react'
+import Nav from '../nav'
+import type { NavItem } from '../nav/nav-selector'
+import { fetchAppList } from '@/service/apps'
+import CreateAppTemplateDialog from '@/app/components/app/create-app-dialog'
+import CreateAppModal from '@/app/components/app/create-app-modal'
+import CreateFromDSLModal from '@/app/components/app/create-from-dsl-modal'
+import type { AppListResponse } from '@/models/app'
+import { useAppContext } from '@/context/app-context'
+import { useStore as useAppStore } from '@/app/components/app/store'
+
+const getKey = (
+ pageIndex: number,
+ previousPageData: AppListResponse,
+ activeTab: string,
+ keywords: string,
+) => {
+ if (!pageIndex || previousPageData.has_more) {
+ const params: any = { url: 'apps', params: { page: pageIndex + 1, limit: 30, name: keywords } }
+
+ if (activeTab !== 'all')
+ params.params.mode = activeTab
+ else
+ delete params.params.mode
+
+ return params
+ }
+ return null
+}
+
+const AppNav = () => {
+ const { t } = useTranslation()
+ const { appId } = useParams()
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const appDetail = useAppStore(state => state.appDetail)
+ const [showNewAppDialog, setShowNewAppDialog] = useState(false)
+ const [showNewAppTemplateDialog, setShowNewAppTemplateDialog] = useState(false)
+ const [showCreateFromDSLModal, setShowCreateFromDSLModal] = useState(false)
+ const [navItems, setNavItems] = useState<NavItem[]>([])
+
+ const { data: appsData, setSize, mutate } = useSWRInfinite(
+ appId
+ ? (pageIndex: number, previousPageData: AppListResponse) => getKey(pageIndex, previousPageData, 'all', '')
+ : () => null,
+ fetchAppList,
+ { revalidateFirstPage: false },
+ )
+
+ const handleLoadmore = useCallback(() => {
+ setSize(size => size + 1)
+ }, [setSize])
+
+ const openModal = (state: string) => {
+ if (state === 'blank')
+ setShowNewAppDialog(true)
+ if (state === 'template')
+ setShowNewAppTemplateDialog(true)
+ if (state === 'dsl')
+ setShowCreateFromDSLModal(true)
+ }
+
+ useEffect(() => {
+ if (appsData) {
+ const appItems = flatten(appsData?.map(appData => appData.data))
+ const navItems = appItems.map((app) => {
+ const link = ((isCurrentWorkspaceEditor, app) => {
+ if (!isCurrentWorkspaceEditor) {
+ return `/app/${app.id}/overview`
+ }
+ else {
+ if (app.mode === 'workflow' || app.mode === 'advanced-chat')
+ return `/app/${app.id}/workflow`
+ else
+ return `/app/${app.id}/configuration`
+ }
+ })(isCurrentWorkspaceEditor, app)
+ return {
+ id: app.id,
+ icon_type: app.icon_type,
+ icon: app.icon,
+ icon_background: app.icon_background,
+ icon_url: app.icon_url,
+ name: app.name,
+ mode: app.mode,
+ link,
+ }
+ })
+ setNavItems(navItems)
+ }
+ }, [appsData, isCurrentWorkspaceEditor, setNavItems])
+
+ // update current app name
+ useEffect(() => {
+ if (appDetail) {
+ const newNavItems = produce(navItems, (draft: NavItem[]) => {
+ navItems.forEach((app, index) => {
+ if (app.id === appDetail.id)
+ draft[index].name = appDetail.name
+ })
+ })
+ setNavItems(newNavItems)
+ }
+ }, [appDetail, navItems])
+
+ return (
+ <>
+ <Nav
+ isApp
+ icon={<RiRobot2Line className='h-4 w-4' />}
+ activeIcon={<RiRobot2Fill className='h-4 w-4' />}
+ text={t('common.menus.apps')}
+ activeSegment={['apps', 'app']}
+ link='/apps'
+ curNav={appDetail}
+ navs={navItems}
+ createText={t('common.menus.newApp')}
+ onCreate={openModal}
+ onLoadmore={handleLoadmore}
+ />
+ <CreateAppModal
+ show={showNewAppDialog}
+ onClose={() => setShowNewAppDialog(false)}
+ onSuccess={() => mutate()}
+ />
+ <CreateAppTemplateDialog
+ show={showNewAppTemplateDialog}
+ onClose={() => setShowNewAppTemplateDialog(false)}
+ onSuccess={() => mutate()}
+ />
+ <CreateFromDSLModal
+ show={showCreateFromDSLModal}
+ onClose={() => setShowCreateFromDSLModal(false)}
+ onSuccess={() => mutate()}
+ />
+ </>
+ )
+}
+
+export default AppNav
diff --git a/app/components/header/app-selector/index.tsx b/app/components/header/app-selector/index.tsx
new file mode 100644
index 0000000..1c0dbc5
--- /dev/null
+++ b/app/components/header/app-selector/index.tsx
@@ -0,0 +1,112 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { Fragment, useState } from 'react'
+import { ChevronDownIcon, PlusIcon } from '@heroicons/react/24/solid'
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import { useRouter } from 'next/navigation'
+import Indicator from '../indicator'
+import type { AppDetailResponse } from '@/models/app'
+import CreateAppDialog from '@/app/components/app/create-app-dialog'
+import AppIcon from '@/app/components/base/app-icon'
+import { useAppContext } from '@/context/app-context'
+import { noop } from 'lodash-es'
+
+type IAppSelectorProps = {
+ appItems: AppDetailResponse[]
+ curApp: AppDetailResponse
+}
+
+export default function AppSelector({ appItems, curApp }: IAppSelectorProps) {
+ const router = useRouter()
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const [showNewAppDialog, setShowNewAppDialog] = useState(false)
+ const { t } = useTranslation()
+
+ const itemClassName = `
+ flex items-center w-full h-10 px-3 text-gray-700 text-[14px]
+ rounded-lg font-normal hover:bg-gray-100 cursor-pointer
+ `
+
+ return (
+ <div className="">
+ <Menu as="div" className="relative inline-block text-left">
+ <div>
+ <MenuButton
+ className="
+ inline-flex h-7 w-full items-center justify-center
+ rounded-[10px] pl-2 pr-2.5 text-[14px] font-semibold
+ text-[#1C64F2] hover:bg-[#EBF5FF]
+ "
+ >
+ {curApp?.name}
+ <ChevronDownIcon
+ className="ml-1 h-3 w-3"
+ aria-hidden="true"
+ />
+ </MenuButton>
+ </div>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems
+ className="
+ absolute -left-11 right-0 mt-1.5 w-60 max-w-80
+ origin-top-right divide-y divide-gray-100 rounded-lg bg-white
+ shadow-lg
+ "
+ >
+ {!!appItems.length && (<div className="overflow-auto px-1 py-1" style={{ maxHeight: '50vh' }}>
+ {
+ appItems.map((app: AppDetailResponse) => (
+ <MenuItem key={app.id}>
+ <div className={itemClassName} onClick={() =>
+ router.push(`/app/${app.id}/${isCurrentWorkspaceEditor ? 'configuration' : 'overview'}`)
+ }>
+ <div className='relative mr-2 h-6 w-6 rounded-[6px] bg-[#D5F5F6]'>
+ <AppIcon size='tiny' />
+ <div className='absolute -bottom-0.5 -right-0.5 flex h-2.5 w-2.5 items-center justify-center rounded bg-white'>
+ <Indicator />
+ </div>
+ </div>
+ {app.name}
+ </div>
+ </MenuItem>
+ ))
+ }
+ </div>)}
+ {isCurrentWorkspaceEditor && <MenuItem>
+ <div className='p-1' onClick={() => setShowNewAppDialog(true)}>
+ <div
+ className='flex h-12 cursor-pointer items-center rounded-lg hover:bg-gray-100'
+ >
+ <div
+ className='
+ ml-4 mr-2 flex
+ h-6 w-6 items-center justify-center rounded-[6px] border-[0.5px]
+ border-dashed border-gray-200 bg-gray-100
+ '
+ >
+ <PlusIcon className='h-4 w-4 text-gray-500' />
+ </div>
+ <div className='text-[14px] font-normal text-gray-700'>{t('common.menus.newApp')}</div>
+ </div>
+ </div>
+ </MenuItem>
+ }
+ </MenuItems>
+ </Transition>
+ </Menu>
+ <CreateAppDialog
+ show={showNewAppDialog}
+ onClose={() => setShowNewAppDialog(false)}
+ onSuccess={noop}
+ />
+ </div>
+ )
+}
diff --git a/app/components/header/assets/alpha.svg b/app/components/header/assets/alpha.svg
new file mode 100644
index 0000000..3be0fdb
--- /dev/null
+++ b/app/components/header/assets/alpha.svg
@@ -0,0 +1,4 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6 5.24975C5.58579 5.24975 5.25 5.58554 5.25 5.99975C5.25 6.41396 5.58579 6.74975 6 6.74975C6.41421 6.74975 6.75 6.41396 6.75 5.99975C6.75 5.58554 6.41421 5.24975 6 5.24975Z" fill="#344054"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.55961 1.2874C7.06059 1.49287 6.53398 1.7771 5.99996 2.13007C5.46595 1.77712 4.93936 1.4929 4.44036 1.28743C3.8603 1.04858 3.29372 0.906291 2.7826 0.902457C2.269 0.898605 1.77103 1.03634 1.40379 1.40358C1.03655 1.77082 0.89882 2.26879 0.902672 2.78238C0.906505 3.2935 1.0488 3.86008 1.28765 4.44015C1.49312 4.93915 1.77733 5.46574 2.13029 5.99975C1.77733 6.53376 1.49311 7.06036 1.28764 7.55936C1.04879 8.13942 0.9065 8.706 0.902666 9.21712C0.898814 9.73072 1.03655 10.2287 1.40379 10.5959C1.77103 10.9632 2.269 11.1009 2.78259 11.097C3.29371 11.0932 3.86029 10.9509 4.44035 10.7121C4.93935 10.5066 5.46595 10.2224 5.99996 9.86944C6.53398 10.2224 7.06059 10.5066 7.55961 10.7121C8.13967 10.951 8.70625 11.0933 9.21737 11.0971C9.73097 11.1009 10.2289 10.9632 10.5962 10.596C10.9634 10.2287 11.1012 9.73075 11.0973 9.21716C11.0935 8.70604 10.9512 8.13946 10.7123 7.5594C10.5068 7.06038 10.2226 6.53377 9.86966 5.99975C10.2226 5.46573 10.5068 4.93912 10.7123 4.44011C10.9512 3.86005 11.0935 3.29347 11.0973 2.78235C11.1011 2.26875 10.9634 1.77078 10.5962 1.40354C10.2289 1.0363 9.73096 0.89857 9.21737 0.902422C8.70625 0.906256 8.13967 1.04855 7.55961 1.2874ZM7.94035 2.21207C7.60184 2.35146 7.2419 2.53581 6.87023 2.7619C7.29274 3.09639 7.71306 3.47021 8.12131 3.87845C8.52954 4.28668 8.90334 4.70698 9.23781 5.12947C9.46391 4.75781 9.64826 4.39787 9.78764 4.05936C9.99666 3.55175 10.0948 3.11609 10.0973 2.77485C10.0999 2.43608 10.01 2.23156 9.88907 2.11065C9.76815 1.98973 9.56364 1.89985 9.22487 1.90239C8.88362 1.90495 8.44796 2.00306 7.94035 2.21207ZM2.21232 4.0594C2.35171 4.39789 2.53604 4.75782 2.76213 5.12947C3.09661 4.70697 3.47042 4.28665 3.87866 3.87842C4.28689 3.47019 4.70719 3.09639 5.12968 2.76191C4.75803 2.53582 4.3981 2.35149 4.05961 2.21211C3.552 2.00309 3.11634 1.90499 2.7751 1.90243C2.43633 1.89989 2.23181 1.98977 2.1109 2.11068C1.98998 2.2316 1.9001 2.43611 1.90264 2.77488C1.9052 3.11613 2.00331 3.55179 2.21232 4.0594ZM4.58577 4.58552C4.11988 5.05141 3.70722 5.5288 3.35371 5.99975C3.70722 6.4707 4.11988 6.94809 4.58577 7.41398C5.05165 7.87986 5.52902 8.29251 5.99996 8.64601C6.47091 8.2925 6.9483 7.87984 7.41419 7.41395C7.88007 6.94807 8.29272 6.47069 8.64623 5.99975C8.29272 5.52881 7.88008 5.05143 7.4142 4.58556C6.94831 4.11966 6.47091 3.70701 5.99996 3.35349C5.52902 3.707 5.05164 4.11965 4.58577 4.58552ZM2.21232 7.94011C2.3517 7.60161 2.53604 7.24168 2.76213 6.87003C3.09661 7.29253 3.47042 7.71285 3.87866 8.12109C4.28689 8.52932 4.70719 8.90312 5.12968 9.23759C4.75803 9.46368 4.3981 9.64802 4.05961 9.7874C3.552 9.99641 3.11634 10.0945 2.77509 10.0971C2.43632 10.0996 2.23181 10.0097 2.11089 9.88882C1.98998 9.76791 1.9001 9.5634 1.90264 9.22462C1.9052 8.88338 2.0033 8.44772 2.21232 7.94011ZM7.94036 9.78743C7.60185 9.64804 7.2419 9.4637 6.87023 9.2376C7.29274 8.90311 7.71306 8.5293 8.1213 8.12106C8.52953 7.71282 8.90334 7.29252 9.23782 6.87003C9.46392 7.24169 9.64826 7.60163 9.78765 7.94015C9.99666 8.44775 10.0948 8.88342 10.0973 9.22466C10.0999 9.56343 10.01 9.76794 9.88907 9.88886C9.76816 10.0098 9.56364 10.0997 9.22487 10.0971C8.88363 10.0946 8.44797 9.99645 7.94036 9.78743Z" fill="#344054"/>
+</svg>
diff --git a/app/components/header/assets/anthropic.svg b/app/components/header/assets/anthropic.svg
new file mode 100644
index 0000000..c0ec02d
--- /dev/null
+++ b/app/components/header/assets/anthropic.svg
@@ -0,0 +1,11 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="#CA9F7B"/>
+<g clip-path="url(#clip0_3907_39360)">
+<path d="M14.9613 7.13043H12.8476L16.7022 16.8696H18.8159L14.9613 7.13043ZM8.85457 7.13043L5 16.8696H7.15539L7.94365 14.8243H11.9763L12.7645 16.8696H14.9199L11.0653 7.13043H8.85457ZM8.64091 13.0156L9.95996 9.59291L11.279 13.0156H8.64091Z" fill="#191918"/>
+</g>
+<defs>
+<clipPath id="clip0_3907_39360">
+<rect width="14" height="9.73913" fill="white" transform="translate(5 7.13043)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/header/assets/azure.svg b/app/components/header/assets/azure.svg
new file mode 100644
index 0000000..3cfe391
--- /dev/null
+++ b/app/components/header/assets/azure.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="#3980C5"/>
+<path d="M18.5963 11.6572C18.748 11.9956 18.8443 12.3574 18.8836 12.7264C18.9216 13.0954 18.9026 13.4689 18.8238 13.8321C18.7465 14.1953 18.6123 14.5439 18.4256 14.8648C18.3031 15.0792 18.1587 15.2805 17.9924 15.4657C17.8276 15.6495 17.6438 15.8158 17.444 15.9617C17.2427 16.1075 17.0283 16.2301 16.8007 16.3307C16.5746 16.4299 16.3383 16.5057 16.0962 16.5553C15.9824 16.9083 15.8132 17.2423 15.5944 17.5428C15.3771 17.8433 15.1131 18.1073 14.8126 18.3247C14.5121 18.5435 14.1795 18.7127 13.8266 18.8264C13.4736 18.9417 13.1045 18.9985 12.7326 18.9985C12.4861 19 12.2381 18.9738 11.996 18.9242C11.7553 18.8731 11.519 18.7958 11.2929 18.6952C11.0668 18.5945 10.8524 18.4691 10.6526 18.3232C10.4542 18.1773 10.2704 18.0096 10.107 17.8243C9.74237 17.9031 9.36896 17.9221 8.99992 17.8841C8.63089 17.8448 8.26914 17.7485 7.92928 17.5968C7.59088 17.4466 7.27727 17.2423 7.00159 16.9929C6.72591 16.7435 6.49107 16.4518 6.30582 16.1309C6.18184 15.9164 6.07973 15.6904 6.00242 15.4555C5.92511 15.2207 5.87406 14.9785 5.84781 14.732C5.82155 14.487 5.82301 14.239 5.84927 13.9925C5.87552 13.7475 5.92949 13.5053 6.0068 13.2705C5.75883 12.9948 5.55462 12.6812 5.40292 12.3428C5.25268 12.0029 5.15495 11.6426 5.11703 11.2736C5.07765 10.9046 5.09807 10.5312 5.17538 10.168C5.25268 9.80476 5.38688 9.45614 5.57358 9.13524C5.69611 8.92082 5.84051 8.71807 6.00534 8.53428C6.17017 8.3505 6.35541 8.18421 6.55525 8.03835C6.75508 7.89248 6.97096 7.7685 7.19705 7.66931C7.42459 7.56867 7.66089 7.49428 7.90303 7.44468C8.0168 7.09023 8.186 6.75766 8.40334 6.45718C8.62213 6.15671 8.88615 5.89269 9.18663 5.6739C9.48711 5.45656 9.81968 5.28736 10.1727 5.17213C10.5257 5.05835 10.8947 5.00001 11.2666 5.00146C11.5132 5.00001 11.7611 5.0248 12.0033 5.07586C12.2454 5.12691 12.4817 5.20276 12.7078 5.3034C12.9339 5.40551 13.1483 5.52949 13.3481 5.67535C13.548 5.82268 13.7317 5.98896 13.8951 6.17421C14.2583 6.0969 14.6317 6.07794 15.0008 6.11586C15.3698 6.15379 15.7301 6.25152 16.0699 6.40176C16.4083 6.55345 16.7219 6.75621 16.9976 7.00563C17.2733 7.2536 17.5082 7.54387 17.6934 7.86623C17.8174 8.07919 17.9195 8.30528 17.9968 8.54158C18.0741 8.77642 18.1266 9.01855 18.1514 9.26506C18.1777 9.51157 18.1777 9.75954 18.15 10.006C18.1237 10.2526 18.0697 10.4947 17.9924 10.7295C18.2418 11.0052 18.4446 11.3174 18.5963 11.6572ZM13.7361 17.8841C14.0541 17.7529 14.3429 17.5589 14.5865 17.3153C14.8301 17.0717 15.0241 16.7829 15.1554 16.4634C15.2866 16.1455 15.3552 15.8041 15.3552 15.4599V12.2071C15.3542 12.2042 15.3533 12.2008 15.3523 12.1969C15.3513 12.194 15.3499 12.1911 15.3479 12.1882C15.346 12.1853 15.3435 12.1828 15.3406 12.1809C15.3377 12.178 15.3348 12.176 15.3319 12.175L14.1547 11.4953V15.4249C14.1547 15.4643 14.1489 15.5051 14.1387 15.543C14.1285 15.5824 14.1139 15.6189 14.0935 15.6539C14.0731 15.6889 14.0497 15.721 14.0206 15.7487C13.9922 15.777 13.9603 15.8015 13.9257 15.8216L11.1383 17.4305C11.1149 17.4451 11.0756 17.4655 11.0551 17.4772C11.1704 17.5749 11.2958 17.661 11.4271 17.7368C11.5598 17.8127 11.6969 17.8769 11.8399 17.9294C11.9828 17.9804 12.1302 18.0198 12.2789 18.0461C12.4292 18.0723 12.5809 18.0854 12.7326 18.0854C13.0768 18.0854 13.4181 18.0169 13.7361 17.8841ZM7.09786 15.6758C7.27144 15.9748 7.50044 16.2344 7.77321 16.4445C8.04743 16.6545 8.35812 16.8077 8.69069 16.8967C9.02326 16.9856 9.37042 17.009 9.71174 16.9637C10.0531 16.9185 10.3813 16.8077 10.6803 16.6356L13.4984 15.0092L13.5057 15.0019C13.5076 14.9999 13.5091 14.997 13.51 14.9931C13.512 14.9902 13.5134 14.9873 13.5144 14.9844V13.6133L10.1129 15.581C10.0779 15.6014 10.0414 15.616 10.0035 15.6276C9.96408 15.6378 9.9247 15.6422 9.88386 15.6422C9.84447 15.6422 9.80509 15.6378 9.76571 15.6276C9.72778 15.616 9.68986 15.6014 9.65485 15.581L6.86739 13.9706C6.8426 13.956 6.80613 13.9342 6.78571 13.921C6.75946 14.0713 6.74633 14.223 6.74633 14.3747C6.74633 14.5264 6.76091 14.6781 6.78717 14.8283C6.81342 14.9771 6.85427 15.1244 6.90532 15.2674C6.95783 15.4103 7.02201 15.5474 7.09786 15.6787V15.6758ZM6.36562 9.59325C6.1935 9.89228 6.08265 10.2219 6.03743 10.5632C5.99221 10.9046 6.01555 11.2503 6.10453 11.5843C6.1935 11.9169 6.34666 12.2276 6.5567 12.5018C6.76675 12.7745 7.02784 13.0035 7.32541 13.1757L10.142 14.8035C10.145 14.8045 10.1484 14.8055 10.1522 14.8064H10.1625C10.1663 14.8064 10.1697 14.8055 10.1727 14.8035C10.1756 14.8025 10.1785 14.8011 10.1814 14.7991L11.3629 14.1165L7.96137 12.1532C7.92782 12.1327 7.89573 12.1079 7.86656 12.0802C7.8383 12.0519 7.81379 12.02 7.79363 11.9854C7.77467 11.9504 7.75862 11.9139 7.74841 11.8746C7.7382 11.8366 7.73237 11.7973 7.73383 11.7564V8.44385C7.59088 8.49636 7.45231 8.56054 7.32103 8.63639C7.18975 8.7137 7.06577 8.80121 6.94908 8.89894C6.83385 8.99667 6.72591 9.10461 6.62818 9.2213C6.53045 9.33653 6.44439 9.46198 6.36854 9.59325H6.36562ZM16.0408 11.8454C16.0758 11.8658 16.1079 11.8892 16.137 11.9183C16.1647 11.946 16.1895 11.9781 16.21 12.0131C16.2289 12.0481 16.245 12.0861 16.2552 12.124C16.2639 12.1634 16.2698 12.2028 16.2683 12.2436V15.5562C16.7365 15.384 17.145 15.0821 17.4469 14.6854C17.7503 14.2886 17.9326 13.8146 17.9749 13.3186C18.0172 12.8227 17.918 12.3238 17.6876 11.8819C17.4571 11.4399 17.1056 11.0723 16.6738 10.8243L13.8572 9.19651C13.8543 9.19553 13.8509 9.19456 13.847 9.19359H13.8368C13.8338 9.19456 13.8304 9.19553 13.8266 9.19651C13.8236 9.19748 13.8207 9.19894 13.8178 9.20088L12.6421 9.88061L16.0437 11.8454H16.0408ZM17.215 10.0804H17.2135V10.0819L17.215 10.0804ZM17.2135 10.079C17.2981 9.58888 17.2412 9.08419 17.0487 8.62472C16.8576 8.16525 16.5382 7.76996 16.1297 7.48407C15.7213 7.19963 15.24 7.03626 14.7426 7.01438C14.2437 6.99396 13.7507 7.11503 13.3189 7.363L10.5023 8.98938C10.4994 8.99132 10.497 8.99375 10.495 8.99667L10.4892 9.00542C10.4882 9.00834 10.4872 9.01174 10.4863 9.01563C10.4853 9.01855 10.4848 9.02196 10.4848 9.02585V10.3853L13.8864 8.42051C13.9214 8.40009 13.9593 8.3855 13.9972 8.37383C14.0366 8.36362 14.076 8.35925 14.1154 8.35925C14.1562 8.35925 14.1956 8.36362 14.235 8.37383C14.2729 8.3855 14.3094 8.40009 14.3444 8.42051L17.1318 10.0308C17.1566 10.0454 17.1931 10.0659 17.2135 10.079ZM9.84301 8.57367C9.84301 8.53428 9.84885 8.4949 9.85906 8.45552C9.86927 8.41759 9.88386 8.37967 9.90428 8.34466C9.9247 8.31111 9.94804 8.27902 9.97721 8.24985C10.0049 8.22214 10.037 8.19734 10.072 8.17838L12.8595 6.5695C12.8857 6.55345 12.9222 6.53303 12.9426 6.52282C12.5605 6.20338 12.0937 5.99917 11.5992 5.93645C11.1047 5.87227 10.603 5.95104 10.1522 6.16254C9.70007 6.37404 9.3179 6.71099 9.05097 7.13107C8.78404 7.55262 8.64256 8.03981 8.64256 8.53866V11.7914C8.64353 11.7953 8.6445 11.7987 8.64547 11.8016C8.64645 11.8045 8.6479 11.8075 8.64985 11.8104C8.65179 11.8133 8.65422 11.8162 8.65714 11.8191C8.65909 11.8211 8.662 11.823 8.66589 11.825L9.84301 12.5047V8.57367ZM10.4819 12.8723L11.9974 13.7475L13.5129 12.8723V11.1234L11.9989 10.2482L10.4834 11.1234L10.4819 12.8723Z" fill="white"/>
+</svg>
diff --git a/app/components/header/assets/bitbucket.svg b/app/components/header/assets/bitbucket.svg
new file mode 100644
index 0000000..4d28ea7
--- /dev/null
+++ b/app/components/header/assets/bitbucket.svg
@@ -0,0 +1,10 @@
+<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_660_1978)">
+<path d="M16.1064 1.77422C16.1184 1.7048 16.115 1.63359 16.0965 1.56561C16.078 1.49763 16.0448 1.43453 15.9993 1.38074C15.9538 1.32696 15.8971 1.2838 15.8331 1.25431C15.7691 1.22481 15.6994 1.20969 15.629 1.21001H0.602662C0.531806 1.20898 0.461593 1.22358 0.397019 1.25276C0.332445 1.28195 0.275097 1.32501 0.229055 1.37888C0.183014 1.43275 0.14941 1.4961 0.130636 1.56443C0.111861 1.63276 0.108377 1.70439 0.120432 1.77422L2.31458 15.2285C2.33294 15.3417 2.3911 15.4448 2.47861 15.519C2.56611 15.5933 2.67723 15.6339 2.79199 15.6335H13.4493C13.6904 15.6335 13.8929 15.4648 13.9315 15.2285L16.1064 1.77422ZM9.78916 10.7823H6.4473L5.54553 6.05643H10.5993L9.78916 10.7823Z" fill="#2684FF"/>
+</g>
+<defs>
+<clipPath id="clip0_660_1978">
+<rect width="16" height="16" fill="white" transform="translate(0 0.5)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/header/assets/file.svg b/app/components/header/assets/file.svg
new file mode 100644
index 0000000..aab093a
--- /dev/null
+++ b/app/components/header/assets/file.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M13.3333 6.99992V4.53325C13.3333 3.41315 13.3333 2.85309 13.1153 2.42527C12.9236 2.04895 12.6176 1.74299 12.2413 1.55124C11.8135 1.33325 11.2534 1.33325 10.1333 1.33325H5.86666C4.74655 1.33325 4.1865 1.33325 3.75868 1.55124C3.38235 1.74299 3.07639 2.04895 2.88464 2.42527C2.66666 2.85309 2.66666 3.41315 2.66666 4.53325V11.4666C2.66666 12.5867 2.66666 13.1467 2.88464 13.5746C3.07639 13.9509 3.38235 14.2569 3.75868 14.4486C4.1865 14.6666 4.74655 14.6666 5.86666 14.6666H7.99999M9.33332 7.33325H5.33332M6.66666 9.99992H5.33332M10.6667 4.66659H5.33332M12 13.9999V9.99992M9.99999 11.9999H14" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/header/assets/github.svg b/app/components/header/assets/github.svg
new file mode 100644
index 0000000..f03798b
--- /dev/null
+++ b/app/components/header/assets/github.svg
@@ -0,0 +1,17 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_131_1011)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0003 0.5C9.15149 0.501478 6.39613 1.51046 4.22687 3.34652C2.05761 5.18259 0.615903 7.72601 0.159545 10.522C-0.296814 13.318 0.261927 16.1842 1.73587 18.6082C3.20981 21.0321 5.50284 22.8558 8.20493 23.753C8.80105 23.8636 9.0256 23.4941 9.0256 23.18C9.0256 22.8658 9.01367 21.955 9.0097 20.9592C5.6714 21.6804 4.96599 19.5505 4.96599 19.5505C4.42152 18.1674 3.63464 17.8039 3.63464 17.8039C2.54571 17.065 3.71611 17.0788 3.71611 17.0788C4.92227 17.1637 5.55616 18.3097 5.55616 18.3097C6.62521 20.1333 8.36389 19.6058 9.04745 19.2976C9.15475 18.5251 9.46673 17.9995 9.8105 17.7012C7.14383 17.4008 4.34204 16.3774 4.34204 11.8054C4.32551 10.6197 4.76802 9.47305 5.57801 8.60268C5.45481 8.30236 5.04348 7.08923 5.69524 5.44143C5.69524 5.44143 6.7027 5.12135 8.9958 6.66444C10.9627 6.12962 13.0379 6.12962 15.0047 6.66444C17.2958 5.12135 18.3013 5.44143 18.3013 5.44143C18.9551 7.08528 18.5437 8.29841 18.4205 8.60268C19.2331 9.47319 19.6765 10.6218 19.6585 11.8094C19.6585 16.3912 16.8507 17.4008 14.1801 17.6952C14.6093 18.0667 14.9928 18.7918 14.9928 19.9061C14.9928 21.5026 14.9789 22.7868 14.9789 23.18C14.9789 23.4981 15.1955 23.8695 15.8035 23.753C18.5059 22.8557 20.7992 21.0317 22.2731 18.6073C23.747 16.183 24.3055 13.3163 23.8486 10.5201C23.3917 7.7238 21.9493 5.18035 19.7793 3.34461C17.6093 1.50886 14.8533 0.500541 12.0042 0.5H12.0003Z" fill="#191717"/>
+<path d="M4.54444 17.6321C4.5186 17.6914 4.42322 17.7092 4.34573 17.6677C4.26823 17.6262 4.21061 17.5491 4.23843 17.4879C4.26625 17.4266 4.35964 17.4108 4.43714 17.4523C4.51463 17.4938 4.57424 17.5729 4.54444 17.6321Z" fill="#191717"/>
+<path d="M5.03123 18.1714C4.99008 18.192 4.943 18.1978 4.89805 18.1877C4.8531 18.1776 4.81308 18.1523 4.78483 18.1161C4.70734 18.0331 4.69143 17.9185 4.75104 17.8671C4.81066 17.8157 4.91797 17.8395 4.99546 17.9224C5.07296 18.0054 5.09084 18.12 5.03123 18.1714Z" fill="#191717"/>
+<path d="M5.50425 18.857C5.43072 18.9084 5.30553 18.857 5.23598 18.7543C5.21675 18.7359 5.20146 18.7138 5.19101 18.6893C5.18056 18.6649 5.17517 18.6386 5.17517 18.612C5.17517 18.5855 5.18056 18.5592 5.19101 18.5347C5.20146 18.5103 5.21675 18.4882 5.23598 18.4698C5.3095 18.4204 5.4347 18.4698 5.50425 18.5705C5.57379 18.6713 5.57578 18.8057 5.50425 18.857V18.857Z" fill="#191717"/>
+<path d="M6.14612 19.5207C6.08054 19.5939 5.94741 19.5741 5.83812 19.4753C5.72883 19.3765 5.70299 19.2422 5.76857 19.171C5.83414 19.0999 5.96727 19.1197 6.08054 19.2165C6.1938 19.3133 6.21566 19.4496 6.14612 19.5207V19.5207Z" fill="#191717"/>
+<path d="M7.04617 19.9081C7.01637 20.001 6.88124 20.0425 6.74612 20.003C6.611 19.9635 6.52158 19.8528 6.54741 19.758C6.57325 19.6631 6.71036 19.6197 6.84747 19.6631C6.98457 19.7066 7.07201 19.8113 7.04617 19.9081Z" fill="#191717"/>
+<path d="M8.02783 19.9752C8.02783 20.072 7.91656 20.155 7.77349 20.1569C7.63042 20.1589 7.51318 20.0799 7.51318 19.9831C7.51318 19.8863 7.62445 19.8033 7.76752 19.8013C7.91059 19.7993 8.02783 19.8764 8.02783 19.9752Z" fill="#191717"/>
+<path d="M8.9419 19.8232C8.95978 19.92 8.86042 20.0207 8.71735 20.0445C8.57428 20.0682 8.4491 20.0109 8.43121 19.916C8.41333 19.8212 8.51666 19.7185 8.65576 19.6928C8.79485 19.6671 8.92401 19.7264 8.9419 19.8232Z" fill="#191717"/>
+</g>
+<defs>
+<clipPath id="clip0_131_1011">
+<rect width="24" height="24" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/header/assets/google.svg b/app/components/header/assets/google.svg
new file mode 100644
index 0000000..6bcacfc
--- /dev/null
+++ b/app/components/header/assets/google.svg
@@ -0,0 +1,13 @@
+<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_729_2080)">
+<path d="M20.3052 10.2302C20.3052 9.55044 20.2501 8.86699 20.1325 8.19824H10.7002V12.0491H16.1016C15.8775 13.291 15.1573 14.3897 14.1027 15.0878V17.5864H17.3252C19.2176 15.8448 20.3052 13.2726 20.3052 10.2302Z" fill="#4285F4"/>
+<path d="M10.6999 20.0008C13.397 20.0008 15.6714 19.1152 17.3286 17.5867L14.1061 15.088C13.2096 15.698 12.0521 16.0434 10.7036 16.0434C8.09474 16.0434 5.88272 14.2833 5.08904 11.917H1.76367V14.4928C3.46127 17.8696 6.91892 20.0008 10.6999 20.0008Z" fill="#34A853"/>
+<path d="M5.08564 11.9172C4.66676 10.6753 4.66676 9.33044 5.08564 8.08848V5.5127H1.76395C0.345611 8.33834 0.345611 11.6674 1.76395 14.493L5.08564 11.9172Z" fill="#FBBC04"/>
+<path d="M10.6999 3.95805C12.1256 3.936 13.5035 4.47247 14.536 5.45722L17.3911 2.60218C15.5833 0.904587 13.1838 -0.0287217 10.6999 0.000673888C6.91892 0.000673888 3.46126 2.13185 1.76367 5.51234L5.08537 8.08813C5.87537 5.71811 8.09106 3.95805 10.6999 3.95805Z" fill="#EA4335"/>
+</g>
+<defs>
+<clipPath id="clip0_729_2080">
+<rect width="20" height="20" fill="white" transform="translate(0.5)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/header/assets/gpt.svg b/app/components/header/assets/gpt.svg
new file mode 100644
index 0000000..c20df23
--- /dev/null
+++ b/app/components/header/assets/gpt.svg
@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="20" height="20" rx="6" fill="black"/>
+<path d="M16.5965 9.65778C16.7482 9.99618 16.8444 10.3579 16.8838 10.727C16.9218 11.096 16.9028 11.4694 16.824 11.8326C16.7467 12.1958 16.6125 12.5444 16.4258 12.8653C16.3033 13.0797 16.1589 13.281 15.9926 13.4663C15.8278 13.6501 15.644 13.8163 15.4442 13.9622C15.2429 14.1081 15.0284 14.2306 14.8009 14.3312C14.5748 14.4304 14.3385 14.5063 14.0964 14.5559C13.9826 14.9089 13.8134 15.2429 13.5946 15.5434C13.3773 15.8439 13.1133 16.1079 12.8128 16.3252C12.5123 16.544 12.1797 16.7132 11.8267 16.827C11.4737 16.9422 11.1047 16.9991 10.7328 16.9991C10.4862 17.0006 10.2383 16.9743 9.99615 16.9247C9.75547 16.8737 9.51917 16.7963 9.29308 16.6957C9.06699 16.5951 8.85257 16.4696 8.65274 16.3237C8.45437 16.1779 8.27058 16.0101 8.10721 15.8249C7.74255 15.9037 7.36914 15.9226 7.00011 15.8847C6.63107 15.8453 6.26933 15.749 5.92947 15.5973C5.59106 15.4471 5.27745 15.2429 5.00177 14.9935C4.72609 14.744 4.49125 14.4523 4.306 14.1314C4.18202 13.917 4.07991 13.6909 4.00261 13.4561C3.9253 13.2212 3.87425 12.9791 3.84799 12.7326C3.82173 12.4875 3.82319 12.2396 3.84945 11.9931C3.8757 11.748 3.92967 11.5059 4.00698 11.271C3.75901 10.9953 3.5548 10.6817 3.40311 10.3433C3.25287 10.0035 3.15514 9.64319 3.11721 9.27415C3.07783 8.90512 3.09825 8.53171 3.17556 8.16851C3.25287 7.80531 3.38706 7.45669 3.57377 7.13579C3.69629 6.92137 3.8407 6.71862 4.00552 6.53483C4.17035 6.35104 4.3556 6.18476 4.55543 6.0389C4.75526 5.89303 4.97114 5.76905 5.19723 5.66986C5.42478 5.56922 5.66108 5.49482 5.90321 5.44523C6.01698 5.09078 6.18619 4.75821 6.40352 4.45773C6.62232 4.15725 6.88633 3.89324 7.18681 3.67445C7.48729 3.45711 7.81986 3.28791 8.17285 3.17267C8.52584 3.0589 8.89488 3.00056 9.26683 3.00201C9.51334 3.00056 9.76131 3.02535 10.0034 3.0764C10.2456 3.12746 10.4819 3.20331 10.708 3.30395C10.934 3.40606 11.1485 3.53004 11.3483 3.6759C11.5481 3.82323 11.7319 3.98951 11.8953 4.17476C12.2585 4.09745 12.6319 4.07849 13.0009 4.11641C13.37 4.15434 13.7303 4.25207 14.0701 4.40231C14.4085 4.554 14.7221 4.75675 14.9978 5.00618C15.2735 5.25415 15.5083 5.54442 15.6936 5.86678C15.8176 6.07974 15.9197 6.30583 15.997 6.54213C16.0743 6.77697 16.1268 7.0191 16.1516 7.26561C16.1778 7.51212 16.1778 7.76009 16.1501 8.0066C16.1239 8.25311 16.0699 8.49524 15.9926 8.73008C16.242 9.00576 16.4448 9.31791 16.5965 9.65778ZM11.7363 15.8847C12.0543 15.7534 12.3431 15.5594 12.5867 15.3158C12.8303 15.0722 13.0243 14.7834 13.1556 14.464C13.2868 14.146 13.3554 13.8047 13.3554 13.4604V10.2077C13.3544 10.2048 13.3534 10.2014 13.3525 10.1975C13.3515 10.1946 13.35 10.1916 13.3481 10.1887C13.3461 10.1858 13.3437 10.1834 13.3408 10.1814C13.3379 10.1785 13.335 10.1766 13.332 10.1756L12.1549 9.49587V13.4254C12.1549 13.4648 12.1491 13.5057 12.1389 13.5436C12.1287 13.583 12.1141 13.6194 12.0937 13.6544C12.0732 13.6894 12.0499 13.7215 12.0207 13.7493C11.9924 13.7775 11.9605 13.802 11.9259 13.8222L9.13847 15.4311C9.11513 15.4456 9.07575 15.4661 9.05533 15.4777C9.17056 15.5755 9.296 15.6615 9.42728 15.7374C9.56001 15.8132 9.69713 15.8774 9.84007 15.9299C9.98302 15.981 10.1303 16.0204 10.2791 16.0466C10.4294 16.0729 10.5811 16.086 10.7328 16.086C11.077 16.086 11.4183 16.0174 11.7363 15.8847ZM5.09804 13.6763C5.27162 13.9753 5.50063 14.235 5.77339 14.445C6.04762 14.6551 6.3583 14.8082 6.69087 14.8972C7.02344 14.9862 7.3706 15.0095 7.71192 14.9643C8.05324 14.9191 8.38143 14.8082 8.68046 14.6361L11.4985 13.0097L11.5058 13.0024C11.5078 13.0005 11.5092 12.9976 11.5102 12.9937C11.5122 12.9908 11.5136 12.9878 11.5146 12.9849V11.6138L8.11305 13.5815C8.07804 13.6019 8.04157 13.6165 8.00365 13.6282C7.96426 13.6384 7.92488 13.6428 7.88404 13.6428C7.84466 13.6428 7.80527 13.6384 7.76589 13.6282C7.72797 13.6165 7.69004 13.6019 7.65503 13.5815L4.86758 11.9712C4.84278 11.9566 4.80631 11.9347 4.78589 11.9216C4.75964 12.0718 4.74651 12.2235 4.74651 12.3752C4.74651 12.5269 4.7611 12.6786 4.78735 12.8289C4.81361 12.9776 4.85445 13.125 4.9055 13.2679C4.95801 13.4108 5.02219 13.548 5.09804 13.6792V13.6763ZM4.36581 7.5938C4.19369 7.89282 4.08283 8.22248 4.03761 8.5638C3.9924 8.90512 4.01573 9.25082 4.10471 9.58484C4.19369 9.91741 4.34684 10.2281 4.55689 10.5023C4.76693 10.7751 5.02803 11.0041 5.32559 11.1762L8.14222 12.8041C8.14514 12.805 8.14854 12.806 8.15243 12.807H8.16264C8.16653 12.807 8.16993 12.806 8.17285 12.8041C8.17577 12.8031 8.17868 12.8016 8.1816 12.7997L9.3631 12.117L5.96156 10.1537C5.92801 10.1333 5.89592 10.1085 5.86674 10.0808C5.83848 10.0524 5.81397 10.0206 5.79381 9.98597C5.77485 9.95096 5.75881 9.9145 5.74859 9.87511C5.73838 9.83719 5.73255 9.7978 5.73401 9.75696V6.4444C5.59106 6.49691 5.45249 6.56109 5.32121 6.63694C5.18994 6.71425 5.06595 6.80176 4.94926 6.89949C4.83403 6.99722 4.72609 7.10516 4.62836 7.22185C4.53063 7.33708 4.44457 7.46253 4.36872 7.5938H4.36581ZM14.0409 9.84594C14.076 9.86636 14.108 9.8897 14.1372 9.91887C14.1649 9.94659 14.1897 9.97868 14.2101 10.0137C14.2291 10.0487 14.2452 10.0866 14.2554 10.1245C14.2641 10.1639 14.27 10.2033 14.2685 10.2441V13.5567C14.7367 13.3846 15.1451 13.0827 15.4471 12.6859C15.7505 12.2892 15.9328 11.8151 15.9751 11.3192C16.0174 10.8232 15.9182 10.3244 15.6877 9.88241C15.4573 9.44044 15.1058 9.07286 14.674 8.82489L11.8574 7.19705C11.8544 7.19608 11.851 7.19511 11.8472 7.19414H11.8369C11.834 7.19511 11.8306 7.19608 11.8267 7.19705C11.8238 7.19803 11.8209 7.19949 11.818 7.20143L10.6423 7.88116L14.0439 9.84594H14.0409ZM15.2151 8.08099H15.2137V8.08245L15.2151 8.08099ZM15.2137 8.07953C15.2983 7.58943 15.2414 7.08474 15.0489 6.62527C14.8578 6.1658 14.5383 5.77051 14.1299 5.48461C13.7215 5.20018 13.2402 5.03681 12.7428 5.01493C12.2439 4.99451 11.7509 5.11558 11.3191 5.36355L8.5025 6.98993C8.49958 6.99187 8.49715 6.9943 8.49521 6.99722L8.48937 7.00597C8.4884 7.00889 8.48743 7.01229 8.48646 7.01618C8.48548 7.0191 8.485 7.0225 8.485 7.02639V8.38584L11.8865 6.42106C11.9215 6.40064 11.9595 6.38605 11.9974 6.37438C12.0368 6.36417 12.0762 6.3598 12.1155 6.3598C12.1564 6.3598 12.1958 6.36417 12.2352 6.37438C12.2731 6.38605 12.3095 6.40064 12.3446 6.42106L15.132 8.03139C15.1568 8.04598 15.1933 8.0664 15.2137 8.07953ZM7.8432 6.57422C7.8432 6.53483 7.84903 6.49545 7.85924 6.45607C7.86945 6.41814 7.88404 6.38022 7.90446 6.34521C7.92488 6.31166 7.94822 6.27957 7.97739 6.2504C8.00511 6.22268 8.0372 6.19789 8.0722 6.17893L10.8597 4.57005C10.8859 4.554 10.9224 4.53358 10.9428 4.52337C10.5606 4.20393 10.0939 3.99972 9.5994 3.937C9.10492 3.87282 8.60315 3.95159 8.15243 4.16309C7.70025 4.37459 7.31809 4.71154 7.05116 5.13162C6.78423 5.55317 6.64274 6.04036 6.64274 6.53921V9.79197C6.64371 9.79586 6.64468 9.79926 6.64566 9.80218C6.64663 9.8051 6.64809 9.80802 6.65003 9.81093C6.65198 9.81385 6.65441 9.81677 6.65733 9.81968C6.65927 9.82163 6.66219 9.82357 6.66608 9.82552L7.8432 10.5052V6.57422ZM8.48208 10.8728L9.9976 11.748L11.5131 10.8728V9.12391L9.99906 8.24873L8.48354 9.12391L8.48208 10.8728Z" fill="white"/>
+</svg>
diff --git a/app/components/header/assets/hugging-face.svg b/app/components/header/assets/hugging-face.svg
new file mode 100644
index 0000000..1f53ec0
--- /dev/null
+++ b/app/components/header/assets/hugging-face.svg
@@ -0,0 +1,21 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="24" height="24" rx="6" fill="white"/>
+<path d="M11.9514 17.4737C15.1838 17.4737 17.8041 14.8534 17.8041 11.6211C17.8041 8.38874 15.1838 5.76843 11.9514 5.76843C8.71913 5.76843 6.09882 8.38874 6.09882 11.6211C6.09882 14.8534 8.71913 17.4737 11.9514 17.4737Z" fill="#FFD21E"/>
+<path d="M17.8041 11.621C17.8041 8.38872 15.1838 5.76841 11.9515 5.76841C8.71917 5.76841 6.09886 8.38872 6.09886 11.621C6.09886 14.8534 8.71917 17.4737 11.9515 17.4737C15.1838 17.4737 17.8041 14.8534 17.8041 11.621ZM5.42517 11.621C5.42517 8.01666 8.3471 5.09473 11.9515 5.09473C15.5559 5.09473 18.4778 8.01666 18.4778 11.621C18.4778 15.2254 15.5559 18.1474 11.9515 18.1474C8.3471 18.1474 5.42517 15.2254 5.42517 11.621Z" fill="#FF9D0B"/>
+<path d="M13.853 10.028C14.0676 10.1038 14.1531 10.5451 14.3699 10.4298C14.7805 10.2114 14.9364 9.70155 14.7181 9.29091C14.4997 8.88028 13.9898 8.72439 13.5792 8.94273C13.1685 9.16107 13.0127 9.67097 13.231 10.0816C13.3341 10.2754 13.6611 9.96028 13.853 10.028Z" fill="#3A3B45"/>
+<path d="M9.88553 10.028C9.6709 10.1038 9.58551 10.5451 9.36868 10.4298C8.95804 10.2114 8.80215 9.70155 9.02049 9.29091C9.23883 8.88028 9.74873 8.72439 10.1594 8.94273C10.57 9.16107 10.7259 9.67097 10.5076 10.0816C10.4045 10.2754 10.0774 9.96028 9.88553 10.028Z" fill="#3A3B45"/>
+<path d="M11.9094 14.0697C13.5647 14.0697 14.0989 12.5938 14.0989 11.836C14.0989 11.4421 13.8341 11.5661 13.41 11.776C13.0181 11.97 12.4901 12.2375 11.9094 12.2375C10.7002 12.2375 9.71991 11.0781 9.71991 11.836C9.71991 12.5938 10.2541 14.0697 11.9094 14.0697Z" fill="#3A3B45"/>
+<mask id="mask0_3907_39368" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="9" y="11" width="6" height="4">
+<path d="M11.9094 14.0697C13.5647 14.0697 14.0989 12.5938 14.0989 11.836C14.0989 11.4421 13.8341 11.5661 13.41 11.776C13.0181 11.97 12.4901 12.2375 11.9094 12.2375C10.7002 12.2375 9.71991 11.0781 9.71991 11.836C9.71991 12.5938 10.2541 14.0697 11.9094 14.0697Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_3907_39368)">
+<path d="M11.9515 15.7894C12.7582 15.7894 13.4122 15.1354 13.4122 14.3287C13.4122 13.7004 13.0154 13.1647 12.4588 12.9585C12.4383 12.9509 12.4176 12.9438 12.3967 12.9371C12.2563 12.8922 12.1068 13.3747 11.9515 13.3747C11.8064 13.3747 11.6663 12.8892 11.534 12.9285C10.9307 13.1081 10.4908 13.6671 10.4908 14.3287C10.4908 15.1354 11.1448 15.7894 11.9515 15.7894Z" fill="#F94040"/>
+</g>
+<path d="M15.9094 10.8211C16.2117 10.8211 16.4567 10.576 16.4567 10.2737C16.4567 9.97139 16.2117 9.72632 15.9094 9.72632C15.6071 9.72632 15.362 9.97139 15.362 10.2737C15.362 10.576 15.6071 10.8211 15.9094 10.8211Z" fill="#FF9D0B"/>
+<path d="M8.07776 10.8211C8.38006 10.8211 8.62513 10.576 8.62513 10.2737C8.62513 9.97139 8.38006 9.72632 8.07776 9.72632C7.77545 9.72632 7.5304 9.97139 7.5304 10.2737C7.5304 10.576 7.77545 10.8211 8.07776 10.8211Z" fill="#FF9D0B"/>
+<path d="M6.9514 12.6737C6.67872 12.6737 6.43502 12.7857 6.26508 12.9888C6.15999 13.1146 6.05018 13.3174 6.04125 13.6211C5.92689 13.5882 5.81691 13.5699 5.71418 13.5699C5.45312 13.5699 5.21733 13.6699 5.0506 13.8516C4.83636 14.0849 4.74121 14.3716 4.78264 14.6584C4.80234 14.795 4.84799 14.9174 4.9162 15.0308C4.77236 15.1471 4.66643 15.3092 4.61523 15.504C4.57514 15.6568 4.53405 15.9749 4.74862 16.3027C4.73498 16.3241 4.72218 16.3463 4.71022 16.369C4.58121 16.6139 4.57295 16.8906 4.68681 17.1483C4.85944 17.5389 5.28841 17.8466 6.12142 18.1769C6.63965 18.3823 7.11375 18.5137 7.11796 18.5149C7.8031 18.6926 8.42272 18.7828 8.95914 18.7828C9.94508 18.7828 10.6509 18.4809 11.0572 17.8853C11.711 16.9263 11.6175 16.0492 10.7715 15.2037C10.3033 14.7359 9.99207 14.046 9.92723 13.8946C9.79653 13.4463 9.45093 12.9479 8.87645 12.9479C8.82811 12.9479 8.7791 12.9518 8.73093 12.9593C8.47931 12.9989 8.25935 13.1438 8.10222 13.3617C7.93262 13.1508 7.7679 12.9831 7.61885 12.8884C7.39418 12.746 7.16967 12.6737 6.9514 12.6737ZM6.9514 13.3474C7.03729 13.3474 7.14222 13.3839 7.25792 13.4574C7.61716 13.6852 8.31039 14.8768 8.5642 15.3403C8.64925 15.4956 8.7946 15.5613 8.92546 15.5613C9.18516 15.5613 9.38794 15.3031 8.94921 14.975C8.2895 14.4814 8.52091 13.6745 8.83586 13.6248C8.84967 13.6226 8.86331 13.6216 8.87645 13.6216C9.16277 13.6216 9.28908 14.1151 9.28908 14.1151C9.28908 14.1151 9.65927 15.0447 10.2952 15.6802C10.9312 16.3158 10.964 16.826 10.5005 17.5057C10.1844 17.9692 9.57927 18.1092 8.95914 18.1092C8.31594 18.1092 7.65658 17.9586 7.28706 17.8628C7.26887 17.858 5.02163 17.2233 5.30626 16.683C5.35409 16.5922 5.43291 16.5558 5.53211 16.5558C5.93295 16.5558 6.66205 17.1524 6.97548 17.1524C7.04554 17.1524 7.09489 17.1225 7.1151 17.0498C7.24866 16.5706 5.08445 16.3692 5.26685 15.6751C5.29902 15.5524 5.38626 15.5025 5.50887 15.5027C6.03855 15.5027 7.22693 16.4342 7.47603 16.4342C7.49506 16.4342 7.5087 16.4287 7.51611 16.4169C7.64091 16.2154 7.57253 16.0748 6.69287 15.5424C5.81321 15.0099 5.19578 14.6895 5.54693 14.3072C5.58735 14.2631 5.64462 14.2436 5.71418 14.2436C6.24824 14.2437 7.51005 15.392 7.51005 15.392C7.51005 15.392 7.8506 15.7462 8.05658 15.7462C8.1039 15.7462 8.14415 15.7275 8.17144 15.6814C8.31746 15.4351 6.81514 14.2966 6.73043 13.8269C6.673 13.5086 6.77068 13.3474 6.9514 13.3474Z" fill="#FF9D0B"/>
+<path d="M10.5005 17.5057C10.964 16.8259 10.9312 16.3158 10.2952 15.6802C9.65925 15.0447 9.28906 14.115 9.28906 14.115C9.28906 14.115 9.15079 13.5751 8.83584 13.6247C8.5209 13.6744 8.28965 14.4813 8.94936 14.975C9.60907 15.4685 8.81799 15.8038 8.56418 15.3403C8.31037 14.8768 7.61732 13.6852 7.25791 13.4573C6.89866 13.2295 6.6457 13.3571 6.73041 13.8269C6.81513 14.2966 8.31761 15.4351 8.17142 15.6815C8.02523 15.9277 7.51003 15.392 7.51003 15.392C7.51003 15.392 5.89791 13.9249 5.54691 14.3072C5.19592 14.6895 5.81319 15.0098 6.69285 15.5424C7.57269 16.0748 7.6409 16.2154 7.5161 16.4168C7.39113 16.6183 5.44922 14.981 5.26682 15.6751C5.08459 16.3692 7.24864 16.5706 7.11509 17.0498C6.98153 17.5291 5.5907 16.1428 5.30624 16.6829C5.0216 17.2232 7.26885 17.858 7.28704 17.8627C8.01294 18.051 9.85648 18.45 10.5005 17.5057Z" fill="#FFD21E"/>
+<path d="M17.0358 12.6737C17.3084 12.6737 17.5521 12.7857 17.7221 12.9888C17.8272 13.1146 17.937 13.3174 17.9459 13.6211C18.0603 13.5882 18.1702 13.5699 18.273 13.5699C18.534 13.5699 18.7698 13.6699 18.9366 13.8516C19.1508 14.0849 19.2459 14.3716 19.2045 14.6584C19.1848 14.795 19.1392 14.9174 19.071 15.0308C19.2148 15.1471 19.3207 15.3092 19.3719 15.504C19.412 15.6568 19.4531 15.9749 19.2385 16.3027C19.2522 16.3241 19.265 16.3463 19.2769 16.369C19.4059 16.6139 19.4142 16.8906 19.3003 17.1483C19.1277 17.5389 18.6987 17.8466 17.8657 18.1769C17.3475 18.3823 16.8734 18.5137 16.8692 18.5149C16.1841 18.6926 15.5644 18.7828 15.028 18.7828C14.0421 18.7828 13.3362 18.4809 12.93 17.8853C12.2762 16.9263 12.3697 16.0492 13.2156 15.2037C13.6838 14.7359 13.9951 14.046 14.0599 13.8946C14.1906 13.4463 14.5362 12.9479 15.1107 12.9479C15.159 12.9479 15.2081 12.9518 15.2562 12.9593C15.5078 12.9989 15.7278 13.1438 15.8849 13.3617C16.0545 13.1508 16.2193 12.9831 16.3683 12.8884C16.593 12.746 16.8175 12.6737 17.0358 12.6737ZM17.0358 13.3474C16.9499 13.3474 16.8449 13.3839 16.7292 13.4574C16.37 13.6852 15.6768 14.8768 15.423 15.3403C15.3379 15.4956 15.1926 15.5613 15.0617 15.5613C14.802 15.5613 14.5992 15.3031 15.0379 14.975C15.6977 14.4814 15.4662 13.6745 15.1513 13.6248C15.1375 13.6226 15.1238 13.6216 15.1107 13.6216C14.8244 13.6216 14.6981 14.1151 14.6981 14.1151C14.6981 14.1151 14.3279 15.0447 13.6919 15.6802C13.056 16.3158 13.0231 16.826 13.4866 17.5057C13.8027 17.9692 14.4079 18.1092 15.028 18.1092C15.6712 18.1092 16.3306 17.9586 16.7001 17.8628C16.7183 17.858 18.9655 17.2233 18.6809 16.683C18.6331 16.5922 18.5542 16.5558 18.455 16.5558C18.0542 16.5558 17.3251 17.1524 17.0117 17.1524C16.9416 17.1524 16.8923 17.1225 16.8721 17.0498C16.7385 16.5706 18.9027 16.3692 18.7203 15.6751C18.6881 15.5524 18.6009 15.5025 18.4783 15.5027C17.9486 15.5027 16.7602 16.4342 16.5111 16.4342C16.4921 16.4342 16.4785 16.4287 16.471 16.4169C16.3462 16.2154 16.4146 16.0748 17.2943 15.5424C18.1739 15.0099 18.7914 14.6895 18.4402 14.3072C18.3998 14.2631 18.3425 14.2436 18.273 14.2436C17.7389 14.2437 16.4771 15.392 16.4771 15.392C16.4771 15.392 16.1366 15.7462 15.9306 15.7462C15.8833 15.7462 15.843 15.7275 15.8157 15.6814C15.6697 15.4351 17.172 14.2966 17.2567 13.8269C17.3142 13.5086 17.2165 13.3474 17.0358 13.3474Z" fill="#FF9D0B"/>
+<path d="M13.4867 17.5057C13.0232 16.8259 13.056 16.3158 13.692 15.6802C14.3279 15.0447 14.6981 14.115 14.6981 14.115C14.6981 14.115 14.8364 13.5751 15.1513 13.6247C15.4663 13.6744 15.6975 14.4813 15.0378 14.975C14.3781 15.4685 15.1692 15.8038 15.423 15.3403C15.6768 14.8768 16.3699 13.6852 16.7293 13.4573C17.0885 13.2295 17.3415 13.3571 17.2568 13.8269C17.1721 14.2966 15.6696 15.4351 15.8158 15.6815C15.962 15.9277 16.4772 15.392 16.4772 15.392C16.4772 15.392 18.0893 13.9249 18.4403 14.3072C18.7913 14.6895 18.174 15.0098 17.2943 15.5424C16.4145 16.0748 16.3463 16.2154 16.4711 16.4168C16.5961 16.6183 18.538 14.981 18.7204 15.6751C18.9026 16.3692 16.7385 16.5706 16.8721 17.0498C17.0057 17.5291 18.3965 16.1428 18.6809 16.6829C18.9656 17.2232 16.7183 17.858 16.7001 17.8627C15.9743 18.051 14.1307 18.45 13.4867 17.5057Z" fill="#FFD21E"/>
+<rect x="0.25" y="0.25" width="23.5" height="23.5" rx="5.75" stroke="black" stroke-opacity="0.05" stroke-width="0.5"/>
+</svg>
diff --git a/app/components/header/assets/notion.svg b/app/components/header/assets/notion.svg
new file mode 100644
index 0000000..eeda894
--- /dev/null
+++ b/app/components/header/assets/notion.svg
@@ -0,0 +1,12 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5364_42310)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M3.5725 18.2611L1.4229 15.5832C0.905706 14.9389 0.625 14.1466 0.625 13.3312V3.63437C0.625 2.4129 1.60224 1.39936 2.86295 1.31328L12.8326 0.632614C13.5569 0.583164 14.2768 0.775682 14.8717 1.17794L18.3745 3.5462C19.0015 3.97012 19.375 4.66312 19.375 5.40266V16.427C19.375 17.6223 18.4141 18.6121 17.1798 18.688L6.11458 19.3692C5.12958 19.4298 4.17749 19.0148 3.5725 18.2611Z" fill="white"/>
+<path d="M7.03006 8.48663V8.35968C7.03006 8.03787 7.28779 7.77098 7.61997 7.7488L10.0396 7.58726L13.3857 12.5146V8.19003L12.5244 8.07522V8.01492C12.5244 7.68933 12.788 7.42068 13.1244 7.40344L15.326 7.29066V7.60749C15.326 7.75622 15.2154 7.88343 15.0638 7.90907L14.534 7.99868V15.0022L13.8691 15.2309C13.3136 15.4219 12.6952 15.2174 12.3772 14.7376L9.12879 9.83568V14.5143L10.1287 14.7056L10.1147 14.7984C10.0711 15.0889 9.82028 15.3086 9.51687 15.3221L7.03006 15.4328C6.99718 15.1204 7.23132 14.8409 7.55431 14.807L7.88143 14.7726V8.53447L7.03006 8.48663Z" fill="black"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12.9218 1.85418L2.95217 2.53485C2.35499 2.57562 1.89209 3.05572 1.89209 3.63431V13.3311C1.89209 13.8748 2.07923 14.4029 2.42402 14.8325L4.57362 17.5104C4.92117 17.9433 5.46812 18.1817 6.03397 18.1469L17.0991 17.4658C17.6663 17.4309 18.1078 16.9761 18.1078 16.4269V5.4026C18.1078 5.06281 17.9362 4.74441 17.6481 4.54963L14.1453 2.18137C13.7883 1.94002 13.3564 1.82451 12.9218 1.85418ZM3.44654 3.78556C3.30788 3.6829 3.37387 3.46903 3.54806 3.45654L12.9889 2.77938C13.2897 2.75781 13.5886 2.84064 13.8318 3.01299L15.7261 4.35502C15.798 4.40597 15.7642 4.51596 15.6752 4.5208L5.67742 5.06454C5.37485 5.081 5.0762 4.99211 4.83563 4.814L3.44654 3.78556ZM5.20848 6.76913C5.20848 6.44433 5.47088 6.17604 5.80642 6.15777L16.3769 5.5821C16.7039 5.56429 16.9792 5.81577 16.9792 6.13232V15.6782C16.9792 16.0024 16.7177 16.2705 16.3829 16.2895L5.8793 16.8871C5.51537 16.9079 5.20848 16.6282 5.20848 16.2759V6.76913Z" fill="black"/>
+</g>
+<defs>
+<clipPath id="clip0_5364_42310">
+<rect width="20" height="20" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/header/assets/salesforce.svg b/app/components/header/assets/salesforce.svg
new file mode 100644
index 0000000..1deebd9
--- /dev/null
+++ b/app/components/header/assets/salesforce.svg
@@ -0,0 +1,12 @@
+<svg width="24" height="17" viewBox="0 0 24 17" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_660_2015)">
+<path d="M9.98736 1.91633C10.7614 1.10782 11.839 0.60636 13.0308 0.60636C14.6151 0.60636 15.9973 1.49199 16.7334 2.80672C17.373 2.52021 18.0811 2.36082 18.826 2.36082C21.6834 2.36082 24 4.70345 24 7.59305C24 10.483 21.6834 12.8256 18.826 12.8256C18.4837 12.8258 18.1423 12.7917 17.8068 12.7238C17.1587 13.8829 15.9234 14.6661 14.5057 14.6661C13.9121 14.6661 13.3508 14.5287 12.851 14.2843C12.1939 15.8338 10.6629 16.9203 8.87863 16.9203C7.02052 16.9203 5.43692 15.7416 4.82907 14.0886C4.56344 14.1451 4.28822 14.1746 4.00581 14.1746C1.79351 14.1746 0 12.3581 0 10.117C0 8.61511 0.805814 7.30378 2.00308 6.6022C1.75659 6.03362 1.61948 5.40606 1.61948 4.74627C1.61948 2.1689 3.70667 0.0795898 6.28103 0.0795898C7.79248 0.0795898 9.13574 0.800021 9.98736 1.91633Z" fill="#00A1E0"/>
+<path d="M3.47612 8.81302C3.46109 8.85245 3.4816 8.86068 3.48638 8.86752C3.5315 8.90042 3.57734 8.9241 3.62349 8.95047C3.86827 9.08069 4.0994 9.11872 4.34111 9.11872C4.83341 9.11872 5.13904 8.8562 5.13904 8.4336V8.42539C5.13904 8.03464 4.79411 7.89276 4.47033 7.79028L4.42829 7.77658C4.18418 7.69705 3.97359 7.62854 3.97359 7.46744V7.45889C3.97359 7.3211 4.09666 7.21963 4.28744 7.21963C4.4994 7.21963 4.75103 7.29025 4.91307 7.38003C4.91307 7.38003 4.96059 7.41089 4.97803 7.36462C4.9876 7.33993 5.06966 7.11853 5.07821 7.09454C5.08744 7.06848 5.07103 7.04929 5.05429 7.039C4.86933 6.92624 4.61359 6.84912 4.34899 6.84912L4.29976 6.84946C3.84917 6.84946 3.53465 7.12228 3.53465 7.51334V7.52158C3.53465 7.93388 3.88165 8.06754 4.20679 8.16077L4.25909 8.17688C4.49602 8.24988 4.70012 8.3126 4.70012 8.47986V8.4881C4.70012 8.64096 4.56749 8.75474 4.35346 8.75474C4.27038 8.75474 4.00542 8.75303 3.71927 8.5717C3.68473 8.55147 3.66457 8.53675 3.6379 8.52064C3.6239 8.51173 3.58868 8.49629 3.5733 8.54292L3.47612 8.81302ZM10.6833 8.81302C10.6682 8.85245 10.6888 8.86068 10.6935 8.86752C10.7387 8.90042 10.7845 8.9241 10.8306 8.95047C11.0754 9.08069 11.3066 9.11872 11.5482 9.11872C12.0405 9.11872 12.3462 8.8562 12.3462 8.4336V8.42539C12.3462 8.03464 12.0012 7.89276 11.6775 7.79028L11.6354 7.77658C11.3913 7.69705 11.1807 7.62854 11.1807 7.46744V7.45889C11.1807 7.3211 11.3038 7.21963 11.4946 7.21963C11.7065 7.21963 11.9581 7.29025 12.1202 7.38003C12.1202 7.38003 12.1677 7.41089 12.1851 7.36462C12.1947 7.33993 12.2768 7.11853 12.2853 7.09454C12.2946 7.06848 12.2781 7.04929 12.2614 7.039C12.0764 6.92624 11.8207 6.84912 11.5561 6.84912L11.5069 6.84946C11.0563 6.84946 10.7417 7.12228 10.7417 7.51334V7.52158C10.7417 7.93388 11.0887 8.06754 11.4139 8.16077L11.4662 8.17688C11.7031 8.24988 11.9076 8.3126 11.9076 8.47986V8.4881C11.9076 8.64096 11.7746 8.75474 11.5605 8.75474C11.4775 8.75474 11.2125 8.75303 10.9264 8.5717C10.8918 8.55147 10.8713 8.53743 10.8454 8.52064C10.8365 8.51481 10.7948 8.4987 10.7804 8.54292L10.6833 8.81302ZM15.6034 7.98525C15.6034 8.22414 15.559 8.41228 15.4715 8.54528C15.385 8.6769 15.254 8.74099 15.0715 8.74099C14.8886 8.74099 14.7583 8.67724 14.6732 8.54528C14.587 8.41265 14.5433 8.22414 14.5433 7.98525C14.5433 7.74672 14.587 7.55888 14.6732 7.42726C14.7583 7.29704 14.8886 7.23363 15.0715 7.23363C15.254 7.23363 15.385 7.29704 15.4718 7.42726C15.559 7.55886 15.6034 7.74669 15.6034 7.98525ZM16.0144 7.54243C15.974 7.40566 15.9111 7.28502 15.8274 7.18461C15.7436 7.08385 15.6376 7.00297 15.5118 6.94401C15.3863 6.88542 15.238 6.8556 15.0715 6.8556C14.9046 6.8556 14.7563 6.88542 14.6308 6.94401C14.505 7.00297 14.399 7.08387 14.3149 7.18461C14.2315 7.28538 14.1686 7.40602 14.1279 7.54243C14.0879 7.67849 14.0677 7.82723 14.0677 7.98525C14.0677 8.14326 14.0879 8.29235 14.1279 8.42806C14.1686 8.56447 14.2312 8.68513 14.3153 8.78588C14.399 8.88665 14.5053 8.96718 14.6308 9.02441C14.7566 9.08166 14.9046 9.11077 15.0715 9.11077C15.238 9.11077 15.386 9.08166 15.5118 9.02441C15.6373 8.96718 15.7436 8.88662 15.8274 8.78588C15.9112 8.68545 15.974 8.56481 16.0144 8.42806C16.0548 8.29201 16.0749 8.1429 16.0749 7.98525C16.0749 7.82759 16.0547 7.67849 16.0144 7.54243ZM19.389 8.67719C19.3753 8.63709 19.3367 8.65216 19.3367 8.65216C19.2768 8.67514 19.2132 8.69638 19.1456 8.707C19.0768 8.7176 19.0013 8.72312 18.9202 8.72312C18.7213 8.72312 18.5633 8.66382 18.4502 8.5466C18.3367 8.42938 18.2731 8.23987 18.2737 7.98349C18.2744 7.75009 18.3305 7.57459 18.4314 7.44094C18.5315 7.30797 18.684 7.23974 18.8874 7.23974C19.057 7.23974 19.1862 7.25928 19.3216 7.30212C19.3216 7.30212 19.3541 7.31616 19.3695 7.27368C19.4053 7.17358 19.432 7.10196 19.4703 6.99194C19.4813 6.96075 19.4546 6.94738 19.445 6.9436C19.3917 6.9227 19.2659 6.88879 19.1708 6.87439C19.0819 6.86068 18.978 6.85348 18.8625 6.85348C18.6898 6.85348 18.5359 6.88296 18.4043 6.94192C18.273 7.00052 18.1616 7.08139 18.0734 7.18218C17.9852 7.28295 17.9182 7.40356 17.8734 7.53998C17.829 7.67603 17.8064 7.82547 17.8064 7.98349C17.8064 8.3252 17.8984 8.60142 18.0799 8.80365C18.2618 9.00656 18.535 9.10972 18.8912 9.10972C19.1018 9.10972 19.3179 9.06689 19.4731 9.00553C19.4731 9.00553 19.5028 8.99112 19.4898 8.95654L19.389 8.67719ZM20.108 7.7564C20.1275 7.62377 20.1641 7.51339 20.2205 7.42738C20.3056 7.2968 20.4355 7.22517 20.6181 7.22517C20.8007 7.22517 20.9213 7.29714 21.0078 7.42738C21.0653 7.51339 21.0902 7.62858 21.1001 7.7564H20.108ZM21.4916 7.46471C21.4567 7.33276 21.3702 7.19943 21.3135 7.13842C21.2239 7.04177 21.1364 6.97426 21.0495 6.93655C20.936 6.88787 20.7999 6.85567 20.6509 6.85567C20.4772 6.85567 20.3196 6.88481 20.1918 6.94512C20.0636 7.00545 19.9559 7.08772 19.8714 7.1902C19.7869 7.29232 19.7234 7.41399 19.683 7.55212C19.6423 7.68957 19.6218 7.83934 19.6218 7.99731C19.6218 8.15808 19.643 8.30785 19.6851 8.44253C19.7275 8.57827 19.7952 8.69788 19.8868 8.79691C19.9781 8.89667 20.0957 8.97482 20.2365 9.02927C20.3764 9.08344 20.5463 9.11155 20.7415 9.11118C21.1432 9.10981 21.3548 9.02003 21.442 8.97169C21.4574 8.96314 21.4721 8.94806 21.4536 8.90488L21.3627 8.64951C21.349 8.61149 21.3104 8.62553 21.3104 8.62553C21.2109 8.66254 21.0694 8.72904 20.7394 8.72837C20.5237 8.72803 20.3637 8.66428 20.2635 8.56452C20.1606 8.4624 20.1104 8.31226 20.1015 8.10047L21.4926 8.10184C21.4926 8.10184 21.5291 8.10116 21.5329 8.0655C21.5343 8.05047 21.5808 7.77901 21.4916 7.46471ZM8.9672 7.7564C8.98702 7.62377 9.02327 7.51339 9.07968 7.42738C9.1648 7.2968 9.29472 7.22517 9.47728 7.22517C9.65984 7.22517 9.78053 7.29714 9.86735 7.42738C9.92444 7.51339 9.9494 7.62858 9.95932 7.7564H8.9672ZM10.3504 7.46471C10.3156 7.33276 10.2294 7.19943 10.1727 7.13842C10.0831 7.04177 9.99557 6.97426 9.90875 6.93655C9.79524 6.88787 9.65919 6.85567 9.51012 6.85567C9.33678 6.85567 9.17883 6.88481 9.05097 6.94512C8.92278 7.00545 8.81508 7.08772 8.73063 7.1902C8.64619 7.29232 8.5826 7.41399 8.54226 7.55212C8.50193 7.68957 8.48107 7.83934 8.48107 7.99731C8.48107 8.15808 8.50226 8.30785 8.54433 8.44253C8.58673 8.57827 8.65443 8.69788 8.74603 8.79691C8.83733 8.89667 8.95492 8.97482 9.09578 9.02927C9.23562 9.08344 9.40552 9.11155 9.60074 9.11118C10.0024 9.10981 10.2141 9.02003 10.3013 8.97169C10.3167 8.96314 10.3313 8.94806 10.3129 8.90488L10.2223 8.64951C10.2083 8.61149 10.1696 8.62553 10.1696 8.62553C10.0702 8.66254 9.92895 8.72904 9.59836 8.72837C9.38298 8.72803 9.22298 8.66428 9.1228 8.56452C9.01988 8.4624 8.96965 8.31226 8.96074 8.10047L10.3518 8.10184C10.3518 8.10184 10.3884 8.10116 10.3922 8.0655C10.3935 8.05047 10.44 7.77901 10.3504 7.46471ZM5.96033 8.66955C5.90596 8.62601 5.89844 8.61505 5.87999 8.58694C5.85263 8.5441 5.83862 8.48309 5.83862 8.40564C5.83862 8.28293 5.87896 8.19485 5.96273 8.13556C5.96172 8.13592 6.08239 8.03103 6.36614 8.03479C6.56545 8.03753 6.74356 8.06701 6.74356 8.06701V8.70108H6.7439C6.7439 8.70108 6.56715 8.73911 6.36818 8.7511C6.08511 8.76825 5.9593 8.66922 5.96033 8.66955ZM6.51382 7.68966C6.45741 7.68554 6.38423 7.68313 6.29671 7.68313C6.17741 7.68313 6.06219 7.69821 5.95415 7.72735C5.84545 7.75647 5.74767 7.80209 5.66356 7.86237C5.57958 7.92246 5.51056 8.00116 5.46185 8.09235C5.41263 8.18421 5.38767 8.29251 5.38767 8.41385C5.38767 8.53723 5.40886 8.6445 5.45126 8.73227C5.49366 8.82034 5.55485 8.89368 5.63278 8.95025C5.71005 9.0068 5.80545 9.04825 5.9162 9.07328C6.02527 9.0983 6.14901 9.11097 6.28441 9.11097C6.42697 9.11097 6.56919 9.09934 6.70697 9.07566C6.84338 9.05235 7.0109 9.01841 7.05739 9.00782C7.08998 8.99994 7.12247 8.9916 7.15483 8.98279C7.18937 8.97424 7.18663 8.9372 7.18663 8.9372L7.18594 7.66189C7.18594 7.3822 7.11142 7.17484 6.96475 7.04632C6.81875 6.91815 6.60372 6.85334 6.32578 6.85334C6.22149 6.85334 6.05364 6.86776 5.95312 6.88797C5.95312 6.88797 5.64919 6.94693 5.52405 7.04495C5.52405 7.04495 5.49671 7.0621 5.51175 7.10049L5.61023 7.36578C5.62253 7.40005 5.6557 7.38839 5.6557 7.38839C5.6557 7.38839 5.6663 7.38427 5.67862 7.37707C5.94632 7.23107 6.28477 7.23553 6.28477 7.23553C6.43521 7.23553 6.55077 7.26568 6.6287 7.32565C6.70459 7.38391 6.74322 7.47199 6.74322 7.65775V7.71671C6.62356 7.69958 6.51382 7.68966 6.51382 7.68966ZM17.7337 6.97108C17.7443 6.93953 17.7221 6.92446 17.7129 6.92104C17.6893 6.91179 17.571 6.88677 17.4797 6.88094C17.305 6.87032 17.2079 6.89979 17.1211 6.93886C17.0349 6.97792 16.9392 7.04098 16.8859 7.11263V6.94298C16.8859 6.91933 16.8691 6.90047 16.8459 6.90047H16.4893C16.466 6.90047 16.4493 6.9193 16.4493 6.94298V9.02304C16.4493 9.04635 16.4684 9.06555 16.4917 9.06555H16.8571C16.8683 9.06548 16.879 9.06097 16.8869 9.053C16.8948 9.04503 16.8992 9.03426 16.8992 9.02304V7.98387C16.8992 7.84438 16.9146 7.70524 16.9454 7.61784C16.9754 7.53145 17.0165 7.46223 17.0671 7.41252C17.118 7.36318 17.1758 7.32857 17.239 7.30903C17.3036 7.28914 17.3751 7.28264 17.4257 7.28264C17.4985 7.28264 17.5785 7.30147 17.5785 7.30147C17.6052 7.30455 17.6202 7.2881 17.6291 7.26378C17.653 7.20003 17.7207 7.00911 17.7337 6.97108Z" fill="white"/>
+<path d="M14.3032 6.00677C14.2588 5.99307 14.2184 5.9838 14.1658 5.97387C14.1124 5.96429 14.0489 5.95947 13.9767 5.95947C13.7251 5.95947 13.5268 6.03076 13.3877 6.17127C13.2492 6.31113 13.1552 6.52396 13.108 6.80399L13.0909 6.89823H12.775C12.775 6.89823 12.7367 6.89685 12.7285 6.93869L12.6769 7.22898C12.6731 7.25641 12.6851 7.27387 12.722 7.27387H13.0294L12.7176 9.01909C12.6933 9.15962 12.6652 9.27513 12.6341 9.36284C12.6037 9.44923 12.574 9.51399 12.537 9.56129C12.5015 9.60655 12.468 9.64012 12.4098 9.65965C12.362 9.67577 12.3066 9.6833 12.2461 9.6833C12.2126 9.6833 12.1678 9.67779 12.1346 9.67095C12.1018 9.66442 12.0844 9.65725 12.0594 9.6466C12.0594 9.6466 12.0235 9.63292 12.0092 9.6689C11.9979 9.69872 11.9158 9.92456 11.9059 9.95235C11.8964 9.98009 11.91 10.0017 11.9274 10.0082C11.9685 10.0226 11.9989 10.0322 12.0546 10.0456C12.1319 10.0637 12.1972 10.0648 12.2584 10.0648C12.3862 10.0648 12.5032 10.0466 12.5999 10.0116C12.697 9.97634 12.7818 9.91497 12.857 9.83205C12.938 9.74224 12.989 9.64833 13.0375 9.51982C13.0857 9.39299 13.1271 9.23534 13.1599 9.05165L13.4734 7.27387H13.9315C13.9315 7.27387 13.9702 7.27524 13.9781 7.23309L14.03 6.94314C14.0334 6.9154 14.0218 6.89825 13.9845 6.89825H13.5397C13.5421 6.88833 13.5623 6.73132 13.6133 6.58364C13.6351 6.52092 13.6761 6.46984 13.7107 6.43487C13.7449 6.4006 13.7842 6.37627 13.8273 6.36221C13.8714 6.34781 13.9217 6.34097 13.9767 6.34097C14.0184 6.34097 14.0598 6.34576 14.0909 6.35226C14.1339 6.36153 14.1507 6.36633 14.162 6.36977C14.2075 6.38348 14.2136 6.37011 14.2225 6.34819L14.3289 6.0555C14.3398 6.0239 14.3128 6.01053 14.3032 6.00677ZM8.08869 9.02287C8.08869 9.04618 8.07194 9.06504 8.04869 9.06504H7.6798C7.65655 9.06504 7.64014 9.04618 7.64014 9.02287V6.04654C7.64014 6.02325 7.65655 6.00439 7.6798 6.00439H8.04869C8.07194 6.00439 8.08869 6.02325 8.08869 6.04654V9.02287Z" fill="white"/>
+</g>
+<defs>
+<clipPath id="clip0_660_2015">
+<rect width="24" height="16.8421" fill="white" transform="translate(0 0.0791016)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/components/header/assets/serpapi.png b/app/components/header/assets/serpapi.png
new file mode 100644
index 0000000..9650453
--- /dev/null
+++ b/app/components/header/assets/serpapi.png
Binary files differ
diff --git a/app/components/header/assets/sync.svg b/app/components/header/assets/sync.svg
new file mode 100644
index 0000000..795077a
--- /dev/null
+++ b/app/components/header/assets/sync.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.69773 13.1783C7.29715 13.8879 9.20212 13.8494 10.8334 12.9075C13.5438 11.3427 14.4724 7.87704 12.9076 5.16672L12.7409 4.87804M3.09233 10.8335C1.52752 8.12314 2.45615 4.65746 5.16647 3.09265C6.7978 2.15081 8.70277 2.11227 10.3022 2.82185M1.66226 10.8892L3.48363 11.3773L3.97166 9.5559M12.0284 6.44393L12.5164 4.62256L14.3378 5.1106" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/header/assets/trash.svg b/app/components/header/assets/trash.svg
new file mode 100644
index 0000000..00c2989
--- /dev/null
+++ b/app/components/header/assets/trash.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M6 2H10M2 4H14M12.6667 4L12.1991 11.0129C12.129 12.065 12.0939 12.5911 11.8667 12.99C11.6666 13.3412 11.3648 13.6235 11.0011 13.7998C10.588 14 10.0607 14 9.00623 14H6.99377C5.93927 14 5.41202 14 4.99889 13.7998C4.63517 13.6235 4.33339 13.3412 4.13332 12.99C3.90607 12.5911 3.871 12.065 3.80086 11.0129L3.33333 4M6.66667 7V10.3333M9.33333 7V10.3333" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/app/components/header/assets/twitter.svg b/app/components/header/assets/twitter.svg
new file mode 100644
index 0000000..3cdbcd0
--- /dev/null
+++ b/app/components/header/assets/twitter.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.03168 15.0003C11.0694 15.0003 14.3718 9.9981 14.3718 5.66018C14.3718 5.5181 14.3718 5.37666 14.3622 5.23586C15.0047 4.77117 15.5593 4.19579 16 3.53666C15.4009 3.80227 14.7654 3.97637 14.1146 4.05314C14.7999 3.64294 15.3128 2.99767 15.5578 2.23746C14.9134 2.61987 14.2084 2.88935 13.4733 3.03426C12.9783 2.50798 12.3237 2.15949 11.6108 2.04272C10.8978 1.92595 10.1663 2.04741 9.52931 2.3883C8.89234 2.72919 8.38548 3.27051 8.08716 3.9285C7.78884 4.58648 7.71569 5.32444 7.87904 6.02818C6.57393 5.96272 5.29717 5.62354 4.13164 5.03267C2.9661 4.4418 1.93784 3.61244 1.1136 2.59842C0.693819 3.32109 0.565248 4.17658 0.754066 4.99071C0.942885 5.80484 1.43489 6.51639 2.12992 6.9805C1.60749 6.9652 1.09643 6.82426 0.64 6.56962V6.61122C0.640207 7.36912 0.902567 8.10362 1.38258 8.69014C1.86259 9.27665 2.53071 9.67907 3.2736 9.82914C2.79032 9.96097 2.28325 9.98024 1.79136 9.88546C2.00121 10.5377 2.40962 11.108 2.95949 11.5168C3.50937 11.9255 4.17322 12.1522 4.85824 12.1651C4.17763 12.7001 3.39821 13.0957 2.56458 13.3291C1.73096 13.5626 0.859476 13.6294 0 13.5258C1.50122 14.4891 3.24795 15.0001 5.03168 14.9978" fill="#1DA1F2"/>
+</svg>
diff --git a/app/components/header/dataset-nav/index.tsx b/app/components/header/dataset-nav/index.tsx
new file mode 100644
index 0000000..8c997f2
--- /dev/null
+++ b/app/components/header/dataset-nav/index.tsx
@@ -0,0 +1,65 @@
+'use client'
+
+import { useCallback } from 'react'
+import { useTranslation } from 'react-i18next'
+import { useParams, useRouter } from 'next/navigation'
+import {
+ RiBook2Fill,
+ RiBook2Line,
+} from '@remixicon/react'
+import useSWR from 'swr'
+import useSWRInfinite from 'swr/infinite'
+import { flatten } from 'lodash-es'
+import Nav from '../nav'
+import type { NavItem } from '../nav/nav-selector'
+import { fetchDatasetDetail, fetchDatasets } from '@/service/datasets'
+import type { DataSetListResponse } from '@/models/datasets'
+
+const getKey = (pageIndex: number, previousPageData: DataSetListResponse) => {
+ if (!pageIndex || previousPageData.has_more)
+ return { url: 'datasets', params: { page: pageIndex + 1, limit: 30 } }
+ return null
+}
+
+const DatasetNav = () => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const { datasetId } = useParams()
+ const { data: currentDataset } = useSWR(
+ datasetId
+ ? {
+ url: 'fetchDatasetDetail',
+ datasetId,
+ }
+ : null,
+ apiParams => fetchDatasetDetail(apiParams.datasetId as string))
+ const { data: datasetsData, setSize } = useSWRInfinite(datasetId ? getKey : () => null, fetchDatasets, { revalidateFirstPage: false, revalidateAll: true })
+ const datasetItems = flatten(datasetsData?.map(datasetData => datasetData.data))
+
+ const handleLoadmore = useCallback(() => {
+ setSize(size => size + 1)
+ }, [setSize])
+
+ return (
+ <Nav
+ icon={<RiBook2Line className='h-4 w-4' />}
+ activeIcon={<RiBook2Fill className='h-4 w-4' />}
+ text={t('common.menus.datasets')}
+ activeSegment='datasets'
+ link='/datasets'
+ curNav={currentDataset as Omit<NavItem, 'link'>}
+ navs={datasetItems.map(dataset => ({
+ id: dataset.id,
+ name: dataset.name,
+ link: dataset.provider === 'external' ? `/datasets/${dataset.id}/hitTesting` : `/datasets/${dataset.id}/documents`,
+ icon: dataset.icon,
+ icon_background: dataset.icon_background,
+ })) as NavItem[]}
+ createText={t('common.menus.newDataset')}
+ onCreate={() => router.push('/datasets/create')}
+ onLoadmore={handleLoadmore}
+ />
+ )
+}
+
+export default DatasetNav
diff --git a/app/components/header/env-nav/index.tsx b/app/components/header/env-nav/index.tsx
new file mode 100644
index 0000000..cec933a
--- /dev/null
+++ b/app/components/header/env-nav/index.tsx
@@ -0,0 +1,46 @@
+'use client'
+
+import { useTranslation } from 'react-i18next'
+import { useAppContext } from '@/context/app-context'
+import { Beaker02 } from '@/app/components/base/icons/src/vender/solid/education'
+import { TerminalSquare } from '@/app/components/base/icons/src/vender/solid/development'
+
+const headerEnvClassName: { [k: string]: string } = {
+ DEVELOPMENT: 'bg-[#FEC84B] border-[#FDB022] text-[#93370D]',
+ TESTING: 'bg-[#A5F0FC] border-[#67E3F9] text-[#164C63]',
+}
+
+const EnvNav = () => {
+ const { t } = useTranslation()
+ const { langeniusVersionInfo } = useAppContext()
+ const showEnvTag = langeniusVersionInfo.current_env === 'TESTING' || langeniusVersionInfo.current_env === 'DEVELOPMENT'
+
+ if (!showEnvTag)
+ return null
+
+ return (
+ <div className={`
+ mr-4 flex h-[22px] items-center rounded-md border px-2 text-xs font-medium
+ ${headerEnvClassName[langeniusVersionInfo.current_env]}
+ `}>
+ {
+ langeniusVersionInfo.current_env === 'TESTING' && (
+ <>
+ <Beaker02 className='mr-1 h-3 w-3' />
+ {t('common.environment.testing')}
+ </>
+ )
+ }
+ {
+ langeniusVersionInfo.current_env === 'DEVELOPMENT' && (
+ <>
+ <TerminalSquare className='mr-1 h-3 w-3' />
+ {t('common.environment.development')}
+ </>
+ )
+ }
+ </div>
+ )
+}
+
+export default EnvNav
diff --git a/app/components/header/explore-nav/index.tsx b/app/components/header/explore-nav/index.tsx
new file mode 100644
index 0000000..b6ebf5d
--- /dev/null
+++ b/app/components/header/explore-nav/index.tsx
@@ -0,0 +1,38 @@
+'use client'
+
+import { useTranslation } from 'react-i18next'
+import Link from 'next/link'
+import { useSelectedLayoutSegment } from 'next/navigation'
+import {
+ RiPlanetFill,
+ RiPlanetLine,
+} from '@remixicon/react'
+import classNames from '@/utils/classnames'
+type ExploreNavProps = {
+ className?: string
+}
+
+const ExploreNav = ({
+ className,
+}: ExploreNavProps) => {
+ const { t } = useTranslation()
+ const selectedSegment = useSelectedLayoutSegment()
+ const activated = selectedSegment === 'explore'
+
+ return (
+ <Link href="/explore/apps" className={classNames(
+ className, 'group',
+ activated && 'bg-components-main-nav-nav-button-bg-active shadow-md',
+ activated ? 'text-components-main-nav-nav-button-text-active' : 'text-components-main-nav-nav-button-text hover:bg-components-main-nav-nav-button-bg-hover',
+ )}>
+ {
+ activated
+ ? <RiPlanetFill className='mr-2 h-4 w-4' />
+ : <RiPlanetLine className='mr-2 h-4 w-4' />
+ }
+ {t('common.menus.explore')}
+ </Link>
+ )
+}
+
+export default ExploreNav
diff --git a/app/components/header/github-star/index.tsx b/app/components/header/github-star/index.tsx
new file mode 100644
index 0000000..b087b9e
--- /dev/null
+++ b/app/components/header/github-star/index.tsx
@@ -0,0 +1,27 @@
+'use client'
+import { useQuery } from '@tanstack/react-query'
+import type { FC } from 'react'
+import type { GithubRepo } from '@/models/common'
+
+const getStar = async () => {
+ const res = await fetch('https://api.github.com/repos/langgenius/dify')
+
+ if (!res.ok)
+ throw new Error('Failed to fetch github star')
+
+ return res.json()
+}
+
+const GithubStar: FC<{ className: string }> = (props) => {
+ const { isFetching, data } = useQuery<GithubRepo>({
+ queryKey: ['github-star'],
+ queryFn: getStar,
+ enabled: process.env.NODE_ENV !== 'development',
+ initialData: { stargazers_count: 81204 },
+ })
+ if (isFetching)
+ return null
+ return <span {...props}>{data.stargazers_count.toLocaleString()}</span>
+}
+
+export default GithubStar
diff --git a/app/components/header/header-wrapper.tsx b/app/components/header/header-wrapper.tsx
new file mode 100644
index 0000000..dd0ec77
--- /dev/null
+++ b/app/components/header/header-wrapper.tsx
@@ -0,0 +1,27 @@
+'use client'
+import { usePathname } from 'next/navigation'
+import s from './index.module.css'
+import classNames from '@/utils/classnames'
+
+type HeaderWrapperProps = {
+ children: React.ReactNode
+}
+
+const HeaderWrapper = ({
+ children,
+}: HeaderWrapperProps) => {
+ const pathname = usePathname()
+ const isBordered = ['/apps', '/datasets', '/datasets/create', '/tools'].includes(pathname)
+
+ return (
+ <div className={classNames(
+ 'sticky top-0 left-0 right-0 z-30 flex flex-col grow-0 shrink-0 basis-auto min-h-[56px]',
+ s.header,
+ isBordered ? 'border-b border-divider-regular' : '',
+ )}
+ >
+ {children}
+ </div>
+ )
+}
+export default HeaderWrapper
diff --git a/app/components/header/index.module.css b/app/components/header/index.module.css
new file mode 100644
index 0000000..9e23bc1
--- /dev/null
+++ b/app/components/header/index.module.css
@@ -0,0 +1,15 @@
+.header-DEVELOPMENT {
+ background: linear-gradient(180deg, rgba(253, 176, 34, 0.08) 0%, rgba(253, 176, 34, 0) 100%);
+ border-top: 4px solid #FDB022;
+}
+
+.header-TESTING {
+ background: linear-gradient(180deg, rgba(6, 174, 212, 0.08) 0%, rgba(6, 174, 212, 0) 100%);
+ border-top: 4px solid #06AED4;
+}
+
+.alpha {
+ width: 12px;
+ height: 12px;
+ background: url(./assets/alpha.svg) center center no-repeat;
+}
diff --git a/app/components/header/index.tsx b/app/components/header/index.tsx
new file mode 100644
index 0000000..c2345fb
--- /dev/null
+++ b/app/components/header/index.tsx
@@ -0,0 +1,115 @@
+'use client'
+import { useCallback, useEffect } from 'react'
+import Link from 'next/link'
+import { useBoolean } from 'ahooks'
+import { useSelectedLayoutSegment } from 'next/navigation'
+import { Bars3Icon } from '@heroicons/react/20/solid'
+import AccountDropdown from './account-dropdown'
+import AppNav from './app-nav'
+import DatasetNav from './dataset-nav'
+import EnvNav from './env-nav'
+import PluginsNav from './plugins-nav'
+import ExploreNav from './explore-nav'
+import ToolsNav from './tools-nav'
+import { WorkspaceProvider } from '@/context/workspace-context'
+import { useAppContext } from '@/context/app-context'
+import DifyLogo from '@/app/components/base/logo/dify-logo'
+import WorkplaceSelector from '@/app/components/header/account-dropdown/workplace-selector'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import { useProviderContext } from '@/context/provider-context'
+import { useModalContext } from '@/context/modal-context'
+import PlanBadge from './plan-badge'
+import LicenseNav from './license-env'
+import { Plan } from '../billing/type'
+
+const navClassName = `
+ flex items-center relative mr-0 sm:mr-3 px-3 h-8 rounded-xl
+ font-medium text-sm
+ cursor-pointer
+`
+
+const Header = () => {
+ const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
+ const selectedSegment = useSelectedLayoutSegment()
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+ const [isShowNavMenu, { toggle, setFalse: hideNavMenu }] = useBoolean(false)
+ const { enableBilling, plan } = useProviderContext()
+ const { setShowPricingModal, setShowAccountSettingModal } = useModalContext()
+ const isFreePlan = plan.type === Plan.sandbox
+ const handlePlanClick = useCallback(() => {
+ if (isFreePlan)
+ setShowPricingModal()
+ else
+ setShowAccountSettingModal({ payload: 'billing' })
+ }, [isFreePlan, setShowAccountSettingModal, setShowPricingModal])
+
+ useEffect(() => {
+ hideNavMenu()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [selectedSegment])
+ return (
+ <div className='relative flex flex-1 items-center justify-between bg-background-body'>
+ <div className='flex items-center'>
+ {isMobile && <div
+ className='flex h-8 w-8 cursor-pointer items-center justify-center'
+ onClick={toggle}
+ >
+ <Bars3Icon className="h-4 w-4 text-gray-500" />
+ </div>}
+ {
+ !isMobile
+ && <div className='flex shrink-0 items-center gap-1.5 self-stretch pl-3'>
+ <Link href="/apps" className='flex h-8 w-[52px] shrink-0 items-center justify-center gap-2'>
+ <DifyLogo />
+ </Link>
+ <div className='font-light text-divider-deep'>/</div>
+ <div className='flex items-center gap-0.5'>
+ <WorkspaceProvider>
+ <WorkplaceSelector />
+ </WorkspaceProvider>
+ {enableBilling ? <PlanBadge allowHover sandboxAsUpgrade plan={plan.type} onClick={handlePlanClick} /> : <LicenseNav />}
+ </div>
+ </div>
+ }
+ </div >
+ {isMobile && (
+ <div className='flex'>
+ <Link href="/apps" className='mr-4 flex items-center'>
+ <DifyLogo />
+ </Link>
+ <div className='font-light text-divider-deep'>/</div>
+ {enableBilling ? <PlanBadge allowHover sandboxAsUpgrade plan={plan.type} onClick={handlePlanClick} /> : <LicenseNav />}
+ </div >
+ )}
+ {
+ !isMobile && (
+ <div className='absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center'>
+ {!isCurrentWorkspaceDatasetOperator && <ExploreNav className={navClassName} />}
+ {!isCurrentWorkspaceDatasetOperator && <AppNav />}
+ {(isCurrentWorkspaceEditor || isCurrentWorkspaceDatasetOperator) && <DatasetNav />}
+ {!isCurrentWorkspaceDatasetOperator && <ToolsNav className={navClassName} />}
+ </div>
+ )
+ }
+ <div className='flex shrink-0 items-center pr-3'>
+ <EnvNav />
+ <div className='mr-2'>
+ <PluginsNav />
+ </div>
+ <AccountDropdown />
+ </div>
+ {
+ (isMobile && isShowNavMenu) && (
+ <div className='flex w-full flex-col gap-y-1 p-2'>
+ {!isCurrentWorkspaceDatasetOperator && <ExploreNav className={navClassName} />}
+ {!isCurrentWorkspaceDatasetOperator && <AppNav />}
+ {(isCurrentWorkspaceEditor || isCurrentWorkspaceDatasetOperator) && <DatasetNav />}
+ {!isCurrentWorkspaceDatasetOperator && <ToolsNav className={navClassName} />}
+ </div>
+ )
+ }
+ </div >
+ )
+}
+export default Header
diff --git a/app/components/header/indicator/index.tsx b/app/components/header/indicator/index.tsx
new file mode 100644
index 0000000..12629e9
--- /dev/null
+++ b/app/components/header/indicator/index.tsx
@@ -0,0 +1,59 @@
+'use client'
+
+import classNames from '@/utils/classnames'
+
+export type IndicatorProps = {
+ color?: 'green' | 'orange' | 'red' | 'blue' | 'yellow' | 'gray'
+ className?: string
+}
+
+export type ColorMap = {
+ green: string
+ orange: string
+ red: string
+ blue: string
+ yellow: string
+ gray: string
+}
+
+const BACKGROUND_MAP: ColorMap = {
+ green: 'bg-components-badge-status-light-success-bg',
+ orange: 'bg-components-badge-status-light-warning-bg',
+ red: 'bg-components-badge-status-light-error-bg',
+ blue: 'bg-components-badge-status-light-normal-bg',
+ yellow: 'bg-components-badge-status-light-warning-bg',
+ gray: 'bg-components-badge-status-light-disabled-bg',
+}
+const BORDER_MAP: ColorMap = {
+ green: 'border-components-badge-status-light-success-border-inner',
+ orange: 'border-components-badge-status-light-warning-border-inner',
+ red: 'border-components-badge-status-light-error-border-inner',
+ blue: 'border-components-badge-status-light-normal-border-inner',
+ yellow: 'border-components-badge-status-light-warning-border-inner',
+ gray: 'border-components-badge-status-light-disabled-border-inner',
+}
+const SHADOW_MAP: ColorMap = {
+ green: 'shadow-status-indicator-green-shadow',
+ orange: 'shadow-status-indicator-warning-shadow',
+ red: 'shadow-status-indicator-red-shadow',
+ blue: 'shadow-status-indicator-blue-shadow',
+ yellow: 'shadow-status-indicator-warning-shadow',
+ gray: 'shadow-status-indicator-gray-shadow',
+}
+
+export default function Indicator({
+ color = 'green',
+ className = '',
+}: IndicatorProps) {
+ return (
+ <div className={classNames(
+ 'w-2 h-2 border border-solid rounded-[3px]',
+ BACKGROUND_MAP[color],
+ BORDER_MAP[color],
+ SHADOW_MAP[color],
+ className,
+ )}>
+
+ </div>
+ )
+}
diff --git a/app/components/header/license-env/index.tsx b/app/components/header/license-env/index.tsx
new file mode 100644
index 0000000..86c53d7
--- /dev/null
+++ b/app/components/header/license-env/index.tsx
@@ -0,0 +1,32 @@
+'use client'
+
+import AppContext from '@/context/app-context'
+import { LicenseStatus } from '@/types/feature'
+import { useTranslation } from 'react-i18next'
+import { useContextSelector } from 'use-context-selector'
+import dayjs from 'dayjs'
+import PremiumBadge from '../../base/premium-badge'
+import { RiHourglass2Fill } from '@remixicon/react'
+
+const LicenseNav = () => {
+ const { t } = useTranslation()
+ const systemFeatures = useContextSelector(AppContext, s => s.systemFeatures)
+
+ if (systemFeatures.license?.status === LicenseStatus.EXPIRING) {
+ const expiredAt = systemFeatures.license?.expired_at
+ const count = dayjs(expiredAt).diff(dayjs(), 'days')
+ return <PremiumBadge color='orange' className='select-none'>
+ <RiHourglass2Fill className='flex size-3 items-center pl-0.5 text-components-premium-badge-indigo-text-stop-0' />
+ {count <= 1 && <span className='system-xs-medium px-0.5'>{t('common.license.expiring', { count })}</span>}
+ {count > 1 && <span className='system-xs-medium px-0.5'>{t('common.license.expiring_plural', { count })}</span>}
+ </PremiumBadge>
+ }
+ if (systemFeatures.license.status === LicenseStatus.ACTIVE) {
+ return <PremiumBadge color="indigo" className='select-none'>
+ <span className='system-xs-medium px-1'>Enterprise</span>
+ </PremiumBadge>
+ }
+ return null
+}
+
+export default LicenseNav
diff --git a/app/components/header/maintenance-notice.tsx b/app/components/header/maintenance-notice.tsx
new file mode 100644
index 0000000..78715bb
--- /dev/null
+++ b/app/components/header/maintenance-notice.tsx
@@ -0,0 +1,39 @@
+import { useState } from 'react'
+import { useContext } from 'use-context-selector'
+import I18n from '@/context/i18n'
+import { X } from '@/app/components/base/icons/src/vender/line/general'
+import { NOTICE_I18N } from '@/i18n/language'
+
+const MaintenanceNotice = () => {
+ const { locale } = useContext(I18n)
+
+ const [showNotice, setShowNotice] = useState(localStorage.getItem('hide-maintenance-notice') !== '1')
+ const handleJumpNotice = () => {
+ window.open(NOTICE_I18N.href, '_blank')
+ }
+
+ const handleCloseNotice = () => {
+ localStorage.setItem('hide-maintenance-notice', '1')
+ setShowNotice(false)
+ }
+
+ const titleByLocale: { [key: string]: string } = NOTICE_I18N.title
+ const descByLocale: { [key: string]: string } = NOTICE_I18N.desc
+
+ if (!showNotice)
+ return null
+
+ return (
+ <div className='z-20 flex h-[38px] shrink-0 items-center border-[0.5px] border-b border-b-[#FEF0C7] bg-[#FFFAEB] px-4'>
+ <div className='mr-2 flex h-[22px] shrink-0 items-center rounded-xl bg-[#F79009] px-2 text-[11px] font-medium text-white'>{titleByLocale[locale]}</div>
+ {
+ (NOTICE_I18N.href && NOTICE_I18N.href !== '#')
+ ? <div className='grow cursor-pointer text-xs font-medium text-gray-700' onClick={handleJumpNotice}>{descByLocale[locale]}</div>
+ : <div className='grow text-xs font-medium text-gray-700'>{descByLocale[locale]}</div>
+ }
+ <X className='h-4 w-4 shrink-0 cursor-pointer text-gray-500' onClick={handleCloseNotice} />
+ </div>
+ )
+}
+
+export default MaintenanceNotice
diff --git a/app/components/header/nav/index.module.css b/app/components/header/nav/index.module.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/components/header/nav/index.module.css
diff --git a/app/components/header/nav/index.tsx b/app/components/header/nav/index.tsx
new file mode 100644
index 0000000..293c66a
--- /dev/null
+++ b/app/components/header/nav/index.tsx
@@ -0,0 +1,95 @@
+'use client'
+
+import React, { useEffect, useState } from 'react'
+import Link from 'next/link'
+import { usePathname, useSearchParams, useSelectedLayoutSegment } from 'next/navigation'
+import type { INavSelectorProps } from './nav-selector'
+import NavSelector from './nav-selector'
+import classNames from '@/utils/classnames'
+import { ArrowNarrowLeft } from '@/app/components/base/icons/src/vender/line/arrows'
+import { useStore as useAppStore } from '@/app/components/app/store'
+
+type INavProps = {
+ icon: React.ReactNode
+ activeIcon?: React.ReactNode
+ text: string
+ activeSegment: string | string[]
+ link: string
+ isApp: boolean
+} & INavSelectorProps
+
+const Nav = ({
+ icon,
+ activeIcon,
+ text,
+ activeSegment,
+ link,
+ curNav,
+ navs,
+ createText,
+ onCreate,
+ onLoadmore,
+ isApp,
+}: INavProps) => {
+ const setAppDetail = useAppStore(state => state.setAppDetail)
+ const [hovered, setHovered] = useState(false)
+ const segment = useSelectedLayoutSegment()
+ const isActivated = Array.isArray(activeSegment) ? activeSegment.includes(segment!) : segment === activeSegment
+ const pathname = usePathname()
+ const searchParams = useSearchParams()
+ const [linkLastSearchParams, setLinkLastSearchParams] = useState('')
+
+ useEffect(() => {
+ if (pathname === link)
+ setLinkLastSearchParams(searchParams.toString())
+ }, [pathname, searchParams])
+
+ return (
+ <div className={`
+ mr-0 flex h-8 shrink-0 items-center rounded-xl px-0.5 text-sm font-medium sm:mr-3
+ ${isActivated && 'bg-components-main-nav-nav-button-bg-active font-semibold shadow-md'}
+ ${!curNav && !isActivated && 'hover:bg-components-main-nav-nav-button-bg-hover'}
+ `}>
+ <Link href={link + (linkLastSearchParams && `?${linkLastSearchParams}`)}>
+ <div
+ onClick={() => setAppDetail()}
+ className={classNames(`
+ flex items-center h-7 px-2.5 cursor-pointer rounded-[10px]
+ ${isActivated ? 'text-components-main-nav-nav-button-text-active' : 'text-components-main-nav-nav-button-text'}
+ ${curNav && isActivated && 'hover:bg-components-main-nav-nav-button-bg-active-hover'}
+ `)}
+ onMouseEnter={() => setHovered(true)}
+ onMouseLeave={() => setHovered(false)}
+ >
+ <div className='mr-2'>
+ {
+ (hovered && curNav)
+ ? <ArrowNarrowLeft className='h-4 w-4' />
+ : isActivated
+ ? activeIcon
+ : icon
+ }
+ </div>
+ {text}
+ </div>
+ </Link>
+ {
+ curNav && isActivated && (
+ <>
+ <div className='font-light text-divider-deep'>/</div>
+ <NavSelector
+ isApp={isApp}
+ curNav={curNav}
+ navs={navs}
+ createText={createText}
+ onCreate={onCreate}
+ onLoadmore={onLoadmore}
+ />
+ </>
+ )
+ }
+ </div>
+ )
+}
+
+export default Nav
diff --git a/app/components/header/nav/nav-selector/index.tsx b/app/components/header/nav/nav-selector/index.tsx
new file mode 100644
index 0000000..65c7cb1
--- /dev/null
+++ b/app/components/header/nav/nav-selector/index.tsx
@@ -0,0 +1,189 @@
+'use client'
+import { useTranslation } from 'react-i18next'
+import { Fragment, useCallback } from 'react'
+import {
+ RiAddLine,
+ RiArrowDownSLine,
+ RiArrowRightSLine,
+} from '@remixicon/react'
+import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
+import { useRouter } from 'next/navigation'
+import { debounce } from 'lodash-es'
+import cn from '@/utils/classnames'
+import AppIcon from '@/app/components/base/app-icon'
+import { AiText, ChatBot, CuteRobot } from '@/app/components/base/icons/src/vender/solid/communication'
+import { Route } from '@/app/components/base/icons/src/vender/solid/mapsAndTravel'
+import { useAppContext } from '@/context/app-context'
+import { useStore as useAppStore } from '@/app/components/app/store'
+import { FileArrow01, FilePlus01, FilePlus02 } from '@/app/components/base/icons/src/vender/line/files'
+import type { AppIconType } from '@/types/app'
+
+export type NavItem = {
+ id: string
+ name: string
+ link: string
+ icon_type: AppIconType | null
+ icon: string
+ icon_background: string
+ icon_url: string | null
+ mode?: string
+}
+export type INavSelectorProps = {
+ navs: NavItem[]
+ curNav?: Omit<NavItem, 'link'>
+ createText: string
+ isApp?: boolean
+ onCreate: (state: string) => void
+ onLoadmore?: () => void
+}
+
+const NavSelector = ({ curNav, navs, createText, isApp, onCreate, onLoadmore }: INavSelectorProps) => {
+ const { t } = useTranslation()
+ const router = useRouter()
+ const { isCurrentWorkspaceEditor } = useAppContext()
+ const setAppDetail = useAppStore(state => state.setAppDetail)
+
+ const handleScroll = useCallback(debounce((e) => {
+ if (typeof onLoadmore === 'function') {
+ const { clientHeight, scrollHeight, scrollTop } = e.target
+
+ if (clientHeight + scrollTop > scrollHeight - 50)
+ onLoadmore()
+ }
+ }, 50), [])
+
+ return (
+ <div className="">
+ <Menu as="div" className="relative inline-block text-left">
+ {({ open }) => (
+ <>
+ <MenuButton className={cn(
+ 'hover:hover:bg-components-main-nav-nav-button-bg-active-hover group inline-flex h-7 w-full items-center justify-center rounded-[10px] pl-2 pr-2.5 text-[14px] font-semibold text-components-main-nav-nav-button-text-active',
+ open && 'bg-components-main-nav-nav-button-bg-active',
+ )}>
+ <div className='max-w-[180px] truncate' title={curNav?.name}>{curNav?.name}</div>
+ <RiArrowDownSLine
+ className={cn('ml-1 h-3 w-3 shrink-0 opacity-50 group-hover:opacity-100', open && '!opacity-100')}
+ aria-hidden="true"
+ />
+ </MenuButton>
+ <MenuItems
+ className="
+ absolute -left-11 right-0 mt-1.5 w-60 max-w-80
+ origin-top-right divide-y divide-gray-100 rounded-lg bg-white
+ shadow-lg
+ "
+ >
+ <div className="overflow-auto px-1 py-1" style={{ maxHeight: '50vh' }} onScroll={handleScroll}>
+ {
+ navs.map(nav => (
+ <MenuItem key={nav.id}>
+ <div className='flex w-full cursor-pointer items-center truncate rounded-lg px-3 py-[6px] text-[14px] font-normal text-gray-700 hover:bg-gray-100' onClick={() => {
+ if (curNav?.id === nav.id)
+ return
+ setAppDetail()
+ router.push(nav.link)
+ }} title={nav.name}>
+ <div className='relative mr-2 h-6 w-6 rounded-md'>
+ <AppIcon size='tiny' iconType={nav.icon_type} icon={nav.icon} background={nav.icon_background} imageUrl={nav.icon_url} />
+ {!!nav.mode && (
+ <span className={cn(
+ 'absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded border-[0.5px] border-[rgba(0,0,0,0.02)] bg-white p-0.5 shadow-sm',
+ )}>
+ {nav.mode === 'advanced-chat' && (
+ <ChatBot className='h-2.5 w-2.5 text-[#1570EF]' />
+ )}
+ {nav.mode === 'agent-chat' && (
+ <CuteRobot className='h-2.5 w-2.5 text-indigo-600' />
+ )}
+ {nav.mode === 'chat' && (
+ <ChatBot className='h-2.5 w-2.5 text-[#1570EF]' />
+ )}
+ {nav.mode === 'completion' && (
+ <AiText className='h-2.5 w-2.5 text-[#0E9384]' />
+ )}
+ {nav.mode === 'workflow' && (
+ <Route className='h-2.5 w-2.5 text-[#f79009]' />
+ )}
+ </span>
+ )}
+ </div>
+ <div className='truncate'>
+ {nav.name}
+ </div>
+ </div>
+ </MenuItem>
+ ))
+ }
+ </div>
+ {!isApp && isCurrentWorkspaceEditor && (
+ <MenuItem as="div" className='w-full p-1'>
+ <div onClick={() => onCreate('')} className={cn(
+ 'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-gray-100',
+ )}>
+ <div className='flex h-6 w-6 shrink-0 items-center justify-center rounded-[6px] border border-[0.5px] border-gray-200 bg-gray-50'>
+ <RiAddLine className='h-4 w-4 text-gray-500' />
+ </div>
+ <div className='grow text-left text-[14px] font-normal text-gray-700'>{createText}</div>
+ </div>
+ </MenuItem>
+ )}
+ {isApp && isCurrentWorkspaceEditor && (
+ <Menu as="div" className="relative h-full w-full">
+ {({ open }) => (
+ <>
+ <MenuButton className='w-full p-1'>
+ <div className={cn(
+ 'flex cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-gray-100',
+ open && '!bg-gray-100',
+ )}>
+ <div className='flex h-6 w-6 shrink-0 items-center justify-center rounded-[6px] border border-[0.5px] border-gray-200 bg-gray-50'>
+ <RiAddLine className='h-4 w-4 text-gray-500' />
+ </div>
+ <div className='grow text-left text-[14px] font-normal text-gray-700'>{createText}</div>
+ <RiArrowRightSLine className='h-3.5 w-3.5 shrink-0 text-gray-500' />
+ </div>
+ </MenuButton>
+ <Transition
+ as={Fragment}
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leave="transition ease-in duration-75"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ >
+ <MenuItems className={cn(
+ 'absolute right-[-198px] top-[3px] z-10 min-w-[200px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg',
+ )}>
+ <div className='p-1'>
+ <div className={cn('flex cursor-pointer items-center rounded-lg px-3 py-[6px] font-normal text-gray-700 hover:bg-gray-100')} onClick={() => onCreate('blank')}>
+ <FilePlus01 className='mr-2 h-4 w-4 shrink-0 text-gray-600' />
+ {t('app.newApp.startFromBlank')}
+ </div>
+ <div className={cn('flex cursor-pointer items-center rounded-lg px-3 py-[6px] font-normal text-gray-700 hover:bg-gray-100')} onClick={() => onCreate('template')}>
+ <FilePlus02 className='mr-2 h-4 w-4 shrink-0 text-gray-600' />
+ {t('app.newApp.startFromTemplate')}
+ </div>
+ </div>
+ <div className='border-t border-gray-100 p-1'>
+ <div className={cn('flex cursor-pointer items-center rounded-lg px-3 py-[6px] font-normal text-gray-700 hover:bg-gray-100')} onClick={() => onCreate('dsl')}>
+ <FileArrow01 className='mr-2 h-4 w-4 shrink-0 text-gray-600' />
+ {t('app.importDSL')}
+ </div>
+ </div>
+ </MenuItems>
+ </Transition>
+ </>
+ )}
+ </Menu>
+ )}
+ </MenuItems>
+ </>
+ )}
+ </Menu>
+ </div>
+ )
+}
+
+export default NavSelector
diff --git a/app/components/header/plan-badge/index.tsx b/app/components/header/plan-badge/index.tsx
new file mode 100644
index 0000000..292025c
--- /dev/null
+++ b/app/components/header/plan-badge/index.tsx
@@ -0,0 +1,64 @@
+import { useProviderContext } from '@/context/provider-context'
+import type { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import {
+ RiGraduationCapFill,
+} from '@remixicon/react'
+import { SparklesSoft } from '../../base/icons/src/public/common'
+import PremiumBadge from '../../base/premium-badge'
+import { Plan } from '../../billing/type'
+
+type PlanBadgeProps = {
+ plan: Plan
+ allowHover?: boolean
+ sandboxAsUpgrade?: boolean
+ onClick?: () => void
+}
+
+const PlanBadge: FC<PlanBadgeProps> = ({ plan, allowHover, sandboxAsUpgrade = false, onClick }) => {
+ const { isFetchedPlan, isEducationWorkspace } = useProviderContext()
+ const { t } = useTranslation()
+
+ if (!isFetchedPlan) return null
+ if (plan === Plan.sandbox && sandboxAsUpgrade) {
+ return <PremiumBadge className='select-none' color='blue' allowHover={allowHover} onClick={onClick}>
+ <SparklesSoft className='flex h-3.5 w-3.5 items-center py-[1px] pl-[3px] text-components-premium-badge-indigo-text-stop-0' />
+ <div className='system-xs-medium'>
+ <span className='whitespace-nowrap p-1'>
+ {t('billing.upgradeBtn.encourageShort')}
+ </span>
+ </div>
+ </PremiumBadge>
+ }
+ if (plan === Plan.sandbox) {
+ return <PremiumBadge className='select-none' size='s' color='gray' allowHover={allowHover} onClick={onClick}>
+ <div className='system-2xs-medium-uppercase'>
+ <span className='p-1'>
+ {plan}
+ </span>
+ </div>
+ </PremiumBadge>
+ }
+ if (plan === Plan.professional) {
+ return <PremiumBadge className='select-none' size='s' color='blue' allowHover={allowHover} onClick={onClick}>
+ <div className='system-2xs-medium-uppercase'>
+ <span className='inline-flex items-center gap-1 p-1'>
+ {isEducationWorkspace && <RiGraduationCapFill className='h-3 w-3' />}
+ pro
+ </span>
+ </div>
+ </PremiumBadge>
+ }
+ if (plan === Plan.team) {
+ return <PremiumBadge className='select-none' size='s' color='indigo' allowHover={allowHover} onClick={onClick}>
+ <div className='system-2xs-medium-uppercase'>
+ <span className='p-1'>
+ {plan}
+ </span>
+ </div>
+ </PremiumBadge>
+ }
+ return null
+}
+
+export default PlanBadge
diff --git a/app/components/header/plugins-nav/downloading-icon.module.css b/app/components/header/plugins-nav/downloading-icon.module.css
new file mode 100644
index 0000000..bbd6a35
--- /dev/null
+++ b/app/components/header/plugins-nav/downloading-icon.module.css
@@ -0,0 +1,44 @@
+@keyframes realistic-blink {
+ 0% { fill: #37ff37; opacity: 0.4; }
+ 15% { fill: #37ff37; opacity: 0.9; }
+ 25% { fill: #37ff37; opacity: 0.3; }
+ 38% { fill: #ff4444; opacity: 0.8; }
+ 42% { fill: #ff4444; opacity: 0.3; }
+ 58% { fill: #37ff37; opacity: 0.9; }
+ 65% { fill: #37ff37; opacity: 0.4; }
+ 79% { fill: #ff4444; opacity: 0.8; }
+ 84% { fill: #ff4444; opacity: 0.3; }
+ 92% { fill: #37ff37; opacity: 0.8; }
+ 100% { fill: #37ff37; opacity: 0.4; }
+}
+
+@keyframes drop {
+ 0% {
+ transform: translateY(-4px);
+ opacity: 0;
+ }
+ 5% {
+ transform: translateY(-4px);
+ opacity: 1;
+ }
+ 65% {
+ transform: translateY(2px);
+ opacity: 1;
+ }
+ 80% {
+ transform: translateY(2px);
+ opacity: 0;
+ }
+ 100% {
+ transform: translateY(2px);
+ opacity: 0;
+ }
+}
+
+#downloadingIconLight {
+ animation: realistic-blink 3s infinite ease-in-out;
+}
+
+#downloadingIconArrow {
+ animation: drop 1.2s cubic-bezier(0.4, 0, 1, 1) infinite;
+}
diff --git a/app/components/header/plugins-nav/downloading-icon.tsx b/app/components/header/plugins-nav/downloading-icon.tsx
new file mode 100644
index 0000000..d3fc486
--- /dev/null
+++ b/app/components/header/plugins-nav/downloading-icon.tsx
@@ -0,0 +1,17 @@
+import s from './downloading-icon.module.css'
+
+const DownloadingIcon = () => {
+ return (
+ <div className="inline-flex text-components-button-secondary-text">
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="install-icon">
+ <g id="install-line">
+ <path d="M8 2V4H5L4.999 14H18.999L19 4H16V2H20C20.5523 2 21 2.44772 21 3V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V3C3 2.44772 3.44772 2 4 2H8ZM18.999 16H4.999L5 20H19L18.999 16Z" fill="currentColor"/>
+ <path id={s.downloadingIconLight} d="M17 19V17H15V19H17Z"/>
+ <path id={s.downloadingIconArrow} d="M13 2V7H16L12 11L8 7H11V2H13Z" fill="currentColor"/>
+ </g>
+ </svg>
+ </div>
+ )
+}
+
+export default DownloadingIcon
diff --git a/app/components/header/plugins-nav/index.tsx b/app/components/header/plugins-nav/index.tsx
new file mode 100644
index 0000000..b22e717
--- /dev/null
+++ b/app/components/header/plugins-nav/index.tsx
@@ -0,0 +1,66 @@
+'use client'
+
+import { useTranslation } from 'react-i18next'
+import Link from 'next/link'
+import classNames from '@/utils/classnames'
+import { Group } from '@/app/components/base/icons/src/vender/other'
+import { useSelectedLayoutSegment } from 'next/navigation'
+import DownloadingIcon from './downloading-icon'
+import { usePluginTaskStatus } from '@/app/components/plugins/plugin-page/plugin-tasks/hooks'
+import Indicator from '@/app/components/header/indicator'
+
+type PluginsNavProps = {
+ className?: string
+}
+
+const PluginsNav = ({
+ className,
+}: PluginsNavProps) => {
+ const { t } = useTranslation()
+ const selectedSegment = useSelectedLayoutSegment()
+ const activated = selectedSegment === 'plugins'
+ const {
+ isInstalling,
+ isInstallingWithError,
+ isFailed,
+ } = usePluginTaskStatus()
+
+ return (
+ <Link href="/plugins" className={classNames(
+ className, 'group', 'plugins-nav-button', // used for use-fold-anim-into.ts
+ )}>
+ <div
+ className={classNames(
+ 'relative flex flex-row h-8 p-1.5 gap-0.5 border border-transparent items-center justify-center rounded-xl system-sm-medium-uppercase',
+ activated && 'border-components-main-nav-nav-button-border bg-components-main-nav-nav-button-bg-active shadow-md text-components-main-nav-nav-button-text',
+ !activated && 'text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
+ (isInstallingWithError || isFailed) && !activated && 'border-components-panel-border-subtle',
+ )}
+ >
+ {
+ (isFailed || isInstallingWithError) && !activated && (
+ <Indicator
+ color='red'
+ className='absolute left-[-1px] top-[-1px]'
+ />
+ )
+ }
+ <div className='mr-0.5 flex h-5 w-5 items-center justify-center'>
+ {
+ (!(isInstalling || isInstallingWithError) || activated) && (
+ <Group className='h-4 w-4' />
+ )
+ }
+ {
+ (isInstalling || isInstallingWithError) && !activated && (
+ <DownloadingIcon />
+ )
+ }
+ </div>
+ <span className='px-0.5'>{t('common.menus.plugins')}</span>
+ </div>
+ </Link>
+ )
+}
+
+export default PluginsNav
diff --git a/app/components/header/tools-nav/index.tsx b/app/components/header/tools-nav/index.tsx
new file mode 100644
index 0000000..b873987
--- /dev/null
+++ b/app/components/header/tools-nav/index.tsx
@@ -0,0 +1,39 @@
+'use client'
+
+import { useTranslation } from 'react-i18next'
+import Link from 'next/link'
+import { useSelectedLayoutSegment } from 'next/navigation'
+import {
+ RiHammerFill,
+ RiHammerLine,
+} from '@remixicon/react'
+import classNames from '@/utils/classnames'
+type ToolsNavProps = {
+ className?: string
+}
+
+const ToolsNav = ({
+ className,
+}: ToolsNavProps) => {
+ const { t } = useTranslation()
+ const selectedSegment = useSelectedLayoutSegment()
+ const activated = selectedSegment === 'tools'
+
+ return (
+ <Link href="/tools" className={classNames(
+ 'group text-sm font-medium',
+ activated && 'font-semibold bg-components-main-nav-nav-button-bg-active hover:bg-components-main-nav-nav-button-bg-active-hover shadow-md',
+ activated ? 'text-components-main-nav-nav-button-text-active' : 'text-components-main-nav-nav-button-text hover:bg-components-main-nav-nav-button-bg-hover',
+ className,
+ )}>
+ {
+ activated
+ ? <RiHammerFill className='mr-2 h-4 w-4' />
+ : <RiHammerLine className='mr-2 h-4 w-4' />
+ }
+ {t('common.menus.tools')}
+ </Link>
+ )
+}
+
+export default ToolsNav
diff --git a/app/components/header/utils/util.ts b/app/components/header/utils/util.ts
new file mode 100644
index 0000000..38a3bcd
--- /dev/null
+++ b/app/components/header/utils/util.ts
@@ -0,0 +1,25 @@
+export const generateMailToLink = (email: string, subject?: string, body?: string): string => {
+ let mailtoLink = `mailto:${email}`
+
+ if (subject)
+ mailtoLink += `?subject=${encodeURIComponent(subject)}`
+
+ if (body)
+ mailtoLink += `&body=${encodeURIComponent(body)}`
+
+ return mailtoLink
+}
+
+export const mailToSupport = (account: string, plan: string, version: string) => {
+ const subject = `Technical Support Request ${plan} ${account}`
+ const body = `
+ Please do not remove the following information:
+ -----------------------------------------------
+ Current Plan: ${plan}
+ Account: ${account}
+ Version: ${version}
+ Platform:
+ Problem Description:
+ `
+ return generateMailToLink('support@dify.ai', subject, body)
+}
diff --git a/app/components/i18n-server.tsx b/app/components/i18n-server.tsx
new file mode 100644
index 0000000..78d5ca4
--- /dev/null
+++ b/app/components/i18n-server.tsx
@@ -0,0 +1,22 @@
+import React from 'react'
+import I18N from './i18n'
+import { ToastProvider } from './base/toast'
+import { getLocaleOnServer } from '@/i18n/server'
+
+export type II18NServerProps = {
+ children: React.ReactNode
+}
+
+const I18NServer = async ({
+ children,
+}: II18NServerProps) => {
+ const locale = await getLocaleOnServer()
+
+ return (
+ <I18N {...{ locale }}>
+ <ToastProvider>{children}</ToastProvider>
+ </I18N>
+ )
+}
+
+export default I18NServer
diff --git a/app/components/i18n.tsx b/app/components/i18n.tsx
new file mode 100644
index 0000000..f04f8d6
--- /dev/null
+++ b/app/components/i18n.tsx
@@ -0,0 +1,31 @@
+'use client'
+
+import type { FC } from 'react'
+import React, { useEffect } from 'react'
+import I18NContext from '@/context/i18n'
+import type { Locale } from '@/i18n'
+import { setLocaleOnClient } from '@/i18n'
+
+export type II18nProps = {
+ locale: Locale
+ children: React.ReactNode
+}
+const I18n: FC<II18nProps> = ({
+ locale,
+ children,
+}) => {
+ useEffect(() => {
+ setLocaleOnClient(locale, false)
+ }, [locale])
+
+ return (
+ <I18NContext.Provider value={{
+ locale,
+ i18n: {},
+ setLocaleOnClient,
+ }}>
+ {children}
+ </I18NContext.Provider>
+ )
+}
+export default React.memo(I18n)
diff --git a/app/components/plugins/base/badges/icon-with-tooltip.tsx b/app/components/plugins/base/badges/icon-with-tooltip.tsx
new file mode 100644
index 0000000..60b164e
--- /dev/null
+++ b/app/components/plugins/base/badges/icon-with-tooltip.tsx
@@ -0,0 +1,37 @@
+import React, { type FC } from 'react'
+import cn from '@/utils/classnames'
+import Tooltip from '@/app/components/base/tooltip'
+import { Theme } from '@/types/app'
+
+type IconWithTooltipProps = {
+ className?: string
+ popupContent?: string
+ theme: Theme
+ BadgeIconLight: React.ElementType
+ BadgeIconDark: React.ElementType
+}
+
+const IconWithTooltip: FC<IconWithTooltipProps> = ({
+ className,
+ theme,
+ popupContent,
+ BadgeIconLight,
+ BadgeIconDark,
+}) => {
+ const isDark = theme === Theme.dark
+ const iconClassName = cn('h-5 w-5', className)
+ const Icon = isDark ? BadgeIconDark : BadgeIconLight
+
+ return (
+ <Tooltip
+ popupClassName='p-1.5 border-[0.5px] border-[0.5px] border-components-panel-border bg-components-tooltip-bg text-text-secondary system-xs-medium'
+ popupContent={popupContent}
+ >
+ <div className='flex shrink-0 items-center justify-center'>
+ <Icon className={iconClassName} />
+ </div>
+ </Tooltip>
+ )
+}
+
+export default React.memo(IconWithTooltip)
diff --git a/app/components/plugins/base/badges/partner.tsx b/app/components/plugins/base/badges/partner.tsx
new file mode 100644
index 0000000..8e649c5
--- /dev/null
+++ b/app/components/plugins/base/badges/partner.tsx
@@ -0,0 +1,29 @@
+import type { FC } from 'react'
+import IconWithTooltip from './icon-with-tooltip'
+import PartnerDark from '@/app/components/base/icons/src/public/plugins/PartnerDark'
+import PartnerLight from '@/app/components/base/icons/src/public/plugins/PartnerLight'
+import useTheme from '@/hooks/use-theme'
+
+type PartnerProps = {
+ className?: string
+ text: string
+}
+
+const Partner: FC<PartnerProps> = ({
+ className,
+ text,
+}) => {
+ const { theme } = useTheme()
+
+ return (
+ <IconWithTooltip
+ className={className}
+ theme={theme}
+ BadgeIconLight={PartnerLight}
+ BadgeIconDark={PartnerDark}
+ popupContent={text}
+ />
+ )
+}
+
+export default Partner
diff --git a/app/components/plugins/base/badges/verified.tsx b/app/components/plugins/base/badges/verified.tsx
new file mode 100644
index 0000000..bea45c0
--- /dev/null
+++ b/app/components/plugins/base/badges/verified.tsx
@@ -0,0 +1,29 @@
+import type { FC } from 'react'
+import IconWithTooltip from './icon-with-tooltip'
+import VerifiedDark from '@/app/components/base/icons/src/public/plugins/VerifiedDark'
+import VerifiedLight from '@/app/components/base/icons/src/public/plugins/VerifiedLight'
+import useTheme from '@/hooks/use-theme'
+
+type VerifiedProps = {
+ className?: string
+ text: string
+}
+
+const Verified: FC<VerifiedProps> = ({
+ className,
+ text,
+}) => {
+ const { theme } = useTheme()
+
+ return (
+ <IconWithTooltip
+ className={className}
+ theme={theme}
+ BadgeIconLight={VerifiedLight}
+ BadgeIconDark={VerifiedDark}
+ popupContent={text}
+ />
+ )
+}
+
+export default Verified
diff --git a/app/components/plugins/base/key-value-item.tsx b/app/components/plugins/base/key-value-item.tsx
new file mode 100644
index 0000000..cfc81aa
--- /dev/null
+++ b/app/components/plugins/base/key-value-item.tsx
@@ -0,0 +1,66 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import copy from 'copy-to-clipboard'
+import {
+ RiClipboardLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { ClipboardCheck } from '../../base/icons/src/vender/line/files'
+import Tooltip from '../../base/tooltip'
+import cn from '@/utils/classnames'
+import ActionButton from '@/app/components/base/action-button'
+
+type Props = {
+ label: string
+ labelWidthClassName?: string
+ value: string
+ maskedValue?: string
+ valueMaxWidthClassName?: string
+}
+
+const KeyValueItem: FC<Props> = ({
+ label,
+ labelWidthClassName = 'w-10',
+ value,
+ maskedValue,
+ valueMaxWidthClassName = 'max-w-[162px]',
+}) => {
+ const { t } = useTranslation()
+ const [isCopied, setIsCopied] = useState(false)
+ const handleCopy = useCallback(() => {
+ copy(value)
+ setIsCopied(true)
+ }, [value])
+
+ useEffect(() => {
+ if (isCopied) {
+ const timer = setTimeout(() => {
+ setIsCopied(false)
+ }, 2000)
+ return () => {
+ clearTimeout(timer)
+ }
+ }
+ }, [isCopied])
+
+ const CopyIcon = isCopied ? ClipboardCheck : RiClipboardLine
+
+ return (
+ <div className='flex items-center gap-1'>
+ <span className={cn('system-xs-medium flex flex-col items-start justify-center text-text-tertiary', labelWidthClassName)}>{label}</span>
+ <div className='flex items-center justify-center gap-0.5'>
+ <span className={cn(valueMaxWidthClassName, ' system-xs-medium truncate text-text-secondary')}>
+ {maskedValue || value}
+ </span>
+ <Tooltip popupContent={t(`common.operation.${isCopied ? 'copied' : 'copy'}`)} position='top'>
+ <ActionButton onClick={handleCopy}>
+ <CopyIcon className='h-3.5 w-3.5 shrink-0 text-text-tertiary' />
+ </ActionButton>
+ </Tooltip>
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(KeyValueItem)
diff --git a/app/components/plugins/card/base/card-icon.tsx b/app/components/plugins/card/base/card-icon.tsx
new file mode 100644
index 0000000..7f7468e
--- /dev/null
+++ b/app/components/plugins/card/base/card-icon.tsx
@@ -0,0 +1,66 @@
+import { RiCheckLine, RiCloseLine } from '@remixicon/react'
+import AppIcon from '@/app/components/base/app-icon'
+import cn from '@/utils/classnames'
+
+const iconSizeMap = {
+ xs: 'w-4 h-4 text-base',
+ tiny: 'w-6 h-6 text-base',
+ small: 'w-8 h-8',
+ medium: 'w-9 h-9',
+ large: 'w-10 h-10',
+}
+const Icon = ({
+ className,
+ src,
+ installed = false,
+ installFailed = false,
+ size = 'large',
+}: {
+ className?: string
+ src: string | {
+ content: string
+ background: string
+ }
+ installed?: boolean
+ installFailed?: boolean
+ size?: 'xs' | 'tiny' | 'small' | 'medium' | 'large'
+}) => {
+ const iconClassName = 'flex justify-center items-center gap-2 absolute bottom-[-4px] right-[-4px] w-[18px] h-[18px] rounded-full border-2 border-components-panel-bg'
+ if (typeof src === 'object') {
+ return (
+ <div className={cn('relative', className)}>
+ <AppIcon
+ size={size}
+ iconType={'emoji'}
+ icon={src.content}
+ background={src.background}
+ className='rounded-md'
+ />
+ </div>
+ )
+ }
+
+ return (
+ <div
+ className={cn('relative shrink-0 rounded-md bg-contain bg-center bg-no-repeat', iconSizeMap[size], className)}
+ style={{
+ backgroundImage: `url(${src})`,
+ }}
+ >
+ {
+ installed
+ && <div className={cn(iconClassName, 'bg-state-success-solid')}>
+ <RiCheckLine className='h-3 w-3 text-text-primary-on-surface' />
+ </div>
+ }
+ {
+ installFailed
+ && <div className={cn(iconClassName, 'bg-state-destructive-solid')}>
+ <RiCloseLine className='h-3 w-3 text-text-primary-on-surface' />
+ </div>
+ }
+ </div>
+ )
+}
+
+export default Icon
diff --git a/app/components/plugins/card/base/corner-mark.tsx b/app/components/plugins/card/base/corner-mark.tsx
new file mode 100644
index 0000000..43c515d
--- /dev/null
+++ b/app/components/plugins/card/base/corner-mark.tsx
@@ -0,0 +1,12 @@
+import { LeftCorner } from '../../../base/icons/src/vender/plugin'
+
+const CornerMark = ({ text }: { text: string }) => {
+ return (
+ <div className='absolute right-0 top-0 flex pl-[13px] '>
+ <LeftCorner className="text-background-section" />
+ <div className="system-2xs-medium-uppercase h-5 rounded-tr-xl bg-background-section pr-2 leading-5 text-text-tertiary">{text}</div>
+ </div>
+ )
+}
+
+export default CornerMark
diff --git a/app/components/plugins/card/base/description.tsx b/app/components/plugins/card/base/description.tsx
new file mode 100644
index 0000000..bffcde3
--- /dev/null
+++ b/app/components/plugins/card/base/description.tsx
@@ -0,0 +1,31 @@
+import type { FC } from 'react'
+import React, { useMemo } from 'react'
+import cn from '@/utils/classnames'
+
+type Props = {
+ className?: string
+ text: string
+ descriptionLineRows: number
+}
+
+const Description: FC<Props> = ({
+ className,
+ text,
+ descriptionLineRows,
+}) => {
+ const lineClassName = useMemo(() => {
+ if (descriptionLineRows === 1)
+ return 'h-4 truncate'
+ else if (descriptionLineRows === 2)
+ return 'h-8 line-clamp-2'
+ else
+ return 'h-12 line-clamp-3'
+ }, [descriptionLineRows])
+ return (
+ <div className={cn('system-xs-regular text-text-tertiary', lineClassName, className)}>
+ {text}
+ </div>
+ )
+}
+
+export default Description
diff --git a/app/components/plugins/card/base/download-count.tsx b/app/components/plugins/card/base/download-count.tsx
new file mode 100644
index 0000000..7b3ae4d
--- /dev/null
+++ b/app/components/plugins/card/base/download-count.tsx
@@ -0,0 +1,19 @@
+import { RiInstallLine } from '@remixicon/react'
+import { formatNumber } from '@/utils/format'
+
+type Props = {
+ downloadCount: number
+}
+
+const DownloadCount = ({
+ downloadCount,
+}: Props) => {
+ return (
+ <div className="flex items-center space-x-1 text-text-tertiary">
+ <RiInstallLine className="h-3 w-3 shrink-0" />
+ <div className="system-xs-regular">{formatNumber(downloadCount)}</div>
+ </div>
+ )
+}
+
+export default DownloadCount
diff --git a/app/components/plugins/card/base/org-info.tsx b/app/components/plugins/card/base/org-info.tsx
new file mode 100644
index 0000000..01561f1
--- /dev/null
+++ b/app/components/plugins/card/base/org-info.tsx
@@ -0,0 +1,30 @@
+import cn from '@/utils/classnames'
+type Props = {
+ className?: string
+ orgName?: string
+ packageName: string
+ packageNameClassName?: string
+}
+
+const OrgInfo = ({
+ className,
+ orgName,
+ packageName,
+ packageNameClassName,
+}: Props) => {
+ return (
+ <div className={cn('flex h-4 items-center space-x-0.5', className)}>
+ {orgName && (
+ <>
+ <span className='system-xs-regular shrink-0 text-text-tertiary'>{orgName}</span>
+ <span className='system-xs-regular shrink-0 text-text-quaternary'>/</span>
+ </>
+ )}
+ <span className={cn('system-xs-regular w-0 shrink-0 grow truncate text-text-tertiary', packageNameClassName)}>
+ {packageName}
+ </span>
+ </div>
+ )
+}
+
+export default OrgInfo
diff --git a/app/components/plugins/card/base/placeholder.tsx b/app/components/plugins/card/base/placeholder.tsx
new file mode 100644
index 0000000..4505be3
--- /dev/null
+++ b/app/components/plugins/card/base/placeholder.tsx
@@ -0,0 +1,51 @@
+import { Group } from '../../../base/icons/src/vender/other'
+import Title from './title'
+import { SkeletonContainer, SkeletonPoint, SkeletonRectangle, SkeletonRow } from '@/app/components/base/skeleton'
+import cn from '@/utils/classnames'
+
+type Props = {
+ wrapClassName: string
+ loadingFileName?: string
+}
+
+export const LoadingPlaceholder = ({ className }: { className?: string }) => (
+ <div className={cn('h-2 rounded-sm bg-text-quaternary opacity-20', className)} />
+)
+
+const Placeholder = ({
+ wrapClassName,
+ loadingFileName,
+}: Props) => {
+ return (
+ <div className={wrapClassName}>
+ <SkeletonRow>
+ <div
+ className='flex h-10 w-10 items-center justify-center gap-2 rounded-[10px] border-[0.5px]
+ border-components-panel-border bg-background-default p-1 backdrop-blur-sm'>
+ <div className='flex h-5 w-5 items-center justify-center'>
+ <Group className='text-text-tertiary' />
+ </div>
+ </div>
+ <div className="grow">
+ <SkeletonContainer>
+ <div className="flex h-5 items-center">
+ {loadingFileName ? (
+ <Title title={loadingFileName} />
+ ) : (
+ <SkeletonRectangle className="w-[260px]" />
+ )}
+ </div>
+ <SkeletonRow className="h-4">
+ <SkeletonRectangle className="w-[41px]" />
+ <SkeletonPoint />
+ <SkeletonRectangle className="w-[180px]" />
+ </SkeletonRow>
+ </SkeletonContainer>
+ </div>
+ </SkeletonRow>
+ <SkeletonRectangle className="mt-3 w-[420px]" />
+ </div>
+ )
+}
+
+export default Placeholder
diff --git a/app/components/plugins/card/base/title.tsx b/app/components/plugins/card/base/title.tsx
new file mode 100644
index 0000000..41e66e7
--- /dev/null
+++ b/app/components/plugins/card/base/title.tsx
@@ -0,0 +1,13 @@
+const Title = ({
+ title,
+}: {
+ title: string
+}) => {
+ return (
+ <div className='system-md-semibold truncate text-text-secondary'>
+ {title}
+ </div>
+ )
+}
+
+export default Title
diff --git a/app/components/plugins/card/card-more-info.tsx b/app/components/plugins/card/card-more-info.tsx
new file mode 100644
index 0000000..4853361
--- /dev/null
+++ b/app/components/plugins/card/card-more-info.tsx
@@ -0,0 +1,36 @@
+import DownloadCount from './base/download-count'
+
+type Props = {
+ downloadCount?: number
+ tags: string[]
+}
+
+const CardMoreInfo = ({
+ downloadCount,
+ tags,
+}: Props) => {
+ return (
+ <div className="flex h-5 items-center">
+ {downloadCount !== undefined && <DownloadCount downloadCount={downloadCount} />}
+ {downloadCount !== undefined && tags && tags.length > 0 && <div className="system-xs-regular mx-2 text-text-quaternary">路</div>}
+ {tags && tags.length > 0 && (
+ <>
+ <div className="flex h-4 flex-wrap space-x-2 overflow-hidden">
+ {tags.map(tag => (
+ <div
+ key={tag}
+ className="system-xs-regular flex max-w-[120px] space-x-1 overflow-hidden"
+ title={`# ${tag}`}
+ >
+ <span className="text-text-quaternary">#</span>
+ <span className="truncate text-text-tertiary">{tag}</span>
+ </div>
+ ))}
+ </div>
+ </>
+ )}
+ </div>
+ )
+}
+
+export default CardMoreInfo
diff --git a/app/components/plugins/card/index.tsx b/app/components/plugins/card/index.tsx
new file mode 100644
index 0000000..1cc18ac
--- /dev/null
+++ b/app/components/plugins/card/index.tsx
@@ -0,0 +1,97 @@
+'use client'
+import React from 'react'
+import type { Plugin } from '../types'
+import Icon from '../card/base/card-icon'
+import CornerMark from './base/corner-mark'
+import Title from './base/title'
+import OrgInfo from './base/org-info'
+import Description from './base/description'
+import Placeholder from './base/placeholder'
+import cn from '@/utils/classnames'
+import { useGetLanguage } from '@/context/i18n'
+import { getLanguage } from '@/i18n/language'
+import { useSingleCategories } from '../hooks'
+import { renderI18nObject } from '@/i18n'
+import { useMixedTranslation } from '@/app/components/plugins/marketplace/hooks'
+import Partner from '../base/badges/partner'
+import Verified from '../base/badges/verified'
+
+export type Props = {
+ className?: string
+ payload: Plugin
+ titleLeft?: React.ReactNode
+ installed?: boolean
+ installFailed?: boolean
+ hideCornerMark?: boolean
+ descriptionLineRows?: number
+ footer?: React.ReactNode
+ isLoading?: boolean
+ loadingFileName?: string
+ locale?: string
+}
+
+const Card = ({
+ className,
+ payload,
+ titleLeft,
+ installed,
+ installFailed,
+ hideCornerMark,
+ descriptionLineRows = 2,
+ footer,
+ isLoading = false,
+ loadingFileName,
+ locale: localeFromProps,
+}: Props) => {
+ const defaultLocale = useGetLanguage()
+ const locale = localeFromProps ? getLanguage(localeFromProps) : defaultLocale
+ const { t } = useMixedTranslation(localeFromProps)
+ const { categoriesMap } = useSingleCategories(t)
+ const { category, type, name, org, label, brief, icon, verified, badges = [] } = payload
+ const isBundle = !['plugin', 'model', 'tool', 'extension', 'agent-strategy'].includes(type)
+ const cornerMark = isBundle ? categoriesMap.bundle?.label : categoriesMap[category]?.label
+ const getLocalizedText = (obj: Record<string, string> | undefined) =>
+ obj ? renderI18nObject(obj, locale) : ''
+ const isPartner = badges.includes('partner')
+
+ const wrapClassName = cn('hover-bg-components-panel-on-panel-item-bg relative rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg p-4 pb-3 shadow-xs', className)
+ if (isLoading) {
+ return (
+ <Placeholder
+ wrapClassName={wrapClassName}
+ loadingFileName={loadingFileName!}
+ />
+ )
+ }
+
+ return (
+ <div className={wrapClassName}>
+ {!hideCornerMark && <CornerMark text={cornerMark} />}
+ {/* Header */}
+ <div className="flex">
+ <Icon src={icon} installed={installed} installFailed={installFailed} />
+ <div className="ml-3 w-0 grow">
+ <div className="flex h-5 items-center">
+ <Title title={getLocalizedText(label)} />
+ {isPartner && <Partner className='ml-0.5 h-4 w-4' text={t('plugin.marketplace.partnerTip')} />}
+ {verified && <Verified className='ml-0.5 h-4 w-4' text={t('plugin.marketplace.verifiedTip')} />}
+ {titleLeft} {/* This can be version badge */}
+ </div>
+ <OrgInfo
+ className="mt-0.5"
+ orgName={org}
+ packageName={name}
+ />
+ </div>
+ </div>
+ <Description
+ className="mt-3"
+ text={getLocalizedText(brief)}
+ descriptionLineRows={descriptionLineRows}
+ />
+ {footer && <div>{footer}</div>}
+ </div>
+ )
+}
+
+export default React.memo(Card)
diff --git a/app/components/plugins/constants.ts b/app/components/plugins/constants.ts
new file mode 100644
index 0000000..02439be
--- /dev/null
+++ b/app/components/plugins/constants.ts
@@ -0,0 +1,27 @@
+export const tagKeys = [
+ 'agent',
+ 'search',
+ 'image',
+ 'videos',
+ 'weather',
+ 'finance',
+ 'design',
+ 'travel',
+ 'social',
+ 'news',
+ 'medical',
+ 'productivity',
+ 'education',
+ 'business',
+ 'entertainment',
+ 'utilities',
+ 'other',
+]
+
+export const categoryKeys = [
+ 'model',
+ 'tool',
+ 'agent-strategy',
+ 'extension',
+ 'bundle',
+]
diff --git a/app/components/plugins/hooks.ts b/app/components/plugins/hooks.ts
new file mode 100644
index 0000000..0349c46
--- /dev/null
+++ b/app/components/plugins/hooks.ts
@@ -0,0 +1,108 @@
+import { useTranslation } from 'react-i18next'
+import type { TFunction } from 'i18next'
+import {
+ categoryKeys,
+ tagKeys,
+} from './constants'
+
+type Tag = {
+ name: string
+ label: string
+}
+
+export const useTags = (translateFromOut?: TFunction) => {
+ const { t: translation } = useTranslation()
+ const t = translateFromOut || translation
+
+ const tags = tagKeys.map((tag) => {
+ return {
+ name: tag,
+ label: t(`pluginTags.tags.${tag}`),
+ }
+ })
+
+ const tagsMap = tags.reduce((acc, tag) => {
+ acc[tag.name] = tag
+ return acc
+ }, {} as Record<string, Tag>)
+
+ return {
+ tags,
+ tagsMap,
+ }
+}
+
+type Category = {
+ name: string
+ label: string
+}
+
+export const useCategories = (translateFromOut?: TFunction) => {
+ const { t: translation } = useTranslation()
+ const t = translateFromOut || translation
+
+ const categories = categoryKeys.map((category) => {
+ if (category === 'agent-strategy') {
+ return {
+ name: 'agent-strategy',
+ label: t('plugin.category.agents'),
+ }
+ }
+ return {
+ name: category,
+ label: t(`plugin.category.${category}s`),
+ }
+ })
+
+ const categoriesMap = categories.reduce((acc, category) => {
+ acc[category.name] = category
+ return acc
+ }, {} as Record<string, Category>)
+
+ return {
+ categories,
+ categoriesMap,
+ }
+}
+
+export const useSingleCategories = (translateFromOut?: TFunction) => {
+ const { t: translation } = useTranslation()
+ const t = translateFromOut || translation
+
+ const categories = categoryKeys.map((category) => {
+ if (category === 'agent-strategy') {
+ return {
+ name: 'agent-strategy',
+ label: t('plugin.categorySingle.agent'),
+ }
+ }
+ return {
+ name: category,
+ label: t(`plugin.categorySingle.${category}`),
+ }
+ })
+
+ const categoriesMap = categories.reduce((acc, category) => {
+ acc[category.name] = category
+ return acc
+ }, {} as Record<string, Category>)
+
+ return {
+ categories,
+ categoriesMap,
+ }
+}
+
+export const PLUGIN_PAGE_TABS_MAP = {
+ plugins: 'plugins',
+ marketplace: 'discover',
+}
+
+export const usePluginPageTabs = () => {
+ const { t } = useTranslation()
+ const tabs = [
+ { value: PLUGIN_PAGE_TABS_MAP.plugins, text: t('common.menus.plugins') },
+ { value: PLUGIN_PAGE_TABS_MAP.marketplace, text: t('common.menus.exploreMarketplace') },
+ ]
+ return tabs
+}
diff --git a/app/components/plugins/install-plugin/base/check-task-status.ts b/app/components/plugins/install-plugin/base/check-task-status.ts
new file mode 100644
index 0000000..320f50d
--- /dev/null
+++ b/app/components/plugins/install-plugin/base/check-task-status.ts
@@ -0,0 +1,63 @@
+import { checkTaskStatus as fetchCheckTaskStatus } from '@/service/plugins'
+import type { PluginStatus } from '../../types'
+import { TaskStatus } from '../../types'
+import { sleep } from '@/utils'
+
+const INTERVAL = 10 * 1000 // 10 seconds
+
+type Params = {
+ taskId: string
+ pluginUniqueIdentifier: string
+}
+
+function checkTaskStatus() {
+ let nextStatus = TaskStatus.running
+ let isStop = false
+
+ const doCheckStatus = async ({
+ taskId,
+ pluginUniqueIdentifier,
+ }: Params) => {
+ if (isStop) {
+ return {
+ status: TaskStatus.success,
+ }
+ }
+ const res = await fetchCheckTaskStatus(taskId)
+ const { plugins } = res.task
+ const plugin = plugins.find((p: PluginStatus) => p.plugin_unique_identifier === pluginUniqueIdentifier)
+ if (!plugin) {
+ nextStatus = TaskStatus.failed
+ return {
+ status: TaskStatus.failed,
+ error: 'Plugin package not found',
+ }
+ }
+ nextStatus = plugin.status
+ if (nextStatus === TaskStatus.running) {
+ await sleep(INTERVAL)
+ return await doCheckStatus({
+ taskId,
+ pluginUniqueIdentifier,
+ })
+ }
+ if (nextStatus === TaskStatus.failed) {
+ return {
+ status: TaskStatus.failed,
+ error: plugin.message,
+ }
+ }
+ return ({
+ status: TaskStatus.success,
+ })
+ }
+
+ return {
+ check: doCheckStatus,
+ stop: () => {
+ isStop = true
+ },
+ }
+}
+
+export default checkTaskStatus
diff --git a/app/components/plugins/install-plugin/base/installed.tsx b/app/components/plugins/install-plugin/base/installed.tsx
new file mode 100644
index 0000000..4da06ef
--- /dev/null
+++ b/app/components/plugins/install-plugin/base/installed.tsx
@@ -0,0 +1,60 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import Card from '../../card'
+import Button from '@/app/components/base/button'
+import type { Plugin, PluginDeclaration, PluginManifestInMarket } from '../../types'
+import { pluginManifestInMarketToPluginProps, pluginManifestToCardPluginProps } from '../utils'
+import Badge, { BadgeState } from '@/app/components/base/badge/index'
+
+type Props = {
+ payload?: Plugin | PluginDeclaration | PluginManifestInMarket | null
+ isMarketPayload?: boolean
+ isFailed: boolean
+ errMsg?: string | null
+ onCancel: () => void
+}
+
+const Installed: FC<Props> = ({
+ payload,
+ isMarketPayload,
+ isFailed,
+ errMsg,
+ onCancel,
+}) => {
+ const { t } = useTranslation()
+
+ const handleClose = () => {
+ onCancel()
+ }
+ return (
+ <>
+ <div className='flex flex-col items-start justify-center gap-4 self-stretch px-6 py-3'>
+ <p className='system-md-regular text-text-secondary'>{(isFailed && errMsg) ? errMsg : t(`plugin.installModal.${isFailed ? 'installFailedDesc' : 'installedSuccessfullyDesc'}`)}</p>
+ {payload && (
+ <div className='flex flex-wrap content-start items-start gap-1 self-stretch rounded-2xl bg-background-section-burn p-2'>
+ <Card
+ className='w-full'
+ payload={isMarketPayload ? pluginManifestInMarketToPluginProps(payload as PluginManifestInMarket) : pluginManifestToCardPluginProps(payload as PluginDeclaration)}
+ installed={!isFailed}
+ installFailed={isFailed}
+ titleLeft={<Badge className='mx-1' size="s" state={BadgeState.Default}>{(payload as PluginDeclaration).version || (payload as PluginManifestInMarket).latest_version}</Badge>}
+ />
+ </div>
+ )}
+ </div>
+ {/* Action Buttons */}
+ <div className='flex items-center justify-end gap-2 self-stretch p-6 pt-5'>
+ <Button
+ variant='primary'
+ className='min-w-[72px]'
+ onClick={handleClose}
+ >
+ {t('common.operation.close')}
+ </Button>
+ </div>
+ </>
+ )
+}
+export default React.memo(Installed)
diff --git a/app/components/plugins/install-plugin/base/loading-error.tsx b/app/components/plugins/install-plugin/base/loading-error.tsx
new file mode 100644
index 0000000..a79a381
--- /dev/null
+++ b/app/components/plugins/install-plugin/base/loading-error.tsx
@@ -0,0 +1,45 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { Group } from '../../../base/icons/src/vender/other'
+import { LoadingPlaceholder } from '@/app/components/plugins/card/base/placeholder'
+import Checkbox from '@/app/components/base/checkbox'
+import { RiCloseLine } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+
+const LoadingError: FC = () => {
+ const { t } = useTranslation()
+ return (
+ <div className='flex items-center space-x-2'>
+ <Checkbox
+ className='shrink-0'
+ checked={false}
+ disabled
+ />
+ <div className='hover-bg-components-panel-on-panel-item-bg relative grow rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg p-4 pb-3 shadow-xs'>
+ <div className="flex">
+ <div
+ className='relative flex h-10 w-10 items-center justify-center gap-2 rounded-[10px] border-[0.5px]
+ border-state-destructive-border bg-state-destructive-hover p-1 backdrop-blur-sm'>
+ <div className='flex h-5 w-5 items-center justify-center'>
+ <Group className='text-text-quaternary' />
+ </div>
+ <div className='absolute bottom-[-4px] right-[-4px] rounded-full border-[2px] border-components-panel-bg bg-state-destructive-solid'>
+ <RiCloseLine className='h-3 w-3 text-text-primary-on-surface' />
+ </div>
+ </div>
+ <div className="ml-3 grow">
+ <div className="system-md-semibold flex h-5 items-center text-text-destructive">
+ {t('plugin.installModal.pluginLoadError')}
+ </div>
+ <div className='system-xs-regular mt-0.5 text-text-tertiary'>
+ {t('plugin.installModal.pluginLoadErrorDesc')}
+ </div>
+ </div>
+ </div>
+ <LoadingPlaceholder className="mt-3 w-[420px]" />
+ </div>
+ </div>
+ )
+}
+export default React.memo(LoadingError)
diff --git a/app/components/plugins/install-plugin/base/loading.tsx b/app/components/plugins/install-plugin/base/loading.tsx
new file mode 100644
index 0000000..61a91cb
--- /dev/null
+++ b/app/components/plugins/install-plugin/base/loading.tsx
@@ -0,0 +1,23 @@
+'use client'
+import React from 'react'
+import Placeholder from '../../card/base/placeholder'
+import Checkbox from '@/app/components/base/checkbox'
+
+const Loading = () => {
+ return (
+ <div className='flex items-center space-x-2'>
+ <Checkbox
+ className='shrink-0'
+ checked={false}
+ disabled
+ />
+ <div className='hover-bg-components-panel-on-panel-item-bg relative grow rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg p-4 pb-3 shadow-xs'>
+ <Placeholder
+ wrapClassName='w-full'
+ />
+ </div>
+ </div>
+ )
+}
+
+export default React.memo(Loading)
diff --git a/app/components/plugins/install-plugin/base/use-get-icon.ts b/app/components/plugins/install-plugin/base/use-get-icon.ts
new file mode 100644
index 0000000..bb46f27
--- /dev/null
+++ b/app/components/plugins/install-plugin/base/use-get-icon.ts
@@ -0,0 +1,16 @@
+import { useCallback } from 'react'
+import { apiPrefix } from '@/config'
+import { useSelector } from '@/context/app-context'
+
+const useGetIcon = () => {
+ const currentWorkspace = useSelector(s => s.currentWorkspace)
+ const getIconUrl = useCallback((fileName: string) => {
+ return `${apiPrefix}/workspaces/current/plugin/icon?tenant_id=${currentWorkspace.id}&filename=${fileName}`
+ }, [currentWorkspace.id])
+
+ return {
+ getIconUrl,
+ }
+}
+
+export default useGetIcon
diff --git a/app/components/plugins/install-plugin/base/version.tsx b/app/components/plugins/install-plugin/base/version.tsx
new file mode 100644
index 0000000..67bbc8e
--- /dev/null
+++ b/app/components/plugins/install-plugin/base/version.tsx
@@ -0,0 +1,34 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import Badge, { BadgeState } from '@/app/components/base/badge/index'
+import type { VersionProps } from '../../types'
+
+const Version: FC<VersionProps> = ({
+ hasInstalled,
+ installedVersion,
+ toInstallVersion,
+}) => {
+ return (
+ <>
+ {
+ !hasInstalled
+ ? (
+ <Badge className='mx-1' size="s" state={BadgeState.Default}>{toInstallVersion}</Badge>
+ )
+ : (
+ <>
+ <Badge className='mx-1' size="s" state={BadgeState.Warning}>
+ {`${installedVersion} -> ${toInstallVersion}`}
+ </Badge>
+ {/* <div className='flex px-0.5 justify-center items-center gap-0.5'>
+ <div className='text-text-warning system-xs-medium'>Used in 3 apps</div>
+ <RiInformation2Line className='w-4 h-4 text-text-tertiary' />
+ </div> */}
+ </>
+ )
+ }
+ </>
+ )
+}
+export default React.memo(Version)
diff --git a/app/components/plugins/install-plugin/hooks.ts b/app/components/plugins/install-plugin/hooks.ts
new file mode 100644
index 0000000..5da4c75
--- /dev/null
+++ b/app/components/plugins/install-plugin/hooks.ts
@@ -0,0 +1,107 @@
+import Toast, { type IToastProps } from '@/app/components/base/toast'
+import { uploadGitHub } from '@/service/plugins'
+import { compareVersion, getLatestVersion } from '@/utils/semver'
+import type { GitHubRepoReleaseResponse } from '../types'
+import { GITHUB_ACCESS_TOKEN } from '@/config'
+
+const formatReleases = (releases: any) => {
+ return releases.map((release: any) => ({
+ tag_name: release.tag_name,
+ assets: release.assets.map((asset: any) => ({
+ browser_download_url: asset.browser_download_url,
+ name: asset.name,
+ })),
+ }))
+}
+
+export const useGitHubReleases = () => {
+ const fetchReleases = async (owner: string, repo: string) => {
+ try {
+ if (!GITHUB_ACCESS_TOKEN) {
+ // Fetch releases without authentication from client
+ const res = await fetch(`https://api.github.com/repos/${owner}/${repo}/releases`)
+ if (!res.ok) throw new Error('Failed to fetch repository releases')
+ const data = await res.json()
+ return formatReleases(data)
+ }
+ else {
+ // Fetch releases with authentication from server
+ const res = await fetch(`/repos/${owner}/${repo}/releases`)
+ const bodyJson = await res.json()
+ if (bodyJson.status !== 200) throw new Error(bodyJson.data.message)
+ return formatReleases(bodyJson.data)
+ }
+ }
+ catch (error) {
+ if (error instanceof Error) {
+ Toast.notify({
+ type: 'error',
+ message: error.message,
+ })
+ }
+ else {
+ Toast.notify({
+ type: 'error',
+ message: 'Failed to fetch repository releases',
+ })
+ }
+ return []
+ }
+ }
+
+ const checkForUpdates = (fetchedReleases: GitHubRepoReleaseResponse[], currentVersion: string) => {
+ let needUpdate = false
+ const toastProps: IToastProps = {
+ type: 'info',
+ message: 'No new version available',
+ }
+ if (fetchedReleases.length === 0) {
+ toastProps.type = 'error'
+ toastProps.message = 'Input releases is empty'
+ return { needUpdate, toastProps }
+ }
+ const versions = fetchedReleases.map(release => release.tag_name)
+ const latestVersion = getLatestVersion(versions)
+ try {
+ needUpdate = compareVersion(latestVersion, currentVersion) === 1
+ if (needUpdate)
+ toastProps.message = `New version available: ${latestVersion}`
+ }
+ catch {
+ needUpdate = false
+ toastProps.type = 'error'
+ toastProps.message = 'Fail to compare versions, please check the version format'
+ }
+ return { needUpdate, toastProps }
+ }
+
+ return { fetchReleases, checkForUpdates }
+}
+
+export const useGitHubUpload = () => {
+ const handleUpload = async (
+ repoUrl: string,
+ selectedVersion: string,
+ selectedPackage: string,
+ onSuccess?: (GitHubPackage: { manifest: any; unique_identifier: string }) => void,
+ ) => {
+ try {
+ const response = await uploadGitHub(repoUrl, selectedVersion, selectedPackage)
+ const GitHubPackage = {
+ manifest: response.manifest,
+ unique_identifier: response.unique_identifier,
+ }
+ if (onSuccess) onSuccess(GitHubPackage)
+ return GitHubPackage
+ }
+ catch (error) {
+ Toast.notify({
+ type: 'error',
+ message: 'Error uploading package',
+ })
+ throw error
+ }
+ }
+
+ return { handleUpload }
+}
diff --git a/app/components/plugins/install-plugin/hooks/use-check-installed.tsx b/app/components/plugins/install-plugin/hooks/use-check-installed.tsx
new file mode 100644
index 0000000..e9d83c8
--- /dev/null
+++ b/app/components/plugins/install-plugin/hooks/use-check-installed.tsx
@@ -0,0 +1,33 @@
+import { useCheckInstalled as useDoCheckInstalled } from '@/service/use-plugins'
+
+import { useMemo } from 'react'
+import type { VersionInfo } from '../../types'
+type Props = {
+ pluginIds: string[],
+ enabled: boolean
+}
+const useCheckInstalled = (props: Props) => {
+ const { data, isLoading, error } = useDoCheckInstalled(props)
+
+ const installedInfo = useMemo(() => {
+ if (!data)
+ return undefined
+
+ const res: Record<string, VersionInfo> = {}
+ data?.plugins.forEach((plugin) => {
+ res[plugin.plugin_id] = {
+ installedId: plugin.id,
+ installedVersion: plugin.declaration.version,
+ uniqueIdentifier: plugin.plugin_unique_identifier,
+ }
+ })
+ return res
+ }, [data])
+ return {
+ installedInfo,
+ isLoading,
+ error,
+ }
+}
+
+export default useCheckInstalled
diff --git a/app/components/plugins/install-plugin/hooks/use-fold-anim-into.ts b/app/components/plugins/install-plugin/hooks/use-fold-anim-into.ts
new file mode 100644
index 0000000..4b8d5e8
--- /dev/null
+++ b/app/components/plugins/install-plugin/hooks/use-fold-anim-into.ts
@@ -0,0 +1,57 @@
+import { sleep } from '@/utils'
+
+const animTime = 750
+const modalClassName = 'install-modal'
+const COUNT_DOWN_TIME = 15000 // 15s
+
+function getElemCenter(elem: HTMLElement) {
+ const rect = elem.getBoundingClientRect()
+ return {
+ x: rect.left + rect.width / 2 + window.scrollX,
+ y: rect.top + rect.height / 2 + window.scrollY,
+ }
+}
+
+const useFoldAnimInto = (onClose: () => void) => {
+ let countDownRunId: number
+ const clearCountDown = () => {
+ clearTimeout(countDownRunId)
+ }
+ // modalElem fold into plugin install task btn
+ const foldIntoAnim = async () => {
+ clearCountDown()
+ const modalElem = document.querySelector(`.${modalClassName}`) as HTMLElement
+ const pluginTaskTriggerElem = document.getElementById('plugin-task-trigger') || document.querySelector('.plugins-nav-button')
+
+ if (!modalElem || !pluginTaskTriggerElem) {
+ onClose()
+ return
+ }
+
+ const modelCenter = getElemCenter(modalElem)
+ const modalElemRect = modalElem.getBoundingClientRect()
+ const pluginTaskTriggerCenter = getElemCenter(pluginTaskTriggerElem)
+ const xDiff = pluginTaskTriggerCenter.x - modelCenter.x
+ const yDiff = pluginTaskTriggerCenter.y - modelCenter.y
+ const scale = 1 / Math.max(modalElemRect.width, modalElemRect.height)
+ modalElem.style.transition = `all cubic-bezier(0.4, 0, 0.2, 1) ${animTime}ms`
+ modalElem.style.transform = `translate(${xDiff}px, ${yDiff}px) scale(${scale})`
+ await sleep(animTime)
+ onClose()
+ }
+
+ const countDownFoldIntoAnim = async () => {
+ countDownRunId = window.setTimeout(() => {
+ foldIntoAnim()
+ }, COUNT_DOWN_TIME)
+ }
+
+ return {
+ modalClassName,
+ foldIntoAnim,
+ clearCountDown,
+ countDownFoldIntoAnim,
+ }
+}
+
+export default useFoldAnimInto
diff --git a/app/components/plugins/install-plugin/hooks/use-hide-logic.ts b/app/components/plugins/install-plugin/hooks/use-hide-logic.ts
new file mode 100644
index 0000000..e5d2d18
--- /dev/null
+++ b/app/components/plugins/install-plugin/hooks/use-hide-logic.ts
@@ -0,0 +1,40 @@
+import { useCallback, useState } from 'react'
+import useFoldAnimInto from './use-fold-anim-into'
+
+const useHideLogic = (onClose: () => void) => {
+ const {
+ modalClassName,
+ foldIntoAnim: doFoldAnimInto,
+ clearCountDown,
+ countDownFoldIntoAnim,
+ } = useFoldAnimInto(onClose)
+
+ const [isInstalling, doSetIsInstalling] = useState(false)
+ const setIsInstalling = useCallback((isInstalling: boolean) => {
+ if (!isInstalling)
+ clearCountDown()
+ doSetIsInstalling(isInstalling)
+ }, [clearCountDown])
+
+ const foldAnimInto = useCallback(() => {
+ if (isInstalling) {
+ doFoldAnimInto()
+ return
+ }
+ onClose()
+ }, [doFoldAnimInto, isInstalling, onClose])
+
+ const handleStartToInstall = useCallback(() => {
+ setIsInstalling(true)
+ countDownFoldIntoAnim()
+ }, [countDownFoldIntoAnim, setIsInstalling])
+
+ return {
+ modalClassName,
+ foldAnimInto,
+ setIsInstalling,
+ handleStartToInstall,
+ }
+}
+
+export default useHideLogic
diff --git a/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list.tsx b/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list.tsx
new file mode 100644
index 0000000..ac26971
--- /dev/null
+++ b/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list.tsx
@@ -0,0 +1,48 @@
+import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { useProviderContext } from '@/context/provider-context'
+import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
+import { useInvalidateAllBuiltInTools, useInvalidateAllToolProviders } from '@/service/use-tools'
+import { useInvalidateStrategyProviders } from '@/service/use-strategy'
+import type { Plugin, PluginDeclaration, PluginManifestInMarket } from '../../types'
+import { PluginType } from '../../types'
+
+const useRefreshPluginList = () => {
+ const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
+ const { mutate: refetchLLMModelList } = useModelList(ModelTypeEnum.textGeneration)
+ const { mutate: refetchEmbeddingModelList } = useModelList(ModelTypeEnum.textEmbedding)
+ const { mutate: refetchRerankModelList } = useModelList(ModelTypeEnum.rerank)
+ const { refreshModelProviders } = useProviderContext()
+
+ const invalidateAllToolProviders = useInvalidateAllToolProviders()
+ const invalidateAllBuiltInTools = useInvalidateAllBuiltInTools()
+
+ const invalidateStrategyProviders = useInvalidateStrategyProviders()
+ return {
+ refreshPluginList: (manifest?: PluginManifestInMarket | Plugin | PluginDeclaration | null, refreshAllType?: boolean) => {
+ // installed list
+ invalidateInstalledPluginList()
+
+ // tool page, tool select
+ if ((manifest && PluginType.tool.includes(manifest.category)) || refreshAllType) {
+ invalidateAllToolProviders()
+ invalidateAllBuiltInTools()
+ // TODO: update suggested tools. It's a function in hook useMarketplacePlugins,handleUpdatePlugins
+ }
+
+ // model select
+ if ((manifest && PluginType.model.includes(manifest.category)) || refreshAllType) {
+ refreshModelProviders()
+ refetchLLMModelList()
+ refetchEmbeddingModelList()
+ refetchRerankModelList()
+ }
+
+ // agent select
+ if ((manifest && PluginType.agent.includes(manifest.category)) || refreshAllType)
+ invalidateStrategyProviders()
+ },
+ }
+}
+
+export default useRefreshPluginList
diff --git a/app/components/plugins/install-plugin/install-bundle/index.tsx b/app/components/plugins/install-plugin/install-bundle/index.tsx
new file mode 100644
index 0000000..c6b4cdf
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-bundle/index.tsx
@@ -0,0 +1,75 @@
+'use client'
+import type { FC } from 'react'
+import Modal from '@/app/components/base/modal'
+import React, { useCallback, useState } from 'react'
+import { InstallStep } from '../../types'
+import type { Dependency } from '../../types'
+import ReadyToInstall from './ready-to-install'
+import { useTranslation } from 'react-i18next'
+import useHideLogic from '../hooks/use-hide-logic'
+import cn from '@/utils/classnames'
+
+const i18nPrefix = 'plugin.installModal'
+
+export enum InstallType {
+ fromLocal = 'fromLocal',
+ fromMarketplace = 'fromMarketplace',
+ fromDSL = 'fromDSL',
+}
+
+type Props = {
+ installType?: InstallType
+ fromDSLPayload: Dependency[]
+ // plugins?: PluginDeclaration[]
+ onClose: () => void
+}
+
+const InstallBundle: FC<Props> = ({
+ installType = InstallType.fromMarketplace,
+ fromDSLPayload,
+ onClose,
+}) => {
+ const { t } = useTranslation()
+ const [step, setStep] = useState<InstallStep>(installType === InstallType.fromMarketplace ? InstallStep.readyToInstall : InstallStep.uploading)
+
+ const {
+ modalClassName,
+ foldAnimInto,
+ setIsInstalling,
+ handleStartToInstall,
+ } = useHideLogic(onClose)
+
+ const getTitle = useCallback(() => {
+ if (step === InstallStep.uploadFailed)
+ return t(`${i18nPrefix}.uploadFailed`)
+ if (step === InstallStep.installed)
+ return t(`${i18nPrefix}.installComplete`)
+
+ return t(`${i18nPrefix}.installPlugin`)
+ }, [step, t])
+
+ return (
+ <Modal
+ isShow={true}
+ onClose={foldAnimInto}
+ className={cn(modalClassName, 'shadows-shadow-xl flex min-w-[560px] flex-col items-start rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-0')}
+ closable
+ >
+ <div className='flex items-start gap-2 self-stretch pb-3 pl-6 pr-14 pt-6'>
+ <div className='title-2xl-semi-bold self-stretch text-text-primary'>
+ {getTitle()}
+ </div>
+ </div>
+ <ReadyToInstall
+ step={step}
+ onStepChange={setStep}
+ onStartToInstall={handleStartToInstall}
+ setIsInstalling={setIsInstalling}
+ allPlugins={fromDSLPayload}
+ onClose={onClose}
+ />
+ </Modal>
+ )
+}
+
+export default React.memo(InstallBundle)
diff --git a/app/components/plugins/install-plugin/install-bundle/item/github-item.tsx b/app/components/plugins/install-plugin/install-bundle/item/github-item.tsx
new file mode 100644
index 0000000..96abaa2
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-bundle/item/github-item.tsx
@@ -0,0 +1,62 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect } from 'react'
+import type { GitHubItemAndMarketPlaceDependency, Plugin } from '../../../types'
+import { pluginManifestToCardPluginProps } from '../../utils'
+import { useUploadGitHub } from '@/service/use-plugins'
+import Loading from '../../base/loading'
+import LoadedItem from './loaded-item'
+import type { VersionProps } from '@/app/components/plugins/types'
+
+type Props = {
+ checked: boolean
+ onCheckedChange: (plugin: Plugin) => void
+ dependency: GitHubItemAndMarketPlaceDependency
+ versionInfo: VersionProps
+ onFetchedPayload: (payload: Plugin) => void
+ onFetchError: () => void
+}
+
+const Item: FC<Props> = ({
+ checked,
+ onCheckedChange,
+ dependency,
+ versionInfo,
+ onFetchedPayload,
+ onFetchError,
+}) => {
+ const info = dependency.value
+ const { data, error } = useUploadGitHub({
+ repo: info.repo!,
+ version: info.release! || info.version!,
+ package: info.packages! || info.package!,
+ })
+ const [payload, setPayload] = React.useState<Plugin | null>(null)
+ useEffect(() => {
+ if (data) {
+ const payload = {
+ ...pluginManifestToCardPluginProps(data.manifest),
+ plugin_id: data.unique_identifier,
+ }
+ onFetchedPayload(payload)
+ setPayload(payload)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [data])
+ useEffect(() => {
+ if (error)
+ onFetchError()
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [error])
+ if (!payload) return <Loading />
+ return (
+ <LoadedItem
+ payload={payload}
+ versionInfo={versionInfo}
+ checked={checked}
+ onCheckedChange={onCheckedChange}
+ />
+ )
+}
+export default React.memo(Item)
diff --git a/app/components/plugins/install-plugin/install-bundle/item/loaded-item.tsx b/app/components/plugins/install-plugin/install-bundle/item/loaded-item.tsx
new file mode 100644
index 0000000..5eb4c94
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-bundle/item/loaded-item.tsx
@@ -0,0 +1,51 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import type { Plugin } from '../../../types'
+import Card from '../../../card'
+import Checkbox from '@/app/components/base/checkbox'
+import useGetIcon from '../../base/use-get-icon'
+import { MARKETPLACE_API_PREFIX } from '@/config'
+import Version from '../../base/version'
+import type { VersionProps } from '../../../types'
+
+type Props = {
+ checked: boolean
+ onCheckedChange: (plugin: Plugin) => void
+ payload: Plugin
+ isFromMarketPlace?: boolean
+ versionInfo: VersionProps
+}
+
+const LoadedItem: FC<Props> = ({
+ checked,
+ onCheckedChange,
+ payload,
+ isFromMarketPlace,
+ versionInfo: particleVersionInfo,
+}) => {
+ const { getIconUrl } = useGetIcon()
+ const versionInfo = {
+ ...particleVersionInfo,
+ toInstallVersion: payload.version,
+ }
+ return (
+ <div className='flex items-center space-x-2'>
+ <Checkbox
+ className='shrink-0'
+ checked={checked}
+ onCheck={() => onCheckedChange(payload)}
+ />
+ <Card
+ className='grow'
+ payload={{
+ ...payload,
+ icon: isFromMarketPlace ? `${MARKETPLACE_API_PREFIX}/plugins/${payload.org}/${payload.name}/icon` : getIconUrl(payload.icon),
+ }}
+ titleLeft={payload.version ? <Version {...versionInfo} /> : null}
+ />
+ </div>
+ )
+}
+
+export default React.memo(LoadedItem)
diff --git a/app/components/plugins/install-plugin/install-bundle/item/marketplace-item.tsx b/app/components/plugins/install-plugin/install-bundle/item/marketplace-item.tsx
new file mode 100644
index 0000000..3389bdb
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-bundle/item/marketplace-item.tsx
@@ -0,0 +1,36 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import type { Plugin } from '../../../types'
+import Loading from '../../base/loading'
+import LoadedItem from './loaded-item'
+import type { VersionProps } from '@/app/components/plugins/types'
+
+type Props = {
+ checked: boolean
+ onCheckedChange: (plugin: Plugin) => void
+ payload?: Plugin
+ version: string
+ versionInfo: VersionProps
+}
+
+const MarketPlaceItem: FC<Props> = ({
+ checked,
+ onCheckedChange,
+ payload,
+ version,
+ versionInfo,
+}) => {
+ if (!payload) return <Loading />
+ return (
+ <LoadedItem
+ checked={checked}
+ onCheckedChange={onCheckedChange}
+ payload={{ ...payload, version }}
+ isFromMarketPlace
+ versionInfo={versionInfo}
+ />
+ )
+}
+
+export default React.memo(MarketPlaceItem)
diff --git a/app/components/plugins/install-plugin/install-bundle/item/package-item.tsx b/app/components/plugins/install-plugin/install-bundle/item/package-item.tsx
new file mode 100644
index 0000000..101c8fa
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-bundle/item/package-item.tsx
@@ -0,0 +1,41 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import type { Plugin } from '../../../types'
+import type { PackageDependency } from '../../../types'
+import { pluginManifestToCardPluginProps } from '../../utils'
+import LoadedItem from './loaded-item'
+import LoadingError from '../../base/loading-error'
+import type { VersionProps } from '@/app/components/plugins/types'
+
+type Props = {
+ checked: boolean
+ onCheckedChange: (plugin: Plugin) => void
+ payload: PackageDependency
+ isFromMarketPlace?: boolean
+ versionInfo: VersionProps
+}
+
+const PackageItem: FC<Props> = ({
+ payload,
+ checked,
+ onCheckedChange,
+ isFromMarketPlace,
+ versionInfo,
+}) => {
+ if (!payload.value?.manifest)
+ return <LoadingError />
+
+ const plugin = pluginManifestToCardPluginProps(payload.value.manifest)
+ return (
+ <LoadedItem
+ payload={plugin}
+ checked={checked}
+ onCheckedChange={onCheckedChange}
+ isFromMarketPlace={isFromMarketPlace}
+ versionInfo={versionInfo}
+ />
+ )
+}
+
+export default React.memo(PackageItem)
diff --git a/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx b/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx
new file mode 100644
index 0000000..63c0b5b
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx
@@ -0,0 +1,57 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import { InstallStep } from '../../types'
+import Install from './steps/install'
+import Installed from './steps/installed'
+import type { Dependency, InstallStatusResponse, Plugin } from '../../types'
+
+type Props = {
+ step: InstallStep
+ onStepChange: (step: InstallStep) => void,
+ onStartToInstall: () => void
+ setIsInstalling: (isInstalling: boolean) => void
+ allPlugins: Dependency[]
+ onClose: () => void
+ isFromMarketPlace?: boolean
+}
+
+const ReadyToInstall: FC<Props> = ({
+ step,
+ onStepChange,
+ onStartToInstall,
+ setIsInstalling,
+ allPlugins,
+ onClose,
+ isFromMarketPlace,
+}) => {
+ const [installedPlugins, setInstalledPlugins] = useState<Plugin[]>([])
+ const [installStatus, setInstallStatus] = useState<InstallStatusResponse[]>([])
+ const handleInstalled = useCallback((plugins: Plugin[], installStatus: InstallStatusResponse[]) => {
+ setInstallStatus(installStatus)
+ setInstalledPlugins(plugins)
+ onStepChange(InstallStep.installed)
+ setIsInstalling(false)
+ }, [onStepChange, setIsInstalling])
+ return (
+ <>
+ {step === InstallStep.readyToInstall && (
+ <Install
+ allPlugins={allPlugins}
+ onCancel={onClose}
+ onStartToInstall={onStartToInstall}
+ onInstalled={handleInstalled}
+ isFromMarketPlace={isFromMarketPlace}
+ />
+ )}
+ {step === InstallStep.installed && (
+ <Installed
+ list={installedPlugins}
+ installStatus={installStatus}
+ onCancel={onClose}
+ />
+ )}
+ </>
+ )
+}
+export default React.memo(ReadyToInstall)
diff --git a/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx b/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx
new file mode 100644
index 0000000..40be3e6
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx
@@ -0,0 +1,221 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import type { Dependency, GitHubItemAndMarketPlaceDependency, PackageDependency, Plugin, VersionInfo } from '../../../types'
+import MarketplaceItem from '../item/marketplace-item'
+import GithubItem from '../item/github-item'
+import { useFetchPluginsInMarketPlaceByIds, useFetchPluginsInMarketPlaceByInfo } from '@/service/use-plugins'
+import useCheckInstalled from '@/app/components/plugins/install-plugin/hooks/use-check-installed'
+import produce from 'immer'
+import PackageItem from '../item/package-item'
+import LoadingError from '../../base/loading-error'
+
+type Props = {
+ allPlugins: Dependency[]
+ selectedPlugins: Plugin[]
+ onSelect: (plugin: Plugin, selectedIndex: number) => void
+ onLoadedAllPlugin: (installedInfo: Record<string, VersionInfo>) => void
+ isFromMarketPlace?: boolean
+}
+
+const InstallByDSLList: FC<Props> = ({
+ allPlugins,
+ selectedPlugins,
+ onSelect,
+ onLoadedAllPlugin,
+ isFromMarketPlace,
+}) => {
+ // DSL has id, to get plugin info to show more info
+ const { isLoading: isFetchingMarketplaceDataById, data: infoGetById, error: infoByIdError } = useFetchPluginsInMarketPlaceByIds(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value.marketplace_plugin_unique_identifier!))
+ // has meta(org,name,version), to get id
+ const { isLoading: isFetchingDataByMeta, data: infoByMeta, error: infoByMetaError } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value!))
+
+ const [plugins, doSetPlugins] = useState<(Plugin | undefined)[]>((() => {
+ const hasLocalPackage = allPlugins.some(d => d.type === 'package')
+ if (!hasLocalPackage)
+ return []
+
+ const _plugins = allPlugins.map((d) => {
+ if (d.type === 'package') {
+ return {
+ ...(d as any).value.manifest,
+ plugin_id: (d as any).value.unique_identifier,
+ }
+ }
+
+ return undefined
+ })
+ return _plugins
+ })())
+
+ const pluginsRef = React.useRef<(Plugin | undefined)[]>(plugins)
+
+ const setPlugins = useCallback((p: (Plugin | undefined)[]) => {
+ doSetPlugins(p)
+ pluginsRef.current = p
+ }, [])
+
+ const [errorIndexes, setErrorIndexes] = useState<number[]>([])
+
+ const handleGitHubPluginFetched = useCallback((index: number) => {
+ return (p: Plugin) => {
+ const nextPlugins = produce(pluginsRef.current, (draft) => {
+ draft[index] = p
+ })
+ setPlugins(nextPlugins)
+ }
+ }, [setPlugins])
+
+ const handleGitHubPluginFetchError = useCallback((index: number) => {
+ return () => {
+ setErrorIndexes([...errorIndexes, index])
+ }
+ }, [errorIndexes])
+
+ const marketPlaceInDSLIndex = useMemo(() => {
+ const res: number[] = []
+ allPlugins.forEach((d, index) => {
+ if (d.type === 'marketplace')
+ res.push(index)
+ })
+ return res
+ }, [allPlugins])
+
+ useEffect(() => {
+ if (!isFetchingMarketplaceDataById && infoGetById?.data.plugins) {
+ const payloads = infoGetById?.data.plugins
+ const failedIndex: number[] = []
+ const nextPlugins = produce(pluginsRef.current, (draft) => {
+ marketPlaceInDSLIndex.forEach((index, i) => {
+ if (payloads[i]) {
+ draft[index] = {
+ ...payloads[i],
+ version: payloads[i].version || payloads[i].latest_version,
+ }
+ }
+ else { failedIndex.push(index) }
+ })
+ })
+ setPlugins(nextPlugins)
+
+ if (failedIndex.length > 0)
+ setErrorIndexes([...errorIndexes, ...failedIndex])
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isFetchingMarketplaceDataById])
+
+ useEffect(() => {
+ if (!isFetchingDataByMeta && infoByMeta?.data.list) {
+ const payloads = infoByMeta?.data.list
+ const failedIndex: number[] = []
+ const nextPlugins = produce(pluginsRef.current, (draft) => {
+ marketPlaceInDSLIndex.forEach((index, i) => {
+ if (payloads[i]) {
+ const item = payloads[i]
+ draft[index] = {
+ ...item.plugin,
+ plugin_id: item.version.unique_identifier,
+ }
+ }
+ else {
+ failedIndex.push(index)
+ }
+ })
+ })
+ setPlugins(nextPlugins)
+ if (failedIndex.length > 0)
+ setErrorIndexes([...errorIndexes, ...failedIndex])
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isFetchingDataByMeta])
+
+ useEffect(() => {
+ // get info all failed
+ if (infoByMetaError || infoByIdError)
+ setErrorIndexes([...errorIndexes, ...marketPlaceInDSLIndex])
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [infoByMetaError, infoByIdError])
+
+ const isLoadedAllData = (plugins.filter(p => !!p).length + errorIndexes.length) === allPlugins.length
+
+ const { installedInfo } = useCheckInstalled({
+ pluginIds: plugins?.filter(p => !!p).map((d) => {
+ return `${d?.org || d?.author}/${d?.name}`
+ }) || [],
+ enabled: isLoadedAllData,
+ })
+
+ const getVersionInfo = useCallback((pluginId: string) => {
+ const pluginDetail = installedInfo?.[pluginId]
+ const hasInstalled = !!pluginDetail
+ return {
+ hasInstalled,
+ installedVersion: pluginDetail?.installedVersion,
+ toInstallVersion: '',
+ }
+ }, [installedInfo])
+
+ useEffect(() => {
+ if (isLoadedAllData && installedInfo)
+ onLoadedAllPlugin(installedInfo!)
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isLoadedAllData, installedInfo])
+
+ const handleSelect = useCallback((index: number) => {
+ return () => {
+ onSelect(plugins[index]!, index)
+ }
+ }, [onSelect, plugins])
+ return (
+ <>
+ {allPlugins.map((d, index) => {
+ if (errorIndexes.includes(index)) {
+ return (
+ <LoadingError key={index} />
+ )
+ }
+ const plugin = plugins[index]
+ if (d.type === 'github') {
+ return (<GithubItem
+ key={index}
+ checked={!!selectedPlugins.find(p => p.plugin_id === plugins[index]?.plugin_id)}
+ onCheckedChange={handleSelect(index)}
+ dependency={d as GitHubItemAndMarketPlaceDependency}
+ onFetchedPayload={handleGitHubPluginFetched(index)}
+ onFetchError={handleGitHubPluginFetchError(index)}
+ versionInfo={getVersionInfo(`${plugin?.org || plugin?.author}/${plugin?.name}`)}
+ />)
+ }
+
+ if (d.type === 'marketplace') {
+ return (
+ <MarketplaceItem
+ key={index}
+ checked={!!selectedPlugins.find(p => p.plugin_id === plugins[index]?.plugin_id)}
+ onCheckedChange={handleSelect(index)}
+ payload={plugin}
+ version={(d as GitHubItemAndMarketPlaceDependency).value.version! || plugin?.version || ''}
+ versionInfo={getVersionInfo(`${plugin?.org || plugin?.author}/${plugin?.name}`)}
+ />
+ )
+ }
+
+ // Local package
+ return (
+ <PackageItem
+ key={index}
+ checked={!!selectedPlugins.find(p => p.plugin_id === plugins[index]?.plugin_id)}
+ onCheckedChange={handleSelect(index)}
+ payload={d as PackageDependency}
+ isFromMarketPlace={isFromMarketPlace}
+ versionInfo={getVersionInfo(`${plugin?.org || plugin?.author}/${plugin?.name}`)}
+ />
+ )
+ })
+ }
+ </>
+ )
+}
+export default React.memo(InstallByDSLList)
diff --git a/app/components/plugins/install-plugin/install-bundle/steps/install.tsx b/app/components/plugins/install-plugin/install-bundle/steps/install.tsx
new file mode 100644
index 0000000..ee2699b
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-bundle/steps/install.tsx
@@ -0,0 +1,118 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback, useState } from 'react'
+import type { Dependency, InstallStatusResponse, Plugin, VersionInfo } from '../../../types'
+import Button from '@/app/components/base/button'
+import { RiLoader2Line } from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import InstallMulti from './install-multi'
+import { useInstallOrUpdate } from '@/service/use-plugins'
+import useRefreshPluginList from '../../hooks/use-refresh-plugin-list'
+import { useCanInstallPluginFromMarketplace } from '@/app/components/plugins/plugin-page/use-permission'
+const i18nPrefix = 'plugin.installModal'
+
+type Props = {
+ allPlugins: Dependency[]
+ onStartToInstall?: () => void
+ onInstalled: (plugins: Plugin[], installStatus: InstallStatusResponse[]) => void
+ onCancel: () => void
+ isFromMarketPlace?: boolean
+ isHideButton?: boolean
+}
+
+const Install: FC<Props> = ({
+ allPlugins,
+ onStartToInstall,
+ onInstalled,
+ onCancel,
+ isFromMarketPlace,
+ isHideButton,
+}) => {
+ const { t } = useTranslation()
+ const [selectedPlugins, setSelectedPlugins] = React.useState<Plugin[]>([])
+ const [selectedIndexes, setSelectedIndexes] = React.useState<number[]>([])
+ const selectedPluginsNum = selectedPlugins.length
+ const { refreshPluginList } = useRefreshPluginList()
+ const handleSelect = (plugin: Plugin, selectedIndex: number) => {
+ const isSelected = !!selectedPlugins.find(p => p.plugin_id === plugin.plugin_id)
+ let nextSelectedPlugins
+ if (isSelected)
+ nextSelectedPlugins = selectedPlugins.filter(p => p.plugin_id !== plugin.plugin_id)
+ else
+ nextSelectedPlugins = [...selectedPlugins, plugin]
+ setSelectedPlugins(nextSelectedPlugins)
+ const nextSelectedIndexes = isSelected ? selectedIndexes.filter(i => i !== selectedIndex) : [...selectedIndexes, selectedIndex]
+ setSelectedIndexes(nextSelectedIndexes)
+ }
+
+ const [canInstall, setCanInstall] = React.useState(false)
+ const [installedInfo, setInstalledInfo] = useState<Record<string, VersionInfo> | undefined>(undefined)
+
+ const handleLoadedAllPlugin = useCallback((installedInfo: Record<string, VersionInfo> | undefined) => {
+ setInstalledInfo(installedInfo)
+ setCanInstall(true)
+ }, [])
+
+ // Install from marketplace and github
+ const { mutate: installOrUpdate, isPending: isInstalling } = useInstallOrUpdate({
+ onSuccess: (res: InstallStatusResponse[]) => {
+ onInstalled(selectedPlugins, res.map((r, i) => {
+ return ({
+ ...r,
+ isFromMarketPlace: allPlugins[selectedIndexes[i]].type === 'marketplace',
+ })
+ }))
+ const hasInstallSuccess = res.some(r => r.success)
+ if (hasInstallSuccess)
+ refreshPluginList(undefined, true)
+ },
+ })
+ const handleInstall = () => {
+ onStartToInstall?.()
+ installOrUpdate({
+ payload: allPlugins.filter((_d, index) => selectedIndexes.includes(index)),
+ plugin: selectedPlugins,
+ installedInfo: installedInfo!,
+ })
+ }
+ const { canInstallPluginFromMarketplace } = useCanInstallPluginFromMarketplace()
+ return (
+ <>
+ <div className='flex flex-col items-start justify-center gap-4 self-stretch px-6 py-3'>
+ <div className='system-md-regular text-text-secondary'>
+ <p>{t(`${i18nPrefix}.${selectedPluginsNum > 1 ? 'readyToInstallPackages' : 'readyToInstallPackage'}`, { num: selectedPluginsNum })}</p>
+ </div>
+ <div className='w-full space-y-1 rounded-2xl bg-background-section-burn p-2'>
+ <InstallMulti
+ allPlugins={allPlugins}
+ selectedPlugins={selectedPlugins}
+ onSelect={handleSelect}
+ onLoadedAllPlugin={handleLoadedAllPlugin}
+ isFromMarketPlace={isFromMarketPlace}
+ />
+ </div>
+ </div>
+ {/* Action Buttons */}
+ {!isHideButton && (
+ <div className='flex items-center justify-end gap-2 self-stretch p-6 pt-5'>
+ {!canInstall && (
+ <Button variant='secondary' className='min-w-[72px]' onClick={onCancel}>
+ {t('common.operation.cancel')}
+ </Button>
+ )}
+ <Button
+ variant='primary'
+ className='flex min-w-[72px] space-x-0.5'
+ disabled={!canInstall || isInstalling || selectedPlugins.length === 0 || !canInstallPluginFromMarketplace}
+ onClick={handleInstall}
+ >
+ {isInstalling && <RiLoader2Line className='h-4 w-4 animate-spin-slow' />}
+ <span>{t(`${i18nPrefix}.${isInstalling ? 'installing' : 'install'}`)}</span>
+ </Button>
+ </div>
+ )}
+
+ </>
+ )
+}
+export default React.memo(Install)
diff --git a/app/components/plugins/install-plugin/install-bundle/steps/installed.tsx b/app/components/plugins/install-plugin/install-bundle/steps/installed.tsx
new file mode 100644
index 0000000..4e16d20
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-bundle/steps/installed.tsx
@@ -0,0 +1,65 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import type { InstallStatusResponse, Plugin } from '../../../types'
+import Card from '@/app/components/plugins/card'
+import Button from '@/app/components/base/button'
+import { useTranslation } from 'react-i18next'
+import Badge, { BadgeState } from '@/app/components/base/badge/index'
+import useGetIcon from '../../base/use-get-icon'
+import { MARKETPLACE_API_PREFIX } from '@/config'
+
+type Props = {
+ list: Plugin[]
+ installStatus: InstallStatusResponse[]
+ onCancel: () => void
+ isHideButton?: boolean
+}
+
+const Installed: FC<Props> = ({
+ list,
+ installStatus,
+ onCancel,
+ isHideButton,
+}) => {
+ const { t } = useTranslation()
+ const { getIconUrl } = useGetIcon()
+ return (
+ <>
+ <div className='flex flex-col items-start justify-center gap-4 self-stretch px-6 py-3'>
+ {/* <p className='text-text-secondary system-md-regular'>{(isFailed && errMsg) ? errMsg : t(`plugin.installModal.${isFailed ? 'installFailedDesc' : 'installedSuccessfullyDesc'}`)}</p> */}
+ <div className='flex flex-wrap content-start items-start gap-1 space-y-1 self-stretch rounded-2xl bg-background-section-burn p-2'>
+ {list.map((plugin, index) => {
+ return (
+ <Card
+ key={plugin.plugin_id}
+ className='w-full'
+ payload={{
+ ...plugin,
+ icon: installStatus[index].isFromMarketPlace ? `${MARKETPLACE_API_PREFIX}/plugins/${plugin.org}/${plugin.name}/icon` : getIconUrl(plugin.icon),
+ }}
+ installed={installStatus[index].success}
+ installFailed={!installStatus[index].success}
+ titleLeft={plugin.version ? <Badge className='mx-1' size="s" state={BadgeState.Default}>{plugin.version}</Badge> : null}
+ />
+ )
+ })}
+ </div>
+ </div>
+ {/* Action Buttons */}
+ {!isHideButton && (
+ <div className='flex items-center justify-end gap-2 self-stretch p-6 pt-5'>
+ <Button
+ variant='primary'
+ className='min-w-[72px]'
+ onClick={onCancel}
+ >
+ {t('common.operation.close')}
+ </Button>
+ </div>
+ )}
+ </>
+ )
+}
+
+export default React.memo(Installed)
diff --git a/app/components/plugins/install-plugin/install-from-github/index.tsx b/app/components/plugins/install-plugin/install-from-github/index.tsx
new file mode 100644
index 0000000..ceb800d
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-github/index.tsx
@@ -0,0 +1,235 @@
+'use client'
+
+import React, { useCallback, useState } from 'react'
+import Modal from '@/app/components/base/modal'
+import type { Item } from '@/app/components/base/select'
+import type { InstallState } from '@/app/components/plugins/types'
+import { useGitHubReleases } from '../hooks'
+import { convertRepoToUrl, parseGitHubUrl } from '../utils'
+import type { PluginDeclaration, UpdateFromGitHubPayload } from '../../types'
+import { InstallStepFromGitHub } from '../../types'
+import Toast from '@/app/components/base/toast'
+import SetURL from './steps/setURL'
+import SelectPackage from './steps/selectPackage'
+import Installed from '../base/installed'
+import Loaded from './steps/loaded'
+import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
+import { useTranslation } from 'react-i18next'
+import useRefreshPluginList from '../hooks/use-refresh-plugin-list'
+import cn from '@/utils/classnames'
+import useHideLogic from '../hooks/use-hide-logic'
+
+const i18nPrefix = 'plugin.installFromGitHub'
+
+type InstallFromGitHubProps = {
+ updatePayload?: UpdateFromGitHubPayload
+ onClose: () => void
+ onSuccess: () => void
+}
+
+const InstallFromGitHub: React.FC<InstallFromGitHubProps> = ({ updatePayload, onClose, onSuccess }) => {
+ const { t } = useTranslation()
+ const { getIconUrl } = useGetIcon()
+ const { fetchReleases } = useGitHubReleases()
+ const { refreshPluginList } = useRefreshPluginList()
+
+ const {
+ modalClassName,
+ foldAnimInto,
+ setIsInstalling,
+ handleStartToInstall,
+ } = useHideLogic(onClose)
+
+ const [state, setState] = useState<InstallState>({
+ step: updatePayload ? InstallStepFromGitHub.selectPackage : InstallStepFromGitHub.setUrl,
+ repoUrl: updatePayload?.originalPackageInfo?.repo
+ ? convertRepoToUrl(updatePayload.originalPackageInfo.repo)
+ : '',
+ selectedVersion: '',
+ selectedPackage: '',
+ releases: updatePayload ? updatePayload.originalPackageInfo.releases : [],
+ })
+ const [uniqueIdentifier, setUniqueIdentifier] = useState<string | null>(null)
+ const [manifest, setManifest] = useState<PluginDeclaration | null>(null)
+ const [errorMsg, setErrorMsg] = useState<string | null>(null)
+
+ const versions: Item[] = state.releases.map(release => ({
+ value: release.tag_name,
+ name: release.tag_name,
+ }))
+
+ const packages: Item[] = state.selectedVersion
+ ? (state.releases
+ .find(release => release.tag_name === state.selectedVersion)
+ ?.assets
+ .map(asset => ({
+ value: asset.name,
+ name: asset.name,
+ })) || [])
+ : []
+
+ const getTitle = useCallback(() => {
+ if (state.step === InstallStepFromGitHub.installed)
+ return t(`${i18nPrefix}.installedSuccessfully`)
+ if (state.step === InstallStepFromGitHub.installFailed)
+ return t(`${i18nPrefix}.installFailed`)
+
+ return updatePayload ? t(`${i18nPrefix}.updatePlugin`) : t(`${i18nPrefix}.installPlugin`)
+ }, [state.step, t, updatePayload])
+
+ const handleUrlSubmit = async () => {
+ const { isValid, owner, repo } = parseGitHubUrl(state.repoUrl)
+ if (!isValid || !owner || !repo) {
+ Toast.notify({
+ type: 'error',
+ message: t('plugin.error.inValidGitHubUrl'),
+ })
+ return
+ }
+ try {
+ const fetchedReleases = await fetchReleases(owner, repo)
+ if (fetchedReleases.length > 0) {
+ setState(prevState => ({
+ ...prevState,
+ releases: fetchedReleases,
+ step: InstallStepFromGitHub.selectPackage,
+ }))
+ }
+ else {
+ Toast.notify({
+ type: 'error',
+ message: t('plugin.error.noReleasesFound'),
+ })
+ }
+ }
+ catch {
+ Toast.notify({
+ type: 'error',
+ message: t('plugin.error.fetchReleasesError'),
+ })
+ }
+ }
+
+ const handleError = (e: any, isInstall: boolean) => {
+ const message = e?.response?.message || t('plugin.installModal.installFailedDesc')
+ setErrorMsg(message)
+ setState(prevState => ({ ...prevState, step: isInstall ? InstallStepFromGitHub.installFailed : InstallStepFromGitHub.uploadFailed }))
+ }
+
+ const handleUploaded = async (GitHubPackage: any) => {
+ try {
+ const icon = await getIconUrl(GitHubPackage.manifest.icon)
+ setManifest({
+ ...GitHubPackage.manifest,
+ icon,
+ })
+ setUniqueIdentifier(GitHubPackage.uniqueIdentifier)
+ setState(prevState => ({ ...prevState, step: InstallStepFromGitHub.readyToInstall }))
+ }
+ catch (e) {
+ handleError(e, false)
+ }
+ }
+
+ const handleUploadFail = useCallback((errorMsg: string) => {
+ setErrorMsg(errorMsg)
+ setState(prevState => ({ ...prevState, step: InstallStepFromGitHub.uploadFailed }))
+ }, [])
+
+ const handleInstalled = useCallback((notRefresh?: boolean) => {
+ setState(prevState => ({ ...prevState, step: InstallStepFromGitHub.installed }))
+ if (!notRefresh)
+ refreshPluginList(manifest)
+ setIsInstalling(false)
+ onSuccess()
+ }, [manifest, onSuccess, refreshPluginList, setIsInstalling])
+
+ const handleFailed = useCallback((errorMsg?: string) => {
+ setState(prevState => ({ ...prevState, step: InstallStepFromGitHub.installFailed }))
+ setIsInstalling(false)
+ if (errorMsg)
+ setErrorMsg(errorMsg)
+ }, [setIsInstalling])
+
+ const handleBack = () => {
+ setState((prevState) => {
+ switch (prevState.step) {
+ case InstallStepFromGitHub.selectPackage:
+ return { ...prevState, step: InstallStepFromGitHub.setUrl }
+ case InstallStepFromGitHub.readyToInstall:
+ return { ...prevState, step: InstallStepFromGitHub.selectPackage }
+ default:
+ return prevState
+ }
+ })
+ }
+
+ return (
+ <Modal
+ isShow={true}
+ onClose={foldAnimInto}
+ className={cn(modalClassName, `shadows-shadow-xl flex min-w-[560px] flex-col items-start rounded-2xl border-[0.5px]
+ border-components-panel-border bg-components-panel-bg p-0`)}
+ closable
+ >
+ <div className='flex items-start gap-2 self-stretch pb-3 pl-6 pr-14 pt-6'>
+ <div className='flex grow flex-col items-start gap-1'>
+ <div className='title-2xl-semi-bold self-stretch text-text-primary'>
+ {getTitle()}
+ </div>
+ <div className='system-xs-regular self-stretch text-text-tertiary'>
+ {!([InstallStepFromGitHub.uploadFailed, InstallStepFromGitHub.installed, InstallStepFromGitHub.installFailed].includes(state.step)) && t('plugin.installFromGitHub.installNote')}
+ </div>
+ </div>
+ </div>
+ {([InstallStepFromGitHub.uploadFailed, InstallStepFromGitHub.installed, InstallStepFromGitHub.installFailed].includes(state.step))
+ ? <Installed
+ payload={manifest}
+ isFailed={[InstallStepFromGitHub.uploadFailed, InstallStepFromGitHub.installFailed].includes(state.step)}
+ errMsg={errorMsg}
+ onCancel={onClose}
+ />
+ : <div className={`flex flex-col items-start justify-center self-stretch px-6 py-3 ${state.step === InstallStepFromGitHub.installed ? 'gap-2' : 'gap-4'}`}>
+ {state.step === InstallStepFromGitHub.setUrl && (
+ <SetURL
+ repoUrl={state.repoUrl}
+ onChange={value => setState(prevState => ({ ...prevState, repoUrl: value }))}
+ onNext={handleUrlSubmit}
+ onCancel={onClose}
+ />
+ )}
+ {state.step === InstallStepFromGitHub.selectPackage && (
+ <SelectPackage
+ updatePayload={updatePayload!}
+ repoUrl={state.repoUrl}
+ selectedVersion={state.selectedVersion}
+ versions={versions}
+ onSelectVersion={item => setState(prevState => ({ ...prevState, selectedVersion: item.value as string }))}
+ selectedPackage={state.selectedPackage}
+ packages={packages}
+ onSelectPackage={item => setState(prevState => ({ ...prevState, selectedPackage: item.value as string }))}
+ onUploaded={handleUploaded}
+ onFailed={handleUploadFail}
+ onBack={handleBack}
+ />
+ )}
+ {state.step === InstallStepFromGitHub.readyToInstall && (
+ <Loaded
+ updatePayload={updatePayload!}
+ uniqueIdentifier={uniqueIdentifier!}
+ payload={manifest as any}
+ repoUrl={state.repoUrl}
+ selectedVersion={state.selectedVersion}
+ selectedPackage={state.selectedPackage}
+ onBack={handleBack}
+ onStartToInstall={handleStartToInstall}
+ onInstalled={handleInstalled}
+ onFailed={handleFailed}
+ />
+ )}
+ </div>}
+ </Modal>
+ )
+}
+
+export default InstallFromGitHub
diff --git a/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx b/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx
new file mode 100644
index 0000000..0764f03
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx
@@ -0,0 +1,180 @@
+'use client'
+
+import React, { useEffect } from 'react'
+import Button from '@/app/components/base/button'
+import { type Plugin, type PluginDeclaration, TaskStatus, type UpdateFromGitHubPayload } from '../../../types'
+import Card from '../../../card'
+import { pluginManifestToCardPluginProps } from '../../utils'
+import { useTranslation } from 'react-i18next'
+import { updateFromGitHub } from '@/service/plugins'
+import { useInstallPackageFromGitHub } from '@/service/use-plugins'
+import { RiLoader2Line } from '@remixicon/react'
+import { usePluginTaskList } from '@/service/use-plugins'
+import checkTaskStatus from '../../base/check-task-status'
+import useCheckInstalled from '@/app/components/plugins/install-plugin/hooks/use-check-installed'
+import { parseGitHubUrl } from '../../utils'
+import Version from '../../base/version'
+
+type LoadedProps = {
+ updatePayload: UpdateFromGitHubPayload
+ uniqueIdentifier: string
+ payload: PluginDeclaration | Plugin
+ repoUrl: string
+ selectedVersion: string
+ selectedPackage: string
+ onBack: () => void
+ onStartToInstall?: () => void
+ onInstalled: (notRefresh?: boolean) => void
+ onFailed: (message?: string) => void
+}
+
+const i18nPrefix = 'plugin.installModal'
+
+const Loaded: React.FC<LoadedProps> = ({
+ updatePayload,
+ uniqueIdentifier,
+ payload,
+ repoUrl,
+ selectedVersion,
+ selectedPackage,
+ onBack,
+ onStartToInstall,
+ onInstalled,
+ onFailed,
+}) => {
+ const { t } = useTranslation()
+ const toInstallVersion = payload.version
+ const pluginId = (payload as Plugin).plugin_id
+ const { installedInfo, isLoading } = useCheckInstalled({
+ pluginIds: [pluginId],
+ enabled: !!pluginId,
+ })
+ const installedInfoPayload = installedInfo?.[pluginId]
+ const installedVersion = installedInfoPayload?.installedVersion
+ const hasInstalled = !!installedVersion
+
+ const [isInstalling, setIsInstalling] = React.useState(false)
+ const { mutateAsync: installPackageFromGitHub } = useInstallPackageFromGitHub()
+ const { handleRefetch } = usePluginTaskList(payload.category)
+ const { check } = checkTaskStatus()
+
+ useEffect(() => {
+ if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier)
+ onInstalled()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [hasInstalled])
+
+ const handleInstall = async () => {
+ if (isInstalling) return
+ setIsInstalling(true)
+ onStartToInstall?.()
+
+ try {
+ const { owner, repo } = parseGitHubUrl(repoUrl)
+ let taskId
+ let isInstalled
+ if (updatePayload) {
+ const { all_installed, task_id } = await updateFromGitHub(
+ `${owner}/${repo}`,
+ selectedVersion,
+ selectedPackage,
+ updatePayload.originalPackageInfo.id,
+ uniqueIdentifier,
+ )
+
+ taskId = task_id
+ isInstalled = all_installed
+ }
+ else {
+ if (hasInstalled) {
+ const {
+ all_installed,
+ task_id,
+ } = await updateFromGitHub(
+ `${owner}/${repo}`,
+ selectedVersion,
+ selectedPackage,
+ installedInfoPayload.uniqueIdentifier,
+ uniqueIdentifier,
+ )
+ taskId = task_id
+ isInstalled = all_installed
+ }
+ else {
+ const { all_installed, task_id } = await installPackageFromGitHub({
+ repoUrl: `${owner}/${repo}`,
+ selectedVersion,
+ selectedPackage,
+ uniqueIdentifier,
+ })
+
+ taskId = task_id
+ isInstalled = all_installed
+ }
+ }
+ if (isInstalled) {
+ onInstalled()
+ return
+ }
+
+ handleRefetch()
+
+ const { status, error } = await check({
+ taskId,
+ pluginUniqueIdentifier: uniqueIdentifier,
+ })
+ if (status === TaskStatus.failed) {
+ onFailed(error)
+ return
+ }
+ onInstalled(true)
+ }
+ catch (e) {
+ if (typeof e === 'string') {
+ onFailed(e)
+ return
+ }
+ onFailed()
+ }
+ finally {
+ setIsInstalling(false)
+ }
+ }
+
+ return (
+ <>
+ <div className='system-md-regular text-text-secondary'>
+ <p>{t(`${i18nPrefix}.readyToInstall`)}</p>
+ </div>
+ <div className='flex flex-wrap content-start items-start gap-1 self-stretch rounded-2xl bg-background-section-burn p-2'>
+ <Card
+ className='w-full'
+ payload={pluginManifestToCardPluginProps(payload as PluginDeclaration)}
+ titleLeft={!isLoading && <Version
+ hasInstalled={hasInstalled}
+ installedVersion={installedVersion}
+ toInstallVersion={toInstallVersion}
+ />}
+ />
+ </div>
+ <div className='mt-4 flex items-center justify-end gap-2 self-stretch'>
+ {!isInstalling && (
+ <Button variant='secondary' className='min-w-[72px]' onClick={onBack}>
+ {t('plugin.installModal.back')}
+ </Button>
+ )}
+ <Button
+ variant='primary'
+ className='flex min-w-[72px] space-x-0.5'
+ onClick={handleInstall}
+ disabled={isInstalling || isLoading}
+ >
+ {isInstalling && <RiLoader2Line className='h-4 w-4 animate-spin-slow' />}
+ <span>{t(`${i18nPrefix}.${isInstalling ? 'installing' : 'install'}`)}</span>
+ </Button>
+ </div>
+ </>
+ )
+}
+
+export default Loaded
diff --git a/app/components/plugins/install-plugin/install-from-github/steps/selectPackage.tsx b/app/components/plugins/install-plugin/install-from-github/steps/selectPackage.tsx
new file mode 100644
index 0000000..24e1e39
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-github/steps/selectPackage.tsx
@@ -0,0 +1,125 @@
+'use client'
+
+import React from 'react'
+import type { Item } from '@/app/components/base/select'
+import { PortalSelect } from '@/app/components/base/select'
+import Button from '@/app/components/base/button'
+import type { PluginDeclaration, UpdateFromGitHubPayload } from '../../../types'
+import { useTranslation } from 'react-i18next'
+import { useGitHubUpload } from '../../hooks'
+
+const i18nPrefix = 'plugin.installFromGitHub'
+
+type SelectPackageProps = {
+ updatePayload: UpdateFromGitHubPayload
+ repoUrl: string
+ selectedVersion: string
+ versions: Item[]
+ onSelectVersion: (item: Item) => void
+ selectedPackage: string
+ packages: Item[]
+ onSelectPackage: (item: Item) => void
+ onUploaded: (result: {
+ uniqueIdentifier: string
+ manifest: PluginDeclaration
+ }) => void
+ onFailed: (errorMsg: string) => void
+ onBack: () => void
+}
+
+const SelectPackage: React.FC<SelectPackageProps> = ({
+ updatePayload,
+ repoUrl,
+ selectedVersion,
+ versions,
+ onSelectVersion,
+ selectedPackage,
+ packages,
+ onSelectPackage,
+ onUploaded,
+ onFailed,
+ onBack,
+}) => {
+ const { t } = useTranslation()
+ const isEdit = Boolean(updatePayload)
+ const [isUploading, setIsUploading] = React.useState(false)
+ const { handleUpload } = useGitHubUpload()
+
+ const handleUploadPackage = async () => {
+ if (isUploading) return
+ setIsUploading(true)
+ try {
+ const repo = repoUrl.replace('https://github.com/', '')
+ await handleUpload(repo, selectedVersion, selectedPackage, (GitHubPackage) => {
+ onUploaded({
+ uniqueIdentifier: GitHubPackage.unique_identifier,
+ manifest: GitHubPackage.manifest,
+ })
+ })
+ }
+ catch (e: any) {
+ if (e.response?.message)
+ onFailed(e.response?.message)
+ else
+ onFailed(t(`${i18nPrefix}.uploadFailed`))
+ }
+ finally {
+ setIsUploading(false)
+ }
+ }
+
+ return (
+ <>
+ <label
+ htmlFor='version'
+ className='flex flex-col items-start justify-center self-stretch text-text-secondary'
+ >
+ <span className='system-sm-semibold'>{t(`${i18nPrefix}.selectVersion`)}</span>
+ </label>
+ <PortalSelect
+ value={selectedVersion}
+ onSelect={onSelectVersion}
+ items={versions}
+ installedValue={updatePayload?.originalPackageInfo.version}
+ placeholder={t(`${i18nPrefix}.selectVersionPlaceholder`) || ''}
+ popupClassName='w-[512px] z-[1001]'
+ />
+ <label
+ htmlFor='package'
+ className='flex flex-col items-start justify-center self-stretch text-text-secondary'
+ >
+ <span className='system-sm-semibold'>{t(`${i18nPrefix}.selectPackage`)}</span>
+ </label>
+ <PortalSelect
+ value={selectedPackage}
+ onSelect={onSelectPackage}
+ items={packages}
+ readonly={!selectedVersion}
+ placeholder={t(`${i18nPrefix}.selectPackagePlaceholder`) || ''}
+ popupClassName='w-[512px] z-[1001]'
+ />
+ <div className='mt-4 flex items-center justify-end gap-2 self-stretch'>
+ {!isEdit
+ && <Button
+ variant='secondary'
+ className='min-w-[72px]'
+ onClick={onBack}
+ disabled={isUploading}
+ >
+ {t('plugin.installModal.back')}
+ </Button>
+ }
+ <Button
+ variant='primary'
+ className='min-w-[72px]'
+ onClick={handleUploadPackage}
+ disabled={!selectedVersion || !selectedPackage || isUploading}
+ >
+ {t('plugin.installModal.next')}
+ </Button>
+ </div>
+ </>
+ )
+}
+
+export default SelectPackage
diff --git a/app/components/plugins/install-plugin/install-from-github/steps/setURL.tsx b/app/components/plugins/install-plugin/install-from-github/steps/setURL.tsx
new file mode 100644
index 0000000..be8ac67
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-github/steps/setURL.tsx
@@ -0,0 +1,56 @@
+'use client'
+
+import React from 'react'
+import Button from '@/app/components/base/button'
+import { useTranslation } from 'react-i18next'
+
+type SetURLProps = {
+ repoUrl: string
+ onChange: (value: string) => void
+ onNext: () => void
+ onCancel: () => void
+}
+
+const SetURL: React.FC<SetURLProps> = ({ repoUrl, onChange, onNext, onCancel }) => {
+ const { t } = useTranslation()
+ return (
+ <>
+ <label
+ htmlFor='repoUrl'
+ className='flex flex-col items-start justify-center self-stretch text-text-secondary'
+ >
+ <span className='system-sm-semibold'>{t('plugin.installFromGitHub.gitHubRepo')}</span>
+ </label>
+ <input
+ type='url'
+ id='repoUrl'
+ name='repoUrl'
+ value={repoUrl}
+ onChange={e => onChange(e.target.value)}
+ className='shadows-shadow-xs system-sm-regular flex grow items-center gap-[2px]
+ self-stretch overflow-hidden text-ellipsis rounded-lg border border-components-input-border-active
+ bg-components-input-bg-active p-2 text-components-input-text-filled'
+ placeholder='Please enter GitHub repo URL'
+ />
+ <div className='mt-4 flex items-center justify-end gap-2 self-stretch'>
+ <Button
+ variant='secondary'
+ className='min-w-[72px]'
+ onClick={onCancel}
+ >
+ {t('plugin.installModal.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ className='min-w-[72px]'
+ onClick={onNext}
+ disabled={!repoUrl.trim()}
+ >
+ {t('plugin.installModal.next')}
+ </Button>
+ </div>
+ </>
+ )
+}
+
+export default SetURL
diff --git a/app/components/plugins/install-plugin/install-from-local-package/index.tsx b/app/components/plugins/install-plugin/install-from-local-package/index.tsx
new file mode 100644
index 0000000..e8e6cf8
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-local-package/index.tsx
@@ -0,0 +1,133 @@
+'use client'
+
+import React, { useCallback, useState } from 'react'
+import Modal from '@/app/components/base/modal'
+import type { Dependency, PluginDeclaration } from '../../types'
+import { InstallStep } from '../../types'
+import Uploading from './steps/uploading'
+import { useTranslation } from 'react-i18next'
+import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
+import ReadyToInstallPackage from './ready-to-install'
+import ReadyToInstallBundle from '../install-bundle/ready-to-install'
+import useHideLogic from '../hooks/use-hide-logic'
+import cn from '@/utils/classnames'
+
+const i18nPrefix = 'plugin.installModal'
+
+type InstallFromLocalPackageProps = {
+ file: File
+ onSuccess: () => void
+ onClose: () => void
+}
+
+const InstallFromLocalPackage: React.FC<InstallFromLocalPackageProps> = ({
+ file,
+ onClose,
+}) => {
+ const { t } = useTranslation()
+ // uploading -> !uploadFailed -> readyToInstall -> installed/failed
+ const [step, setStep] = useState<InstallStep>(InstallStep.uploading)
+ const [uniqueIdentifier, setUniqueIdentifier] = useState<string | null>(null)
+ const [manifest, setManifest] = useState<PluginDeclaration | null>(null)
+ const [errorMsg, setErrorMsg] = useState<string | null>(null)
+ const isBundle = file.name.endsWith('.difybndl')
+ const [dependencies, setDependencies] = useState<Dependency[]>([])
+
+ const {
+ modalClassName,
+ foldAnimInto,
+ setIsInstalling,
+ handleStartToInstall,
+ } = useHideLogic(onClose)
+
+ const getTitle = useCallback(() => {
+ if (step === InstallStep.uploadFailed)
+ return t(`${i18nPrefix}.uploadFailed`)
+ if (isBundle && step === InstallStep.installed)
+ return t(`${i18nPrefix}.installComplete`)
+ if (step === InstallStep.installed)
+ return t(`${i18nPrefix}.installedSuccessfully`)
+ if (step === InstallStep.installFailed)
+ return t(`${i18nPrefix}.installFailed`)
+
+ return t(`${i18nPrefix}.installPlugin`)
+ }, [isBundle, step, t])
+
+ const { getIconUrl } = useGetIcon()
+
+ const handlePackageUploaded = useCallback(async (result: {
+ uniqueIdentifier: string
+ manifest: PluginDeclaration
+ }) => {
+ const {
+ manifest,
+ uniqueIdentifier,
+ } = result
+ const icon = await getIconUrl(manifest!.icon)
+ setUniqueIdentifier(uniqueIdentifier)
+ setManifest({
+ ...manifest,
+ icon,
+ })
+ setStep(InstallStep.readyToInstall)
+ }, [getIconUrl])
+
+ const handleBundleUploaded = useCallback((result: Dependency[]) => {
+ setDependencies(result)
+ setStep(InstallStep.readyToInstall)
+ }, [])
+
+ const handleUploadFail = useCallback((errorMsg: string) => {
+ setErrorMsg(errorMsg)
+ setStep(InstallStep.uploadFailed)
+ }, [])
+
+ return (
+ <Modal
+ isShow={true}
+ onClose={foldAnimInto}
+ className={cn(modalClassName, 'shadows-shadow-xl flex min-w-[560px] flex-col items-start rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-0')}
+ closable
+ >
+ <div className='flex items-start gap-2 self-stretch pb-3 pl-6 pr-14 pt-6'>
+ <div className='title-2xl-semi-bold self-stretch text-text-primary'>
+ {getTitle()}
+ </div>
+ </div>
+ {step === InstallStep.uploading && (
+ <Uploading
+ isBundle={isBundle}
+ file={file}
+ onCancel={onClose}
+ onPackageUploaded={handlePackageUploaded}
+ onBundleUploaded={handleBundleUploaded}
+ onFailed={handleUploadFail}
+ />
+ )}
+ {isBundle ? (
+ <ReadyToInstallBundle
+ step={step}
+ onStepChange={setStep}
+ onStartToInstall={handleStartToInstall}
+ setIsInstalling={setIsInstalling}
+ onClose={onClose}
+ allPlugins={dependencies}
+ />
+ ) : (
+ <ReadyToInstallPackage
+ step={step}
+ onStepChange={setStep}
+ onStartToInstall={handleStartToInstall}
+ setIsInstalling={setIsInstalling}
+ onClose={onClose}
+ uniqueIdentifier={uniqueIdentifier}
+ manifest={manifest}
+ errorMsg={errorMsg}
+ onError={setErrorMsg}
+ />
+ )}
+ </Modal>
+ )
+}
+
+export default InstallFromLocalPackage
diff --git a/app/components/plugins/install-plugin/install-from-local-package/ready-to-install.tsx b/app/components/plugins/install-plugin/install-from-local-package/ready-to-install.tsx
new file mode 100644
index 0000000..f85cde1
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-local-package/ready-to-install.tsx
@@ -0,0 +1,76 @@
+'use client'
+import type { FC } from 'react'
+import React, { useCallback } from 'react'
+import type { PluginDeclaration } from '../../types'
+import { InstallStep } from '../../types'
+import Install from './steps/install'
+import Installed from '../base/installed'
+import useRefreshPluginList from '../hooks/use-refresh-plugin-list'
+
+type Props = {
+ step: InstallStep
+ onStepChange: (step: InstallStep) => void,
+ onStartToInstall: () => void
+ setIsInstalling: (isInstalling: boolean) => void
+ onClose: () => void
+ uniqueIdentifier: string | null,
+ manifest: PluginDeclaration | null,
+ errorMsg: string | null,
+ onError: (errorMsg: string) => void,
+}
+
+const ReadyToInstall: FC<Props> = ({
+ step,
+ onStepChange,
+ onStartToInstall,
+ setIsInstalling,
+ onClose,
+ uniqueIdentifier,
+ manifest,
+ errorMsg,
+ onError,
+}) => {
+ const { refreshPluginList } = useRefreshPluginList()
+
+ const handleInstalled = useCallback((notRefresh?: boolean) => {
+ onStepChange(InstallStep.installed)
+ if (!notRefresh)
+ refreshPluginList(manifest)
+ setIsInstalling(false)
+ }, [manifest, onStepChange, refreshPluginList, setIsInstalling])
+
+ const handleFailed = useCallback((errorMsg?: string) => {
+ onStepChange(InstallStep.installFailed)
+ setIsInstalling(false)
+ if (errorMsg)
+ onError(errorMsg)
+ }, [onError, onStepChange, setIsInstalling])
+
+ return (
+ <>
+ {
+ step === InstallStep.readyToInstall && (
+ <Install
+ uniqueIdentifier={uniqueIdentifier!}
+ payload={manifest!}
+ onCancel={onClose}
+ onInstalled={handleInstalled}
+ onFailed={handleFailed}
+ onStartToInstall={onStartToInstall}
+ />
+ )
+ }
+ {
+ ([InstallStep.uploadFailed, InstallStep.installed, InstallStep.installFailed].includes(step)) && (
+ <Installed
+ payload={manifest}
+ isFailed={[InstallStep.uploadFailed, InstallStep.installFailed].includes(step)}
+ errMsg={errorMsg}
+ onCancel={onClose}
+ />
+ )
+ }
+ </>
+ )
+}
+export default React.memo(ReadyToInstall)
diff --git a/app/components/plugins/install-plugin/install-from-local-package/steps/install.tsx b/app/components/plugins/install-plugin/install-from-local-package/steps/install.tsx
new file mode 100644
index 0000000..4125172
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-local-package/steps/install.tsx
@@ -0,0 +1,164 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useMemo } from 'react'
+import { type PluginDeclaration, TaskStatus } from '../../../types'
+import Card from '../../../card'
+import { pluginManifestToCardPluginProps } from '../../utils'
+import Button from '@/app/components/base/button'
+import { Trans, useTranslation } from 'react-i18next'
+import { RiLoader2Line } from '@remixicon/react'
+import checkTaskStatus from '../../base/check-task-status'
+import { useInstallPackageFromLocal, usePluginTaskList } from '@/service/use-plugins'
+import useCheckInstalled from '@/app/components/plugins/install-plugin/hooks/use-check-installed'
+import { uninstallPlugin } from '@/service/plugins'
+import Version from '../../base/version'
+import { useAppContext } from '@/context/app-context'
+import { gte } from 'semver'
+
+const i18nPrefix = 'plugin.installModal'
+
+type Props = {
+ uniqueIdentifier: string
+ payload: PluginDeclaration
+ onCancel: () => void
+ onStartToInstall?: () => void
+ onInstalled: (notRefresh?: boolean) => void
+ onFailed: (message?: string) => void
+}
+
+const Installed: FC<Props> = ({
+ uniqueIdentifier,
+ payload,
+ onCancel,
+ onStartToInstall,
+ onInstalled,
+ onFailed,
+}) => {
+ const { t } = useTranslation()
+ const toInstallVersion = payload.version
+ const pluginId = `${payload.author}/${payload.name}`
+ const { installedInfo, isLoading } = useCheckInstalled({
+ pluginIds: [pluginId],
+ enabled: !!pluginId,
+ })
+ const installedInfoPayload = installedInfo?.[pluginId]
+ const installedVersion = installedInfoPayload?.installedVersion
+ const hasInstalled = !!installedVersion
+
+ useEffect(() => {
+ if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier)
+ onInstalled()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [hasInstalled])
+
+ const [isInstalling, setIsInstalling] = React.useState(false)
+ const { mutateAsync: installPackageFromLocal } = useInstallPackageFromLocal()
+
+ const {
+ check,
+ stop,
+ } = checkTaskStatus()
+
+ const handleCancel = () => {
+ stop()
+ onCancel()
+ }
+
+ const { handleRefetch } = usePluginTaskList(payload.category)
+ const handleInstall = async () => {
+ if (isInstalling) return
+ setIsInstalling(true)
+ onStartToInstall?.()
+
+ try {
+ if (hasInstalled)
+ await uninstallPlugin(installedInfoPayload.installedId)
+
+ const {
+ all_installed,
+ task_id,
+ } = await installPackageFromLocal(uniqueIdentifier)
+ const taskId = task_id
+ const isInstalled = all_installed
+
+ if (isInstalled) {
+ onInstalled()
+ return
+ }
+ handleRefetch()
+ const { status, error } = await check({
+ taskId,
+ pluginUniqueIdentifier: uniqueIdentifier,
+ })
+ if (status === TaskStatus.failed) {
+ onFailed(error)
+ return
+ }
+ onInstalled(true)
+ }
+ catch (e) {
+ if (typeof e === 'string') {
+ onFailed(e)
+ return
+ }
+ onFailed()
+ }
+ }
+
+ const { langeniusVersionInfo } = useAppContext()
+ const isDifyVersionCompatible = useMemo(() => {
+ if (!langeniusVersionInfo.current_version)
+ return true
+ return gte(langeniusVersionInfo.current_version, payload.meta.minimum_dify_version ?? '0.0.0')
+ }, [langeniusVersionInfo.current_version, payload.meta.minimum_dify_version])
+
+ return (
+ <>
+ <div className='flex flex-col items-start justify-center gap-4 self-stretch px-6 py-3'>
+ <div className='system-md-regular text-text-secondary'>
+ <p>{t(`${i18nPrefix}.readyToInstall`)}</p>
+ <p>
+ <Trans
+ i18nKey={`${i18nPrefix}.fromTrustSource`}
+ components={{ trustSource: <span className='system-md-semibold' /> }}
+ />
+ </p>
+ {!isDifyVersionCompatible && (
+ <p className='system-md-regular flex items-center gap-1 text-text-secondary text-text-warning'>
+ {t('plugin.difyVersionNotCompatible', { minimalDifyVersion: payload.meta.minimum_dify_version })}
+ </p>
+ )}
+ </div>
+ <div className='flex flex-wrap content-start items-start gap-1 self-stretch rounded-2xl bg-background-section-burn p-2'>
+ <Card
+ className='w-full'
+ payload={pluginManifestToCardPluginProps(payload)}
+ titleLeft={!isLoading && <Version
+ hasInstalled={hasInstalled}
+ installedVersion={installedVersion}
+ toInstallVersion={toInstallVersion}
+ />}
+ />
+ </div>
+ </div>
+ {/* Action Buttons */}
+ <div className='flex items-center justify-end gap-2 self-stretch p-6 pt-5'>
+ {!isInstalling && (
+ <Button variant='secondary' className='min-w-[72px]' onClick={handleCancel}>
+ {t('common.operation.cancel')}
+ </Button>
+ )}
+ <Button
+ variant='primary'
+ className='flex min-w-[72px] space-x-0.5'
+ disabled={isInstalling || isLoading}
+ onClick={handleInstall}
+ >
+ {isInstalling && <RiLoader2Line className='h-4 w-4 animate-spin-slow' />}
+ <span>{t(`${i18nPrefix}.${isInstalling ? 'installing' : 'install'}`)}</span>
+ </Button>
+ </div>
+ </>
+ )
+}
+export default React.memo(Installed)
diff --git a/app/components/plugins/install-plugin/install-from-local-package/steps/uploading.tsx b/app/components/plugins/install-plugin/install-from-local-package/steps/uploading.tsx
new file mode 100644
index 0000000..5b1c478
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-local-package/steps/uploading.tsx
@@ -0,0 +1,99 @@
+'use client'
+import type { FC } from 'react'
+import React from 'react'
+import { RiLoader2Line } from '@remixicon/react'
+import Card from '../../../card'
+import type { Dependency, PluginDeclaration } from '../../../types'
+import Button from '@/app/components/base/button'
+import { useTranslation } from 'react-i18next'
+import { uploadFile } from '@/service/plugins'
+const i18nPrefix = 'plugin.installModal'
+
+type Props = {
+ isBundle: boolean
+ file: File
+ onCancel: () => void
+ onPackageUploaded: (result: {
+ uniqueIdentifier: string
+ manifest: PluginDeclaration
+ }) => void
+ onBundleUploaded: (result: Dependency[]) => void
+ onFailed: (errorMsg: string) => void
+}
+
+const Uploading: FC<Props> = ({
+ isBundle,
+ file,
+ onCancel,
+ onPackageUploaded,
+ onBundleUploaded,
+ onFailed,
+}) => {
+ const { t } = useTranslation()
+ const fileName = file.name
+ const handleUpload = async () => {
+ try {
+ await uploadFile(file, isBundle)
+ }
+ catch (e: any) {
+ if (e.response?.message) {
+ onFailed(e.response?.message)
+ }
+ else { // Why it would into this branch?
+ const res = e.response
+ if (isBundle) {
+ onBundleUploaded(res)
+ return
+ }
+ onPackageUploaded({
+ uniqueIdentifier: res.unique_identifier,
+ manifest: res.manifest,
+ })
+ }
+ }
+ }
+
+ React.useEffect(() => {
+ handleUpload()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+ return (
+ <>
+ <div className='flex flex-col items-start justify-center gap-4 self-stretch px-6 py-3'>
+ <div className='flex items-center gap-1 self-stretch'>
+ <RiLoader2Line className='h-4 w-4 animate-spin-slow text-text-accent' />
+ <div className='system-md-regular text-text-secondary'>
+ {t(`${i18nPrefix}.uploadingPackage`, {
+ packageName: fileName,
+ })}
+ </div>
+ </div>
+ <div className='flex flex-wrap content-start items-start gap-1 self-stretch rounded-2xl bg-background-section-burn p-2'>
+ <Card
+ className='w-full'
+ payload={{ name: fileName } as any}
+ isLoading
+ loadingFileName={fileName}
+ installed={false}
+ />
+ </div>
+ </div>
+
+ {/* Action Buttons */}
+ <div className='flex items-center justify-end gap-2 self-stretch p-6 pt-5'>
+ <Button variant='secondary' className='min-w-[72px]' onClick={onCancel}>
+ {t('common.operation.cancel')}
+ </Button>
+ <Button
+ variant='primary'
+ className='min-w-[72px]'
+ disabled
+ >
+ {t(`${i18nPrefix}.install`)}
+ </Button>
+ </div>
+ </>
+ )
+}
+
+export default React.memo(Uploading)
diff --git a/app/components/plugins/install-plugin/install-from-marketplace/index.tsx b/app/components/plugins/install-plugin/install-from-marketplace/index.tsx
new file mode 100644
index 0000000..f41cd61
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-marketplace/index.tsx
@@ -0,0 +1,125 @@
+'use client'
+
+import React, { useCallback, useState } from 'react'
+import Modal from '@/app/components/base/modal'
+import type { Dependency, Plugin, PluginManifestInMarket } from '../../types'
+import { InstallStep } from '../../types'
+import Install from './steps/install'
+import Installed from '../base/installed'
+import { useTranslation } from 'react-i18next'
+import useRefreshPluginList from '../hooks/use-refresh-plugin-list'
+import ReadyToInstallBundle from '../install-bundle/ready-to-install'
+import cn from '@/utils/classnames'
+import useHideLogic from '../hooks/use-hide-logic'
+
+const i18nPrefix = 'plugin.installModal'
+
+type InstallFromMarketplaceProps = {
+ uniqueIdentifier: string
+ manifest: PluginManifestInMarket | Plugin
+ isBundle?: boolean
+ dependencies?: Dependency[]
+ onSuccess: () => void
+ onClose: () => void
+}
+
+const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
+ uniqueIdentifier,
+ manifest,
+ isBundle,
+ dependencies,
+ onSuccess,
+ onClose,
+}) => {
+ const { t } = useTranslation()
+ // readyToInstall -> check installed -> installed/failed
+ const [step, setStep] = useState<InstallStep>(InstallStep.readyToInstall)
+ const [errorMsg, setErrorMsg] = useState<string | null>(null)
+ const { refreshPluginList } = useRefreshPluginList()
+
+ const {
+ modalClassName,
+ foldAnimInto,
+ setIsInstalling,
+ handleStartToInstall,
+ } = useHideLogic(onClose)
+
+ const getTitle = useCallback(() => {
+ if (isBundle && step === InstallStep.installed)
+ return t(`${i18nPrefix}.installComplete`)
+ if (step === InstallStep.installed)
+ return t(`${i18nPrefix}.installedSuccessfully`)
+ if (step === InstallStep.installFailed)
+ return t(`${i18nPrefix}.installFailed`)
+ return t(`${i18nPrefix}.installPlugin`)
+ }, [isBundle, step, t])
+
+ const handleInstalled = useCallback((notRefresh?: boolean) => {
+ setStep(InstallStep.installed)
+ if (!notRefresh)
+ refreshPluginList(manifest)
+ setIsInstalling(false)
+ }, [manifest, refreshPluginList, setIsInstalling])
+
+ const handleFailed = useCallback((errorMsg?: string) => {
+ setStep(InstallStep.installFailed)
+ setIsInstalling(false)
+ if (errorMsg)
+ setErrorMsg(errorMsg)
+ }, [setIsInstalling])
+
+ return (
+ <Modal
+ isShow={true}
+ onClose={foldAnimInto}
+ wrapperClassName='z-[9999]'
+ className={cn(modalClassName, 'shadows-shadow-xl flex min-w-[560px] flex-col items-start rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-0')}
+ closable
+ >
+ <div className='flex items-start gap-2 self-stretch pb-3 pl-6 pr-14 pt-6'>
+ <div className='title-2xl-semi-bold self-stretch text-text-primary'>
+ {getTitle()}
+ </div>
+ </div>
+ {
+ isBundle ? (
+ <ReadyToInstallBundle
+ step={step}
+ onStepChange={setStep}
+ onStartToInstall={handleStartToInstall}
+ setIsInstalling={setIsInstalling}
+ onClose={onClose}
+ allPlugins={dependencies!}
+ isFromMarketPlace
+ />
+ ) : (<>
+ {
+ step === InstallStep.readyToInstall && (
+ <Install
+ uniqueIdentifier={uniqueIdentifier}
+ payload={manifest!}
+ onCancel={onClose}
+ onInstalled={handleInstalled}
+ onFailed={handleFailed}
+ onStartToInstall={handleStartToInstall}
+ />
+ )}
+ {
+ [InstallStep.installed, InstallStep.installFailed].includes(step) && (
+ <Installed
+ payload={manifest!}
+ isMarketPayload
+ isFailed={step === InstallStep.installFailed}
+ errMsg={errorMsg}
+ onCancel={onSuccess}
+ />
+ )
+ }
+ </>
+ )
+ }
+ </Modal >
+ )
+}
+
+export default InstallFromMarketplace
diff --git a/app/components/plugins/install-plugin/install-from-marketplace/steps/install.tsx b/app/components/plugins/install-plugin/install-from-marketplace/steps/install.tsx
new file mode 100644
index 0000000..53f1f40
--- /dev/null
+++ b/app/components/plugins/install-plugin/install-from-marketplace/steps/install.tsx
@@ -0,0 +1,172 @@
+'use client'
+import type { FC } from 'react'
+import React, { useEffect, useMemo } from 'react'
+// import { RiInformation2Line } from '@remixicon/react'
+import { type Plugin, type PluginManifestInMarket, TaskStatus } from '../../../types'
+import Card from '../../../card'
+import { pluginManifestInMarketToPluginProps } from '../../utils'
+import Button from '@/app/components/base/button'
+import { useTranslation } from 'react-i18next'
+import { RiLoader2Line } from '@remixicon/react'